blob: 47c6e4798baf42f8a8a44e2514ee12bad94c4b70 [file] [log] [blame]
Jingoo Hane9474be2012-02-03 18:01:55 +09001/*
2 * Samsung SoC DP (Display Port) interface driver.
3 *
4 * Copyright (C) 2012 Samsung Electronics Co., Ltd.
5 * Author: Jingoo Han <jg1.han@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12
13#include <linux/module.h>
14#include <linux/platform_device.h>
Jingoo Hane9474be2012-02-03 18:01:55 +090015#include <linux/err.h>
16#include <linux/clk.h>
17#include <linux/io.h>
18#include <linux/interrupt.h>
Ajay Kumarc4e235c2012-10-13 05:48:00 +090019#include <linux/of.h>
Andrew Brestickerb8b52472014-04-22 04:09:10 +053020#include <linux/of_gpio.h>
21#include <linux/gpio.h>
Inki Daef37cd5e2014-05-09 14:25:20 +090022#include <linux/component.h>
Jingoo Han8114fab2013-10-16 21:58:16 +053023#include <linux/phy/phy.h>
Sean Paul1417f102014-01-30 16:19:23 -050024#include <video/of_display_timing.h>
25#include <video/of_videomode.h>
Jingoo Hane9474be2012-02-03 18:01:55 +090026
Sean Paul1417f102014-01-30 16:19:23 -050027#include <drm/drmP.h>
Sean Paulcaa5d1e2014-01-30 16:19:30 -050028#include <drm/drm_crtc.h>
29#include <drm/drm_crtc_helper.h>
Ajay Kumar5f1dcd82014-07-31 23:12:14 +053030#include <drm/drm_panel.h>
Sean Paul1634ba22014-02-24 19:20:15 +090031#include <drm/bridge/ptn3460.h>
Sean Paul1417f102014-01-30 16:19:23 -050032
Jingoo Hane9474be2012-02-03 18:01:55 +090033#include "exynos_dp_core.h"
34
Sean Paulcaa5d1e2014-01-30 16:19:30 -050035#define ctx_from_connector(c) container_of(c, struct exynos_dp_device, \
36 connector)
37
Sean Paul1634ba22014-02-24 19:20:15 +090038struct bridge_init {
39 struct i2c_client *client;
40 struct device_node *node;
41};
42
Ajay Kumar5f1dcd82014-07-31 23:12:14 +053043static void exynos_dp_init_dp(struct exynos_dp_device *dp)
Jingoo Hane9474be2012-02-03 18:01:55 +090044{
45 exynos_dp_reset(dp);
46
Jingoo Han24db03a2012-05-25 16:21:08 +090047 exynos_dp_swreset(dp);
48
Jingoo Han75435c72012-08-23 19:55:13 +090049 exynos_dp_init_analog_param(dp);
50 exynos_dp_init_interrupt(dp);
51
Jingoo Hane9474be2012-02-03 18:01:55 +090052 /* SW defined function Normal operation */
53 exynos_dp_enable_sw_function(dp);
54
55 exynos_dp_config_interrupt(dp);
56 exynos_dp_init_analog_func(dp);
57
58 exynos_dp_init_hpd(dp);
59 exynos_dp_init_aux(dp);
Jingoo Hane9474be2012-02-03 18:01:55 +090060}
61
62static int exynos_dp_detect_hpd(struct exynos_dp_device *dp)
63{
64 int timeout_loop = 0;
65
Jingoo Hane9474be2012-02-03 18:01:55 +090066 while (exynos_dp_get_plug_in_status(dp) != 0) {
67 timeout_loop++;
68 if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
69 dev_err(dp->dev, "failed to get hpd plug status\n");
70 return -ETIMEDOUT;
71 }
Jingoo Hana2c81bc2012-07-18 18:50:59 +090072 usleep_range(10, 11);
Jingoo Hane9474be2012-02-03 18:01:55 +090073 }
74
75 return 0;
76}
77
78static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data)
79{
80 int i;
81 unsigned char sum = 0;
82
83 for (i = 0; i < EDID_BLOCK_LENGTH; i++)
84 sum = sum + edid_data[i];
85
86 return sum;
87}
88
89static int exynos_dp_read_edid(struct exynos_dp_device *dp)
90{
91 unsigned char edid[EDID_BLOCK_LENGTH * 2];
92 unsigned int extend_block = 0;
93 unsigned char sum;
94 unsigned char test_vector;
95 int retval;
96
97 /*
98 * EDID device address is 0x50.
99 * However, if necessary, you must have set upper address
100 * into E-EDID in I2C device, 0x30.
101 */
102
103 /* Read Extension Flag, Number of 128-byte EDID extension blocks */
Sean Paul99f54152012-11-01 02:13:00 +0000104 retval = exynos_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
Jingoo Hane9474be2012-02-03 18:01:55 +0900105 EDID_EXTENSION_FLAG,
106 &extend_block);
Sean Paul99f54152012-11-01 02:13:00 +0000107 if (retval)
108 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900109
110 if (extend_block > 0) {
111 dev_dbg(dp->dev, "EDID data includes a single extension!\n");
112
113 /* Read EDID data */
114 retval = exynos_dp_read_bytes_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
115 EDID_HEADER_PATTERN,
116 EDID_BLOCK_LENGTH,
117 &edid[EDID_HEADER_PATTERN]);
118 if (retval != 0) {
119 dev_err(dp->dev, "EDID Read failed!\n");
120 return -EIO;
121 }
122 sum = exynos_dp_calc_edid_check_sum(edid);
123 if (sum != 0) {
124 dev_err(dp->dev, "EDID bad checksum!\n");
125 return -EIO;
126 }
127
128 /* Read additional EDID data */
129 retval = exynos_dp_read_bytes_from_i2c(dp,
130 I2C_EDID_DEVICE_ADDR,
131 EDID_BLOCK_LENGTH,
132 EDID_BLOCK_LENGTH,
133 &edid[EDID_BLOCK_LENGTH]);
134 if (retval != 0) {
135 dev_err(dp->dev, "EDID Read failed!\n");
136 return -EIO;
137 }
138 sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]);
139 if (sum != 0) {
140 dev_err(dp->dev, "EDID bad checksum!\n");
141 return -EIO;
142 }
143
Jingoo Han073ea2a2014-05-07 20:44:51 +0900144 exynos_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST,
Jingoo Hane9474be2012-02-03 18:01:55 +0900145 &test_vector);
Jingoo Han073ea2a2014-05-07 20:44:51 +0900146 if (test_vector & DP_TEST_LINK_EDID_READ) {
Jingoo Hane9474be2012-02-03 18:01:55 +0900147 exynos_dp_write_byte_to_dpcd(dp,
Jingoo Han073ea2a2014-05-07 20:44:51 +0900148 DP_TEST_EDID_CHECKSUM,
Jingoo Hane9474be2012-02-03 18:01:55 +0900149 edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
150 exynos_dp_write_byte_to_dpcd(dp,
Jingoo Han073ea2a2014-05-07 20:44:51 +0900151 DP_TEST_RESPONSE,
152 DP_TEST_EDID_CHECKSUM_WRITE);
Jingoo Hane9474be2012-02-03 18:01:55 +0900153 }
154 } else {
155 dev_info(dp->dev, "EDID data does not include any extensions.\n");
156
157 /* Read EDID data */
158 retval = exynos_dp_read_bytes_from_i2c(dp,
159 I2C_EDID_DEVICE_ADDR,
160 EDID_HEADER_PATTERN,
161 EDID_BLOCK_LENGTH,
162 &edid[EDID_HEADER_PATTERN]);
163 if (retval != 0) {
164 dev_err(dp->dev, "EDID Read failed!\n");
165 return -EIO;
166 }
167 sum = exynos_dp_calc_edid_check_sum(edid);
168 if (sum != 0) {
169 dev_err(dp->dev, "EDID bad checksum!\n");
170 return -EIO;
171 }
172
173 exynos_dp_read_byte_from_dpcd(dp,
Jingoo Han073ea2a2014-05-07 20:44:51 +0900174 DP_TEST_REQUEST,
Jingoo Hane9474be2012-02-03 18:01:55 +0900175 &test_vector);
Jingoo Han073ea2a2014-05-07 20:44:51 +0900176 if (test_vector & DP_TEST_LINK_EDID_READ) {
Jingoo Hane9474be2012-02-03 18:01:55 +0900177 exynos_dp_write_byte_to_dpcd(dp,
Jingoo Han073ea2a2014-05-07 20:44:51 +0900178 DP_TEST_EDID_CHECKSUM,
Jingoo Hane9474be2012-02-03 18:01:55 +0900179 edid[EDID_CHECKSUM]);
180 exynos_dp_write_byte_to_dpcd(dp,
Jingoo Han073ea2a2014-05-07 20:44:51 +0900181 DP_TEST_RESPONSE,
182 DP_TEST_EDID_CHECKSUM_WRITE);
Jingoo Hane9474be2012-02-03 18:01:55 +0900183 }
184 }
185
186 dev_err(dp->dev, "EDID Read success!\n");
187 return 0;
188}
189
190static int exynos_dp_handle_edid(struct exynos_dp_device *dp)
191{
192 u8 buf[12];
193 int i;
194 int retval;
195
Jingoo Han073ea2a2014-05-07 20:44:51 +0900196 /* Read DPCD DP_DPCD_REV~RECEIVE_PORT1_CAP_1 */
197 retval = exynos_dp_read_bytes_from_dpcd(dp, DP_DPCD_REV,
Sean Paul99f54152012-11-01 02:13:00 +0000198 12, buf);
199 if (retval)
200 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900201
202 /* Read EDID */
203 for (i = 0; i < 3; i++) {
204 retval = exynos_dp_read_edid(dp);
Sean Paul99f54152012-11-01 02:13:00 +0000205 if (!retval)
Jingoo Hane9474be2012-02-03 18:01:55 +0900206 break;
207 }
208
209 return retval;
210}
211
212static void exynos_dp_enable_rx_to_enhanced_mode(struct exynos_dp_device *dp,
213 bool enable)
214{
215 u8 data;
216
Jingoo Han073ea2a2014-05-07 20:44:51 +0900217 exynos_dp_read_byte_from_dpcd(dp, DP_LANE_COUNT_SET, &data);
Jingoo Hane9474be2012-02-03 18:01:55 +0900218
219 if (enable)
Jingoo Han073ea2a2014-05-07 20:44:51 +0900220 exynos_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET,
221 DP_LANE_COUNT_ENHANCED_FRAME_EN |
Jingoo Hane9474be2012-02-03 18:01:55 +0900222 DPCD_LANE_COUNT_SET(data));
223 else
Jingoo Han073ea2a2014-05-07 20:44:51 +0900224 exynos_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET,
Jingoo Hane9474be2012-02-03 18:01:55 +0900225 DPCD_LANE_COUNT_SET(data));
226}
227
228static int exynos_dp_is_enhanced_mode_available(struct exynos_dp_device *dp)
229{
230 u8 data;
231 int retval;
232
Jingoo Han073ea2a2014-05-07 20:44:51 +0900233 exynos_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data);
Jingoo Hane9474be2012-02-03 18:01:55 +0900234 retval = DPCD_ENHANCED_FRAME_CAP(data);
235
236 return retval;
237}
238
239static void exynos_dp_set_enhanced_mode(struct exynos_dp_device *dp)
240{
241 u8 data;
242
243 data = exynos_dp_is_enhanced_mode_available(dp);
244 exynos_dp_enable_rx_to_enhanced_mode(dp, data);
245 exynos_dp_enable_enhanced_mode(dp, data);
246}
247
248static void exynos_dp_training_pattern_dis(struct exynos_dp_device *dp)
249{
250 exynos_dp_set_training_pattern(dp, DP_NONE);
251
252 exynos_dp_write_byte_to_dpcd(dp,
Jingoo Han073ea2a2014-05-07 20:44:51 +0900253 DP_TRAINING_PATTERN_SET,
254 DP_TRAINING_PATTERN_DISABLE);
Jingoo Hane9474be2012-02-03 18:01:55 +0900255}
256
257static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp,
258 int pre_emphasis, int lane)
259{
260 switch (lane) {
261 case 0:
262 exynos_dp_set_lane0_pre_emphasis(dp, pre_emphasis);
263 break;
264 case 1:
265 exynos_dp_set_lane1_pre_emphasis(dp, pre_emphasis);
266 break;
267
268 case 2:
269 exynos_dp_set_lane2_pre_emphasis(dp, pre_emphasis);
270 break;
271
272 case 3:
273 exynos_dp_set_lane3_pre_emphasis(dp, pre_emphasis);
274 break;
275 }
276}
277
Sean Paulace2d7f2012-10-31 23:21:00 +0000278static int exynos_dp_link_start(struct exynos_dp_device *dp)
Jingoo Hane9474be2012-02-03 18:01:55 +0900279{
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900280 u8 buf[4];
Sean Paul49ce41f2012-10-31 23:21:00 +0000281 int lane, lane_count, pll_tries, retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900282
283 lane_count = dp->link_train.lane_count;
284
285 dp->link_train.lt_state = CLOCK_RECOVERY;
286 dp->link_train.eq_loop = 0;
287
288 for (lane = 0; lane < lane_count; lane++)
289 dp->link_train.cr_loop[lane] = 0;
290
Jingoo Hane9474be2012-02-03 18:01:55 +0900291 /* Set link rate and count as you want to establish*/
292 exynos_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
293 exynos_dp_set_lane_count(dp, dp->link_train.lane_count);
294
295 /* Setup RX configuration */
296 buf[0] = dp->link_train.link_rate;
297 buf[1] = dp->link_train.lane_count;
Jingoo Han073ea2a2014-05-07 20:44:51 +0900298 retval = exynos_dp_write_bytes_to_dpcd(dp, DP_LINK_BW_SET,
Jingoo Hane9474be2012-02-03 18:01:55 +0900299 2, buf);
Sean Paulace2d7f2012-10-31 23:21:00 +0000300 if (retval)
301 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900302
303 /* Set TX pre-emphasis to minimum */
304 for (lane = 0; lane < lane_count; lane++)
305 exynos_dp_set_lane_lane_pre_emphasis(dp,
306 PRE_EMPHASIS_LEVEL_0, lane);
307
Sean Paul49ce41f2012-10-31 23:21:00 +0000308 /* Wait for PLL lock */
309 pll_tries = 0;
310 while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
311 if (pll_tries == DP_TIMEOUT_LOOP_COUNT) {
312 dev_err(dp->dev, "Wait for PLL lock timed out\n");
313 return -ETIMEDOUT;
314 }
315
316 pll_tries++;
317 usleep_range(90, 120);
318 }
319
Jingoo Hane9474be2012-02-03 18:01:55 +0900320 /* Set training pattern 1 */
321 exynos_dp_set_training_pattern(dp, TRAINING_PTN1);
322
323 /* Set RX training pattern */
Sean Paulfadec4b2012-10-31 23:21:00 +0000324 retval = exynos_dp_write_byte_to_dpcd(dp,
Jingoo Han073ea2a2014-05-07 20:44:51 +0900325 DP_TRAINING_PATTERN_SET,
326 DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_1);
Sean Paulfadec4b2012-10-31 23:21:00 +0000327 if (retval)
328 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900329
330 for (lane = 0; lane < lane_count; lane++)
Sonika Jindal0ded9252014-08-08 16:23:42 +0530331 buf[lane] = DP_TRAIN_PRE_EMPH_LEVEL_0 |
332 DP_TRAIN_VOLTAGE_SWING_LEVEL_0;
Sean Paulfadec4b2012-10-31 23:21:00 +0000333
Jingoo Han073ea2a2014-05-07 20:44:51 +0900334 retval = exynos_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET,
Sean Paulfadec4b2012-10-31 23:21:00 +0000335 lane_count, buf);
Sean Paulace2d7f2012-10-31 23:21:00 +0000336
337 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900338}
339
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900340static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane)
Jingoo Hane9474be2012-02-03 18:01:55 +0900341{
342 int shift = (lane & 1) * 4;
343 u8 link_value = link_status[lane>>1];
344
345 return (link_value >> shift) & 0xf;
346}
347
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900348static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count)
Jingoo Hane9474be2012-02-03 18:01:55 +0900349{
350 int lane;
351 u8 lane_status;
352
353 for (lane = 0; lane < lane_count; lane++) {
354 lane_status = exynos_dp_get_lane_status(link_status, lane);
Jingoo Han073ea2a2014-05-07 20:44:51 +0900355 if ((lane_status & DP_LANE_CR_DONE) == 0)
Jingoo Hane9474be2012-02-03 18:01:55 +0900356 return -EINVAL;
357 }
358 return 0;
359}
360
Sean Paulfadec4b2012-10-31 23:21:00 +0000361static int exynos_dp_channel_eq_ok(u8 link_status[2], u8 link_align,
362 int lane_count)
Jingoo Hane9474be2012-02-03 18:01:55 +0900363{
364 int lane;
Jingoo Hane9474be2012-02-03 18:01:55 +0900365 u8 lane_status;
366
Jingoo Han073ea2a2014-05-07 20:44:51 +0900367 if ((link_align & DP_INTERLANE_ALIGN_DONE) == 0)
Jingoo Hane9474be2012-02-03 18:01:55 +0900368 return -EINVAL;
369
370 for (lane = 0; lane < lane_count; lane++) {
Sean Paulfadec4b2012-10-31 23:21:00 +0000371 lane_status = exynos_dp_get_lane_status(link_status, lane);
Jingoo Han073ea2a2014-05-07 20:44:51 +0900372 lane_status &= DP_CHANNEL_EQ_BITS;
373 if (lane_status != DP_CHANNEL_EQ_BITS)
Jingoo Hane9474be2012-02-03 18:01:55 +0900374 return -EINVAL;
375 }
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900376
Jingoo Hane9474be2012-02-03 18:01:55 +0900377 return 0;
378}
379
380static unsigned char exynos_dp_get_adjust_request_voltage(u8 adjust_request[2],
381 int lane)
382{
383 int shift = (lane & 1) * 4;
384 u8 link_value = adjust_request[lane>>1];
385
386 return (link_value >> shift) & 0x3;
387}
388
389static unsigned char exynos_dp_get_adjust_request_pre_emphasis(
390 u8 adjust_request[2],
391 int lane)
392{
393 int shift = (lane & 1) * 4;
394 u8 link_value = adjust_request[lane>>1];
395
396 return ((link_value >> shift) & 0xc) >> 2;
397}
398
399static void exynos_dp_set_lane_link_training(struct exynos_dp_device *dp,
400 u8 training_lane_set, int lane)
401{
402 switch (lane) {
403 case 0:
404 exynos_dp_set_lane0_link_training(dp, training_lane_set);
405 break;
406 case 1:
407 exynos_dp_set_lane1_link_training(dp, training_lane_set);
408 break;
409
410 case 2:
411 exynos_dp_set_lane2_link_training(dp, training_lane_set);
412 break;
413
414 case 3:
415 exynos_dp_set_lane3_link_training(dp, training_lane_set);
416 break;
417 }
418}
419
420static unsigned int exynos_dp_get_lane_link_training(
421 struct exynos_dp_device *dp,
422 int lane)
423{
424 u32 reg;
425
426 switch (lane) {
427 case 0:
428 reg = exynos_dp_get_lane0_link_training(dp);
429 break;
430 case 1:
431 reg = exynos_dp_get_lane1_link_training(dp);
432 break;
433 case 2:
434 reg = exynos_dp_get_lane2_link_training(dp);
435 break;
436 case 3:
437 reg = exynos_dp_get_lane3_link_training(dp);
438 break;
Jingoo Han64c43df2012-06-20 10:25:48 +0900439 default:
440 WARN_ON(1);
441 return 0;
Jingoo Hane9474be2012-02-03 18:01:55 +0900442 }
443
444 return reg;
445}
446
447static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp)
448{
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900449 exynos_dp_training_pattern_dis(dp);
450 exynos_dp_set_enhanced_mode(dp);
Jingoo Hane9474be2012-02-03 18:01:55 +0900451
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900452 dp->link_train.lt_state = FAILED;
Jingoo Hane9474be2012-02-03 18:01:55 +0900453}
454
Sean Paulfadec4b2012-10-31 23:21:00 +0000455static void exynos_dp_get_adjust_training_lane(struct exynos_dp_device *dp,
456 u8 adjust_request[2])
457{
458 int lane, lane_count;
459 u8 voltage_swing, pre_emphasis, training_lane;
460
461 lane_count = dp->link_train.lane_count;
462 for (lane = 0; lane < lane_count; lane++) {
463 voltage_swing = exynos_dp_get_adjust_request_voltage(
464 adjust_request, lane);
465 pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
466 adjust_request, lane);
467 training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
468 DPCD_PRE_EMPHASIS_SET(pre_emphasis);
469
470 if (voltage_swing == VOLTAGE_LEVEL_3)
Jingoo Han073ea2a2014-05-07 20:44:51 +0900471 training_lane |= DP_TRAIN_MAX_SWING_REACHED;
Sean Paulfadec4b2012-10-31 23:21:00 +0000472 if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
Jingoo Han073ea2a2014-05-07 20:44:51 +0900473 training_lane |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
Sean Paulfadec4b2012-10-31 23:21:00 +0000474
475 dp->link_train.training_lane[lane] = training_lane;
476 }
477}
478
Jingoo Hane9474be2012-02-03 18:01:55 +0900479static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
480{
Sean Paulace2d7f2012-10-31 23:21:00 +0000481 int lane, lane_count, retval;
Sean Paulfadec4b2012-10-31 23:21:00 +0000482 u8 voltage_swing, pre_emphasis, training_lane;
483 u8 link_status[2], adjust_request[2];
Jingoo Hane9474be2012-02-03 18:01:55 +0900484
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900485 usleep_range(100, 101);
Jingoo Hane9474be2012-02-03 18:01:55 +0900486
Jingoo Hane9474be2012-02-03 18:01:55 +0900487 lane_count = dp->link_train.lane_count;
488
Sean Paulfadec4b2012-10-31 23:21:00 +0000489 retval = exynos_dp_read_bytes_from_dpcd(dp,
Jingoo Han073ea2a2014-05-07 20:44:51 +0900490 DP_LANE0_1_STATUS, 2, link_status);
Sean Paulfadec4b2012-10-31 23:21:00 +0000491 if (retval)
492 return retval;
493
494 retval = exynos_dp_read_bytes_from_dpcd(dp,
Jingoo Han073ea2a2014-05-07 20:44:51 +0900495 DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
Sean Paulace2d7f2012-10-31 23:21:00 +0000496 if (retval)
497 return retval;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900498
Jingoo Hane9474be2012-02-03 18:01:55 +0900499 if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
500 /* set training pattern 2 for EQ */
501 exynos_dp_set_training_pattern(dp, TRAINING_PTN2);
502
Sean Paulace2d7f2012-10-31 23:21:00 +0000503 retval = exynos_dp_write_byte_to_dpcd(dp,
Jingoo Han073ea2a2014-05-07 20:44:51 +0900504 DP_TRAINING_PATTERN_SET,
505 DP_LINK_SCRAMBLING_DISABLE |
506 DP_TRAINING_PATTERN_2);
Sean Paulace2d7f2012-10-31 23:21:00 +0000507 if (retval)
508 return retval;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900509
510 dev_info(dp->dev, "Link Training Clock Recovery success\n");
511 dp->link_train.lt_state = EQUALIZER_TRAINING;
512 } else {
513 for (lane = 0; lane < lane_count; lane++) {
514 training_lane = exynos_dp_get_lane_link_training(
515 dp, lane);
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900516 voltage_swing = exynos_dp_get_adjust_request_voltage(
517 adjust_request, lane);
518 pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
519 adjust_request, lane);
520
Sean Paulfadec4b2012-10-31 23:21:00 +0000521 if (DPCD_VOLTAGE_SWING_GET(training_lane) ==
522 voltage_swing &&
523 DPCD_PRE_EMPHASIS_GET(training_lane) ==
524 pre_emphasis)
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900525 dp->link_train.cr_loop[lane]++;
Sean Paulfadec4b2012-10-31 23:21:00 +0000526
527 if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP ||
528 voltage_swing == VOLTAGE_LEVEL_3 ||
529 pre_emphasis == PRE_EMPHASIS_LEVEL_3) {
530 dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n",
531 dp->link_train.cr_loop[lane],
532 voltage_swing, pre_emphasis);
533 exynos_dp_reduce_link_rate(dp);
534 return -EIO;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900535 }
Jingoo Hane9474be2012-02-03 18:01:55 +0900536 }
537 }
538
Sean Paulfadec4b2012-10-31 23:21:00 +0000539 exynos_dp_get_adjust_training_lane(dp, adjust_request);
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900540
Sean Paulfadec4b2012-10-31 23:21:00 +0000541 for (lane = 0; lane < lane_count; lane++)
542 exynos_dp_set_lane_link_training(dp,
543 dp->link_train.training_lane[lane], lane);
544
545 retval = exynos_dp_write_bytes_to_dpcd(dp,
Jingoo Han073ea2a2014-05-07 20:44:51 +0900546 DP_TRAINING_LANE0_SET, lane_count,
Sean Paulfadec4b2012-10-31 23:21:00 +0000547 dp->link_train.training_lane);
548 if (retval)
549 return retval;
550
551 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900552}
553
554static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
555{
Sean Paulace2d7f2012-10-31 23:21:00 +0000556 int lane, lane_count, retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900557 u32 reg;
Sean Paulfadec4b2012-10-31 23:21:00 +0000558 u8 link_align, link_status[2], adjust_request[2];
Jingoo Hane9474be2012-02-03 18:01:55 +0900559
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900560 usleep_range(400, 401);
Jingoo Hane9474be2012-02-03 18:01:55 +0900561
Jingoo Hane9474be2012-02-03 18:01:55 +0900562 lane_count = dp->link_train.lane_count;
563
Sean Paulfadec4b2012-10-31 23:21:00 +0000564 retval = exynos_dp_read_bytes_from_dpcd(dp,
Jingoo Han073ea2a2014-05-07 20:44:51 +0900565 DP_LANE0_1_STATUS, 2, link_status);
Sean Paulace2d7f2012-10-31 23:21:00 +0000566 if (retval)
567 return retval;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900568
Sean Paulfadec4b2012-10-31 23:21:00 +0000569 if (exynos_dp_clock_recovery_ok(link_status, lane_count)) {
570 exynos_dp_reduce_link_rate(dp);
571 return -EIO;
Jingoo Hane9474be2012-02-03 18:01:55 +0900572 }
573
Sean Paulfadec4b2012-10-31 23:21:00 +0000574 retval = exynos_dp_read_bytes_from_dpcd(dp,
Jingoo Han073ea2a2014-05-07 20:44:51 +0900575 DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
Sean Paulfadec4b2012-10-31 23:21:00 +0000576 if (retval)
577 return retval;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900578
Sean Paulfadec4b2012-10-31 23:21:00 +0000579 retval = exynos_dp_read_byte_from_dpcd(dp,
Jingoo Han073ea2a2014-05-07 20:44:51 +0900580 DP_LANE_ALIGN_STATUS_UPDATED, &link_align);
Sean Paulfadec4b2012-10-31 23:21:00 +0000581 if (retval)
582 return retval;
583
584 exynos_dp_get_adjust_training_lane(dp, adjust_request);
585
586 if (!exynos_dp_channel_eq_ok(link_status, link_align, lane_count)) {
587 /* traing pattern Set to Normal */
588 exynos_dp_training_pattern_dis(dp);
589
590 dev_info(dp->dev, "Link Training success!\n");
591
592 exynos_dp_get_link_bandwidth(dp, &reg);
593 dp->link_train.link_rate = reg;
594 dev_dbg(dp->dev, "final bandwidth = %.2x\n",
595 dp->link_train.link_rate);
596
597 exynos_dp_get_lane_count(dp, &reg);
598 dp->link_train.lane_count = reg;
599 dev_dbg(dp->dev, "final lane count = %.2x\n",
600 dp->link_train.lane_count);
601
602 /* set enhanced mode if available */
603 exynos_dp_set_enhanced_mode(dp);
604 dp->link_train.lt_state = FINISHED;
605
606 return 0;
607 }
608
609 /* not all locked */
610 dp->link_train.eq_loop++;
611
612 if (dp->link_train.eq_loop > MAX_EQ_LOOP) {
613 dev_err(dp->dev, "EQ Max loop\n");
614 exynos_dp_reduce_link_rate(dp);
615 return -EIO;
616 }
617
618 for (lane = 0; lane < lane_count; lane++)
619 exynos_dp_set_lane_link_training(dp,
620 dp->link_train.training_lane[lane], lane);
621
Jingoo Han073ea2a2014-05-07 20:44:51 +0900622 retval = exynos_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET,
Sean Paulfadec4b2012-10-31 23:21:00 +0000623 lane_count, dp->link_train.training_lane);
624
625 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900626}
627
628static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp,
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900629 u8 *bandwidth)
Jingoo Hane9474be2012-02-03 18:01:55 +0900630{
631 u8 data;
632
633 /*
634 * For DP rev.1.1, Maximum link rate of Main Link lanes
635 * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
636 */
Jingoo Han073ea2a2014-05-07 20:44:51 +0900637 exynos_dp_read_byte_from_dpcd(dp, DP_MAX_LINK_RATE, &data);
Jingoo Hane9474be2012-02-03 18:01:55 +0900638 *bandwidth = data;
639}
640
641static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp,
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900642 u8 *lane_count)
Jingoo Hane9474be2012-02-03 18:01:55 +0900643{
644 u8 data;
645
646 /*
647 * For DP rev.1.1, Maximum number of Main Link lanes
648 * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
649 */
Jingoo Han073ea2a2014-05-07 20:44:51 +0900650 exynos_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data);
Jingoo Hane9474be2012-02-03 18:01:55 +0900651 *lane_count = DPCD_MAX_LANE_COUNT(data);
652}
653
654static void exynos_dp_init_training(struct exynos_dp_device *dp,
655 enum link_lane_count_type max_lane,
656 enum link_rate_type max_rate)
657{
658 /*
659 * MACRO_RST must be applied after the PLL_LOCK to avoid
660 * the DP inter pair skew issue for at least 10 us
661 */
662 exynos_dp_reset_macro(dp);
663
664 /* Initialize by reading RX's DPCD */
665 exynos_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate);
666 exynos_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
667
668 if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) &&
669 (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) {
670 dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n",
671 dp->link_train.link_rate);
672 dp->link_train.link_rate = LINK_RATE_1_62GBPS;
673 }
674
675 if (dp->link_train.lane_count == 0) {
676 dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n",
677 dp->link_train.lane_count);
678 dp->link_train.lane_count = (u8)LANE_COUNT1;
679 }
680
681 /* Setup TX lane count & rate */
682 if (dp->link_train.lane_count > max_lane)
683 dp->link_train.lane_count = max_lane;
684 if (dp->link_train.link_rate > max_rate)
685 dp->link_train.link_rate = max_rate;
686
687 /* All DP analog module power up */
688 exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
689}
690
691static int exynos_dp_sw_link_training(struct exynos_dp_device *dp)
692{
Sean Paulace2d7f2012-10-31 23:21:00 +0000693 int retval = 0, training_finished = 0;
Jingoo Hane9474be2012-02-03 18:01:55 +0900694
695 dp->link_train.lt_state = START;
696
697 /* Process here */
Sean Paulace2d7f2012-10-31 23:21:00 +0000698 while (!retval && !training_finished) {
Jingoo Hane9474be2012-02-03 18:01:55 +0900699 switch (dp->link_train.lt_state) {
700 case START:
Sean Paulace2d7f2012-10-31 23:21:00 +0000701 retval = exynos_dp_link_start(dp);
702 if (retval)
703 dev_err(dp->dev, "LT link start failed!\n");
Jingoo Hane9474be2012-02-03 18:01:55 +0900704 break;
705 case CLOCK_RECOVERY:
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900706 retval = exynos_dp_process_clock_recovery(dp);
707 if (retval)
708 dev_err(dp->dev, "LT CR failed!\n");
Jingoo Hane9474be2012-02-03 18:01:55 +0900709 break;
710 case EQUALIZER_TRAINING:
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900711 retval = exynos_dp_process_equalizer_training(dp);
712 if (retval)
713 dev_err(dp->dev, "LT EQ failed!\n");
Jingoo Hane9474be2012-02-03 18:01:55 +0900714 break;
715 case FINISHED:
716 training_finished = 1;
717 break;
718 case FAILED:
719 return -EREMOTEIO;
720 }
721 }
Sean Paulace2d7f2012-10-31 23:21:00 +0000722 if (retval)
723 dev_err(dp->dev, "eDP link training failed (%d)\n", retval);
Jingoo Hane9474be2012-02-03 18:01:55 +0900724
725 return retval;
726}
727
728static int exynos_dp_set_link_train(struct exynos_dp_device *dp,
729 u32 count,
730 u32 bwtype)
731{
732 int i;
733 int retval;
734
735 for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) {
736 exynos_dp_init_training(dp, count, bwtype);
737 retval = exynos_dp_sw_link_training(dp);
738 if (retval == 0)
739 break;
740
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900741 usleep_range(100, 110);
Jingoo Hane9474be2012-02-03 18:01:55 +0900742 }
743
744 return retval;
745}
746
Ajay Kumar3fcb6eb2012-11-09 14:05:06 +0900747static int exynos_dp_config_video(struct exynos_dp_device *dp)
Jingoo Hane9474be2012-02-03 18:01:55 +0900748{
749 int retval = 0;
750 int timeout_loop = 0;
751 int done_count = 0;
752
Ajay Kumar3fcb6eb2012-11-09 14:05:06 +0900753 exynos_dp_config_video_slave_mode(dp);
Jingoo Hane9474be2012-02-03 18:01:55 +0900754
Ajay Kumar3fcb6eb2012-11-09 14:05:06 +0900755 exynos_dp_set_video_color_format(dp);
Jingoo Hane9474be2012-02-03 18:01:55 +0900756
757 if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
758 dev_err(dp->dev, "PLL is not locked yet.\n");
759 return -EINVAL;
760 }
761
762 for (;;) {
763 timeout_loop++;
764 if (exynos_dp_is_slave_video_stream_clock_on(dp) == 0)
765 break;
766 if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
767 dev_err(dp->dev, "Timeout of video streamclk ok\n");
768 return -ETIMEDOUT;
769 }
770
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900771 usleep_range(1, 2);
Jingoo Hane9474be2012-02-03 18:01:55 +0900772 }
773
774 /* Set to use the register calculated M/N video */
775 exynos_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0);
776
777 /* For video bist, Video timing must be generated by register */
778 exynos_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE);
779
780 /* Disable video mute */
781 exynos_dp_enable_video_mute(dp, 0);
782
783 /* Configure video slave mode */
784 exynos_dp_enable_video_master(dp, 0);
785
786 /* Enable video */
787 exynos_dp_start_video(dp);
788
789 timeout_loop = 0;
790
791 for (;;) {
792 timeout_loop++;
793 if (exynos_dp_is_video_stream_on(dp) == 0) {
794 done_count++;
795 if (done_count > 10)
796 break;
797 } else if (done_count) {
798 done_count = 0;
799 }
800 if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
801 dev_err(dp->dev, "Timeout of video streamclk ok\n");
802 return -ETIMEDOUT;
803 }
804
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900805 usleep_range(1000, 1001);
Jingoo Hane9474be2012-02-03 18:01:55 +0900806 }
807
808 if (retval != 0)
809 dev_err(dp->dev, "Video stream is not detected!\n");
810
811 return retval;
812}
813
814static void exynos_dp_enable_scramble(struct exynos_dp_device *dp, bool enable)
815{
816 u8 data;
817
818 if (enable) {
819 exynos_dp_enable_scrambling(dp);
820
821 exynos_dp_read_byte_from_dpcd(dp,
Jingoo Han073ea2a2014-05-07 20:44:51 +0900822 DP_TRAINING_PATTERN_SET,
Jingoo Hane9474be2012-02-03 18:01:55 +0900823 &data);
824 exynos_dp_write_byte_to_dpcd(dp,
Jingoo Han073ea2a2014-05-07 20:44:51 +0900825 DP_TRAINING_PATTERN_SET,
826 (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE));
Jingoo Hane9474be2012-02-03 18:01:55 +0900827 } else {
828 exynos_dp_disable_scrambling(dp);
829
830 exynos_dp_read_byte_from_dpcd(dp,
Jingoo Han073ea2a2014-05-07 20:44:51 +0900831 DP_TRAINING_PATTERN_SET,
Jingoo Hane9474be2012-02-03 18:01:55 +0900832 &data);
833 exynos_dp_write_byte_to_dpcd(dp,
Jingoo Han073ea2a2014-05-07 20:44:51 +0900834 DP_TRAINING_PATTERN_SET,
835 (u8)(data | DP_LINK_SCRAMBLING_DISABLE));
Jingoo Hane9474be2012-02-03 18:01:55 +0900836 }
837}
838
839static irqreturn_t exynos_dp_irq_handler(int irq, void *arg)
840{
841 struct exynos_dp_device *dp = arg;
842
Sean Paulc30ffb92012-11-01 19:13:46 +0900843 enum dp_irq_type irq_type;
844
845 irq_type = exynos_dp_get_irq_type(dp);
846 switch (irq_type) {
847 case DP_IRQ_TYPE_HP_CABLE_IN:
848 dev_dbg(dp->dev, "Received irq - cable in\n");
849 schedule_work(&dp->hotplug_work);
850 exynos_dp_clear_hotplug_interrupts(dp);
851 break;
852 case DP_IRQ_TYPE_HP_CABLE_OUT:
853 dev_dbg(dp->dev, "Received irq - cable out\n");
854 exynos_dp_clear_hotplug_interrupts(dp);
855 break;
856 case DP_IRQ_TYPE_HP_CHANGE:
857 /*
858 * We get these change notifications once in a while, but there
859 * is nothing we can do with them. Just ignore it for now and
860 * only handle cable changes.
861 */
862 dev_dbg(dp->dev, "Received irq - hotplug change; ignoring.\n");
863 exynos_dp_clear_hotplug_interrupts(dp);
864 break;
865 default:
866 dev_err(dp->dev, "Received irq - unknown type!\n");
867 break;
868 }
Jingoo Hane9474be2012-02-03 18:01:55 +0900869 return IRQ_HANDLED;
870}
871
Sean Paul784fa9a2012-11-09 13:55:08 +0900872static void exynos_dp_hotplug(struct work_struct *work)
873{
874 struct exynos_dp_device *dp;
Sean Paul784fa9a2012-11-09 13:55:08 +0900875
876 dp = container_of(work, struct exynos_dp_device, hotplug_work);
877
Ajay Kumar4deabfa2014-07-31 23:12:13 +0530878 if (dp->drm_dev)
879 drm_helper_hpd_irq_event(dp->drm_dev);
880}
881
882static void exynos_dp_commit(struct exynos_drm_display *display)
883{
884 struct exynos_dp_device *dp = display->ctx;
885 int ret;
886
Ajay Kumar5f1dcd82014-07-31 23:12:14 +0530887 /* Keep the panel disabled while we configure video */
888 if (dp->panel) {
889 if (drm_panel_disable(dp->panel))
890 DRM_ERROR("failed to disable the panel\n");
891 }
892
Sean Paul784fa9a2012-11-09 13:55:08 +0900893 ret = exynos_dp_detect_hpd(dp);
894 if (ret) {
Sean Paulc30ffb92012-11-01 19:13:46 +0900895 /* Cable has been disconnected, we're done */
Sean Paul784fa9a2012-11-09 13:55:08 +0900896 return;
897 }
898
899 ret = exynos_dp_handle_edid(dp);
900 if (ret) {
901 dev_err(dp->dev, "unable to handle edid\n");
902 return;
903 }
904
905 ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count,
906 dp->video_info->link_rate);
907 if (ret) {
908 dev_err(dp->dev, "unable to do link train\n");
909 return;
910 }
911
912 exynos_dp_enable_scramble(dp, 1);
913 exynos_dp_enable_rx_to_enhanced_mode(dp, 1);
914 exynos_dp_enable_enhanced_mode(dp, 1);
915
916 exynos_dp_set_lane_count(dp, dp->video_info->lane_count);
917 exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate);
918
919 exynos_dp_init_video(dp);
Ajay Kumar3fcb6eb2012-11-09 14:05:06 +0900920 ret = exynos_dp_config_video(dp);
Sean Paul784fa9a2012-11-09 13:55:08 +0900921 if (ret)
922 dev_err(dp->dev, "unable to config video\n");
Ajay Kumar5f1dcd82014-07-31 23:12:14 +0530923
924 /* Safe to enable the panel now */
925 if (dp->panel) {
926 if (drm_panel_enable(dp->panel))
927 DRM_ERROR("failed to enable the panel\n");
928 }
Sean Paul784fa9a2012-11-09 13:55:08 +0900929}
930
Sean Paulcaa5d1e2014-01-30 16:19:30 -0500931static enum drm_connector_status exynos_dp_detect(
932 struct drm_connector *connector, bool force)
Sean Paul1417f102014-01-30 16:19:23 -0500933{
Sean Paulcaa5d1e2014-01-30 16:19:30 -0500934 return connector_status_connected;
Sean Paul1417f102014-01-30 16:19:23 -0500935}
936
Sean Paulcaa5d1e2014-01-30 16:19:30 -0500937static void exynos_dp_connector_destroy(struct drm_connector *connector)
938{
Andrzej Hajda7c61b1e2014-09-09 15:16:12 +0200939 drm_connector_unregister(connector);
940 drm_connector_cleanup(connector);
Sean Paulcaa5d1e2014-01-30 16:19:30 -0500941}
942
943static struct drm_connector_funcs exynos_dp_connector_funcs = {
944 .dpms = drm_helper_connector_dpms,
945 .fill_modes = drm_helper_probe_single_connector_modes,
946 .detect = exynos_dp_detect,
947 .destroy = exynos_dp_connector_destroy,
948};
949
950static int exynos_dp_get_modes(struct drm_connector *connector)
951{
952 struct exynos_dp_device *dp = ctx_from_connector(connector);
953 struct drm_display_mode *mode;
954
Ajay Kumar5f1dcd82014-07-31 23:12:14 +0530955 if (dp->panel)
956 return drm_panel_get_modes(dp->panel);
957
Sean Paulcaa5d1e2014-01-30 16:19:30 -0500958 mode = drm_mode_create(connector->dev);
959 if (!mode) {
960 DRM_ERROR("failed to create a new display mode.\n");
961 return 0;
962 }
963
Ajay Kumar5f1dcd82014-07-31 23:12:14 +0530964 drm_display_mode_from_videomode(&dp->priv.vm, mode);
965 mode->width_mm = dp->priv.width_mm;
966 mode->height_mm = dp->priv.height_mm;
Sean Paulcaa5d1e2014-01-30 16:19:30 -0500967 connector->display_info.width_mm = mode->width_mm;
968 connector->display_info.height_mm = mode->height_mm;
969
970 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
971 drm_mode_set_name(mode);
972 drm_mode_probed_add(connector, mode);
973
974 return 1;
975}
976
Sean Paulcaa5d1e2014-01-30 16:19:30 -0500977static struct drm_encoder *exynos_dp_best_encoder(
978 struct drm_connector *connector)
979{
980 struct exynos_dp_device *dp = ctx_from_connector(connector);
981
982 return dp->encoder;
983}
984
985static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = {
986 .get_modes = exynos_dp_get_modes,
Sean Paulcaa5d1e2014-01-30 16:19:30 -0500987 .best_encoder = exynos_dp_best_encoder,
988};
989
Sean Paul1634ba22014-02-24 19:20:15 +0900990static bool find_bridge(const char *compat, struct bridge_init *bridge)
991{
992 bridge->client = NULL;
993 bridge->node = of_find_compatible_node(NULL, NULL, compat);
994 if (!bridge->node)
995 return false;
996
997 bridge->client = of_find_i2c_device_by_node(bridge->node);
998 if (!bridge->client)
999 return false;
1000
1001 return true;
1002}
1003
1004/* returns the number of bridges attached */
1005static int exynos_drm_attach_lcd_bridge(struct drm_device *dev,
1006 struct drm_encoder *encoder)
1007{
1008 struct bridge_init bridge;
1009 int ret;
1010
1011 if (find_bridge("nxp,ptn3460", &bridge)) {
1012 ret = ptn3460_init(dev, encoder, bridge.client, bridge.node);
1013 if (!ret)
1014 return 1;
1015 }
1016 return 0;
1017}
1018
Sean Paulcaa5d1e2014-01-30 16:19:30 -05001019static int exynos_dp_create_connector(struct exynos_drm_display *display,
1020 struct drm_encoder *encoder)
Sean Paul1417f102014-01-30 16:19:23 -05001021{
Sean Paulcaa5d1e2014-01-30 16:19:30 -05001022 struct exynos_dp_device *dp = display->ctx;
1023 struct drm_connector *connector = &dp->connector;
1024 int ret;
1025
1026 dp->encoder = encoder;
Sean Paul1634ba22014-02-24 19:20:15 +09001027
1028 /* Pre-empt DP connector creation if there's a bridge */
1029 ret = exynos_drm_attach_lcd_bridge(dp->drm_dev, encoder);
1030 if (ret)
1031 return 0;
1032
Sean Paulcaa5d1e2014-01-30 16:19:30 -05001033 connector->polled = DRM_CONNECTOR_POLL_HPD;
1034
1035 ret = drm_connector_init(dp->drm_dev, connector,
1036 &exynos_dp_connector_funcs, DRM_MODE_CONNECTOR_eDP);
1037 if (ret) {
1038 DRM_ERROR("Failed to initialize connector with drm\n");
1039 return ret;
1040 }
1041
1042 drm_connector_helper_add(connector, &exynos_dp_connector_helper_funcs);
Thomas Wood34ea3d32014-05-29 16:57:41 +01001043 drm_connector_register(connector);
Sean Paulcaa5d1e2014-01-30 16:19:30 -05001044 drm_mode_connector_attach_encoder(connector, encoder);
1045
Ajay Kumar5f1dcd82014-07-31 23:12:14 +05301046 if (dp->panel)
1047 ret = drm_panel_attach(dp->panel, &dp->connector);
1048
1049 return ret;
Sean Paul1417f102014-01-30 16:19:23 -05001050}
1051
Sean Paul12f5ad62014-01-30 16:19:25 -05001052static void exynos_dp_phy_init(struct exynos_dp_device *dp)
1053{
Vivek Gautamb128aef2014-11-12 15:12:10 +05301054 if (dp->phy)
Sean Paul12f5ad62014-01-30 16:19:25 -05001055 phy_power_on(dp->phy);
Sean Paul12f5ad62014-01-30 16:19:25 -05001056}
1057
1058static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
1059{
Vivek Gautamb128aef2014-11-12 15:12:10 +05301060 if (dp->phy)
Sean Paul12f5ad62014-01-30 16:19:25 -05001061 phy_power_off(dp->phy);
Sean Paul12f5ad62014-01-30 16:19:25 -05001062}
1063
Ajay Kumar4deabfa2014-07-31 23:12:13 +05301064static void exynos_dp_poweron(struct exynos_drm_display *display)
Sean Paul12f5ad62014-01-30 16:19:25 -05001065{
Ajay Kumar4deabfa2014-07-31 23:12:13 +05301066 struct exynos_dp_device *dp = display->ctx;
1067
Sean Paul12f5ad62014-01-30 16:19:25 -05001068 if (dp->dpms_mode == DRM_MODE_DPMS_ON)
1069 return;
1070
Ajay Kumar5f1dcd82014-07-31 23:12:14 +05301071 if (dp->panel) {
1072 if (drm_panel_prepare(dp->panel)) {
1073 DRM_ERROR("failed to setup the panel\n");
1074 return;
1075 }
1076 }
1077
Sean Paul12f5ad62014-01-30 16:19:25 -05001078 clk_prepare_enable(dp->clock);
1079 exynos_dp_phy_init(dp);
1080 exynos_dp_init_dp(dp);
1081 enable_irq(dp->irq);
Ajay Kumar4deabfa2014-07-31 23:12:13 +05301082 exynos_dp_commit(display);
Sean Paul12f5ad62014-01-30 16:19:25 -05001083}
1084
Ajay Kumar4deabfa2014-07-31 23:12:13 +05301085static void exynos_dp_poweroff(struct exynos_drm_display *display)
Sean Paul12f5ad62014-01-30 16:19:25 -05001086{
Ajay Kumar4deabfa2014-07-31 23:12:13 +05301087 struct exynos_dp_device *dp = display->ctx;
1088
Sean Paul12f5ad62014-01-30 16:19:25 -05001089 if (dp->dpms_mode != DRM_MODE_DPMS_ON)
1090 return;
1091
Ajay Kumar5f1dcd82014-07-31 23:12:14 +05301092 if (dp->panel) {
1093 if (drm_panel_disable(dp->panel)) {
1094 DRM_ERROR("failed to disable the panel\n");
1095 return;
1096 }
1097 }
1098
Sean Paul12f5ad62014-01-30 16:19:25 -05001099 disable_irq(dp->irq);
1100 flush_work(&dp->hotplug_work);
1101 exynos_dp_phy_exit(dp);
1102 clk_disable_unprepare(dp->clock);
Ajay Kumar5f1dcd82014-07-31 23:12:14 +05301103
1104 if (dp->panel) {
1105 if (drm_panel_unprepare(dp->panel))
1106 DRM_ERROR("failed to turnoff the panel\n");
1107 }
Sean Paul12f5ad62014-01-30 16:19:25 -05001108}
1109
1110static void exynos_dp_dpms(struct exynos_drm_display *display, int mode)
1111{
1112 struct exynos_dp_device *dp = display->ctx;
1113
1114 switch (mode) {
1115 case DRM_MODE_DPMS_ON:
Ajay Kumar4deabfa2014-07-31 23:12:13 +05301116 exynos_dp_poweron(display);
Sean Paul12f5ad62014-01-30 16:19:25 -05001117 break;
1118 case DRM_MODE_DPMS_STANDBY:
1119 case DRM_MODE_DPMS_SUSPEND:
1120 case DRM_MODE_DPMS_OFF:
Ajay Kumar4deabfa2014-07-31 23:12:13 +05301121 exynos_dp_poweroff(display);
Sean Paul12f5ad62014-01-30 16:19:25 -05001122 break;
1123 default:
1124 break;
Damien Lespiau10d9b4e2014-06-09 14:21:08 +01001125 }
Sean Paul12f5ad62014-01-30 16:19:25 -05001126 dp->dpms_mode = mode;
1127}
1128
Sean Paul1417f102014-01-30 16:19:23 -05001129static struct exynos_drm_display_ops exynos_dp_display_ops = {
Sean Paulcaa5d1e2014-01-30 16:19:30 -05001130 .create_connector = exynos_dp_create_connector,
Sean Paul12f5ad62014-01-30 16:19:25 -05001131 .dpms = exynos_dp_dpms,
Ajay Kumar4deabfa2014-07-31 23:12:13 +05301132 .commit = exynos_dp_commit,
Sean Paul1417f102014-01-30 16:19:23 -05001133};
1134
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301135static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev)
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001136{
1137 struct device_node *dp_node = dev->of_node;
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001138 struct video_info *dp_video_config;
1139
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001140 dp_video_config = devm_kzalloc(dev,
1141 sizeof(*dp_video_config), GFP_KERNEL);
Jingoo Han7a5b68272014-04-17 19:08:14 +09001142 if (!dp_video_config)
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001143 return ERR_PTR(-ENOMEM);
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001144
1145 dp_video_config->h_sync_polarity =
1146 of_property_read_bool(dp_node, "hsync-active-high");
1147
1148 dp_video_config->v_sync_polarity =
1149 of_property_read_bool(dp_node, "vsync-active-high");
1150
1151 dp_video_config->interlaced =
1152 of_property_read_bool(dp_node, "interlaced");
1153
1154 if (of_property_read_u32(dp_node, "samsung,color-space",
1155 &dp_video_config->color_space)) {
1156 dev_err(dev, "failed to get color-space\n");
1157 return ERR_PTR(-EINVAL);
1158 }
1159
1160 if (of_property_read_u32(dp_node, "samsung,dynamic-range",
1161 &dp_video_config->dynamic_range)) {
1162 dev_err(dev, "failed to get dynamic-range\n");
1163 return ERR_PTR(-EINVAL);
1164 }
1165
1166 if (of_property_read_u32(dp_node, "samsung,ycbcr-coeff",
1167 &dp_video_config->ycbcr_coeff)) {
1168 dev_err(dev, "failed to get ycbcr-coeff\n");
1169 return ERR_PTR(-EINVAL);
1170 }
1171
1172 if (of_property_read_u32(dp_node, "samsung,color-depth",
1173 &dp_video_config->color_depth)) {
1174 dev_err(dev, "failed to get color-depth\n");
1175 return ERR_PTR(-EINVAL);
1176 }
1177
1178 if (of_property_read_u32(dp_node, "samsung,link-rate",
1179 &dp_video_config->link_rate)) {
1180 dev_err(dev, "failed to get link-rate\n");
1181 return ERR_PTR(-EINVAL);
1182 }
1183
1184 if (of_property_read_u32(dp_node, "samsung,lane-count",
1185 &dp_video_config->lane_count)) {
1186 dev_err(dev, "failed to get lane-count\n");
1187 return ERR_PTR(-EINVAL);
1188 }
1189
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301190 return dp_video_config;
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001191}
1192
Sean Paul1417f102014-01-30 16:19:23 -05001193static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp)
1194{
1195 int ret;
1196
Ajay Kumar5f1dcd82014-07-31 23:12:14 +05301197 ret = of_get_videomode(dp->dev->of_node, &dp->priv.vm,
Sean Paul1417f102014-01-30 16:19:23 -05001198 OF_USE_NATIVE_MODE);
1199 if (ret) {
1200 DRM_ERROR("failed: of_get_videomode() : %d\n", ret);
1201 return ret;
1202 }
1203 return 0;
1204}
1205
Inki Daef37cd5e2014-05-09 14:25:20 +09001206static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
Jingoo Hane9474be2012-02-03 18:01:55 +09001207{
Andrzej Hajda1df6e5f2014-11-17 09:54:24 +01001208 struct exynos_dp_device *dp = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001209 struct platform_device *pdev = to_platform_device(dev);
1210 struct drm_device *drm_dev = data;
Jingoo Hane9474be2012-02-03 18:01:55 +09001211 struct resource *res;
Andrew Brestickerb8b52472014-04-22 04:09:10 +05301212 unsigned int irq_flags;
Jingoo Hane9474be2012-02-03 18:01:55 +09001213 int ret = 0;
1214
Jingoo Hane9474be2012-02-03 18:01:55 +09001215 dp->dev = &pdev->dev;
Sean Paul12f5ad62014-01-30 16:19:25 -05001216 dp->dpms_mode = DRM_MODE_DPMS_OFF;
Jingoo Hane9474be2012-02-03 18:01:55 +09001217
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301218 dp->video_info = exynos_dp_dt_parse_pdata(&pdev->dev);
1219 if (IS_ERR(dp->video_info))
1220 return PTR_ERR(dp->video_info);
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001221
Vivek Gautamb128aef2014-11-12 15:12:10 +05301222 dp->phy = devm_phy_get(dp->dev, "dp");
1223 if (IS_ERR(dp->phy)) {
1224 dev_err(dp->dev, "no DP phy configured\n");
1225 ret = PTR_ERR(dp->phy);
1226 if (ret) {
1227 /*
1228 * phy itself is not enabled, so we can move forward
1229 * assigning NULL to phy pointer.
1230 */
1231 if (ret == -ENOSYS || ret == -ENODEV)
1232 dp->phy = NULL;
1233 else
1234 return ret;
1235 }
1236 }
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001237
Ajay Kumar5f1dcd82014-07-31 23:12:14 +05301238 if (!dp->panel) {
1239 ret = exynos_dp_dt_parse_panel(dp);
1240 if (ret)
1241 return ret;
1242 }
Sean Paul1417f102014-01-30 16:19:23 -05001243
Damien Cassoud913f362012-08-01 18:20:39 +02001244 dp->clock = devm_clk_get(&pdev->dev, "dp");
Jingoo Hane9474be2012-02-03 18:01:55 +09001245 if (IS_ERR(dp->clock)) {
1246 dev_err(&pdev->dev, "failed to get clock\n");
Jingoo Han4d10ecf82012-05-25 16:20:45 +09001247 return PTR_ERR(dp->clock);
Jingoo Hane9474be2012-02-03 18:01:55 +09001248 }
1249
Jingoo Han37414fb2012-10-04 15:45:14 +09001250 clk_prepare_enable(dp->clock);
Jingoo Hane9474be2012-02-03 18:01:55 +09001251
1252 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Jingoo Hane9474be2012-02-03 18:01:55 +09001253
Thierry Redingbc3bad12013-01-21 11:09:23 +01001254 dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
1255 if (IS_ERR(dp->reg_base))
1256 return PTR_ERR(dp->reg_base);
Jingoo Hane9474be2012-02-03 18:01:55 +09001257
Andrew Brestickerb8b52472014-04-22 04:09:10 +05301258 dp->hpd_gpio = of_get_named_gpio(dev->of_node, "samsung,hpd-gpio", 0);
1259
1260 if (gpio_is_valid(dp->hpd_gpio)) {
1261 /*
1262 * Set up the hotplug GPIO from the device tree as an interrupt.
1263 * Simply specifying a different interrupt in the device tree
1264 * doesn't work since we handle hotplug rather differently when
1265 * using a GPIO. We also need the actual GPIO specifier so
1266 * that we can get the current state of the GPIO.
1267 */
1268 ret = devm_gpio_request_one(&pdev->dev, dp->hpd_gpio, GPIOF_IN,
1269 "hpd_gpio");
1270 if (ret) {
1271 dev_err(&pdev->dev, "failed to get hpd gpio\n");
1272 return ret;
1273 }
1274 dp->irq = gpio_to_irq(dp->hpd_gpio);
1275 irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
1276 } else {
1277 dp->hpd_gpio = -ENODEV;
1278 dp->irq = platform_get_irq(pdev, 0);
1279 irq_flags = 0;
1280 }
1281
Sean Paul1cefc1d2012-10-31 23:21:00 +00001282 if (dp->irq == -ENXIO) {
Jingoo Hane9474be2012-02-03 18:01:55 +09001283 dev_err(&pdev->dev, "failed to get irq\n");
Damien Cassoud913f362012-08-01 18:20:39 +02001284 return -ENODEV;
Jingoo Hane9474be2012-02-03 18:01:55 +09001285 }
1286
Sean Paul784fa9a2012-11-09 13:55:08 +09001287 INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug);
1288
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301289 exynos_dp_phy_init(dp);
Jingoo Hane9474be2012-02-03 18:01:55 +09001290
1291 exynos_dp_init_dp(dp);
1292
Andrew Brestickerb8b52472014-04-22 04:09:10 +05301293 ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler,
1294 irq_flags, "exynos-dp", dp);
Ajay Kumar22ce19c2012-11-09 13:59:09 +09001295 if (ret) {
1296 dev_err(&pdev->dev, "failed to request irq\n");
1297 return ret;
1298 }
Sean Paul12f5ad62014-01-30 16:19:25 -05001299 disable_irq(dp->irq);
Jingoo Hane9474be2012-02-03 18:01:55 +09001300
Inki Daef37cd5e2014-05-09 14:25:20 +09001301 dp->drm_dev = drm_dev;
Sean Paul12f5ad62014-01-30 16:19:25 -05001302
Andrzej Hajda1df6e5f2014-11-17 09:54:24 +01001303 return exynos_drm_create_enc_conn(drm_dev, &dp->display);
Inki Daef37cd5e2014-05-09 14:25:20 +09001304}
1305
1306static void exynos_dp_unbind(struct device *dev, struct device *master,
1307 void *data)
1308{
Andrzej Hajda1df6e5f2014-11-17 09:54:24 +01001309 struct exynos_dp_device *dp = dev_get_drvdata(dev);
Inki Daef37cd5e2014-05-09 14:25:20 +09001310
Andrzej Hajda1df6e5f2014-11-17 09:54:24 +01001311 exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_OFF);
Inki Daef37cd5e2014-05-09 14:25:20 +09001312}
1313
1314static const struct component_ops exynos_dp_ops = {
1315 .bind = exynos_dp_bind,
1316 .unbind = exynos_dp_unbind,
1317};
1318
1319static int exynos_dp_probe(struct platform_device *pdev)
1320{
Ajay Kumar5f1dcd82014-07-31 23:12:14 +05301321 struct device *dev = &pdev->dev;
1322 struct device_node *panel_node;
1323 struct exynos_dp_device *dp;
Inki Daedf5225b2014-05-29 18:28:02 +09001324 int ret;
1325
Ajay Kumar5f1dcd82014-07-31 23:12:14 +05301326 dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
1327 GFP_KERNEL);
1328 if (!dp)
1329 return -ENOMEM;
1330
Andrzej Hajda1df6e5f2014-11-17 09:54:24 +01001331 dp->display.type = EXYNOS_DISPLAY_TYPE_LCD;
1332 dp->display.ops = &exynos_dp_display_ops;
1333 platform_set_drvdata(pdev, dp);
1334
1335 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
1336 dp->display.type);
1337 if (ret)
1338 return ret;
1339
Ajay Kumar5f1dcd82014-07-31 23:12:14 +05301340 panel_node = of_parse_phandle(dev->of_node, "panel", 0);
1341 if (panel_node) {
1342 dp->panel = of_drm_find_panel(panel_node);
1343 of_node_put(panel_node);
1344 if (!dp->panel)
1345 return -EPROBE_DEFER;
1346 }
1347
Andrzej Hajda1df6e5f2014-11-17 09:54:24 +01001348 dp->display.ctx = dp;
Ajay Kumar5f1dcd82014-07-31 23:12:14 +05301349
Inki Daedf5225b2014-05-29 18:28:02 +09001350 ret = component_add(&pdev->dev, &exynos_dp_ops);
1351 if (ret)
1352 exynos_drm_component_del(&pdev->dev,
1353 EXYNOS_DEVICE_TYPE_CONNECTOR);
1354
1355 return ret;
Jingoo Hane9474be2012-02-03 18:01:55 +09001356}
1357
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001358static int exynos_dp_remove(struct platform_device *pdev)
Jingoo Hane9474be2012-02-03 18:01:55 +09001359{
Inki Daedf5225b2014-05-29 18:28:02 +09001360 component_del(&pdev->dev, &exynos_dp_ops);
1361 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
1362
Jingoo Hane9474be2012-02-03 18:01:55 +09001363 return 0;
1364}
1365
1366#ifdef CONFIG_PM_SLEEP
1367static int exynos_dp_suspend(struct device *dev)
1368{
Andrzej Hajda1df6e5f2014-11-17 09:54:24 +01001369 struct exynos_dp_device *dp = dev_get_drvdata(dev);
Jingoo Hane9474be2012-02-03 18:01:55 +09001370
Andrzej Hajda1df6e5f2014-11-17 09:54:24 +01001371 exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_OFF);
Jingoo Hane9474be2012-02-03 18:01:55 +09001372 return 0;
1373}
1374
1375static int exynos_dp_resume(struct device *dev)
1376{
Andrzej Hajda1df6e5f2014-11-17 09:54:24 +01001377 struct exynos_dp_device *dp = dev_get_drvdata(dev);
Jingoo Hane9474be2012-02-03 18:01:55 +09001378
Andrzej Hajda1df6e5f2014-11-17 09:54:24 +01001379 exynos_dp_dpms(&dp->display, DRM_MODE_DPMS_ON);
Jingoo Hane9474be2012-02-03 18:01:55 +09001380 return 0;
1381}
1382#endif
1383
1384static const struct dev_pm_ops exynos_dp_pm_ops = {
1385 SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume)
1386};
1387
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001388static const struct of_device_id exynos_dp_match[] = {
1389 { .compatible = "samsung,exynos5-dp" },
1390 {},
1391};
Sjoerd Simonsbd024b82014-07-30 11:29:41 +09001392MODULE_DEVICE_TABLE(of, exynos_dp_match);
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001393
Sean Paul1417f102014-01-30 16:19:23 -05001394struct platform_driver dp_driver = {
Jingoo Hane9474be2012-02-03 18:01:55 +09001395 .probe = exynos_dp_probe,
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001396 .remove = exynos_dp_remove,
Jingoo Hane9474be2012-02-03 18:01:55 +09001397 .driver = {
1398 .name = "exynos-dp",
1399 .owner = THIS_MODULE,
1400 .pm = &exynos_dp_pm_ops,
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301401 .of_match_table = exynos_dp_match,
Jingoo Hane9474be2012-02-03 18:01:55 +09001402 },
1403};
1404
Jingoo Hane9474be2012-02-03 18:01:55 +09001405MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
1406MODULE_DESCRIPTION("Samsung SoC DP Driver");
Jingoo Han8f589bb2014-06-03 21:46:11 +09001407MODULE_LICENSE("GPL v2");