diff options
-rw-r--r-- | Documentation/devicetree/bindings/video/exynos_dp.txt | 80 | ||||
-rw-r--r-- | drivers/video/exynos/exynos_dp_core.c | 697 | ||||
-rw-r--r-- | drivers/video/exynos/exynos_dp_core.h | 21 | ||||
-rw-r--r-- | drivers/video/exynos/exynos_dp_reg.c | 77 | ||||
-rw-r--r-- | drivers/video/exynos/exynos_dp_reg.h | 3 |
5 files changed, 583 insertions, 295 deletions
diff --git a/Documentation/devicetree/bindings/video/exynos_dp.txt b/Documentation/devicetree/bindings/video/exynos_dp.txt new file mode 100644 index 000000000000..c60da67a5d76 --- /dev/null +++ b/Documentation/devicetree/bindings/video/exynos_dp.txt | |||
@@ -0,0 +1,80 @@ | |||
1 | The Exynos display port interface should be configured based on | ||
2 | the type of panel connected to it. | ||
3 | |||
4 | We use two nodes: | ||
5 | -dp-controller node | ||
6 | -dptx-phy node(defined inside dp-controller node) | ||
7 | |||
8 | For the DP-PHY initialization, we use the dptx-phy node. | ||
9 | Required properties for dptx-phy: | ||
10 | -reg: | ||
11 | Base address of DP PHY register. | ||
12 | -samsung,enable-mask: | ||
13 | The bit-mask used to enable/disable DP PHY. | ||
14 | |||
15 | For the Panel initialization, we read data from dp-controller node. | ||
16 | Required properties for dp-controller: | ||
17 | -compatible: | ||
18 | should be "samsung,exynos5-dp". | ||
19 | -reg: | ||
20 | physical base address of the controller and length | ||
21 | of memory mapped region. | ||
22 | -interrupts: | ||
23 | interrupt combiner values. | ||
24 | -interrupt-parent: | ||
25 | phandle to Interrupt combiner node. | ||
26 | -samsung,color-space: | ||
27 | input video data format. | ||
28 | COLOR_RGB = 0, COLOR_YCBCR422 = 1, COLOR_YCBCR444 = 2 | ||
29 | -samsung,dynamic-range: | ||
30 | dynamic range for input video data. | ||
31 | VESA = 0, CEA = 1 | ||
32 | -samsung,ycbcr-coeff: | ||
33 | YCbCr co-efficients for input video. | ||
34 | COLOR_YCBCR601 = 0, COLOR_YCBCR709 = 1 | ||
35 | -samsung,color-depth: | ||
36 | number of bits per colour component. | ||
37 | COLOR_6 = 0, COLOR_8 = 1, COLOR_10 = 2, COLOR_12 = 3 | ||
38 | -samsung,link-rate: | ||
39 | link rate supported by the panel. | ||
40 | LINK_RATE_1_62GBPS = 0x6, LINK_RATE_2_70GBPS = 0x0A | ||
41 | -samsung,lane-count: | ||
42 | number of lanes supported by the panel. | ||
43 | LANE_COUNT1 = 1, LANE_COUNT2 = 2, LANE_COUNT4 = 4 | ||
44 | |||
45 | Optional properties for dp-controller: | ||
46 | -interlaced: | ||
47 | interlace scan mode. | ||
48 | Progressive if defined, Interlaced if not defined | ||
49 | -vsync-active-high: | ||
50 | VSYNC polarity configuration. | ||
51 | High if defined, Low if not defined | ||
52 | -hsync-active-high: | ||
53 | HSYNC polarity configuration. | ||
54 | High if defined, Low if not defined | ||
55 | |||
56 | Example: | ||
57 | |||
58 | SOC specific portion: | ||
59 | dp-controller { | ||
60 | compatible = "samsung,exynos5-dp"; | ||
61 | reg = <0x145b0000 0x10000>; | ||
62 | interrupts = <10 3>; | ||
63 | interrupt-parent = <&combiner>; | ||
64 | |||
65 | dptx-phy { | ||
66 | reg = <0x10040720>; | ||
67 | samsung,enable-mask = <1>; | ||
68 | }; | ||
69 | |||
70 | }; | ||
71 | |||
72 | Board Specific portion: | ||
73 | dp-controller { | ||
74 | samsung,color-space = <0>; | ||
75 | samsung,dynamic-range = <0>; | ||
76 | samsung,ycbcr-coeff = <0>; | ||
77 | samsung,color-depth = <1>; | ||
78 | samsung,link-rate = <0x0a>; | ||
79 | samsung,lane-count = <4>; | ||
80 | }; | ||
diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c index d55470e75412..28fd686c6b81 100644 --- a/drivers/video/exynos/exynos_dp_core.c +++ b/drivers/video/exynos/exynos_dp_core.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/of.h> | ||
21 | 22 | ||
22 | #include <video/exynos_dp.h> | 23 | #include <video/exynos_dp.h> |
23 | 24 | ||
@@ -48,10 +49,6 @@ static int exynos_dp_detect_hpd(struct exynos_dp_device *dp) | |||
48 | { | 49 | { |
49 | int timeout_loop = 0; | 50 | int timeout_loop = 0; |
50 | 51 | ||
51 | exynos_dp_init_hpd(dp); | ||
52 | |||
53 | usleep_range(200, 210); | ||
54 | |||
55 | while (exynos_dp_get_plug_in_status(dp) != 0) { | 52 | while (exynos_dp_get_plug_in_status(dp) != 0) { |
56 | timeout_loop++; | 53 | timeout_loop++; |
57 | if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { | 54 | if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { |
@@ -90,9 +87,11 @@ static int exynos_dp_read_edid(struct exynos_dp_device *dp) | |||
90 | */ | 87 | */ |
91 | 88 | ||
92 | /* Read Extension Flag, Number of 128-byte EDID extension blocks */ | 89 | /* Read Extension Flag, Number of 128-byte EDID extension blocks */ |
93 | exynos_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, | 90 | retval = exynos_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, |
94 | EDID_EXTENSION_FLAG, | 91 | EDID_EXTENSION_FLAG, |
95 | &extend_block); | 92 | &extend_block); |
93 | if (retval) | ||
94 | return retval; | ||
96 | 95 | ||
97 | if (extend_block > 0) { | 96 | if (extend_block > 0) { |
98 | dev_dbg(dp->dev, "EDID data includes a single extension!\n"); | 97 | dev_dbg(dp->dev, "EDID data includes a single extension!\n"); |
@@ -181,14 +180,15 @@ static int exynos_dp_handle_edid(struct exynos_dp_device *dp) | |||
181 | int retval; | 180 | int retval; |
182 | 181 | ||
183 | /* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */ | 182 | /* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */ |
184 | exynos_dp_read_bytes_from_dpcd(dp, | 183 | retval = exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_DPCD_REV, |
185 | DPCD_ADDR_DPCD_REV, | 184 | 12, buf); |
186 | 12, buf); | 185 | if (retval) |
186 | return retval; | ||
187 | 187 | ||
188 | /* Read EDID */ | 188 | /* Read EDID */ |
189 | for (i = 0; i < 3; i++) { | 189 | for (i = 0; i < 3; i++) { |
190 | retval = exynos_dp_read_edid(dp); | 190 | retval = exynos_dp_read_edid(dp); |
191 | if (retval == 0) | 191 | if (!retval) |
192 | break; | 192 | break; |
193 | } | 193 | } |
194 | 194 | ||
@@ -261,11 +261,10 @@ static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp, | |||
261 | } | 261 | } |
262 | } | 262 | } |
263 | 263 | ||
264 | static void exynos_dp_link_start(struct exynos_dp_device *dp) | 264 | static int exynos_dp_link_start(struct exynos_dp_device *dp) |
265 | { | 265 | { |
266 | u8 buf[4]; | 266 | u8 buf[4]; |
267 | int lane; | 267 | int lane, lane_count, pll_tries, retval; |
268 | int lane_count; | ||
269 | 268 | ||
270 | lane_count = dp->link_train.lane_count; | 269 | lane_count = dp->link_train.lane_count; |
271 | 270 | ||
@@ -275,10 +274,6 @@ static void exynos_dp_link_start(struct exynos_dp_device *dp) | |||
275 | for (lane = 0; lane < lane_count; lane++) | 274 | for (lane = 0; lane < lane_count; lane++) |
276 | dp->link_train.cr_loop[lane] = 0; | 275 | dp->link_train.cr_loop[lane] = 0; |
277 | 276 | ||
278 | /* Set sink to D0 (Sink Not Ready) mode. */ | ||
279 | exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_SINK_POWER_STATE, | ||
280 | DPCD_SET_POWER_STATE_D0); | ||
281 | |||
282 | /* Set link rate and count as you want to establish*/ | 277 | /* Set link rate and count as you want to establish*/ |
283 | exynos_dp_set_link_bandwidth(dp, dp->link_train.link_rate); | 278 | exynos_dp_set_link_bandwidth(dp, dp->link_train.link_rate); |
284 | exynos_dp_set_lane_count(dp, dp->link_train.lane_count); | 279 | exynos_dp_set_lane_count(dp, dp->link_train.lane_count); |
@@ -286,29 +281,46 @@ static void exynos_dp_link_start(struct exynos_dp_device *dp) | |||
286 | /* Setup RX configuration */ | 281 | /* Setup RX configuration */ |
287 | buf[0] = dp->link_train.link_rate; | 282 | buf[0] = dp->link_train.link_rate; |
288 | buf[1] = dp->link_train.lane_count; | 283 | buf[1] = dp->link_train.lane_count; |
289 | exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET, | 284 | retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET, |
290 | 2, buf); | 285 | 2, buf); |
286 | if (retval) | ||
287 | return retval; | ||
291 | 288 | ||
292 | /* Set TX pre-emphasis to minimum */ | 289 | /* Set TX pre-emphasis to minimum */ |
293 | for (lane = 0; lane < lane_count; lane++) | 290 | for (lane = 0; lane < lane_count; lane++) |
294 | exynos_dp_set_lane_lane_pre_emphasis(dp, | 291 | exynos_dp_set_lane_lane_pre_emphasis(dp, |
295 | PRE_EMPHASIS_LEVEL_0, lane); | 292 | PRE_EMPHASIS_LEVEL_0, lane); |
296 | 293 | ||
294 | /* Wait for PLL lock */ | ||
295 | pll_tries = 0; | ||
296 | while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { | ||
297 | if (pll_tries == DP_TIMEOUT_LOOP_COUNT) { | ||
298 | dev_err(dp->dev, "Wait for PLL lock timed out\n"); | ||
299 | return -ETIMEDOUT; | ||
300 | } | ||
301 | |||
302 | pll_tries++; | ||
303 | usleep_range(90, 120); | ||
304 | } | ||
305 | |||
297 | /* Set training pattern 1 */ | 306 | /* Set training pattern 1 */ |
298 | exynos_dp_set_training_pattern(dp, TRAINING_PTN1); | 307 | exynos_dp_set_training_pattern(dp, TRAINING_PTN1); |
299 | 308 | ||
300 | /* Set RX training pattern */ | 309 | /* Set RX training pattern */ |
301 | exynos_dp_write_byte_to_dpcd(dp, | 310 | retval = exynos_dp_write_byte_to_dpcd(dp, |
302 | DPCD_ADDR_TRAINING_PATTERN_SET, | 311 | DPCD_ADDR_TRAINING_PATTERN_SET, |
303 | DPCD_SCRAMBLING_DISABLED | | 312 | DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1); |
304 | DPCD_TRAINING_PATTERN_1); | 313 | if (retval) |
314 | return retval; | ||
305 | 315 | ||
306 | for (lane = 0; lane < lane_count; lane++) | 316 | for (lane = 0; lane < lane_count; lane++) |
307 | buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 | | 317 | buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 | |
308 | DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0; | 318 | DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0; |
309 | exynos_dp_write_bytes_to_dpcd(dp, | 319 | |
310 | DPCD_ADDR_TRAINING_LANE0_SET, | 320 | retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET, |
311 | lane_count, buf); | 321 | lane_count, buf); |
322 | |||
323 | return retval; | ||
312 | } | 324 | } |
313 | 325 | ||
314 | static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane) | 326 | static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane) |
@@ -332,18 +344,17 @@ static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count) | |||
332 | return 0; | 344 | return 0; |
333 | } | 345 | } |
334 | 346 | ||
335 | static int exynos_dp_channel_eq_ok(u8 link_align[3], int lane_count) | 347 | static int exynos_dp_channel_eq_ok(u8 link_status[2], u8 link_align, |
348 | int lane_count) | ||
336 | { | 349 | { |
337 | int lane; | 350 | int lane; |
338 | u8 lane_align; | ||
339 | u8 lane_status; | 351 | u8 lane_status; |
340 | 352 | ||
341 | lane_align = link_align[2]; | 353 | if ((link_align & DPCD_INTERLANE_ALIGN_DONE) == 0) |
342 | if ((lane_align & DPCD_INTERLANE_ALIGN_DONE) == 0) | ||
343 | return -EINVAL; | 354 | return -EINVAL; |
344 | 355 | ||
345 | for (lane = 0; lane < lane_count; lane++) { | 356 | for (lane = 0; lane < lane_count; lane++) { |
346 | lane_status = exynos_dp_get_lane_status(link_align, lane); | 357 | lane_status = exynos_dp_get_lane_status(link_status, lane); |
347 | lane_status &= DPCD_CHANNEL_EQ_BITS; | 358 | lane_status &= DPCD_CHANNEL_EQ_BITS; |
348 | if (lane_status != DPCD_CHANNEL_EQ_BITS) | 359 | if (lane_status != DPCD_CHANNEL_EQ_BITS) |
349 | return -EINVAL; | 360 | return -EINVAL; |
@@ -427,60 +438,60 @@ static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp) | |||
427 | dp->link_train.lt_state = FAILED; | 438 | dp->link_train.lt_state = FAILED; |
428 | } | 439 | } |
429 | 440 | ||
430 | static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) | 441 | static void exynos_dp_get_adjust_training_lane(struct exynos_dp_device *dp, |
442 | u8 adjust_request[2]) | ||
431 | { | 443 | { |
432 | u8 link_status[2]; | 444 | int lane, lane_count; |
433 | int lane; | 445 | u8 voltage_swing, pre_emphasis, training_lane; |
434 | int lane_count; | ||
435 | 446 | ||
436 | u8 adjust_request[2]; | 447 | lane_count = dp->link_train.lane_count; |
437 | u8 voltage_swing; | 448 | for (lane = 0; lane < lane_count; lane++) { |
438 | u8 pre_emphasis; | 449 | voltage_swing = exynos_dp_get_adjust_request_voltage( |
439 | u8 training_lane; | 450 | adjust_request, lane); |
451 | pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( | ||
452 | adjust_request, lane); | ||
453 | training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | | ||
454 | DPCD_PRE_EMPHASIS_SET(pre_emphasis); | ||
455 | |||
456 | if (voltage_swing == VOLTAGE_LEVEL_3) | ||
457 | training_lane |= DPCD_MAX_SWING_REACHED; | ||
458 | if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) | ||
459 | training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; | ||
460 | |||
461 | dp->link_train.training_lane[lane] = training_lane; | ||
462 | } | ||
463 | } | ||
464 | |||
465 | static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) | ||
466 | { | ||
467 | int lane, lane_count, retval; | ||
468 | u8 voltage_swing, pre_emphasis, training_lane; | ||
469 | u8 link_status[2], adjust_request[2]; | ||
440 | 470 | ||
441 | usleep_range(100, 101); | 471 | usleep_range(100, 101); |
442 | 472 | ||
443 | lane_count = dp->link_train.lane_count; | 473 | lane_count = dp->link_train.lane_count; |
444 | 474 | ||
445 | exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, | 475 | retval = exynos_dp_read_bytes_from_dpcd(dp, |
446 | 2, link_status); | 476 | DPCD_ADDR_LANE0_1_STATUS, 2, link_status); |
477 | if (retval) | ||
478 | return retval; | ||
479 | |||
480 | retval = exynos_dp_read_bytes_from_dpcd(dp, | ||
481 | DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request); | ||
482 | if (retval) | ||
483 | return retval; | ||
447 | 484 | ||
448 | if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { | 485 | if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { |
449 | /* set training pattern 2 for EQ */ | 486 | /* set training pattern 2 for EQ */ |
450 | exynos_dp_set_training_pattern(dp, TRAINING_PTN2); | 487 | exynos_dp_set_training_pattern(dp, TRAINING_PTN2); |
451 | 488 | ||
452 | for (lane = 0; lane < lane_count; lane++) { | 489 | retval = exynos_dp_write_byte_to_dpcd(dp, |
453 | exynos_dp_read_bytes_from_dpcd(dp, | 490 | DPCD_ADDR_TRAINING_PATTERN_SET, |
454 | DPCD_ADDR_ADJUST_REQUEST_LANE0_1, | 491 | DPCD_SCRAMBLING_DISABLED | |
455 | 2, adjust_request); | 492 | DPCD_TRAINING_PATTERN_2); |
456 | voltage_swing = exynos_dp_get_adjust_request_voltage( | 493 | if (retval) |
457 | adjust_request, lane); | 494 | return retval; |
458 | pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( | ||
459 | adjust_request, lane); | ||
460 | training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | | ||
461 | DPCD_PRE_EMPHASIS_SET(pre_emphasis); | ||
462 | |||
463 | if (voltage_swing == VOLTAGE_LEVEL_3) | ||
464 | training_lane |= DPCD_MAX_SWING_REACHED; | ||
465 | if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) | ||
466 | training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; | ||
467 | |||
468 | dp->link_train.training_lane[lane] = training_lane; | ||
469 | |||
470 | exynos_dp_set_lane_link_training(dp, | ||
471 | dp->link_train.training_lane[lane], | ||
472 | lane); | ||
473 | } | ||
474 | |||
475 | exynos_dp_write_byte_to_dpcd(dp, | ||
476 | DPCD_ADDR_TRAINING_PATTERN_SET, | ||
477 | DPCD_SCRAMBLING_DISABLED | | ||
478 | DPCD_TRAINING_PATTERN_2); | ||
479 | |||
480 | exynos_dp_write_bytes_to_dpcd(dp, | ||
481 | DPCD_ADDR_TRAINING_LANE0_SET, | ||
482 | lane_count, | ||
483 | dp->link_train.training_lane); | ||
484 | 495 | ||
485 | dev_info(dp->dev, "Link Training Clock Recovery success\n"); | 496 | dev_info(dp->dev, "Link Training Clock Recovery success\n"); |
486 | dp->link_train.lt_state = EQUALIZER_TRAINING; | 497 | dp->link_train.lt_state = EQUALIZER_TRAINING; |
@@ -488,152 +499,116 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) | |||
488 | for (lane = 0; lane < lane_count; lane++) { | 499 | for (lane = 0; lane < lane_count; lane++) { |
489 | training_lane = exynos_dp_get_lane_link_training( | 500 | training_lane = exynos_dp_get_lane_link_training( |
490 | dp, lane); | 501 | dp, lane); |
491 | exynos_dp_read_bytes_from_dpcd(dp, | ||
492 | DPCD_ADDR_ADJUST_REQUEST_LANE0_1, | ||
493 | 2, adjust_request); | ||
494 | voltage_swing = exynos_dp_get_adjust_request_voltage( | 502 | voltage_swing = exynos_dp_get_adjust_request_voltage( |
495 | adjust_request, lane); | 503 | adjust_request, lane); |
496 | pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( | 504 | pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( |
497 | adjust_request, lane); | 505 | adjust_request, lane); |
498 | 506 | ||
499 | if (voltage_swing == VOLTAGE_LEVEL_3 || | 507 | if (DPCD_VOLTAGE_SWING_GET(training_lane) == |
500 | pre_emphasis == PRE_EMPHASIS_LEVEL_3) { | 508 | voltage_swing && |
501 | dev_err(dp->dev, "voltage or pre emphasis reached max level\n"); | 509 | DPCD_PRE_EMPHASIS_GET(training_lane) == |
502 | goto reduce_link_rate; | 510 | pre_emphasis) |
503 | } | ||
504 | |||
505 | if ((DPCD_VOLTAGE_SWING_GET(training_lane) == | ||
506 | voltage_swing) && | ||
507 | (DPCD_PRE_EMPHASIS_GET(training_lane) == | ||
508 | pre_emphasis)) { | ||
509 | dp->link_train.cr_loop[lane]++; | 511 | dp->link_train.cr_loop[lane]++; |
510 | if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP) { | ||
511 | dev_err(dp->dev, "CR Max loop\n"); | ||
512 | goto reduce_link_rate; | ||
513 | } | ||
514 | } | ||
515 | |||
516 | training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | | ||
517 | DPCD_PRE_EMPHASIS_SET(pre_emphasis); | ||
518 | 512 | ||
519 | if (voltage_swing == VOLTAGE_LEVEL_3) | 513 | if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP || |
520 | training_lane |= DPCD_MAX_SWING_REACHED; | 514 | voltage_swing == VOLTAGE_LEVEL_3 || |
521 | if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) | 515 | pre_emphasis == PRE_EMPHASIS_LEVEL_3) { |
522 | training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; | 516 | dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n", |
517 | dp->link_train.cr_loop[lane], | ||
518 | voltage_swing, pre_emphasis); | ||
519 | exynos_dp_reduce_link_rate(dp); | ||
520 | return -EIO; | ||
521 | } | ||
522 | } | ||
523 | } | ||
523 | 524 | ||
524 | dp->link_train.training_lane[lane] = training_lane; | 525 | exynos_dp_get_adjust_training_lane(dp, adjust_request); |
525 | 526 | ||
526 | exynos_dp_set_lane_link_training(dp, | 527 | for (lane = 0; lane < lane_count; lane++) |
527 | dp->link_train.training_lane[lane], lane); | 528 | exynos_dp_set_lane_link_training(dp, |
528 | } | 529 | dp->link_train.training_lane[lane], lane); |
529 | 530 | ||
530 | exynos_dp_write_bytes_to_dpcd(dp, | 531 | retval = exynos_dp_write_bytes_to_dpcd(dp, |
531 | DPCD_ADDR_TRAINING_LANE0_SET, | 532 | DPCD_ADDR_TRAINING_LANE0_SET, lane_count, |
532 | lane_count, | ||
533 | dp->link_train.training_lane); | 533 | dp->link_train.training_lane); |
534 | } | 534 | if (retval) |
535 | 535 | return retval; | |
536 | return 0; | ||
537 | 536 | ||
538 | reduce_link_rate: | 537 | return retval; |
539 | exynos_dp_reduce_link_rate(dp); | ||
540 | return -EIO; | ||
541 | } | 538 | } |
542 | 539 | ||
543 | static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) | 540 | static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) |
544 | { | 541 | { |
545 | u8 link_status[2]; | 542 | int lane, lane_count, retval; |
546 | u8 link_align[3]; | ||
547 | int lane; | ||
548 | int lane_count; | ||
549 | u32 reg; | 543 | u32 reg; |
550 | 544 | u8 link_align, link_status[2], adjust_request[2]; | |
551 | u8 adjust_request[2]; | ||
552 | u8 voltage_swing; | ||
553 | u8 pre_emphasis; | ||
554 | u8 training_lane; | ||
555 | 545 | ||
556 | usleep_range(400, 401); | 546 | usleep_range(400, 401); |
557 | 547 | ||
558 | lane_count = dp->link_train.lane_count; | 548 | lane_count = dp->link_train.lane_count; |
559 | 549 | ||
560 | exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, | 550 | retval = exynos_dp_read_bytes_from_dpcd(dp, |
561 | 2, link_status); | 551 | DPCD_ADDR_LANE0_1_STATUS, 2, link_status); |
552 | if (retval) | ||
553 | return retval; | ||
562 | 554 | ||
563 | if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { | 555 | if (exynos_dp_clock_recovery_ok(link_status, lane_count)) { |
564 | link_align[0] = link_status[0]; | 556 | exynos_dp_reduce_link_rate(dp); |
565 | link_align[1] = link_status[1]; | 557 | return -EIO; |
558 | } | ||
566 | 559 | ||
567 | exynos_dp_read_byte_from_dpcd(dp, | 560 | retval = exynos_dp_read_bytes_from_dpcd(dp, |
568 | DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, | 561 | DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request); |
569 | &link_align[2]); | 562 | if (retval) |
563 | return retval; | ||
570 | 564 | ||
571 | for (lane = 0; lane < lane_count; lane++) { | 565 | retval = exynos_dp_read_byte_from_dpcd(dp, |
572 | exynos_dp_read_bytes_from_dpcd(dp, | 566 | DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, &link_align); |
573 | DPCD_ADDR_ADJUST_REQUEST_LANE0_1, | 567 | if (retval) |
574 | 2, adjust_request); | 568 | return retval; |
575 | voltage_swing = exynos_dp_get_adjust_request_voltage( | ||
576 | adjust_request, lane); | ||
577 | pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( | ||
578 | adjust_request, lane); | ||
579 | training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | | ||
580 | DPCD_PRE_EMPHASIS_SET(pre_emphasis); | ||
581 | 569 | ||
582 | if (voltage_swing == VOLTAGE_LEVEL_3) | 570 | exynos_dp_get_adjust_training_lane(dp, adjust_request); |
583 | training_lane |= DPCD_MAX_SWING_REACHED; | ||
584 | if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) | ||
585 | training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; | ||
586 | 571 | ||
587 | dp->link_train.training_lane[lane] = training_lane; | 572 | if (!exynos_dp_channel_eq_ok(link_status, link_align, lane_count)) { |
588 | } | 573 | /* traing pattern Set to Normal */ |
574 | exynos_dp_training_pattern_dis(dp); | ||
589 | 575 | ||
590 | if (exynos_dp_channel_eq_ok(link_align, lane_count) == 0) { | 576 | dev_info(dp->dev, "Link Training success!\n"); |
591 | /* traing pattern Set to Normal */ | ||
592 | exynos_dp_training_pattern_dis(dp); | ||
593 | 577 | ||
594 | dev_info(dp->dev, "Link Training success!\n"); | 578 | exynos_dp_get_link_bandwidth(dp, ®); |
595 | 579 | dp->link_train.link_rate = reg; | |
596 | exynos_dp_get_link_bandwidth(dp, ®); | 580 | dev_dbg(dp->dev, "final bandwidth = %.2x\n", |
597 | dp->link_train.link_rate = reg; | 581 | dp->link_train.link_rate); |
598 | dev_dbg(dp->dev, "final bandwidth = %.2x\n", | ||
599 | dp->link_train.link_rate); | ||
600 | 582 | ||
601 | exynos_dp_get_lane_count(dp, ®); | 583 | exynos_dp_get_lane_count(dp, ®); |
602 | dp->link_train.lane_count = reg; | 584 | dp->link_train.lane_count = reg; |
603 | dev_dbg(dp->dev, "final lane count = %.2x\n", | 585 | dev_dbg(dp->dev, "final lane count = %.2x\n", |
604 | dp->link_train.lane_count); | 586 | dp->link_train.lane_count); |
605 | 587 | ||
606 | /* set enhanced mode if available */ | 588 | /* set enhanced mode if available */ |
607 | exynos_dp_set_enhanced_mode(dp); | 589 | exynos_dp_set_enhanced_mode(dp); |
608 | dp->link_train.lt_state = FINISHED; | 590 | dp->link_train.lt_state = FINISHED; |
609 | } else { | ||
610 | /* not all locked */ | ||
611 | dp->link_train.eq_loop++; | ||
612 | 591 | ||
613 | if (dp->link_train.eq_loop > MAX_EQ_LOOP) { | 592 | return 0; |
614 | dev_err(dp->dev, "EQ Max loop\n"); | 593 | } |
615 | goto reduce_link_rate; | ||
616 | } | ||
617 | 594 | ||
618 | for (lane = 0; lane < lane_count; lane++) | 595 | /* not all locked */ |
619 | exynos_dp_set_lane_link_training(dp, | 596 | dp->link_train.eq_loop++; |
620 | dp->link_train.training_lane[lane], | ||
621 | lane); | ||
622 | 597 | ||
623 | exynos_dp_write_bytes_to_dpcd(dp, | 598 | if (dp->link_train.eq_loop > MAX_EQ_LOOP) { |
624 | DPCD_ADDR_TRAINING_LANE0_SET, | 599 | dev_err(dp->dev, "EQ Max loop\n"); |
625 | lane_count, | 600 | exynos_dp_reduce_link_rate(dp); |
626 | dp->link_train.training_lane); | 601 | return -EIO; |
627 | } | ||
628 | } else { | ||
629 | goto reduce_link_rate; | ||
630 | } | 602 | } |
631 | 603 | ||
632 | return 0; | 604 | for (lane = 0; lane < lane_count; lane++) |
605 | exynos_dp_set_lane_link_training(dp, | ||
606 | dp->link_train.training_lane[lane], lane); | ||
607 | |||
608 | retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET, | ||
609 | lane_count, dp->link_train.training_lane); | ||
633 | 610 | ||
634 | reduce_link_rate: | 611 | return retval; |
635 | exynos_dp_reduce_link_rate(dp); | ||
636 | return -EIO; | ||
637 | } | 612 | } |
638 | 613 | ||
639 | static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp, | 614 | static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp, |
@@ -701,16 +676,17 @@ static void exynos_dp_init_training(struct exynos_dp_device *dp, | |||
701 | 676 | ||
702 | static int exynos_dp_sw_link_training(struct exynos_dp_device *dp) | 677 | static int exynos_dp_sw_link_training(struct exynos_dp_device *dp) |
703 | { | 678 | { |
704 | int retval = 0; | 679 | int retval = 0, training_finished = 0; |
705 | int training_finished = 0; | ||
706 | 680 | ||
707 | dp->link_train.lt_state = START; | 681 | dp->link_train.lt_state = START; |
708 | 682 | ||
709 | /* Process here */ | 683 | /* Process here */ |
710 | while (!training_finished) { | 684 | while (!retval && !training_finished) { |
711 | switch (dp->link_train.lt_state) { | 685 | switch (dp->link_train.lt_state) { |
712 | case START: | 686 | case START: |
713 | exynos_dp_link_start(dp); | 687 | retval = exynos_dp_link_start(dp); |
688 | if (retval) | ||
689 | dev_err(dp->dev, "LT link start failed!\n"); | ||
714 | break; | 690 | break; |
715 | case CLOCK_RECOVERY: | 691 | case CLOCK_RECOVERY: |
716 | retval = exynos_dp_process_clock_recovery(dp); | 692 | retval = exynos_dp_process_clock_recovery(dp); |
@@ -729,6 +705,8 @@ static int exynos_dp_sw_link_training(struct exynos_dp_device *dp) | |||
729 | return -EREMOTEIO; | 705 | return -EREMOTEIO; |
730 | } | 706 | } |
731 | } | 707 | } |
708 | if (retval) | ||
709 | dev_err(dp->dev, "eDP link training failed (%d)\n", retval); | ||
732 | 710 | ||
733 | return retval; | 711 | return retval; |
734 | } | 712 | } |
@@ -752,19 +730,15 @@ static int exynos_dp_set_link_train(struct exynos_dp_device *dp, | |||
752 | return retval; | 730 | return retval; |
753 | } | 731 | } |
754 | 732 | ||
755 | static int exynos_dp_config_video(struct exynos_dp_device *dp, | 733 | static int exynos_dp_config_video(struct exynos_dp_device *dp) |
756 | struct video_info *video_info) | ||
757 | { | 734 | { |
758 | int retval = 0; | 735 | int retval = 0; |
759 | int timeout_loop = 0; | 736 | int timeout_loop = 0; |
760 | int done_count = 0; | 737 | int done_count = 0; |
761 | 738 | ||
762 | exynos_dp_config_video_slave_mode(dp, video_info); | 739 | exynos_dp_config_video_slave_mode(dp); |
763 | 740 | ||
764 | exynos_dp_set_video_color_format(dp, video_info->color_depth, | 741 | exynos_dp_set_video_color_format(dp); |
765 | video_info->color_space, | ||
766 | video_info->dynamic_range, | ||
767 | video_info->ycbcr_coeff); | ||
768 | 742 | ||
769 | if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { | 743 | if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { |
770 | dev_err(dp->dev, "PLL is not locked yet.\n"); | 744 | dev_err(dp->dev, "PLL is not locked yet.\n"); |
@@ -852,10 +826,213 @@ static irqreturn_t exynos_dp_irq_handler(int irq, void *arg) | |||
852 | { | 826 | { |
853 | struct exynos_dp_device *dp = arg; | 827 | struct exynos_dp_device *dp = arg; |
854 | 828 | ||
855 | dev_err(dp->dev, "exynos_dp_irq_handler\n"); | 829 | enum dp_irq_type irq_type; |
830 | |||
831 | irq_type = exynos_dp_get_irq_type(dp); | ||
832 | switch (irq_type) { | ||
833 | case DP_IRQ_TYPE_HP_CABLE_IN: | ||
834 | dev_dbg(dp->dev, "Received irq - cable in\n"); | ||
835 | schedule_work(&dp->hotplug_work); | ||
836 | exynos_dp_clear_hotplug_interrupts(dp); | ||
837 | break; | ||
838 | case DP_IRQ_TYPE_HP_CABLE_OUT: | ||
839 | dev_dbg(dp->dev, "Received irq - cable out\n"); | ||
840 | exynos_dp_clear_hotplug_interrupts(dp); | ||
841 | break; | ||
842 | case DP_IRQ_TYPE_HP_CHANGE: | ||
843 | /* | ||
844 | * We get these change notifications once in a while, but there | ||
845 | * is nothing we can do with them. Just ignore it for now and | ||
846 | * only handle cable changes. | ||
847 | */ | ||
848 | dev_dbg(dp->dev, "Received irq - hotplug change; ignoring.\n"); | ||
849 | exynos_dp_clear_hotplug_interrupts(dp); | ||
850 | break; | ||
851 | default: | ||
852 | dev_err(dp->dev, "Received irq - unknown type!\n"); | ||
853 | break; | ||
854 | } | ||
856 | return IRQ_HANDLED; | 855 | return IRQ_HANDLED; |
857 | } | 856 | } |
858 | 857 | ||
858 | static void exynos_dp_hotplug(struct work_struct *work) | ||
859 | { | ||
860 | struct exynos_dp_device *dp; | ||
861 | int ret; | ||
862 | |||
863 | dp = container_of(work, struct exynos_dp_device, hotplug_work); | ||
864 | |||
865 | ret = exynos_dp_detect_hpd(dp); | ||
866 | if (ret) { | ||
867 | /* Cable has been disconnected, we're done */ | ||
868 | return; | ||
869 | } | ||
870 | |||
871 | ret = exynos_dp_handle_edid(dp); | ||
872 | if (ret) { | ||
873 | dev_err(dp->dev, "unable to handle edid\n"); | ||
874 | return; | ||
875 | } | ||
876 | |||
877 | ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count, | ||
878 | dp->video_info->link_rate); | ||
879 | if (ret) { | ||
880 | dev_err(dp->dev, "unable to do link train\n"); | ||
881 | return; | ||
882 | } | ||
883 | |||
884 | exynos_dp_enable_scramble(dp, 1); | ||
885 | exynos_dp_enable_rx_to_enhanced_mode(dp, 1); | ||
886 | exynos_dp_enable_enhanced_mode(dp, 1); | ||
887 | |||
888 | exynos_dp_set_lane_count(dp, dp->video_info->lane_count); | ||
889 | exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate); | ||
890 | |||
891 | exynos_dp_init_video(dp); | ||
892 | ret = exynos_dp_config_video(dp); | ||
893 | if (ret) | ||
894 | dev_err(dp->dev, "unable to config video\n"); | ||
895 | } | ||
896 | |||
897 | #ifdef CONFIG_OF | ||
898 | static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev) | ||
899 | { | ||
900 | struct device_node *dp_node = dev->of_node; | ||
901 | struct exynos_dp_platdata *pd; | ||
902 | struct video_info *dp_video_config; | ||
903 | |||
904 | pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); | ||
905 | if (!pd) { | ||
906 | dev_err(dev, "memory allocation for pdata failed\n"); | ||
907 | return ERR_PTR(-ENOMEM); | ||
908 | } | ||
909 | dp_video_config = devm_kzalloc(dev, | ||
910 | sizeof(*dp_video_config), GFP_KERNEL); | ||
911 | |||
912 | if (!dp_video_config) { | ||
913 | dev_err(dev, "memory allocation for video config failed\n"); | ||
914 | return ERR_PTR(-ENOMEM); | ||
915 | } | ||
916 | pd->video_info = dp_video_config; | ||
917 | |||
918 | dp_video_config->h_sync_polarity = | ||
919 | of_property_read_bool(dp_node, "hsync-active-high"); | ||
920 | |||
921 | dp_video_config->v_sync_polarity = | ||
922 | of_property_read_bool(dp_node, "vsync-active-high"); | ||
923 | |||
924 | dp_video_config->interlaced = | ||
925 | of_property_read_bool(dp_node, "interlaced"); | ||
926 | |||
927 | if (of_property_read_u32(dp_node, "samsung,color-space", | ||
928 | &dp_video_config->color_space)) { | ||
929 | dev_err(dev, "failed to get color-space\n"); | ||
930 | return ERR_PTR(-EINVAL); | ||
931 | } | ||
932 | |||
933 | if (of_property_read_u32(dp_node, "samsung,dynamic-range", | ||
934 | &dp_video_config->dynamic_range)) { | ||
935 | dev_err(dev, "failed to get dynamic-range\n"); | ||
936 | return ERR_PTR(-EINVAL); | ||
937 | } | ||
938 | |||
939 | if (of_property_read_u32(dp_node, "samsung,ycbcr-coeff", | ||
940 | &dp_video_config->ycbcr_coeff)) { | ||
941 | dev_err(dev, "failed to get ycbcr-coeff\n"); | ||
942 | return ERR_PTR(-EINVAL); | ||
943 | } | ||
944 | |||
945 | if (of_property_read_u32(dp_node, "samsung,color-depth", | ||
946 | &dp_video_config->color_depth)) { | ||
947 | dev_err(dev, "failed to get color-depth\n"); | ||
948 | return ERR_PTR(-EINVAL); | ||
949 | } | ||
950 | |||
951 | if (of_property_read_u32(dp_node, "samsung,link-rate", | ||
952 | &dp_video_config->link_rate)) { | ||
953 | dev_err(dev, "failed to get link-rate\n"); | ||
954 | return ERR_PTR(-EINVAL); | ||
955 | } | ||
956 | |||
957 | if (of_property_read_u32(dp_node, "samsung,lane-count", | ||
958 | &dp_video_config->lane_count)) { | ||
959 | dev_err(dev, "failed to get lane-count\n"); | ||
960 | return ERR_PTR(-EINVAL); | ||
961 | } | ||
962 | |||
963 | return pd; | ||
964 | } | ||
965 | |||
966 | static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp) | ||
967 | { | ||
968 | struct device_node *dp_phy_node; | ||
969 | u32 phy_base; | ||
970 | |||
971 | dp_phy_node = of_find_node_by_name(dp->dev->of_node, "dptx-phy"); | ||
972 | if (!dp_phy_node) { | ||
973 | dev_err(dp->dev, "could not find dptx-phy node\n"); | ||
974 | return -ENODEV; | ||
975 | } | ||
976 | |||
977 | if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) { | ||
978 | dev_err(dp->dev, "faild to get reg for dptx-phy\n"); | ||
979 | return -EINVAL; | ||
980 | } | ||
981 | |||
982 | if (of_property_read_u32(dp_phy_node, "samsung,enable-mask", | ||
983 | &dp->enable_mask)) { | ||
984 | dev_err(dp->dev, "faild to get enable-mask for dptx-phy\n"); | ||
985 | return -EINVAL; | ||
986 | } | ||
987 | |||
988 | dp->phy_addr = ioremap(phy_base, SZ_4); | ||
989 | if (!dp->phy_addr) { | ||
990 | dev_err(dp->dev, "failed to ioremap dp-phy\n"); | ||
991 | return -ENOMEM; | ||
992 | } | ||
993 | |||
994 | return 0; | ||
995 | } | ||
996 | |||
997 | static void exynos_dp_phy_init(struct exynos_dp_device *dp) | ||
998 | { | ||
999 | u32 reg; | ||
1000 | |||
1001 | reg = __raw_readl(dp->phy_addr); | ||
1002 | reg |= dp->enable_mask; | ||
1003 | __raw_writel(reg, dp->phy_addr); | ||
1004 | } | ||
1005 | |||
1006 | static void exynos_dp_phy_exit(struct exynos_dp_device *dp) | ||
1007 | { | ||
1008 | u32 reg; | ||
1009 | |||
1010 | reg = __raw_readl(dp->phy_addr); | ||
1011 | reg &= ~(dp->enable_mask); | ||
1012 | __raw_writel(reg, dp->phy_addr); | ||
1013 | } | ||
1014 | #else | ||
1015 | static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev) | ||
1016 | { | ||
1017 | return NULL; | ||
1018 | } | ||
1019 | |||
1020 | static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp) | ||
1021 | { | ||
1022 | return -EINVAL; | ||
1023 | } | ||
1024 | |||
1025 | static void exynos_dp_phy_init(struct exynos_dp_device *dp) | ||
1026 | { | ||
1027 | return; | ||
1028 | } | ||
1029 | |||
1030 | static void exynos_dp_phy_exit(struct exynos_dp_device *dp) | ||
1031 | { | ||
1032 | return; | ||
1033 | } | ||
1034 | #endif /* CONFIG_OF */ | ||
1035 | |||
859 | static int __devinit exynos_dp_probe(struct platform_device *pdev) | 1036 | static int __devinit exynos_dp_probe(struct platform_device *pdev) |
860 | { | 1037 | { |
861 | struct resource *res; | 1038 | struct resource *res; |
@@ -864,12 +1041,6 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) | |||
864 | 1041 | ||
865 | int ret = 0; | 1042 | int ret = 0; |
866 | 1043 | ||
867 | pdata = pdev->dev.platform_data; | ||
868 | if (!pdata) { | ||
869 | dev_err(&pdev->dev, "no platform data\n"); | ||
870 | return -EINVAL; | ||
871 | } | ||
872 | |||
873 | dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), | 1044 | dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), |
874 | GFP_KERNEL); | 1045 | GFP_KERNEL); |
875 | if (!dp) { | 1046 | if (!dp) { |
@@ -879,6 +1050,22 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) | |||
879 | 1050 | ||
880 | dp->dev = &pdev->dev; | 1051 | dp->dev = &pdev->dev; |
881 | 1052 | ||
1053 | if (pdev->dev.of_node) { | ||
1054 | pdata = exynos_dp_dt_parse_pdata(&pdev->dev); | ||
1055 | if (IS_ERR(pdata)) | ||
1056 | return PTR_ERR(pdata); | ||
1057 | |||
1058 | ret = exynos_dp_dt_parse_phydata(dp); | ||
1059 | if (ret) | ||
1060 | return ret; | ||
1061 | } else { | ||
1062 | pdata = pdev->dev.platform_data; | ||
1063 | if (!pdata) { | ||
1064 | dev_err(&pdev->dev, "no platform data\n"); | ||
1065 | return -EINVAL; | ||
1066 | } | ||
1067 | } | ||
1068 | |||
882 | dp->clock = devm_clk_get(&pdev->dev, "dp"); | 1069 | dp->clock = devm_clk_get(&pdev->dev, "dp"); |
883 | if (IS_ERR(dp->clock)) { | 1070 | if (IS_ERR(dp->clock)) { |
884 | dev_err(&pdev->dev, "failed to get clock\n"); | 1071 | dev_err(&pdev->dev, "failed to get clock\n"); |
@@ -896,50 +1083,29 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) | |||
896 | } | 1083 | } |
897 | 1084 | ||
898 | dp->irq = platform_get_irq(pdev, 0); | 1085 | dp->irq = platform_get_irq(pdev, 0); |
899 | if (!dp->irq) { | 1086 | if (dp->irq == -ENXIO) { |
900 | dev_err(&pdev->dev, "failed to get irq\n"); | 1087 | dev_err(&pdev->dev, "failed to get irq\n"); |
901 | return -ENODEV; | 1088 | return -ENODEV; |
902 | } | 1089 | } |
903 | 1090 | ||
904 | ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0, | 1091 | INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug); |
905 | "exynos-dp", dp); | ||
906 | if (ret) { | ||
907 | dev_err(&pdev->dev, "failed to request irq\n"); | ||
908 | return ret; | ||
909 | } | ||
910 | 1092 | ||
911 | dp->video_info = pdata->video_info; | 1093 | dp->video_info = pdata->video_info; |
912 | if (pdata->phy_init) | ||
913 | pdata->phy_init(); | ||
914 | |||
915 | exynos_dp_init_dp(dp); | ||
916 | |||
917 | ret = exynos_dp_detect_hpd(dp); | ||
918 | if (ret) { | ||
919 | dev_err(&pdev->dev, "unable to detect hpd\n"); | ||
920 | return ret; | ||
921 | } | ||
922 | 1094 | ||
923 | exynos_dp_handle_edid(dp); | 1095 | if (pdev->dev.of_node) { |
924 | 1096 | if (dp->phy_addr) | |
925 | ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count, | 1097 | exynos_dp_phy_init(dp); |
926 | dp->video_info->link_rate); | 1098 | } else { |
927 | if (ret) { | 1099 | if (pdata->phy_init) |
928 | dev_err(&pdev->dev, "unable to do link train\n"); | 1100 | pdata->phy_init(); |
929 | return ret; | ||
930 | } | 1101 | } |
931 | 1102 | ||
932 | exynos_dp_enable_scramble(dp, 1); | 1103 | exynos_dp_init_dp(dp); |
933 | exynos_dp_enable_rx_to_enhanced_mode(dp, 1); | ||
934 | exynos_dp_enable_enhanced_mode(dp, 1); | ||
935 | |||
936 | exynos_dp_set_lane_count(dp, dp->video_info->lane_count); | ||
937 | exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate); | ||
938 | 1104 | ||
939 | exynos_dp_init_video(dp); | 1105 | ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0, |
940 | ret = exynos_dp_config_video(dp, dp->video_info); | 1106 | "exynos-dp", dp); |
941 | if (ret) { | 1107 | if (ret) { |
942 | dev_err(&pdev->dev, "unable to config video\n"); | 1108 | dev_err(&pdev->dev, "failed to request irq\n"); |
943 | return ret; | 1109 | return ret; |
944 | } | 1110 | } |
945 | 1111 | ||
@@ -953,23 +1119,41 @@ static int __devexit exynos_dp_remove(struct platform_device *pdev) | |||
953 | struct exynos_dp_platdata *pdata = pdev->dev.platform_data; | 1119 | struct exynos_dp_platdata *pdata = pdev->dev.platform_data; |
954 | struct exynos_dp_device *dp = platform_get_drvdata(pdev); | 1120 | struct exynos_dp_device *dp = platform_get_drvdata(pdev); |
955 | 1121 | ||
956 | if (pdata && pdata->phy_exit) | 1122 | disable_irq(dp->irq); |
957 | pdata->phy_exit(); | 1123 | |
1124 | if (work_pending(&dp->hotplug_work)) | ||
1125 | flush_work(&dp->hotplug_work); | ||
1126 | |||
1127 | if (pdev->dev.of_node) { | ||
1128 | if (dp->phy_addr) | ||
1129 | exynos_dp_phy_exit(dp); | ||
1130 | } else { | ||
1131 | if (pdata->phy_exit) | ||
1132 | pdata->phy_exit(); | ||
1133 | } | ||
958 | 1134 | ||
959 | clk_disable_unprepare(dp->clock); | 1135 | clk_disable_unprepare(dp->clock); |
960 | 1136 | ||
1137 | |||
961 | return 0; | 1138 | return 0; |
962 | } | 1139 | } |
963 | 1140 | ||
964 | #ifdef CONFIG_PM_SLEEP | 1141 | #ifdef CONFIG_PM_SLEEP |
965 | static int exynos_dp_suspend(struct device *dev) | 1142 | static int exynos_dp_suspend(struct device *dev) |
966 | { | 1143 | { |
967 | struct platform_device *pdev = to_platform_device(dev); | 1144 | struct exynos_dp_platdata *pdata = dev->platform_data; |
968 | struct exynos_dp_platdata *pdata = pdev->dev.platform_data; | 1145 | struct exynos_dp_device *dp = dev_get_drvdata(dev); |
969 | struct exynos_dp_device *dp = platform_get_drvdata(pdev); | ||
970 | 1146 | ||
971 | if (pdata && pdata->phy_exit) | 1147 | if (work_pending(&dp->hotplug_work)) |
972 | pdata->phy_exit(); | 1148 | flush_work(&dp->hotplug_work); |
1149 | |||
1150 | if (dev->of_node) { | ||
1151 | if (dp->phy_addr) | ||
1152 | exynos_dp_phy_exit(dp); | ||
1153 | } else { | ||
1154 | if (pdata->phy_exit) | ||
1155 | pdata->phy_exit(); | ||
1156 | } | ||
973 | 1157 | ||
974 | clk_disable_unprepare(dp->clock); | 1158 | clk_disable_unprepare(dp->clock); |
975 | 1159 | ||
@@ -978,32 +1162,22 @@ static int exynos_dp_suspend(struct device *dev) | |||
978 | 1162 | ||
979 | static int exynos_dp_resume(struct device *dev) | 1163 | static int exynos_dp_resume(struct device *dev) |
980 | { | 1164 | { |
981 | struct platform_device *pdev = to_platform_device(dev); | 1165 | struct exynos_dp_platdata *pdata = dev->platform_data; |
982 | struct exynos_dp_platdata *pdata = pdev->dev.platform_data; | 1166 | struct exynos_dp_device *dp = dev_get_drvdata(dev); |
983 | struct exynos_dp_device *dp = platform_get_drvdata(pdev); | ||
984 | 1167 | ||
985 | if (pdata && pdata->phy_init) | 1168 | if (dev->of_node) { |
986 | pdata->phy_init(); | 1169 | if (dp->phy_addr) |
1170 | exynos_dp_phy_init(dp); | ||
1171 | } else { | ||
1172 | if (pdata->phy_init) | ||
1173 | pdata->phy_init(); | ||
1174 | } | ||
987 | 1175 | ||
988 | clk_prepare_enable(dp->clock); | 1176 | clk_prepare_enable(dp->clock); |
989 | 1177 | ||
990 | exynos_dp_init_dp(dp); | 1178 | exynos_dp_init_dp(dp); |
991 | 1179 | ||
992 | exynos_dp_detect_hpd(dp); | 1180 | enable_irq(dp->irq); |
993 | exynos_dp_handle_edid(dp); | ||
994 | |||
995 | exynos_dp_set_link_train(dp, dp->video_info->lane_count, | ||
996 | dp->video_info->link_rate); | ||
997 | |||
998 | exynos_dp_enable_scramble(dp, 1); | ||
999 | exynos_dp_enable_rx_to_enhanced_mode(dp, 1); | ||
1000 | exynos_dp_enable_enhanced_mode(dp, 1); | ||
1001 | |||
1002 | exynos_dp_set_lane_count(dp, dp->video_info->lane_count); | ||
1003 | exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate); | ||
1004 | |||
1005 | exynos_dp_init_video(dp); | ||
1006 | exynos_dp_config_video(dp, dp->video_info); | ||
1007 | 1181 | ||
1008 | return 0; | 1182 | return 0; |
1009 | } | 1183 | } |
@@ -1013,6 +1187,12 @@ static const struct dev_pm_ops exynos_dp_pm_ops = { | |||
1013 | SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume) | 1187 | SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume) |
1014 | }; | 1188 | }; |
1015 | 1189 | ||
1190 | static const struct of_device_id exynos_dp_match[] = { | ||
1191 | { .compatible = "samsung,exynos5-dp" }, | ||
1192 | {}, | ||
1193 | }; | ||
1194 | MODULE_DEVICE_TABLE(of, exynos_dp_match); | ||
1195 | |||
1016 | static struct platform_driver exynos_dp_driver = { | 1196 | static struct platform_driver exynos_dp_driver = { |
1017 | .probe = exynos_dp_probe, | 1197 | .probe = exynos_dp_probe, |
1018 | .remove = __devexit_p(exynos_dp_remove), | 1198 | .remove = __devexit_p(exynos_dp_remove), |
@@ -1020,6 +1200,7 @@ static struct platform_driver exynos_dp_driver = { | |||
1020 | .name = "exynos-dp", | 1200 | .name = "exynos-dp", |
1021 | .owner = THIS_MODULE, | 1201 | .owner = THIS_MODULE, |
1022 | .pm = &exynos_dp_pm_ops, | 1202 | .pm = &exynos_dp_pm_ops, |
1203 | .of_match_table = of_match_ptr(exynos_dp_match), | ||
1023 | }, | 1204 | }, |
1024 | }; | 1205 | }; |
1025 | 1206 | ||
diff --git a/drivers/video/exynos/exynos_dp_core.h b/drivers/video/exynos/exynos_dp_core.h index 57b8a6531c0e..6c567bbf2fb8 100644 --- a/drivers/video/exynos/exynos_dp_core.h +++ b/drivers/video/exynos/exynos_dp_core.h | |||
@@ -13,6 +13,13 @@ | |||
13 | #ifndef _EXYNOS_DP_CORE_H | 13 | #ifndef _EXYNOS_DP_CORE_H |
14 | #define _EXYNOS_DP_CORE_H | 14 | #define _EXYNOS_DP_CORE_H |
15 | 15 | ||
16 | enum dp_irq_type { | ||
17 | DP_IRQ_TYPE_HP_CABLE_IN, | ||
18 | DP_IRQ_TYPE_HP_CABLE_OUT, | ||
19 | DP_IRQ_TYPE_HP_CHANGE, | ||
20 | DP_IRQ_TYPE_UNKNOWN, | ||
21 | }; | ||
22 | |||
16 | struct link_train { | 23 | struct link_train { |
17 | int eq_loop; | 24 | int eq_loop; |
18 | int cr_loop[4]; | 25 | int cr_loop[4]; |
@@ -29,9 +36,12 @@ struct exynos_dp_device { | |||
29 | struct clk *clock; | 36 | struct clk *clock; |
30 | unsigned int irq; | 37 | unsigned int irq; |
31 | void __iomem *reg_base; | 38 | void __iomem *reg_base; |
39 | void __iomem *phy_addr; | ||
40 | unsigned int enable_mask; | ||
32 | 41 | ||
33 | struct video_info *video_info; | 42 | struct video_info *video_info; |
34 | struct link_train link_train; | 43 | struct link_train link_train; |
44 | struct work_struct hotplug_work; | ||
35 | }; | 45 | }; |
36 | 46 | ||
37 | /* exynos_dp_reg.c */ | 47 | /* exynos_dp_reg.c */ |
@@ -50,6 +60,8 @@ void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp, | |||
50 | bool enable); | 60 | bool enable); |
51 | void exynos_dp_init_analog_func(struct exynos_dp_device *dp); | 61 | void exynos_dp_init_analog_func(struct exynos_dp_device *dp); |
52 | void exynos_dp_init_hpd(struct exynos_dp_device *dp); | 62 | void exynos_dp_init_hpd(struct exynos_dp_device *dp); |
63 | enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp); | ||
64 | void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp); | ||
53 | void exynos_dp_reset_aux(struct exynos_dp_device *dp); | 65 | void exynos_dp_reset_aux(struct exynos_dp_device *dp); |
54 | void exynos_dp_init_aux(struct exynos_dp_device *dp); | 66 | void exynos_dp_init_aux(struct exynos_dp_device *dp); |
55 | int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp); | 67 | int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp); |
@@ -107,11 +119,7 @@ u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp); | |||
107 | void exynos_dp_reset_macro(struct exynos_dp_device *dp); | 119 | void exynos_dp_reset_macro(struct exynos_dp_device *dp); |
108 | void exynos_dp_init_video(struct exynos_dp_device *dp); | 120 | void exynos_dp_init_video(struct exynos_dp_device *dp); |
109 | 121 | ||
110 | void exynos_dp_set_video_color_format(struct exynos_dp_device *dp, | 122 | void exynos_dp_set_video_color_format(struct exynos_dp_device *dp); |
111 | u32 color_depth, | ||
112 | u32 color_space, | ||
113 | u32 dynamic_range, | ||
114 | u32 ycbcr_coeff); | ||
115 | int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp); | 123 | int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp); |
116 | void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp, | 124 | void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp, |
117 | enum clock_recovery_m_value_type type, | 125 | enum clock_recovery_m_value_type type, |
@@ -121,8 +129,7 @@ void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type); | |||
121 | void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable); | 129 | void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable); |
122 | void exynos_dp_start_video(struct exynos_dp_device *dp); | 130 | void exynos_dp_start_video(struct exynos_dp_device *dp); |
123 | int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp); | 131 | int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp); |
124 | void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp, | 132 | void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp); |
125 | struct video_info *video_info); | ||
126 | void exynos_dp_enable_scrambling(struct exynos_dp_device *dp); | 133 | void exynos_dp_enable_scrambling(struct exynos_dp_device *dp); |
127 | void exynos_dp_disable_scrambling(struct exynos_dp_device *dp); | 134 | void exynos_dp_disable_scrambling(struct exynos_dp_device *dp); |
128 | 135 | ||
diff --git a/drivers/video/exynos/exynos_dp_reg.c b/drivers/video/exynos/exynos_dp_reg.c index 3f5ca8a0d5ea..29d9d035c73a 100644 --- a/drivers/video/exynos/exynos_dp_reg.c +++ b/drivers/video/exynos/exynos_dp_reg.c | |||
@@ -19,11 +19,11 @@ | |||
19 | #include "exynos_dp_core.h" | 19 | #include "exynos_dp_core.h" |
20 | #include "exynos_dp_reg.h" | 20 | #include "exynos_dp_reg.h" |
21 | 21 | ||
22 | #define COMMON_INT_MASK_1 (0) | 22 | #define COMMON_INT_MASK_1 0 |
23 | #define COMMON_INT_MASK_2 (0) | 23 | #define COMMON_INT_MASK_2 0 |
24 | #define COMMON_INT_MASK_3 (0) | 24 | #define COMMON_INT_MASK_3 0 |
25 | #define COMMON_INT_MASK_4 (0) | 25 | #define COMMON_INT_MASK_4 (HOTPLUG_CHG | HPD_LOST | PLUG) |
26 | #define INT_STA_MASK (0) | 26 | #define INT_STA_MASK INT_HPD |
27 | 27 | ||
28 | void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable) | 28 | void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable) |
29 | { | 29 | { |
@@ -88,7 +88,7 @@ void exynos_dp_init_analog_param(struct exynos_dp_device *dp) | |||
88 | void exynos_dp_init_interrupt(struct exynos_dp_device *dp) | 88 | void exynos_dp_init_interrupt(struct exynos_dp_device *dp) |
89 | { | 89 | { |
90 | /* Set interrupt pin assertion polarity as high */ | 90 | /* Set interrupt pin assertion polarity as high */ |
91 | writel(INT_POL, dp->reg_base + EXYNOS_DP_INT_CTL); | 91 | writel(INT_POL1 | INT_POL0, dp->reg_base + EXYNOS_DP_INT_CTL); |
92 | 92 | ||
93 | /* Clear pending regisers */ | 93 | /* Clear pending regisers */ |
94 | writel(0xff, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1); | 94 | writel(0xff, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1); |
@@ -324,7 +324,7 @@ void exynos_dp_init_analog_func(struct exynos_dp_device *dp) | |||
324 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); | 324 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); |
325 | } | 325 | } |
326 | 326 | ||
327 | void exynos_dp_init_hpd(struct exynos_dp_device *dp) | 327 | void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp) |
328 | { | 328 | { |
329 | u32 reg; | 329 | u32 reg; |
330 | 330 | ||
@@ -333,12 +333,38 @@ void exynos_dp_init_hpd(struct exynos_dp_device *dp) | |||
333 | 333 | ||
334 | reg = INT_HPD; | 334 | reg = INT_HPD; |
335 | writel(reg, dp->reg_base + EXYNOS_DP_INT_STA); | 335 | writel(reg, dp->reg_base + EXYNOS_DP_INT_STA); |
336 | } | ||
337 | |||
338 | void exynos_dp_init_hpd(struct exynos_dp_device *dp) | ||
339 | { | ||
340 | u32 reg; | ||
341 | |||
342 | exynos_dp_clear_hotplug_interrupts(dp); | ||
336 | 343 | ||
337 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); | 344 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); |
338 | reg &= ~(F_HPD | HPD_CTRL); | 345 | reg &= ~(F_HPD | HPD_CTRL); |
339 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3); | 346 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3); |
340 | } | 347 | } |
341 | 348 | ||
349 | enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp) | ||
350 | { | ||
351 | u32 reg; | ||
352 | |||
353 | /* Parse hotplug interrupt status register */ | ||
354 | reg = readl(dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4); | ||
355 | |||
356 | if (reg & PLUG) | ||
357 | return DP_IRQ_TYPE_HP_CABLE_IN; | ||
358 | |||
359 | if (reg & HPD_LOST) | ||
360 | return DP_IRQ_TYPE_HP_CABLE_OUT; | ||
361 | |||
362 | if (reg & HOTPLUG_CHG) | ||
363 | return DP_IRQ_TYPE_HP_CHANGE; | ||
364 | |||
365 | return DP_IRQ_TYPE_UNKNOWN; | ||
366 | } | ||
367 | |||
342 | void exynos_dp_reset_aux(struct exynos_dp_device *dp) | 368 | void exynos_dp_reset_aux(struct exynos_dp_device *dp) |
343 | { | 369 | { |
344 | u32 reg; | 370 | u32 reg; |
@@ -491,7 +517,7 @@ int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp, | |||
491 | int i; | 517 | int i; |
492 | int retval; | 518 | int retval; |
493 | 519 | ||
494 | for (i = 0; i < 10; i++) { | 520 | for (i = 0; i < 3; i++) { |
495 | /* Clear AUX CH data buffer */ | 521 | /* Clear AUX CH data buffer */ |
496 | reg = BUF_CLR; | 522 | reg = BUF_CLR; |
497 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | 523 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); |
@@ -552,7 +578,7 @@ int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp, | |||
552 | else | 578 | else |
553 | cur_data_count = count - start_offset; | 579 | cur_data_count = count - start_offset; |
554 | 580 | ||
555 | for (i = 0; i < 10; i++) { | 581 | for (i = 0; i < 3; i++) { |
556 | /* Select DPCD device address */ | 582 | /* Select DPCD device address */ |
557 | reg = AUX_ADDR_7_0(reg_addr + start_offset); | 583 | reg = AUX_ADDR_7_0(reg_addr + start_offset); |
558 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); | 584 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); |
@@ -617,7 +643,7 @@ int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp, | |||
617 | cur_data_count = count - start_offset; | 643 | cur_data_count = count - start_offset; |
618 | 644 | ||
619 | /* AUX CH Request Transaction process */ | 645 | /* AUX CH Request Transaction process */ |
620 | for (i = 0; i < 10; i++) { | 646 | for (i = 0; i < 3; i++) { |
621 | /* Select DPCD device address */ | 647 | /* Select DPCD device address */ |
622 | reg = AUX_ADDR_7_0(reg_addr + start_offset); | 648 | reg = AUX_ADDR_7_0(reg_addr + start_offset); |
623 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); | 649 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); |
@@ -700,17 +726,15 @@ int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp, | |||
700 | int i; | 726 | int i; |
701 | int retval; | 727 | int retval; |
702 | 728 | ||
703 | for (i = 0; i < 10; i++) { | 729 | for (i = 0; i < 3; i++) { |
704 | /* Clear AUX CH data buffer */ | 730 | /* Clear AUX CH data buffer */ |
705 | reg = BUF_CLR; | 731 | reg = BUF_CLR; |
706 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | 732 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); |
707 | 733 | ||
708 | /* Select EDID device */ | 734 | /* Select EDID device */ |
709 | retval = exynos_dp_select_i2c_device(dp, device_addr, reg_addr); | 735 | retval = exynos_dp_select_i2c_device(dp, device_addr, reg_addr); |
710 | if (retval != 0) { | 736 | if (retval != 0) |
711 | dev_err(dp->dev, "Select EDID device fail!\n"); | ||
712 | continue; | 737 | continue; |
713 | } | ||
714 | 738 | ||
715 | /* | 739 | /* |
716 | * Set I2C transaction and read data | 740 | * Set I2C transaction and read data |
@@ -750,7 +774,7 @@ int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp, | |||
750 | int retval = 0; | 774 | int retval = 0; |
751 | 775 | ||
752 | for (i = 0; i < count; i += 16) { | 776 | for (i = 0; i < count; i += 16) { |
753 | for (j = 0; j < 100; j++) { | 777 | for (j = 0; j < 3; j++) { |
754 | /* Clear AUX CH data buffer */ | 778 | /* Clear AUX CH data buffer */ |
755 | reg = BUF_CLR; | 779 | reg = BUF_CLR; |
756 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | 780 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); |
@@ -1034,24 +1058,20 @@ void exynos_dp_init_video(struct exynos_dp_device *dp) | |||
1034 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8); | 1058 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8); |
1035 | } | 1059 | } |
1036 | 1060 | ||
1037 | void exynos_dp_set_video_color_format(struct exynos_dp_device *dp, | 1061 | void exynos_dp_set_video_color_format(struct exynos_dp_device *dp) |
1038 | u32 color_depth, | ||
1039 | u32 color_space, | ||
1040 | u32 dynamic_range, | ||
1041 | u32 ycbcr_coeff) | ||
1042 | { | 1062 | { |
1043 | u32 reg; | 1063 | u32 reg; |
1044 | 1064 | ||
1045 | /* Configure the input color depth, color space, dynamic range */ | 1065 | /* Configure the input color depth, color space, dynamic range */ |
1046 | reg = (dynamic_range << IN_D_RANGE_SHIFT) | | 1066 | reg = (dp->video_info->dynamic_range << IN_D_RANGE_SHIFT) | |
1047 | (color_depth << IN_BPC_SHIFT) | | 1067 | (dp->video_info->color_depth << IN_BPC_SHIFT) | |
1048 | (color_space << IN_COLOR_F_SHIFT); | 1068 | (dp->video_info->color_space << IN_COLOR_F_SHIFT); |
1049 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_2); | 1069 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_2); |
1050 | 1070 | ||
1051 | /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */ | 1071 | /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */ |
1052 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_3); | 1072 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_3); |
1053 | reg &= ~IN_YC_COEFFI_MASK; | 1073 | reg &= ~IN_YC_COEFFI_MASK; |
1054 | if (ycbcr_coeff) | 1074 | if (dp->video_info->ycbcr_coeff) |
1055 | reg |= IN_YC_COEFFI_ITU709; | 1075 | reg |= IN_YC_COEFFI_ITU709; |
1056 | else | 1076 | else |
1057 | reg |= IN_YC_COEFFI_ITU601; | 1077 | reg |= IN_YC_COEFFI_ITU601; |
@@ -1178,8 +1198,7 @@ int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp) | |||
1178 | return 0; | 1198 | return 0; |
1179 | } | 1199 | } |
1180 | 1200 | ||
1181 | void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp, | 1201 | void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp) |
1182 | struct video_info *video_info) | ||
1183 | { | 1202 | { |
1184 | u32 reg; | 1203 | u32 reg; |
1185 | 1204 | ||
@@ -1190,17 +1209,17 @@ void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp, | |||
1190 | 1209 | ||
1191 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | 1210 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); |
1192 | reg &= ~INTERACE_SCAN_CFG; | 1211 | reg &= ~INTERACE_SCAN_CFG; |
1193 | reg |= (video_info->interlaced << 2); | 1212 | reg |= (dp->video_info->interlaced << 2); |
1194 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | 1213 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); |
1195 | 1214 | ||
1196 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | 1215 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); |
1197 | reg &= ~VSYNC_POLARITY_CFG; | 1216 | reg &= ~VSYNC_POLARITY_CFG; |
1198 | reg |= (video_info->v_sync_polarity << 1); | 1217 | reg |= (dp->video_info->v_sync_polarity << 1); |
1199 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | 1218 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); |
1200 | 1219 | ||
1201 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | 1220 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); |
1202 | reg &= ~HSYNC_POLARITY_CFG; | 1221 | reg &= ~HSYNC_POLARITY_CFG; |
1203 | reg |= (video_info->h_sync_polarity << 0); | 1222 | reg |= (dp->video_info->h_sync_polarity << 0); |
1204 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | 1223 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); |
1205 | 1224 | ||
1206 | reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE; | 1225 | reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE; |
diff --git a/drivers/video/exynos/exynos_dp_reg.h b/drivers/video/exynos/exynos_dp_reg.h index 1f2f014cfe88..2e9bd0e0b9f2 100644 --- a/drivers/video/exynos/exynos_dp_reg.h +++ b/drivers/video/exynos/exynos_dp_reg.h | |||
@@ -242,7 +242,8 @@ | |||
242 | 242 | ||
243 | /* EXYNOS_DP_INT_CTL */ | 243 | /* EXYNOS_DP_INT_CTL */ |
244 | #define SOFT_INT_CTRL (0x1 << 2) | 244 | #define SOFT_INT_CTRL (0x1 << 2) |
245 | #define INT_POL (0x1 << 0) | 245 | #define INT_POL1 (0x1 << 1) |
246 | #define INT_POL0 (0x1 << 0) | ||
246 | 247 | ||
247 | /* EXYNOS_DP_SYS_CTL_1 */ | 248 | /* EXYNOS_DP_SYS_CTL_1 */ |
248 | #define DET_STA (0x1 << 2) | 249 | #define DET_STA (0x1 << 2) |