aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/exynos
diff options
context:
space:
mode:
authorSean Paul <seanpaul@chromium.org>2012-10-31 19:21:00 -0400
committerJingoo Han <jg1.han@samsung.com>2012-11-28 20:33:27 -0500
commitfadec4b7e59e3a89c43dcba1c9812a9f99d2a61a (patch)
tree3ac223022c0faefc87489b0bd140e37202d2bba2 /drivers/video/exynos
parentace2d7f2b537a072e39ddb4f51467d32b4900f8c (diff)
video: exynos_dp: Clean up SW link training
Clean up some of the SW training code to make it more clear and reduce duplicate code. [jg1.han@samsung.com: used exynos_dp_write_bytes_to_dpcd()] Signed-off-by: Sean Paul <seanpaul@chromium.org> Signed-off-by: Jingoo Han <jg1.han@samsung.com>
Diffstat (limited to 'drivers/video/exynos')
-rw-r--r--drivers/video/exynos/exynos_dp_core.c292
1 files changed, 119 insertions, 173 deletions
diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c
index e007906694fa..7161f9f86c9f 100644
--- a/drivers/video/exynos/exynos_dp_core.c
+++ b/drivers/video/exynos/exynos_dp_core.c
@@ -277,7 +277,7 @@ static int exynos_dp_link_start(struct exynos_dp_device *dp)
277 277
278 /* Set sink to D0 (Sink Not Ready) mode. */ 278 /* Set sink to D0 (Sink Not Ready) mode. */
279 retval = exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_SINK_POWER_STATE, 279 retval = exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_SINK_POWER_STATE,
280 DPCD_SET_POWER_STATE_D0); 280 DPCD_SET_POWER_STATE_D0);
281 if (retval) 281 if (retval)
282 return retval; 282 return retval;
283 283
@@ -302,17 +302,18 @@ static int exynos_dp_link_start(struct exynos_dp_device *dp)
302 exynos_dp_set_training_pattern(dp, TRAINING_PTN1); 302 exynos_dp_set_training_pattern(dp, TRAINING_PTN1);
303 303
304 /* Set RX training pattern */ 304 /* Set RX training pattern */
305 exynos_dp_write_byte_to_dpcd(dp, 305 retval = exynos_dp_write_byte_to_dpcd(dp,
306 DPCD_ADDR_TRAINING_PATTERN_SET, 306 DPCD_ADDR_TRAINING_PATTERN_SET,
307 DPCD_SCRAMBLING_DISABLED | 307 DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1);
308 DPCD_TRAINING_PATTERN_1); 308 if (retval)
309 return retval;
309 310
310 for (lane = 0; lane < lane_count; lane++) 311 for (lane = 0; lane < lane_count; lane++)
311 buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 | 312 buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 |
312 DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0; 313 DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0;
313 retval = exynos_dp_write_bytes_to_dpcd(dp, 314
314 DPCD_ADDR_TRAINING_LANE0_SET, 315 retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
315 lane_count, buf); 316 lane_count, buf);
316 317
317 return retval; 318 return retval;
318} 319}
@@ -338,18 +339,17 @@ static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count)
338 return 0; 339 return 0;
339} 340}
340 341
341static int exynos_dp_channel_eq_ok(u8 link_align[3], int lane_count) 342static int exynos_dp_channel_eq_ok(u8 link_status[2], u8 link_align,
343 int lane_count)
342{ 344{
343 int lane; 345 int lane;
344 u8 lane_align;
345 u8 lane_status; 346 u8 lane_status;
346 347
347 lane_align = link_align[2]; 348 if ((link_align & DPCD_INTERLANE_ALIGN_DONE) == 0)
348 if ((lane_align & DPCD_INTERLANE_ALIGN_DONE) == 0)
349 return -EINVAL; 349 return -EINVAL;
350 350
351 for (lane = 0; lane < lane_count; lane++) { 351 for (lane = 0; lane < lane_count; lane++) {
352 lane_status = exynos_dp_get_lane_status(link_align, lane); 352 lane_status = exynos_dp_get_lane_status(link_status, lane);
353 lane_status &= DPCD_CHANNEL_EQ_BITS; 353 lane_status &= DPCD_CHANNEL_EQ_BITS;
354 if (lane_status != DPCD_CHANNEL_EQ_BITS) 354 if (lane_status != DPCD_CHANNEL_EQ_BITS)
355 return -EINVAL; 355 return -EINVAL;
@@ -433,22 +433,47 @@ static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp)
433 dp->link_train.lt_state = FAILED; 433 dp->link_train.lt_state = FAILED;
434} 434}
435 435
436static void exynos_dp_get_adjust_training_lane(struct exynos_dp_device *dp,
437 u8 adjust_request[2])
438{
439 int lane, lane_count;
440 u8 voltage_swing, pre_emphasis, training_lane;
441
442 lane_count = dp->link_train.lane_count;
443 for (lane = 0; lane < lane_count; lane++) {
444 voltage_swing = exynos_dp_get_adjust_request_voltage(
445 adjust_request, lane);
446 pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
447 adjust_request, lane);
448 training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
449 DPCD_PRE_EMPHASIS_SET(pre_emphasis);
450
451 if (voltage_swing == VOLTAGE_LEVEL_3)
452 training_lane |= DPCD_MAX_SWING_REACHED;
453 if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
454 training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
455
456 dp->link_train.training_lane[lane] = training_lane;
457 }
458}
459
436static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) 460static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
437{ 461{
438 u8 link_status[2];
439 int lane, lane_count, retval; 462 int lane, lane_count, retval;
440 463 u8 voltage_swing, pre_emphasis, training_lane;
441 u8 adjust_request[2]; 464 u8 link_status[2], adjust_request[2];
442 u8 voltage_swing;
443 u8 pre_emphasis;
444 u8 training_lane;
445 465
446 usleep_range(100, 101); 466 usleep_range(100, 101);
447 467
448 lane_count = dp->link_train.lane_count; 468 lane_count = dp->link_train.lane_count;
449 469
450 retval = exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, 470 retval = exynos_dp_read_bytes_from_dpcd(dp,
451 2, link_status); 471 DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
472 if (retval)
473 return retval;
474
475 retval = exynos_dp_read_bytes_from_dpcd(dp,
476 DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
452 if (retval) 477 if (retval)
453 return retval; 478 return retval;
454 479
@@ -456,43 +481,10 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
456 /* set training pattern 2 for EQ */ 481 /* set training pattern 2 for EQ */
457 exynos_dp_set_training_pattern(dp, TRAINING_PTN2); 482 exynos_dp_set_training_pattern(dp, TRAINING_PTN2);
458 483
459 for (lane = 0; lane < lane_count; lane++) {
460 retval = exynos_dp_read_bytes_from_dpcd(dp,
461 DPCD_ADDR_ADJUST_REQUEST_LANE0_1,
462 2, adjust_request);
463 if (retval)
464 return retval;
465
466 voltage_swing = exynos_dp_get_adjust_request_voltage(
467 adjust_request, lane);
468 pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
469 adjust_request, lane);
470 training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
471 DPCD_PRE_EMPHASIS_SET(pre_emphasis);
472
473 if (voltage_swing == VOLTAGE_LEVEL_3)
474 training_lane |= DPCD_MAX_SWING_REACHED;
475 if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
476 training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
477
478 dp->link_train.training_lane[lane] = training_lane;
479
480 exynos_dp_set_lane_link_training(dp,
481 dp->link_train.training_lane[lane],
482 lane);
483 }
484
485 retval = exynos_dp_write_byte_to_dpcd(dp, 484 retval = exynos_dp_write_byte_to_dpcd(dp,
486 DPCD_ADDR_TRAINING_PATTERN_SET, 485 DPCD_ADDR_TRAINING_PATTERN_SET,
487 DPCD_SCRAMBLING_DISABLED | 486 DPCD_SCRAMBLING_DISABLED |
488 DPCD_TRAINING_PATTERN_2); 487 DPCD_TRAINING_PATTERN_2);
489 if (retval)
490 return retval;
491
492 retval = exynos_dp_write_bytes_to_dpcd(dp,
493 DPCD_ADDR_TRAINING_LANE0_SET,
494 lane_count,
495 dp->link_train.training_lane);
496 if (retval) 488 if (retval)
497 return retval; 489 return retval;
498 490
@@ -502,162 +494,116 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
502 for (lane = 0; lane < lane_count; lane++) { 494 for (lane = 0; lane < lane_count; lane++) {
503 training_lane = exynos_dp_get_lane_link_training( 495 training_lane = exynos_dp_get_lane_link_training(
504 dp, lane); 496 dp, lane);
505 retval = exynos_dp_read_bytes_from_dpcd(dp,
506 DPCD_ADDR_ADJUST_REQUEST_LANE0_1,
507 2, adjust_request);
508 if (retval)
509 return retval;
510
511 voltage_swing = exynos_dp_get_adjust_request_voltage( 497 voltage_swing = exynos_dp_get_adjust_request_voltage(
512 adjust_request, lane); 498 adjust_request, lane);
513 pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( 499 pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
514 adjust_request, lane); 500 adjust_request, lane);
515 501
516 if (voltage_swing == VOLTAGE_LEVEL_3 || 502 if (DPCD_VOLTAGE_SWING_GET(training_lane) ==
517 pre_emphasis == PRE_EMPHASIS_LEVEL_3) { 503 voltage_swing &&
518 dev_err(dp->dev, "voltage or pre emphasis reached max level\n"); 504 DPCD_PRE_EMPHASIS_GET(training_lane) ==
519 goto reduce_link_rate; 505 pre_emphasis)
520 }
521
522 if ((DPCD_VOLTAGE_SWING_GET(training_lane) ==
523 voltage_swing) &&
524 (DPCD_PRE_EMPHASIS_GET(training_lane) ==
525 pre_emphasis)) {
526 dp->link_train.cr_loop[lane]++; 506 dp->link_train.cr_loop[lane]++;
527 if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP) {
528 dev_err(dp->dev, "CR Max loop\n");
529 goto reduce_link_rate;
530 }
531 }
532
533 training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
534 DPCD_PRE_EMPHASIS_SET(pre_emphasis);
535 507
536 if (voltage_swing == VOLTAGE_LEVEL_3) 508 if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP ||
537 training_lane |= DPCD_MAX_SWING_REACHED; 509 voltage_swing == VOLTAGE_LEVEL_3 ||
538 if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) 510 pre_emphasis == PRE_EMPHASIS_LEVEL_3) {
539 training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; 511 dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n",
512 dp->link_train.cr_loop[lane],
513 voltage_swing, pre_emphasis);
514 exynos_dp_reduce_link_rate(dp);
515 return -EIO;
516 }
517 }
518 }
540 519
541 dp->link_train.training_lane[lane] = training_lane; 520 exynos_dp_get_adjust_training_lane(dp, adjust_request);
542 521
543 exynos_dp_set_lane_link_training(dp, 522 for (lane = 0; lane < lane_count; lane++)
544 dp->link_train.training_lane[lane], lane); 523 exynos_dp_set_lane_link_training(dp,
545 } 524 dp->link_train.training_lane[lane], lane);
546 525
547 retval = exynos_dp_write_bytes_to_dpcd(dp, 526 retval = exynos_dp_write_bytes_to_dpcd(dp,
548 DPCD_ADDR_TRAINING_LANE0_SET, lane_count, 527 DPCD_ADDR_TRAINING_LANE0_SET, lane_count,
549 dp->link_train.training_lane); 528 dp->link_train.training_lane);
550 if (retval) 529 if (retval)
551 return retval; 530 return retval;
552 }
553 531
554 return retval; 532 return retval;
555
556reduce_link_rate:
557 exynos_dp_reduce_link_rate(dp);
558 return -EIO;
559} 533}
560 534
561static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) 535static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
562{ 536{
563 u8 link_status[2];
564 u8 link_align[3];
565 int lane, lane_count, retval; 537 int lane, lane_count, retval;
566 u32 reg; 538 u32 reg;
567 539 u8 link_align, link_status[2], adjust_request[2];
568 u8 adjust_request[2];
569 u8 voltage_swing;
570 u8 pre_emphasis;
571 u8 training_lane;
572 540
573 usleep_range(400, 401); 541 usleep_range(400, 401);
574 542
575 lane_count = dp->link_train.lane_count; 543 lane_count = dp->link_train.lane_count;
576 544
577 retval = exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, 545 retval = exynos_dp_read_bytes_from_dpcd(dp,
578 2, link_status); 546 DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
579 if (retval) 547 if (retval)
580 return retval; 548 return retval;
581 549
582 if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { 550 if (exynos_dp_clock_recovery_ok(link_status, lane_count)) {
583 link_align[0] = link_status[0]; 551 exynos_dp_reduce_link_rate(dp);
584 link_align[1] = link_status[1]; 552 return -EIO;
585 553 }
586 exynos_dp_read_byte_from_dpcd(dp,
587 DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED,
588 &link_align[2]);
589
590 for (lane = 0; lane < lane_count; lane++) {
591 retval = exynos_dp_read_bytes_from_dpcd(dp,
592 DPCD_ADDR_ADJUST_REQUEST_LANE0_1,
593 2, adjust_request);
594 if (retval)
595 return retval;
596 554
597 voltage_swing = exynos_dp_get_adjust_request_voltage( 555 retval = exynos_dp_read_bytes_from_dpcd(dp,
598 adjust_request, lane); 556 DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
599 pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( 557 if (retval)
600 adjust_request, lane); 558 return retval;
601 training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
602 DPCD_PRE_EMPHASIS_SET(pre_emphasis);
603 559
604 if (voltage_swing == VOLTAGE_LEVEL_3) 560 retval = exynos_dp_read_byte_from_dpcd(dp,
605 training_lane |= DPCD_MAX_SWING_REACHED; 561 DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, &link_align);
606 if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) 562 if (retval)
607 training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; 563 return retval;
608 564
609 dp->link_train.training_lane[lane] = training_lane; 565 exynos_dp_get_adjust_training_lane(dp, adjust_request);
610 }
611 566
612 if (exynos_dp_channel_eq_ok(link_align, lane_count) == 0) { 567 if (!exynos_dp_channel_eq_ok(link_status, link_align, lane_count)) {
613 /* traing pattern Set to Normal */ 568 /* traing pattern Set to Normal */
614 exynos_dp_training_pattern_dis(dp); 569 exynos_dp_training_pattern_dis(dp);
615 570
616 dev_info(dp->dev, "Link Training success!\n"); 571 dev_info(dp->dev, "Link Training success!\n");
617 572
618 exynos_dp_get_link_bandwidth(dp, &reg); 573 exynos_dp_get_link_bandwidth(dp, &reg);
619 dp->link_train.link_rate = reg; 574 dp->link_train.link_rate = reg;
620 dev_dbg(dp->dev, "final bandwidth = %.2x\n", 575 dev_dbg(dp->dev, "final bandwidth = %.2x\n",
621 dp->link_train.link_rate); 576 dp->link_train.link_rate);
622 577
623 exynos_dp_get_lane_count(dp, &reg); 578 exynos_dp_get_lane_count(dp, &reg);
624 dp->link_train.lane_count = reg; 579 dp->link_train.lane_count = reg;
625 dev_dbg(dp->dev, "final lane count = %.2x\n", 580 dev_dbg(dp->dev, "final lane count = %.2x\n",
626 dp->link_train.lane_count); 581 dp->link_train.lane_count);
627 582
628 /* set enhanced mode if available */ 583 /* set enhanced mode if available */
629 exynos_dp_set_enhanced_mode(dp); 584 exynos_dp_set_enhanced_mode(dp);
630 dp->link_train.lt_state = FINISHED; 585 dp->link_train.lt_state = FINISHED;
631 } else {
632 /* not all locked */
633 dp->link_train.eq_loop++;
634 586
635 if (dp->link_train.eq_loop > MAX_EQ_LOOP) { 587 return 0;
636 dev_err(dp->dev, "EQ Max loop\n"); 588 }
637 goto reduce_link_rate;
638 }
639 589
640 for (lane = 0; lane < lane_count; lane++) 590 /* not all locked */
641 exynos_dp_set_lane_link_training(dp, 591 dp->link_train.eq_loop++;
642 dp->link_train.training_lane[lane],
643 lane);
644 592
645 retval = exynos_dp_write_bytes_to_dpcd(dp, 593 if (dp->link_train.eq_loop > MAX_EQ_LOOP) {
646 DPCD_ADDR_TRAINING_LANE0_SET, 594 dev_err(dp->dev, "EQ Max loop\n");
647 lane_count, 595 exynos_dp_reduce_link_rate(dp);
648 dp->link_train.training_lane); 596 return -EIO;
649 if (retval)
650 return retval;
651 }
652 } else {
653 goto reduce_link_rate;
654 } 597 }
655 598
656 return 0; 599 for (lane = 0; lane < lane_count; lane++)
600 exynos_dp_set_lane_link_training(dp,
601 dp->link_train.training_lane[lane], lane);
657 602
658reduce_link_rate: 603 retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
659 exynos_dp_reduce_link_rate(dp); 604 lane_count, dp->link_train.training_lane);
660 return -EIO; 605
606 return retval;
661} 607}
662 608
663static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp, 609static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp,