diff options
author | Jingoo Han <jg1.han@samsung.com> | 2012-07-19 00:52:59 -0400 |
---|---|---|
committer | Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | 2012-08-23 08:57:18 -0400 |
commit | d5c0eed01c0d6e316589578859d8d99aca2d3b06 (patch) | |
tree | 1ac22cd70d1eb877ba732834f75da845ab23f33c /drivers/video | |
parent | c1c52848cef52e157468b8879fc3cae23b6f3a99 (diff) |
video: exynos_dp: adjust voltage swing and pre-emphasis during Link Training
This patch adds adjustement for voltage swing and pre-emphasis during
Link Training procedure. According to the DP specification, unless all
the LANEx_CR_DONE bits are set, the transmitter must read
the ADJUST_REQUEST_LANEx_x, increase the voltage swing according to
the request, and update the TRAINING_LANEx_SET bytes to match the new
voltage swing setting.
Refer to the DP specification v1.1a, Section 3.5.1.3 Link Training.
Signed-off-by: Jingoo Han <jg1.han@samsung.com>
Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/exynos/exynos_dp_core.c | 282 | ||||
-rw-r--r-- | drivers/video/exynos/exynos_dp_core.h | 2 |
2 files changed, 144 insertions, 140 deletions
diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c index c6c016a506ce..9c0140f5e696 100644 --- a/drivers/video/exynos/exynos_dp_core.c +++ b/drivers/video/exynos/exynos_dp_core.c | |||
@@ -260,7 +260,7 @@ static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp, | |||
260 | 260 | ||
261 | static void exynos_dp_link_start(struct exynos_dp_device *dp) | 261 | static void exynos_dp_link_start(struct exynos_dp_device *dp) |
262 | { | 262 | { |
263 | u8 buf[5]; | 263 | u8 buf[4]; |
264 | int lane; | 264 | int lane; |
265 | int lane_count; | 265 | int lane_count; |
266 | 266 | ||
@@ -295,10 +295,10 @@ static void exynos_dp_link_start(struct exynos_dp_device *dp) | |||
295 | exynos_dp_set_training_pattern(dp, TRAINING_PTN1); | 295 | exynos_dp_set_training_pattern(dp, TRAINING_PTN1); |
296 | 296 | ||
297 | /* Set RX training pattern */ | 297 | /* Set RX training pattern */ |
298 | buf[0] = DPCD_SCRAMBLING_DISABLED | | ||
299 | DPCD_TRAINING_PATTERN_1; | ||
300 | exynos_dp_write_byte_to_dpcd(dp, | 298 | exynos_dp_write_byte_to_dpcd(dp, |
301 | DPCD_ADDR_TRAINING_PATTERN_SET, buf[0]); | 299 | DPCD_ADDR_TRAINING_PATTERN_SET, |
300 | DPCD_SCRAMBLING_DISABLED | | ||
301 | DPCD_TRAINING_PATTERN_1); | ||
302 | 302 | ||
303 | for (lane = 0; lane < lane_count; lane++) | 303 | for (lane = 0; lane < lane_count; lane++) |
304 | buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 | | 304 | buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 | |
@@ -308,7 +308,7 @@ static void exynos_dp_link_start(struct exynos_dp_device *dp) | |||
308 | lane_count, buf); | 308 | lane_count, buf); |
309 | } | 309 | } |
310 | 310 | ||
311 | static unsigned char exynos_dp_get_lane_status(u8 link_status[6], int lane) | 311 | static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane) |
312 | { | 312 | { |
313 | int shift = (lane & 1) * 4; | 313 | int shift = (lane & 1) * 4; |
314 | u8 link_value = link_status[lane>>1]; | 314 | u8 link_value = link_status[lane>>1]; |
@@ -316,7 +316,7 @@ static unsigned char exynos_dp_get_lane_status(u8 link_status[6], int lane) | |||
316 | return (link_value >> shift) & 0xf; | 316 | return (link_value >> shift) & 0xf; |
317 | } | 317 | } |
318 | 318 | ||
319 | static int exynos_dp_clock_recovery_ok(u8 link_status[6], int lane_count) | 319 | static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count) |
320 | { | 320 | { |
321 | int lane; | 321 | int lane; |
322 | u8 lane_status; | 322 | u8 lane_status; |
@@ -329,22 +329,23 @@ static int exynos_dp_clock_recovery_ok(u8 link_status[6], int lane_count) | |||
329 | return 0; | 329 | return 0; |
330 | } | 330 | } |
331 | 331 | ||
332 | static int exynos_dp_channel_eq_ok(u8 link_status[6], int lane_count) | 332 | static int exynos_dp_channel_eq_ok(u8 link_align[3], int lane_count) |
333 | { | 333 | { |
334 | int lane; | 334 | int lane; |
335 | u8 lane_align; | 335 | u8 lane_align; |
336 | u8 lane_status; | 336 | u8 lane_status; |
337 | 337 | ||
338 | lane_align = link_status[2]; | 338 | lane_align = link_align[2]; |
339 | if ((lane_align & DPCD_INTERLANE_ALIGN_DONE) == 0) | 339 | if ((lane_align & DPCD_INTERLANE_ALIGN_DONE) == 0) |
340 | return -EINVAL; | 340 | return -EINVAL; |
341 | 341 | ||
342 | for (lane = 0; lane < lane_count; lane++) { | 342 | for (lane = 0; lane < lane_count; lane++) { |
343 | lane_status = exynos_dp_get_lane_status(link_status, lane); | 343 | lane_status = exynos_dp_get_lane_status(link_align, lane); |
344 | lane_status &= DPCD_CHANNEL_EQ_BITS; | 344 | lane_status &= DPCD_CHANNEL_EQ_BITS; |
345 | if (lane_status != DPCD_CHANNEL_EQ_BITS) | 345 | if (lane_status != DPCD_CHANNEL_EQ_BITS) |
346 | return -EINVAL; | 346 | return -EINVAL; |
347 | } | 347 | } |
348 | |||
348 | return 0; | 349 | return 0; |
349 | } | 350 | } |
350 | 351 | ||
@@ -417,69 +418,17 @@ static unsigned int exynos_dp_get_lane_link_training( | |||
417 | 418 | ||
418 | static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp) | 419 | static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp) |
419 | { | 420 | { |
420 | if (dp->link_train.link_rate == LINK_RATE_2_70GBPS) { | 421 | exynos_dp_training_pattern_dis(dp); |
421 | /* set to reduced bit rate */ | 422 | exynos_dp_set_enhanced_mode(dp); |
422 | dp->link_train.link_rate = LINK_RATE_1_62GBPS; | ||
423 | dev_err(dp->dev, "set to bandwidth %.2x\n", | ||
424 | dp->link_train.link_rate); | ||
425 | dp->link_train.lt_state = START; | ||
426 | } else { | ||
427 | exynos_dp_training_pattern_dis(dp); | ||
428 | /* set enhanced mode if available */ | ||
429 | exynos_dp_set_enhanced_mode(dp); | ||
430 | dp->link_train.lt_state = FAILED; | ||
431 | } | ||
432 | } | ||
433 | |||
434 | static void exynos_dp_get_adjust_train(struct exynos_dp_device *dp, | ||
435 | u8 adjust_request[2]) | ||
436 | { | ||
437 | int lane; | ||
438 | int lane_count; | ||
439 | u8 voltage_swing; | ||
440 | u8 pre_emphasis; | ||
441 | u8 training_lane; | ||
442 | 423 | ||
443 | lane_count = dp->link_train.lane_count; | 424 | dp->link_train.lt_state = FAILED; |
444 | for (lane = 0; lane < lane_count; lane++) { | ||
445 | voltage_swing = exynos_dp_get_adjust_request_voltage( | ||
446 | adjust_request, lane); | ||
447 | pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( | ||
448 | adjust_request, lane); | ||
449 | training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | | ||
450 | DPCD_PRE_EMPHASIS_SET(pre_emphasis); | ||
451 | |||
452 | if (voltage_swing == VOLTAGE_LEVEL_3 || | ||
453 | pre_emphasis == PRE_EMPHASIS_LEVEL_3) { | ||
454 | training_lane |= DPCD_MAX_SWING_REACHED; | ||
455 | training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; | ||
456 | } | ||
457 | dp->link_train.training_lane[lane] = training_lane; | ||
458 | } | ||
459 | } | ||
460 | |||
461 | static int exynos_dp_check_max_cr_loop(struct exynos_dp_device *dp, | ||
462 | u8 voltage_swing) | ||
463 | { | ||
464 | int lane; | ||
465 | int lane_count; | ||
466 | |||
467 | lane_count = dp->link_train.lane_count; | ||
468 | for (lane = 0; lane < lane_count; lane++) { | ||
469 | if (voltage_swing == VOLTAGE_LEVEL_3 || | ||
470 | dp->link_train.cr_loop[lane] == MAX_CR_LOOP) | ||
471 | return -EINVAL; | ||
472 | } | ||
473 | return 0; | ||
474 | } | 425 | } |
475 | 426 | ||
476 | static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) | 427 | static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) |
477 | { | 428 | { |
478 | u8 data; | 429 | u8 link_status[2]; |
479 | u8 link_status[6]; | ||
480 | int lane; | 430 | int lane; |
481 | int lane_count; | 431 | int lane_count; |
482 | u8 buf[5]; | ||
483 | 432 | ||
484 | u8 adjust_request[2]; | 433 | u8 adjust_request[2]; |
485 | u8 voltage_swing; | 434 | u8 voltage_swing; |
@@ -488,98 +437,152 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) | |||
488 | 437 | ||
489 | usleep_range(100, 101); | 438 | usleep_range(100, 101); |
490 | 439 | ||
491 | exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, | ||
492 | 6, link_status); | ||
493 | lane_count = dp->link_train.lane_count; | 440 | lane_count = dp->link_train.lane_count; |
494 | 441 | ||
442 | exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, | ||
443 | 2, link_status); | ||
444 | |||
495 | if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { | 445 | if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { |
496 | /* set training pattern 2 for EQ */ | 446 | /* set training pattern 2 for EQ */ |
497 | exynos_dp_set_training_pattern(dp, TRAINING_PTN2); | 447 | exynos_dp_set_training_pattern(dp, TRAINING_PTN2); |
498 | 448 | ||
499 | adjust_request[0] = link_status[4]; | 449 | for (lane = 0; lane < lane_count; lane++) { |
500 | adjust_request[1] = link_status[5]; | 450 | exynos_dp_read_bytes_from_dpcd(dp, |
451 | DPCD_ADDR_ADJUST_REQUEST_LANE0_1, | ||
452 | 2, adjust_request); | ||
453 | voltage_swing = exynos_dp_get_adjust_request_voltage( | ||
454 | adjust_request, lane); | ||
455 | pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( | ||
456 | adjust_request, lane); | ||
457 | training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | | ||
458 | DPCD_PRE_EMPHASIS_SET(pre_emphasis); | ||
501 | 459 | ||
502 | exynos_dp_get_adjust_train(dp, adjust_request); | 460 | if (voltage_swing == VOLTAGE_LEVEL_3) |
461 | training_lane |= DPCD_MAX_SWING_REACHED; | ||
462 | if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) | ||
463 | training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; | ||
503 | 464 | ||
504 | buf[0] = DPCD_SCRAMBLING_DISABLED | | 465 | dp->link_train.training_lane[lane] = training_lane; |
505 | DPCD_TRAINING_PATTERN_2; | ||
506 | exynos_dp_write_byte_to_dpcd(dp, | ||
507 | DPCD_ADDR_TRAINING_PATTERN_SET, | ||
508 | buf[0]); | ||
509 | 466 | ||
510 | for (lane = 0; lane < lane_count; lane++) { | ||
511 | exynos_dp_set_lane_link_training(dp, | 467 | exynos_dp_set_lane_link_training(dp, |
512 | dp->link_train.training_lane[lane], | 468 | dp->link_train.training_lane[lane], |
513 | lane); | 469 | lane); |
514 | buf[lane] = dp->link_train.training_lane[lane]; | ||
515 | exynos_dp_write_byte_to_dpcd(dp, | ||
516 | DPCD_ADDR_TRAINING_LANE0_SET + lane, | ||
517 | buf[lane]); | ||
518 | } | 470 | } |
519 | dp->link_train.lt_state = EQUALIZER_TRAINING; | ||
520 | } else { | ||
521 | exynos_dp_read_byte_from_dpcd(dp, | ||
522 | DPCD_ADDR_ADJUST_REQUEST_LANE0_1, | ||
523 | &data); | ||
524 | adjust_request[0] = data; | ||
525 | 471 | ||
526 | exynos_dp_read_byte_from_dpcd(dp, | 472 | exynos_dp_write_byte_to_dpcd(dp, |
527 | DPCD_ADDR_ADJUST_REQUEST_LANE2_3, | 473 | DPCD_ADDR_TRAINING_PATTERN_SET, |
528 | &data); | 474 | DPCD_SCRAMBLING_DISABLED | |
529 | adjust_request[1] = data; | 475 | DPCD_TRAINING_PATTERN_2); |
476 | |||
477 | exynos_dp_write_bytes_to_dpcd(dp, | ||
478 | DPCD_ADDR_TRAINING_LANE0_SET, | ||
479 | lane_count, | ||
480 | dp->link_train.training_lane); | ||
530 | 481 | ||
482 | dev_info(dp->dev, "Link Training Clock Recovery success\n"); | ||
483 | dp->link_train.lt_state = EQUALIZER_TRAINING; | ||
484 | } else { | ||
531 | for (lane = 0; lane < lane_count; lane++) { | 485 | for (lane = 0; lane < lane_count; lane++) { |
532 | training_lane = exynos_dp_get_lane_link_training( | 486 | training_lane = exynos_dp_get_lane_link_training( |
533 | dp, lane); | 487 | dp, lane); |
488 | exynos_dp_read_bytes_from_dpcd(dp, | ||
489 | DPCD_ADDR_ADJUST_REQUEST_LANE0_1, | ||
490 | 2, adjust_request); | ||
534 | voltage_swing = exynos_dp_get_adjust_request_voltage( | 491 | voltage_swing = exynos_dp_get_adjust_request_voltage( |
535 | adjust_request, lane); | 492 | adjust_request, lane); |
536 | pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( | 493 | pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( |
537 | adjust_request, lane); | 494 | adjust_request, lane); |
538 | if ((DPCD_VOLTAGE_SWING_GET(training_lane) == voltage_swing) && | ||
539 | (DPCD_PRE_EMPHASIS_GET(training_lane) == pre_emphasis)) | ||
540 | dp->link_train.cr_loop[lane]++; | ||
541 | dp->link_train.training_lane[lane] = training_lane; | ||
542 | } | ||
543 | 495 | ||
544 | if (exynos_dp_check_max_cr_loop(dp, voltage_swing) != 0) { | 496 | if (voltage_swing == VOLTAGE_LEVEL_3 || |
545 | exynos_dp_reduce_link_rate(dp); | 497 | pre_emphasis == PRE_EMPHASIS_LEVEL_3) { |
546 | } else { | 498 | dev_err(dp->dev, "voltage or pre emphasis reached max level\n"); |
547 | exynos_dp_get_adjust_train(dp, adjust_request); | 499 | goto reduce_link_rate; |
500 | } | ||
548 | 501 | ||
549 | for (lane = 0; lane < lane_count; lane++) { | 502 | if ((DPCD_VOLTAGE_SWING_GET(training_lane) == |
550 | exynos_dp_set_lane_link_training(dp, | 503 | voltage_swing) && |
551 | dp->link_train.training_lane[lane], | 504 | (DPCD_PRE_EMPHASIS_GET(training_lane) == |
552 | lane); | 505 | pre_emphasis)) { |
553 | buf[lane] = dp->link_train.training_lane[lane]; | 506 | dp->link_train.cr_loop[lane]++; |
554 | exynos_dp_write_byte_to_dpcd(dp, | 507 | if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP) { |
555 | DPCD_ADDR_TRAINING_LANE0_SET + lane, | 508 | dev_err(dp->dev, "CR Max loop\n"); |
556 | buf[lane]); | 509 | goto reduce_link_rate; |
510 | } | ||
557 | } | 511 | } |
512 | |||
513 | training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | | ||
514 | DPCD_PRE_EMPHASIS_SET(pre_emphasis); | ||
515 | |||
516 | if (voltage_swing == VOLTAGE_LEVEL_3) | ||
517 | training_lane |= DPCD_MAX_SWING_REACHED; | ||
518 | if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) | ||
519 | training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; | ||
520 | |||
521 | dp->link_train.training_lane[lane] = training_lane; | ||
522 | |||
523 | exynos_dp_set_lane_link_training(dp, | ||
524 | dp->link_train.training_lane[lane], lane); | ||
558 | } | 525 | } |
526 | |||
527 | exynos_dp_write_bytes_to_dpcd(dp, | ||
528 | DPCD_ADDR_TRAINING_LANE0_SET, | ||
529 | lane_count, | ||
530 | dp->link_train.training_lane); | ||
559 | } | 531 | } |
560 | 532 | ||
561 | return 0; | 533 | return 0; |
534 | |||
535 | reduce_link_rate: | ||
536 | exynos_dp_reduce_link_rate(dp); | ||
537 | return -EIO; | ||
562 | } | 538 | } |
563 | 539 | ||
564 | 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) |
565 | { | 541 | { |
566 | u8 link_status[6]; | 542 | u8 link_status[2]; |
543 | u8 link_align[3]; | ||
567 | int lane; | 544 | int lane; |
568 | int lane_count; | 545 | int lane_count; |
569 | u8 buf[5]; | ||
570 | u32 reg; | 546 | u32 reg; |
571 | 547 | ||
572 | u8 adjust_request[2]; | 548 | u8 adjust_request[2]; |
549 | u8 voltage_swing; | ||
550 | u8 pre_emphasis; | ||
551 | u8 training_lane; | ||
573 | 552 | ||
574 | usleep_range(400, 401); | 553 | usleep_range(400, 401); |
575 | 554 | ||
576 | exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, | ||
577 | 6, link_status); | ||
578 | lane_count = dp->link_train.lane_count; | 555 | lane_count = dp->link_train.lane_count; |
579 | 556 | ||
557 | exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, | ||
558 | 2, link_status); | ||
559 | |||
580 | if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { | 560 | if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { |
581 | adjust_request[0] = link_status[4]; | 561 | link_align[0] = link_status[0]; |
582 | adjust_request[1] = link_status[5]; | 562 | link_align[1] = link_status[1]; |
563 | |||
564 | exynos_dp_read_byte_from_dpcd(dp, | ||
565 | DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, | ||
566 | &link_align[2]); | ||
567 | |||
568 | for (lane = 0; lane < lane_count; lane++) { | ||
569 | exynos_dp_read_bytes_from_dpcd(dp, | ||
570 | DPCD_ADDR_ADJUST_REQUEST_LANE0_1, | ||
571 | 2, adjust_request); | ||
572 | voltage_swing = exynos_dp_get_adjust_request_voltage( | ||
573 | adjust_request, lane); | ||
574 | pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( | ||
575 | adjust_request, lane); | ||
576 | training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | | ||
577 | DPCD_PRE_EMPHASIS_SET(pre_emphasis); | ||
578 | |||
579 | if (voltage_swing == VOLTAGE_LEVEL_3) | ||
580 | training_lane |= DPCD_MAX_SWING_REACHED; | ||
581 | if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) | ||
582 | training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; | ||
583 | |||
584 | dp->link_train.training_lane[lane] = training_lane; | ||
585 | } | ||
583 | 586 | ||
584 | if (exynos_dp_channel_eq_ok(link_status, lane_count) == 0) { | 587 | if (exynos_dp_channel_eq_ok(link_status, lane_count) == 0) { |
585 | /* traing pattern Set to Normal */ | 588 | /* traing pattern Set to Normal */ |
@@ -596,39 +599,42 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) | |||
596 | dp->link_train.lane_count = reg; | 599 | dp->link_train.lane_count = reg; |
597 | dev_dbg(dp->dev, "final lane count = %.2x\n", | 600 | dev_dbg(dp->dev, "final lane count = %.2x\n", |
598 | dp->link_train.lane_count); | 601 | dp->link_train.lane_count); |
602 | |||
599 | /* set enhanced mode if available */ | 603 | /* set enhanced mode if available */ |
600 | exynos_dp_set_enhanced_mode(dp); | 604 | exynos_dp_set_enhanced_mode(dp); |
601 | |||
602 | dp->link_train.lt_state = FINISHED; | 605 | dp->link_train.lt_state = FINISHED; |
603 | } else { | 606 | } else { |
604 | /* not all locked */ | 607 | /* not all locked */ |
605 | dp->link_train.eq_loop++; | 608 | dp->link_train.eq_loop++; |
606 | 609 | ||
607 | if (dp->link_train.eq_loop > MAX_EQ_LOOP) { | 610 | if (dp->link_train.eq_loop > MAX_EQ_LOOP) { |
608 | exynos_dp_reduce_link_rate(dp); | 611 | dev_err(dp->dev, "EQ Max loop\n"); |
609 | } else { | 612 | goto reduce_link_rate; |
610 | exynos_dp_get_adjust_train(dp, adjust_request); | ||
611 | |||
612 | for (lane = 0; lane < lane_count; lane++) { | ||
613 | exynos_dp_set_lane_link_training(dp, | ||
614 | dp->link_train.training_lane[lane], | ||
615 | lane); | ||
616 | buf[lane] = dp->link_train.training_lane[lane]; | ||
617 | exynos_dp_write_byte_to_dpcd(dp, | ||
618 | DPCD_ADDR_TRAINING_LANE0_SET + lane, | ||
619 | buf[lane]); | ||
620 | } | ||
621 | } | 613 | } |
614 | |||
615 | for (lane = 0; lane < lane_count; lane++) | ||
616 | exynos_dp_set_lane_link_training(dp, | ||
617 | dp->link_train.training_lane[lane], | ||
618 | lane); | ||
619 | |||
620 | exynos_dp_write_bytes_to_dpcd(dp, | ||
621 | DPCD_ADDR_TRAINING_LANE0_SET, | ||
622 | lane_count, | ||
623 | dp->link_train.training_lane); | ||
622 | } | 624 | } |
623 | } else { | 625 | } else { |
624 | exynos_dp_reduce_link_rate(dp); | 626 | goto reduce_link_rate; |
625 | } | 627 | } |
626 | 628 | ||
627 | return 0; | 629 | return 0; |
630 | |||
631 | reduce_link_rate: | ||
632 | exynos_dp_reduce_link_rate(dp); | ||
633 | return -EIO; | ||
628 | } | 634 | } |
629 | 635 | ||
630 | static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp, | 636 | static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp, |
631 | u8 *bandwidth) | 637 | u8 *bandwidth) |
632 | { | 638 | { |
633 | u8 data; | 639 | u8 data; |
634 | 640 | ||
@@ -641,7 +647,7 @@ static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp, | |||
641 | } | 647 | } |
642 | 648 | ||
643 | static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp, | 649 | static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp, |
644 | u8 *lane_count) | 650 | u8 *lane_count) |
645 | { | 651 | { |
646 | u8 data; | 652 | u8 data; |
647 | 653 | ||
@@ -693,13 +699,7 @@ static void exynos_dp_init_training(struct exynos_dp_device *dp, | |||
693 | static int exynos_dp_sw_link_training(struct exynos_dp_device *dp) | 699 | static int exynos_dp_sw_link_training(struct exynos_dp_device *dp) |
694 | { | 700 | { |
695 | int retval = 0; | 701 | int retval = 0; |
696 | int training_finished; | 702 | int training_finished = 0; |
697 | |||
698 | /* Turn off unnecessary lane */ | ||
699 | if (dp->link_train.lane_count == 1) | ||
700 | exynos_dp_set_analog_power_down(dp, CH1_BLOCK, 1); | ||
701 | |||
702 | training_finished = 0; | ||
703 | 703 | ||
704 | dp->link_train.lt_state = START; | 704 | dp->link_train.lt_state = START; |
705 | 705 | ||
@@ -710,10 +710,14 @@ static int exynos_dp_sw_link_training(struct exynos_dp_device *dp) | |||
710 | exynos_dp_link_start(dp); | 710 | exynos_dp_link_start(dp); |
711 | break; | 711 | break; |
712 | case CLOCK_RECOVERY: | 712 | case CLOCK_RECOVERY: |
713 | exynos_dp_process_clock_recovery(dp); | 713 | retval = exynos_dp_process_clock_recovery(dp); |
714 | if (retval) | ||
715 | dev_err(dp->dev, "LT CR failed!\n"); | ||
714 | break; | 716 | break; |
715 | case EQUALIZER_TRAINING: | 717 | case EQUALIZER_TRAINING: |
716 | exynos_dp_process_equalizer_training(dp); | 718 | retval = exynos_dp_process_equalizer_training(dp); |
719 | if (retval) | ||
720 | dev_err(dp->dev, "LT EQ failed!\n"); | ||
717 | break; | 721 | break; |
718 | case FINISHED: | 722 | case FINISHED: |
719 | training_finished = 1; | 723 | training_finished = 1; |
diff --git a/drivers/video/exynos/exynos_dp_core.h b/drivers/video/exynos/exynos_dp_core.h index 8526e548c385..44c11e18e0f7 100644 --- a/drivers/video/exynos/exynos_dp_core.h +++ b/drivers/video/exynos/exynos_dp_core.h | |||
@@ -144,7 +144,7 @@ void exynos_dp_disable_scrambling(struct exynos_dp_device *dp); | |||
144 | #define DPCD_ADDR_TRAINING_PATTERN_SET 0x0102 | 144 | #define DPCD_ADDR_TRAINING_PATTERN_SET 0x0102 |
145 | #define DPCD_ADDR_TRAINING_LANE0_SET 0x0103 | 145 | #define DPCD_ADDR_TRAINING_LANE0_SET 0x0103 |
146 | #define DPCD_ADDR_LANE0_1_STATUS 0x0202 | 146 | #define DPCD_ADDR_LANE0_1_STATUS 0x0202 |
147 | #define DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED 0x0204 | 147 | #define DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED 0x0204 |
148 | #define DPCD_ADDR_ADJUST_REQUEST_LANE0_1 0x0206 | 148 | #define DPCD_ADDR_ADJUST_REQUEST_LANE0_1 0x0206 |
149 | #define DPCD_ADDR_ADJUST_REQUEST_LANE2_3 0x0207 | 149 | #define DPCD_ADDR_ADJUST_REQUEST_LANE2_3 0x0207 |
150 | #define DPCD_ADDR_TEST_REQUEST 0x0218 | 150 | #define DPCD_ADDR_TEST_REQUEST 0x0218 |