]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/amd/display: Add ESD detection for replay recovery
authorWeiguang Li <wei-guang.li@amd.com>
Mon, 8 Dec 2025 06:13:20 +0000 (14:13 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 11 Mar 2026 14:56:00 +0000 (10:56 -0400)
[HOW]
Add Replay recovery flow so that when HPD occurs and ESD is detected,
Replay can restore the system back to normal.

Reviewed-by: Wenjing Liu <wenjing.liu@amd.com>
Reviewed-by: Robin Chen <robin.chen@amd.com>
Reviewed-by: Aric Cyr <aric.cyr@amd.com>
Signed-off-by: Weiguang Li <wei-guang.li@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c
drivers/gpu/drm/amd/display/include/dpcd_defs.h

index cc18a3bebef2be23c8f4c7d77235d6314b7b91dc..1860d44f63c1f4cf1f29dac0e6a2d0e58fba336b 100644 (file)
@@ -223,9 +223,10 @@ static void handle_hpd_irq_vesa_replay_sink(struct dc_link *link)
        }
 }
 
-static void handle_hpd_irq_replay_sink(struct dc_link *link)
+static void handle_hpd_irq_replay_sink(struct dc_link *link, bool *need_re_enable)
 {
        union dpcd_replay_configuration replay_configuration = {0};
+       union dpcd_replay_configuration replay_sink_status = {0};
        /*AMD Replay version reuse DP_PSR_ERROR_STATUS for REPLAY_ERROR status.*/
        union psr_error_status replay_error_status = {0};
        bool ret = false;
@@ -265,9 +266,17 @@ static void handle_hpd_irq_replay_sink(struct dc_link *link)
                &replay_error_status.raw,
                sizeof(replay_error_status.raw));
 
+       dm_helpers_dp_read_dpcd(
+               link->ctx,
+               link,
+               DP_PR_REPLAY_SINK_STATUS,
+               &replay_sink_status.raw,
+               1);
+
        if (replay_error_status.bits.LINK_CRC_ERROR ||
                replay_configuration.bits.DESYNC_ERROR_STATUS ||
-               replay_configuration.bits.STATE_TRANSITION_ERROR_STATUS) {
+               replay_configuration.bits.STATE_TRANSITION_ERROR_STATUS ||
+               replay_sink_status.bits.SINK_DEVICE_REPLAY_STATUS == 0x7) {
                bool allow_active;
 
                link->replay_settings.config.replay_error_status.raw |= replay_error_status.raw;
@@ -299,8 +308,7 @@ static void handle_hpd_irq_replay_sink(struct dc_link *link)
                if (link->replay_settings.replay_allow_active) {
                        allow_active = false;
                        edp_set_replay_allow_active(link, &allow_active, true, false, NULL);
-                       allow_active = true;
-                       edp_set_replay_allow_active(link, &allow_active, true, false, NULL);
+                       *need_re_enable = true;
                }
        }
 }
@@ -460,6 +468,7 @@ bool dp_handle_hpd_rx_irq(struct dc_link *link,
        union device_service_irq device_service_clear = {0};
        enum dc_status result;
        bool status = false;
+       bool replay_re_enable_needed = false;
 
        if (out_link_loss)
                *out_link_loss = false;
@@ -519,7 +528,7 @@ bool dp_handle_hpd_rx_irq(struct dc_link *link,
                /* PSR-related error was detected and handled */
                return true;
 
-       handle_hpd_irq_replay_sink(link);
+       handle_hpd_irq_replay_sink(link, &replay_re_enable_needed);
 
        /* If PSR-related error handled, Main link may be off,
         * so do not handle as a normal sink status change interrupt.
@@ -538,16 +547,16 @@ bool dp_handle_hpd_rx_irq(struct dc_link *link,
                return false;
        }
 
-       /* For now we only handle 'Downstream port status' case.
+       /* Handle 'Downstream port status' case for all DP link types.
         * If we got sink count changed it means
         * Downstream port status changed,
         * then DM should call DC to do the detection.
-        * NOTE: Do not handle link loss on eDP since it is internal link
+        * NOTE: Now includes eDP link loss detection and retraining
         */
-       if ((link->connector_signal != SIGNAL_TYPE_EDP) &&
-                       dp_parse_link_loss_status(
-                                       link,
-                                       &hpd_irq_dpcd_data)) {
+
+       if (dp_parse_link_loss_status(
+                       link,
+                       &hpd_irq_dpcd_data)) {
                /* Connectivity log: link loss */
                CONN_DATA_LINK_LOSS(link,
                                        hpd_irq_dpcd_data.raw,
@@ -576,6 +585,11 @@ bool dp_handle_hpd_rx_irq(struct dc_link *link,
                        != link->dpcd_sink_count)
                status = true;
 
+       if (replay_re_enable_needed) {
+               bool allow_active = true;
+
+               edp_set_replay_allow_active(link, &allow_active, true, false, NULL);
+       }
        /* reasons for HPD RX:
         * 1. Link Loss - ie Re-train the Link
         * 2. MST sideband message
index 1afa10e85eb5936f3694a17f1e4c2366abbde76d..4a8ca0ac12666502ad419771aa1a19e689964f4a 100644 (file)
@@ -64,6 +64,9 @@
 #ifndef DP_PR_ERROR_STATUS                  // can remove this once the define gets into linux drm_dp_helper.h
 #define DP_PR_ERROR_STATUS                  0x2020  /* DP 2.0 */
 #endif /* DP_PR_ERROR_STATUS */
+#ifndef DP_PR_REPLAY_SINK_STATUS            // can remove this once the define gets into linux drm_dp_helper.h
+#define DP_PR_REPLAY_SINK_STATUS            0x2022
+#endif /* DP_PR_REPLAY_SINK_STATUS */
 #ifndef DP_PR_LINK_CRC_ERROR               // can remove this once the define gets into linux drm_dp_helper.h
 #define DP_PR_LINK_CRC_ERROR               (1 << 0)
 #endif /* DP_PR_LINK_CRC_ERROR */