aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link.c95
1 files changed, 77 insertions, 18 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
index ea5d5ffd5522..2fa521812d23 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
@@ -469,6 +469,13 @@ static void link_disconnect_sink(struct dc_link *link)
469 link->dpcd_sink_count = 0; 469 link->dpcd_sink_count = 0;
470} 470}
471 471
472static void link_disconnect_remap(struct dc_sink *prev_sink, struct dc_link *link)
473{
474 dc_sink_release(link->local_sink);
475 link->local_sink = prev_sink;
476}
477
478
472static bool detect_dp( 479static bool detect_dp(
473 struct dc_link *link, 480 struct dc_link *link,
474 struct display_sink_capability *sink_caps, 481 struct display_sink_capability *sink_caps,
@@ -551,6 +558,17 @@ static bool detect_dp(
551 return true; 558 return true;
552} 559}
553 560
561static bool is_same_edid(struct dc_edid *old_edid, struct dc_edid *new_edid)
562{
563 if (old_edid->length != new_edid->length)
564 return false;
565
566 if (new_edid->length == 0)
567 return false;
568
569 return (memcmp(old_edid->raw_edid, new_edid->raw_edid, new_edid->length) == 0);
570}
571
554bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) 572bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
555{ 573{
556 struct dc_sink_init_data sink_init_data = { 0 }; 574 struct dc_sink_init_data sink_init_data = { 0 };
@@ -558,9 +576,13 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
558 uint8_t i; 576 uint8_t i;
559 bool converter_disable_audio = false; 577 bool converter_disable_audio = false;
560 struct audio_support *aud_support = &link->dc->res_pool->audio_support; 578 struct audio_support *aud_support = &link->dc->res_pool->audio_support;
579 bool same_edid = false;
561 enum dc_edid_status edid_status; 580 enum dc_edid_status edid_status;
562 struct dc_context *dc_ctx = link->ctx; 581 struct dc_context *dc_ctx = link->ctx;
563 struct dc_sink *sink = NULL; 582 struct dc_sink *sink = NULL;
583 struct dc_sink *prev_sink = NULL;
584 struct dpcd_caps prev_dpcd_caps;
585 bool same_dpcd = true;
564 enum dc_connection_type new_connection_type = dc_connection_none; 586 enum dc_connection_type new_connection_type = dc_connection_none;
565 DC_LOGGER_INIT(link->ctx->logger); 587 DC_LOGGER_INIT(link->ctx->logger);
566 if (link->connector_signal == SIGNAL_TYPE_VIRTUAL) 588 if (link->connector_signal == SIGNAL_TYPE_VIRTUAL)
@@ -575,6 +597,11 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
575 link->local_sink) 597 link->local_sink)
576 return true; 598 return true;
577 599
600 prev_sink = link->local_sink;
601 if (prev_sink != NULL) {
602 dc_sink_retain(prev_sink);
603 memcpy(&prev_dpcd_caps, &link->dpcd_caps, sizeof(struct dpcd_caps));
604 }
578 link_disconnect_sink(link); 605 link_disconnect_sink(link);
579 606
580 if (new_connection_type != dc_connection_none) { 607 if (new_connection_type != dc_connection_none) {
@@ -616,14 +643,25 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
616 link, 643 link,
617 &sink_caps, 644 &sink_caps,
618 &converter_disable_audio, 645 &converter_disable_audio,
619 aud_support, reason)) 646 aud_support, reason)) {
647 if (prev_sink != NULL)
648 dc_sink_release(prev_sink);
620 return false; 649 return false;
650 }
621 651
652 // Check if dpcp block is the same
653 if (prev_sink != NULL) {
654 if (memcmp(&link->dpcd_caps, &prev_dpcd_caps, sizeof(struct dpcd_caps)))
655 same_dpcd = false;
656 }
622 /* Active dongle downstream unplug */ 657 /* Active dongle downstream unplug */
623 if (link->type == dc_connection_active_dongle 658 if (link->type == dc_connection_active_dongle
624 && link->dpcd_caps.sink_count. 659 && link->dpcd_caps.sink_count.
625 bits.SINK_COUNT == 0) 660 bits.SINK_COUNT == 0) {
661 if (prev_sink != NULL)
662 dc_sink_release(prev_sink);
626 return true; 663 return true;
664 }
627 665
628 if (link->type == dc_connection_mst_branch) { 666 if (link->type == dc_connection_mst_branch) {
629 LINK_INFO("link=%d, mst branch is now Connected\n", 667 LINK_INFO("link=%d, mst branch is now Connected\n",
@@ -634,6 +672,8 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
634 * pbn_per_slot value leading to exception on dc_fixpt_div() 672 * pbn_per_slot value leading to exception on dc_fixpt_div()
635 */ 673 */
636 link->verified_link_cap = link->reported_link_cap; 674 link->verified_link_cap = link->reported_link_cap;
675 if (prev_sink != NULL)
676 dc_sink_release(prev_sink);
637 return false; 677 return false;
638 } 678 }
639 679
@@ -643,6 +683,8 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
643 default: 683 default:
644 DC_ERROR("Invalid connector type! signal:%d\n", 684 DC_ERROR("Invalid connector type! signal:%d\n",
645 link->connector_signal); 685 link->connector_signal);
686 if (prev_sink != NULL)
687 dc_sink_release(prev_sink);
646 return false; 688 return false;
647 } /* switch() */ 689 } /* switch() */
648 690
@@ -665,6 +707,8 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
665 sink = dc_sink_create(&sink_init_data); 707 sink = dc_sink_create(&sink_init_data);
666 if (!sink) { 708 if (!sink) {
667 DC_ERROR("Failed to create sink!\n"); 709 DC_ERROR("Failed to create sink!\n");
710 if (prev_sink != NULL)
711 dc_sink_release(prev_sink);
668 return false; 712 return false;
669 } 713 }
670 714
@@ -688,22 +732,33 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
688 break; 732 break;
689 } 733 }
690 734
691 if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT && 735 // Check if edid is the same
692 sink_caps.transaction_type == 736 if ((prev_sink != NULL) && ((edid_status == EDID_THE_SAME) || (edid_status == EDID_OK)))
693 DDC_TRANSACTION_TYPE_I2C_OVER_AUX) { 737 same_edid = is_same_edid(&prev_sink->dc_edid, &sink->dc_edid);
694 /*
695 * TODO debug why Dell 2413 doesn't like
696 * two link trainings
697 */
698 738
699 /* deal with non-mst cases */ 739 // If both edid and dpcd are the same, then discard new sink and revert back to original sink
700 dp_hbr_verify_link_cap(link, &link->reported_link_cap); 740 if ((same_edid) && (same_dpcd)) {
701 } 741 link_disconnect_remap(prev_sink, link);
742 sink = prev_sink;
743 prev_sink = NULL;
744 } else {
745 if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
746 sink_caps.transaction_type ==
747 DDC_TRANSACTION_TYPE_I2C_OVER_AUX) {
748 /*
749 * TODO debug why Dell 2413 doesn't like
750 * two link trainings
751 */
752
753 /* deal with non-mst cases */
754 dp_hbr_verify_link_cap(link, &link->reported_link_cap);
755 }
702 756
703 /* HDMI-DVI Dongle */ 757 /* HDMI-DVI Dongle */
704 if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A && 758 if (sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A &&
705 !sink->edid_caps.edid_hdmi) 759 !sink->edid_caps.edid_hdmi)
706 sink->sink_signal = SIGNAL_TYPE_DVI_SINGLE_LINK; 760 sink->sink_signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
761 }
707 762
708 /* Connectivity log: detection */ 763 /* Connectivity log: detection */
709 for (i = 0; i < sink->dc_edid.length / EDID_BLOCK_SIZE; i++) { 764 for (i = 0; i < sink->dc_edid.length / EDID_BLOCK_SIZE; i++) {
@@ -762,10 +817,14 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
762 sink_caps.signal = SIGNAL_TYPE_NONE; 817 sink_caps.signal = SIGNAL_TYPE_NONE;
763 } 818 }
764 819
765 LINK_INFO("link=%d, dc_sink_in=%p is now %s\n", 820 LINK_INFO("link=%d, dc_sink_in=%p is now %s prev_sink=%p dpcd same=%d edid same=%d\n",
766 link->link_index, sink, 821 link->link_index, sink,
767 (sink_caps.signal == SIGNAL_TYPE_NONE ? 822 (sink_caps.signal == SIGNAL_TYPE_NONE ?
768 "Disconnected":"Connected")); 823 "Disconnected":"Connected"), prev_sink,
824 same_dpcd, same_edid);
825
826 if (prev_sink != NULL)
827 dc_sink_release(prev_sink);
769 828
770 return true; 829 return true;
771} 830}