]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/amd/display: Add Replay/PSR active check in link loss status check
authorAllen Li <Allen.Li@amd.com>
Tue, 10 Mar 2026 08:49:08 +0000 (16:49 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 17 Apr 2026 19:41:16 +0000 (15:41 -0400)
[Why&How]
To avoid unnecessary link retraining when the panel is in Replay/PSR mode,
we need to check if it's in active state and ESD information before we
decide to retrain the link.

Reviewed-by: ChunTao Tso <chuntao.tso@amd.com>
Signed-off-by: Allen Li <allen.li@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c

index 1860d44f63c1f4cf1f29dac0e6a2d0e58fba336b..dd19b912c48c5f83c3f7af53546569cb46b5ce87 100644 (file)
@@ -223,7 +223,7 @@ static void handle_hpd_irq_vesa_replay_sink(struct dc_link *link)
        }
 }
 
-static void handle_hpd_irq_replay_sink(struct dc_link *link, bool *need_re_enable)
+static void handle_hpd_irq_replay_sink(struct dc_link *link, bool *need_re_enable, bool *replay_esd_detection_needed)
 {
        union dpcd_replay_configuration replay_configuration = {0};
        union dpcd_replay_configuration replay_sink_status = {0};
@@ -311,6 +311,14 @@ static void handle_hpd_irq_replay_sink(struct dc_link *link, bool *need_re_enabl
                        *need_re_enable = true;
                }
        }
+
+       if (!link->replay_settings.replay_allow_active &&
+           replay_sink_status.bits.SINK_DEVICE_REPLAY_STATUS == 0x7) {
+           /* If sink device replay status is 0x7 and replay is disabled,
+            * it means sink is in a bad state and link retraining is needed to recover
+            */
+           *replay_esd_detection_needed = true;
+       }
 }
 
 void dp_handle_link_loss(struct dc_link *link)
@@ -469,6 +477,7 @@ bool dp_handle_hpd_rx_irq(struct dc_link *link,
        enum dc_status result;
        bool status = false;
        bool replay_re_enable_needed = false;
+       bool replay_esd_detection_needed = false;
 
        if (out_link_loss)
                *out_link_loss = false;
@@ -482,6 +491,7 @@ bool dp_handle_hpd_rx_irq(struct dc_link *link,
        DC_LOG_HW_HPD_IRQ("%s: Got short pulse HPD on link %d\n",
                __func__, link->link_index);
 
+       handle_hpd_irq_replay_sink(link, &replay_re_enable_needed, &replay_esd_detection_needed);
 
         /* All the "handle_hpd_irq_xxx()" methods
                 * should be called only after
@@ -528,8 +538,6 @@ 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, &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.
         */
@@ -552,27 +560,30 @@ bool dp_handle_hpd_rx_irq(struct dc_link *link,
         * Downstream port status changed,
         * then DM should call DC to do the detection.
         * NOTE: Now includes eDP link loss detection and retraining
+        * Link will be retrained if panel is not EDP or
+        * Replay ESD recovery is needed.
         */
-
-       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,
-                                       sizeof(hpd_irq_dpcd_data),
-                                       "Status: ");
-
-               if (defer_handling && has_left_work)
-                       *has_left_work = true;
-               else
-                       dp_handle_link_loss(link);
-
-               status = false;
-               if (out_link_loss)
-                       *out_link_loss = true;
-
-               dp_trace_link_loss_increment(link);
+       if (link->connector_signal != SIGNAL_TYPE_EDP || replay_esd_detection_needed) {
+               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,
+                                               sizeof(hpd_irq_dpcd_data),
+                                               "Status: ");
+
+                       if (defer_handling && has_left_work)
+                               *has_left_work = true;
+                       else
+                               dp_handle_link_loss(link);
+
+                       status = false;
+                       if (out_link_loss)
+                               *out_link_loss = true;
+
+                       dp_trace_link_loss_increment(link);
+               }
        }
 
        if (link->dpcd_caps.usb4_dp_tun_info.dp_tun_cap.bits.dp_tunneling) {