drm/amd/display: Work around bad DPCD state on link loss
authorIlya Bakoulin <ilya.bakoulin@amd.com>
Fri, 2 Jun 2023 21:01:23 +0000 (17:01 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 30 Jun 2023 17:11:35 +0000 (13:11 -0400)
[Why]
This display doesn't properly indicate link loss through DPCD bits such
as CR_DONE / CHANNEL_EQ_DONE / SYMBOL_LOCKED / INTERLANE_ALIGN_DONE,
which all remain set.

In addition, DPCD200Eh doesn't match the value of DPCD204h in all cases.

For these reasons, we can miss re-training the link, since we don't
properly detect link loss with this display.

[Why]
Add display-specific workaround to read DPCD204h, so that we can detect
link loss based on 128b132b-specific status bits in this register.

Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Reviewed-by: Wenjing Liu <wenjing.liu@amd.com>
Acked-by: Rodrigo Siqueira <rodrigo.siqueira@amd.com>
Signed-off-by: Ilya Bakoulin <ilya.bakoulin@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c

index ea0b78ef351df16748d1761ac6893b9193085b06..24f580bdac6a0ceefe79f7a634e4417206163c22 100644 (file)
@@ -1525,6 +1525,7 @@ struct dc_link {
                bool dpia_forced_tbt3_mode;
                bool dongle_mode_timing_override;
                bool blank_stream_on_ocs_change;
+               bool read_dpcd204h_on_irq_hpd;
        } wa_flags;
        struct link_mst_stream_allocation_table mst_stream_alloc_table;
 
index b1b11eb0f9bb434a14d916f0d8b5af826acc26cb..ef8739df91bcc79b519b4ee8e51e18b754c704a4 100644 (file)
@@ -208,6 +208,25 @@ void dp_handle_link_loss(struct dc_link *link)
        }
 }
 
+static void read_dpcd204h_on_irq_hpd(struct dc_link *link, union hpd_irq_data *irq_data)
+{
+       enum dc_status retval;
+       union lane_align_status_updated dpcd_lane_status_updated;
+
+       retval = core_link_read_dpcd(
+                       link,
+                       DP_LANE_ALIGN_STATUS_UPDATED,
+                       &dpcd_lane_status_updated.raw,
+                       sizeof(union lane_align_status_updated));
+
+       if (retval == DC_OK) {
+               irq_data->bytes.lane_status_updated.bits.EQ_INTERLANE_ALIGN_DONE_128b_132b =
+                               dpcd_lane_status_updated.bits.EQ_INTERLANE_ALIGN_DONE_128b_132b;
+               irq_data->bytes.lane_status_updated.bits.CDS_INTERLANE_ALIGN_DONE_128b_132b =
+                               dpcd_lane_status_updated.bits.CDS_INTERLANE_ALIGN_DONE_128b_132b;
+       }
+}
+
 enum dc_status dp_read_hpd_rx_irq_data(
        struct dc_link *link,
        union hpd_irq_data *irq_data)
@@ -249,6 +268,13 @@ enum dc_status dp_read_hpd_rx_irq_data(
                irq_data->bytes.lane23_status.raw = tmp[DP_LANE2_3_STATUS_ESI - DP_SINK_COUNT_ESI];
                irq_data->bytes.lane_status_updated.raw = tmp[DP_LANE_ALIGN_STATUS_UPDATED_ESI - DP_SINK_COUNT_ESI];
                irq_data->bytes.sink_status.raw = tmp[DP_SINK_STATUS_ESI - DP_SINK_COUNT_ESI];
+
+               /*
+                * This display doesn't have correct values in DPCD200Eh.
+                * Read and check DPCD204h instead.
+                */
+               if (link->wa_flags.read_dpcd204h_on_irq_hpd)
+                       read_dpcd204h_on_irq_hpd(link, irq_data);
        }
 
        return retval;