]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/amd/display: PR error HPD_IRQ handling
authorJack Chang <jack.chang@amd.com>
Thu, 6 Nov 2025 02:58:26 +0000 (10:58 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Sat, 10 Jan 2026 19:21:53 +0000 (14:21 -0500)
[Why & How]
Add error handling for IRQ_HPD in Panel Replay

Reviewed-by: Robin Chen <robin.chen@amd.com>
Reviewed-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Jack Chang <jack.chang@amd.com>
Signed-off-by: Matthew Stewart <matthew.stewart2@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/dc_dp_types.h
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c
drivers/gpu/drm/amd/display/include/dpcd_defs.h

index d0d9297ccac077b0882fbd1fe4996e3fd8829625..5e3646b7550c12e3cae7b63c5e1a0b2c09f75e73 100644 (file)
@@ -1423,6 +1423,17 @@ union dpcd_sink_active_vtotal_control_mode {
        unsigned char raw;
 };
 
+union pr_error_status {
+       struct {
+               unsigned char LINK_CRC_ERROR        :1;
+               unsigned char RFB_STORAGE_ERROR     :1;
+               unsigned char VSC_SDP_ERROR         :1;
+               unsigned char ASSDP_MISSING_ERROR   :1;
+               unsigned char RESERVED              :4;
+       } bits;
+       unsigned char raw;
+};
+
 union psr_error_status {
        struct {
                unsigned char LINK_CRC_ERROR        :1;
index 47abd3ec69b363f90335b85a23cdd442d0acdb5a..cc18a3bebef2be23c8f4c7d77235d6314b7b91dc 100644 (file)
@@ -34,6 +34,7 @@
 #include "link_dp_training.h"
 #include "link_dp_capability.h"
 #include "link_edp_panel_control.h"
+#include "link_dp_panel_replay.h"
 #include "link/accessories/link_dp_trace.h"
 #include "link/link_dpms.h"
 #include "dm_helpers.h"
@@ -186,6 +187,42 @@ static bool handle_hpd_irq_psr_sink(struct dc_link *link)
        return false;
 }
 
+static void handle_hpd_irq_vesa_replay_sink(struct dc_link *link)
+{
+       union pr_error_status pr_error_status = {0};
+
+       if (!link->replay_settings.replay_feature_enabled ||
+                       link->replay_settings.config.replay_version != DC_VESA_PANEL_REPLAY)
+               return;
+
+       dm_helpers_dp_read_dpcd(
+               link->ctx,
+               link,
+               DP_PR_ERROR_STATUS,
+               &pr_error_status.raw,
+               sizeof(pr_error_status.raw));
+
+       if (pr_error_status.bits.LINK_CRC_ERROR ||
+                       pr_error_status.bits.RFB_STORAGE_ERROR ||
+                       pr_error_status.bits.VSC_SDP_ERROR ||
+                       pr_error_status.bits.ASSDP_MISSING_ERROR) {
+
+               /* Acknowledge and clear error bits */
+               dm_helpers_dp_write_dpcd(
+                       link->ctx,
+                       link,
+                       DP_PR_ERROR_STATUS, /*DpcdAddress_PR_Error_Status*/
+                       &pr_error_status.raw,
+                       sizeof(pr_error_status.raw));
+
+               /* Replay error, disable and re-enable Replay */
+               if (link->replay_settings.replay_allow_active) {
+                       dp_pr_enable(link, false);
+                       dp_pr_enable(link, true);
+               }
+       }
+}
+
 static void handle_hpd_irq_replay_sink(struct dc_link *link)
 {
        union dpcd_replay_configuration replay_configuration = {0};
@@ -197,6 +234,11 @@ static void handle_hpd_irq_replay_sink(struct dc_link *link)
        if (!link->replay_settings.replay_feature_enabled)
                return;
 
+       if (link->replay_settings.config.replay_version != DC_FREESYNC_REPLAY) {
+               handle_hpd_irq_vesa_replay_sink(link);
+               return;
+       }
+
        while (retries < 10) {
                ret = dm_helpers_dp_read_dpcd(
                        link->ctx,
index 43d58df67babafc2aadc6925044581804809e2d4..7d8359a7d99d46e6e74988674eb031ad54b1f4c3 100644 (file)
 #ifndef DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2 // can remove this once the define gets into linux drm_dp_helper.h
 #define DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2 0x1b1
 #endif /* DP_PANEL_REPLAY_ENABLE_AND_CONFIGURATION_2 */
+#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_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 */
+#ifndef DP_PR_RFB_STORAGE_ERROR            // can remove this once the define gets into linux drm_dp_helper.h
+#define DP_PR_RFB_STORAGE_ERROR            (1 << 1)
+#endif /* DP_PR_RFB_STORAGE_ERROR */
+#ifndef DP_PR_VSC_SDP_UNCORRECTABLE_ERROR // can remove this once the define gets into linux drm_dp_helper.h
+#define DP_PR_VSC_SDP_UNCORRECTABLE_ERROR  (1 << 2) /* eDP 1.4 */
+#endif /* DP_PR_VSC_SDP_UNCORRECTABLE_ERROR */
+#ifndef DP_PR_ASSDP_MISSING_ERROR          // can remove this once the define gets into linux drm_dp_helper.h
+#define DP_PR_ASSDP_MISSING_ERROR          (1 << 3) /* eDP 1.5 */
+#endif /* DP_PR_ASSDP_MISSING_ERROR */
 
 enum dpcd_revision {
        DPCD_REV_10 = 0x10,