* [RFC PATCH] drm/amd/display: extend HPD debounce filter to DisplayPort SST
@ 2026-06-25 15:04 Nick Haghiri
2026-06-25 19:15 ` Ivan Lipski
0 siblings, 1 reply; 10+ messages in thread
From: Nick Haghiri @ 2026-06-25 15:04 UTC (permalink / raw)
To: amd-gfx, Alex Deucher
Cc: Harry Wentland, Leo Li, Ivan Lipski, Rodrigo Siqueira,
Christian König, dri-devel, linux-kernel, Nick Haghiri
Commit c97da4785b3b ("drm/amd/display: Add an HPD filter for HDMI") and
commit 6a681cd90345 ("drm/amd/display: Add an hdmi_hpd_debounce_delay_ms
module") added a filter that, on an HDMI disconnect, waits
hdmi_hpd_debounce_delay_ms and suppresses the hotplug if the sink comes
back with an unchanged EDID, instead of churning userspace.
DisplayPort SST sinks show the same pattern: some monitors briefly drop
and re-assert HPD when they enter deep sleep after DPMS-off. On the DP
path that toggle is forwarded as a real hotplug, so the compositor
re-probes and re-enables the output and the panel can never stay powered
off while connected.
Extend the existing filter to DisplayPort SST behind a new
dp_hpd_debounce_delay_ms module parameter (default 0/off, mirroring the
HDMI knob). eDP and MST are excluded; are_sinks_equal() and the debounce
work are reused unchanged.
Signed-off-by: Nick Haghiri <nick@haghiri.net>
---
RFC notes / open questions (below the --- so they stay out of the commit):
- Near-mechanical port of the HDMI filter to DisplayPort SST. I run it
daily on an RX 9070 XT (RDNA4) driving an MSI MPG 274U over DP, which
briefly drops and re-asserts HPD on DPMS-off and otherwise keeps the
panel from staying asleep; dp_hpd_debounce_delay_ms=1500 fixes it.
- The DP path reuses the existing debounce work and ->hdmi_prev_sink, so
those names are now a little misleading. Happy to rename them to a
generic hpd_* if you'd prefer.
- I added a separate dp_hpd_debounce_delay_ms knob to mirror the HDMI
one; folding both into a single hpd_debounce_delay_ms applied by signal
type would work too. Let me know which you'd rather have.
drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 +
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 12 +++++++++
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 6 +++++
.../display/amdgpu_dm/amdgpu_dm_connector.c | 20 ++++++++-------
.../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 25 ++++++++++++-------
5 files changed, 46 insertions(+), 18 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index e2d4be3c1..c085a6cc1 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -271,6 +271,7 @@ extern int amdgpu_user_queue;
extern int amdgpu_ptl;
extern uint amdgpu_hdmi_hpd_debounce_delay_ms;
+extern uint amdgpu_dp_hpd_debounce_delay_ms;
#define AMDGPU_SG_THRESHOLD (256*1024*1024)
#define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 65f2de86f..78df53b8c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -246,6 +246,7 @@ int amdgpu_umsch_mm_fwlog;
int amdgpu_rebar = -1; /* auto */
int amdgpu_user_queue = -1;
uint amdgpu_hdmi_hpd_debounce_delay_ms;
+uint amdgpu_dp_hpd_debounce_delay_ms;
int amdgpu_ptl = -1; /* auto */
DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
@@ -1113,6 +1114,17 @@ module_param_named(user_queue, amdgpu_user_queue, int, 0444);
MODULE_PARM_DESC(hdmi_hpd_debounce_delay_ms, "HDMI HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms, uint, 0644);
+/*
+ * DOC: dp_hpd_debounce_delay_ms (uint)
+ * DisplayPort SST HPD disconnect debounce delay in milliseconds.
+ *
+ * Used to filter short disconnect->reconnect HPD toggles some DisplayPort SST
+ * sinks generate while entering/leaving power save. Set to 0 to disable by
+ * default. eDP and MST are not affected.
+ */
+MODULE_PARM_DESC(dp_hpd_debounce_delay_ms, "DisplayPort SST HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
+module_param_named(dp_hpd_debounce_delay_ms, amdgpu_dp_hpd_debounce_delay_ms, uint, 0644);
+
/**
* DOC: ptl (int)
* Enable PTL feature at boot time. Possible values:
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 2f4a56741..abc17f547 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -64,6 +64,11 @@ enum amd_vsdb_panel_type {
* Maximum HDMI HPD debounce delay in milliseconds
*/
#define AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS 5000
+
+/*
+ * Maximum DisplayPort SST HPD debounce delay in milliseconds
+ */
+#define AMDGPU_DM_MAX_DP_HPD_DEBOUNCE_MS 5000
/*
#include "include/amdgpu_dal_power_if.h"
#include "amdgpu_dm_irq.h"
@@ -875,6 +880,7 @@ struct amdgpu_dm_connector {
/* HDMI HPD debounce support */
unsigned int hdmi_hpd_debounce_delay_ms;
+ unsigned int dp_hpd_debounce_delay_ms;
struct delayed_work hdmi_hpd_debounce_work;
struct dc_sink *hdmi_prev_sink;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 6143cdcf2..c79a8ada8 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -1747,8 +1747,8 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
if (aconnector->mst_mgr.dev)
drm_dp_mst_topology_mgr_destroy(&aconnector->mst_mgr);
- /* Cancel and flush any pending HDMI HPD debounce work */
- if (aconnector->hdmi_hpd_debounce_delay_ms) {
+ /* Cancel and flush any pending HPD debounce work */
+ if (aconnector->hdmi_hpd_debounce_delay_ms || aconnector->dp_hpd_debounce_delay_ms) {
cancel_delayed_work_sync(&aconnector->hdmi_hpd_debounce_work);
if (aconnector->hdmi_prev_sink) {
dc_sink_release(aconnector->hdmi_prev_sink);
@@ -2829,16 +2829,18 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
mutex_init(&aconnector->handle_mst_msg_ready);
/*
- * If HDMI HPD debounce delay is set, use the minimum between selected
- * value and AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS
+ * If an HPD debounce delay is set, clamp each signal's delay to its
+ * maximum. The debounce work and cached sink are shared by both the
+ * HDMI and DisplayPort SST paths.
*/
- if (amdgpu_hdmi_hpd_debounce_delay_ms) {
- aconnector->hdmi_hpd_debounce_delay_ms = min(amdgpu_hdmi_hpd_debounce_delay_ms,
- AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS);
+ aconnector->hdmi_hpd_debounce_delay_ms = amdgpu_hdmi_hpd_debounce_delay_ms ?
+ min(amdgpu_hdmi_hpd_debounce_delay_ms, AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS) : 0;
+ aconnector->dp_hpd_debounce_delay_ms = amdgpu_dp_hpd_debounce_delay_ms ?
+ min(amdgpu_dp_hpd_debounce_delay_ms, AMDGPU_DM_MAX_DP_HPD_DEBOUNCE_MS) : 0;
+
+ if (aconnector->hdmi_hpd_debounce_delay_ms || aconnector->dp_hpd_debounce_delay_ms) {
INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, amdgpu_dm_hdmi_hpd_debounce_work);
aconnector->hdmi_prev_sink = NULL;
- } else {
- aconnector->hdmi_hpd_debounce_delay_ms = 0;
}
dm->hdmi_frl_status_polling_delay_ms = 200;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
index 85711a2f2..2a732d19b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
@@ -1302,6 +1302,7 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
struct dc *dc = aconnector->dc_link->ctx->dc;
bool ret = false;
bool debounce_required = false;
+ unsigned int debounce_delay_ms = 0;
if (adev->dm.disable_hpd_irq)
return;
@@ -1325,10 +1326,16 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n");
/*
- * Check for HDMI disconnect with debounce enabled.
+ * Check for an HDMI or DisplayPort SST disconnect with debounce
+ * enabled. eDP and MST are intentionally excluded.
*/
- debounce_required = (aconnector->hdmi_hpd_debounce_delay_ms > 0 &&
- dc_is_hdmi_signal(aconnector->dc_link->connector_signal) &&
+ if (dc_is_hdmi_signal(aconnector->dc_link->connector_signal))
+ debounce_delay_ms = aconnector->hdmi_hpd_debounce_delay_ms;
+ else if (aconnector->dc_link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
+ aconnector->dc_link->type != dc_connection_mst_branch)
+ debounce_delay_ms = aconnector->dp_hpd_debounce_delay_ms;
+
+ debounce_required = (debounce_delay_ms > 0 &&
new_connection_type == dc_connection_none &&
aconnector->dc_link->local_sink != NULL);
@@ -1344,12 +1351,12 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
drm_kms_helper_connector_hotplug_event(connector);
} else if (debounce_required) {
/*
- * HDMI disconnect detected - schedule delayed work instead of
+ * Disconnect detected - schedule delayed work instead of
* processing immediately. This allows us to coalesce spurious
- * HDMI signals from physical unplugs.
+ * HDMI/DP HPD signals from physical unplugs.
*/
- drm_dbg_kms(dev, "HDMI HPD: Disconnect detected, scheduling debounce work (%u ms)\n",
- aconnector->hdmi_hpd_debounce_delay_ms);
+ drm_dbg_kms(dev, "HPD: Disconnect detected, scheduling debounce work (%u ms)\n",
+ debounce_delay_ms);
/* Cache the current sink for later comparison */
if (aconnector->hdmi_prev_sink)
@@ -1361,8 +1368,8 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
/* Schedule delayed detection. */
if (mod_delayed_work(system_percpu_wq,
&aconnector->hdmi_hpd_debounce_work,
- msecs_to_jiffies(aconnector->hdmi_hpd_debounce_delay_ms)))
- drm_dbg_kms(dev, "HDMI HPD: Re-scheduled debounce work\n");
+ msecs_to_jiffies(debounce_delay_ms)))
+ drm_dbg_kms(dev, "HPD: Re-scheduled debounce work\n");
} else {
--
2.54.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH] drm/amd/display: extend HPD debounce filter to DisplayPort SST
2026-06-25 15:04 [RFC PATCH] drm/amd/display: extend HPD debounce filter to DisplayPort SST Nick Haghiri
@ 2026-06-25 19:15 ` Ivan Lipski
2026-06-25 19:45 ` Nick Haghiri
0 siblings, 1 reply; 10+ messages in thread
From: Ivan Lipski @ 2026-06-25 19:15 UTC (permalink / raw)
To: Nick Haghiri, amd-gfx, Alex Deucher
Cc: Harry Wentland, Leo Li, Ivan Lipski, Rodrigo Siqueira,
Christian König, dri-devel, linux-kernel
On 6/25/26 11:04, Nick Haghiri wrote:
> [You don't often get email from nick@haghiri.net. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>
> Commit c97da4785b3b ("drm/amd/display: Add an HPD filter for HDMI") and
> commit 6a681cd90345 ("drm/amd/display: Add an hdmi_hpd_debounce_delay_ms
> module") added a filter that, on an HDMI disconnect, waits
> hdmi_hpd_debounce_delay_ms and suppresses the hotplug if the sink comes
> back with an unchanged EDID, instead of churning userspace.
>
> DisplayPort SST sinks show the same pattern: some monitors briefly drop
> and re-assert HPD when they enter deep sleep after DPMS-off. On the DP
> path that toggle is forwarded as a real hotplug, so the compositor
> re-probes and re-enables the output and the panel can never stay powered
> off while connected.
>
> Extend the existing filter to DisplayPort SST behind a new
> dp_hpd_debounce_delay_ms module parameter (default 0/off, mirroring the
> HDMI knob). eDP and MST are excluded; are_sinks_equal() and the debounce
> work are reused unchanged.
>
> Signed-off-by: Nick Haghiri <nick@haghiri.net>
> ---
>
> RFC notes / open questions (below the --- so they stay out of the commit):
>
> - Near-mechanical port of the HDMI filter to DisplayPort SST. I run it
> daily on an RX 9070 XT (RDNA4) driving an MSI MPG 274U over DP, which
> briefly drops and re-asserts HPD on DPMS-off and otherwise keeps the
> panel from staying asleep; dp_hpd_debounce_delay_ms=1500 fixes it.
> - The DP path reuses the existing debounce work and ->hdmi_prev_sink, so
> those names are now a little misleading. Happy to rename them to a
> generic hpd_* if you'd prefer.
> - I added a separate dp_hpd_debounce_delay_ms knob to mirror the HDMI
> one; folding both into a single hpd_debounce_delay_ms applied by signal
> type would work too. Let me know which you'd rather have.
Hey Nick, thank you for this patch.
I don't think I've encountered a situation when a monitor with DP can
wake a system up from DPMS, so that's interesting. What distro and
desktop environment are you using? I'd like to reproduce this issue and
help with it.
I think generalizing the hpd_debounce_delay for both DP and HDMI would
be better. Maybe we can also enable hpd_debounce_delay by default
for monitors, that are known to have this issue, using apply_edid_quirks
> drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 +
> drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 12 +++++++++
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 6 +++++
> .../display/amdgpu_dm/amdgpu_dm_connector.c | 20 ++++++++-------
> .../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 25 ++++++++++++-------
> 5 files changed, 46 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index e2d4be3c1..c085a6cc1 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -271,6 +271,7 @@ extern int amdgpu_user_queue;
> extern int amdgpu_ptl;
>
> extern uint amdgpu_hdmi_hpd_debounce_delay_ms;
> +extern uint amdgpu_dp_hpd_debounce_delay_ms;
>
> #define AMDGPU_SG_THRESHOLD (256*1024*1024)
> #define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> index 65f2de86f..78df53b8c 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> @@ -246,6 +246,7 @@ int amdgpu_umsch_mm_fwlog;
> int amdgpu_rebar = -1; /* auto */
> int amdgpu_user_queue = -1;
> uint amdgpu_hdmi_hpd_debounce_delay_ms;
> +uint amdgpu_dp_hpd_debounce_delay_ms;
> int amdgpu_ptl = -1; /* auto */
>
> DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
> @@ -1113,6 +1114,17 @@ module_param_named(user_queue, amdgpu_user_queue, int, 0444);
> MODULE_PARM_DESC(hdmi_hpd_debounce_delay_ms, "HDMI HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
> module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms, uint, 0644);
>
> +/*
> + * DOC: dp_hpd_debounce_delay_ms (uint)
> + * DisplayPort SST HPD disconnect debounce delay in milliseconds.
> + *
> + * Used to filter short disconnect->reconnect HPD toggles some DisplayPort SST
> + * sinks generate while entering/leaving power save. Set to 0 to disable by
> + * default. eDP and MST are not affected.
> + */
> +MODULE_PARM_DESC(dp_hpd_debounce_delay_ms, "DisplayPort SST HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
> +module_param_named(dp_hpd_debounce_delay_ms, amdgpu_dp_hpd_debounce_delay_ms, uint, 0644);
> +
> /**
> * DOC: ptl (int)
> * Enable PTL feature at boot time. Possible values:
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> index 2f4a56741..abc17f547 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> @@ -64,6 +64,11 @@ enum amd_vsdb_panel_type {
> * Maximum HDMI HPD debounce delay in milliseconds
> */
> #define AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS 5000
> +
> +/*
> + * Maximum DisplayPort SST HPD debounce delay in milliseconds
> + */
> +#define AMDGPU_DM_MAX_DP_HPD_DEBOUNCE_MS 5000
> /*
> #include "include/amdgpu_dal_power_if.h"
> #include "amdgpu_dm_irq.h"
> @@ -875,6 +880,7 @@ struct amdgpu_dm_connector {
>
> /* HDMI HPD debounce support */
> unsigned int hdmi_hpd_debounce_delay_ms;
> + unsigned int dp_hpd_debounce_delay_ms;
> struct delayed_work hdmi_hpd_debounce_work;
> struct dc_sink *hdmi_prev_sink;
>
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> index 6143cdcf2..c79a8ada8 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> @@ -1747,8 +1747,8 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
> if (aconnector->mst_mgr.dev)
> drm_dp_mst_topology_mgr_destroy(&aconnector->mst_mgr);
>
> - /* Cancel and flush any pending HDMI HPD debounce work */
> - if (aconnector->hdmi_hpd_debounce_delay_ms) {
> + /* Cancel and flush any pending HPD debounce work */
> + if (aconnector->hdmi_hpd_debounce_delay_ms || aconnector->dp_hpd_debounce_delay_ms) {
> cancel_delayed_work_sync(&aconnector->hdmi_hpd_debounce_work);
> if (aconnector->hdmi_prev_sink) {
> dc_sink_release(aconnector->hdmi_prev_sink);
> @@ -2829,16 +2829,18 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
> mutex_init(&aconnector->handle_mst_msg_ready);
>
> /*
> - * If HDMI HPD debounce delay is set, use the minimum between selected
> - * value and AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS
> + * If an HPD debounce delay is set, clamp each signal's delay to its
> + * maximum. The debounce work and cached sink are shared by both the
> + * HDMI and DisplayPort SST paths.
> */
> - if (amdgpu_hdmi_hpd_debounce_delay_ms) {
> - aconnector->hdmi_hpd_debounce_delay_ms = min(amdgpu_hdmi_hpd_debounce_delay_ms,
> - AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS);
> + aconnector->hdmi_hpd_debounce_delay_ms = amdgpu_hdmi_hpd_debounce_delay_ms ?
> + min(amdgpu_hdmi_hpd_debounce_delay_ms, AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS) : 0;
> + aconnector->dp_hpd_debounce_delay_ms = amdgpu_dp_hpd_debounce_delay_ms ?
> + min(amdgpu_dp_hpd_debounce_delay_ms, AMDGPU_DM_MAX_DP_HPD_DEBOUNCE_MS) : 0;
> +
> + if (aconnector->hdmi_hpd_debounce_delay_ms || aconnector->dp_hpd_debounce_delay_ms) {
> INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, amdgpu_dm_hdmi_hpd_debounce_work);
> aconnector->hdmi_prev_sink = NULL;
> - } else {
> - aconnector->hdmi_hpd_debounce_delay_ms = 0;
> }
>
> dm->hdmi_frl_status_polling_delay_ms = 200;
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
> index 85711a2f2..2a732d19b 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
> @@ -1302,6 +1302,7 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
> struct dc *dc = aconnector->dc_link->ctx->dc;
> bool ret = false;
> bool debounce_required = false;
> + unsigned int debounce_delay_ms = 0;
>
> if (adev->dm.disable_hpd_irq)
> return;
> @@ -1325,10 +1326,16 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
> drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n");
>
> /*
> - * Check for HDMI disconnect with debounce enabled.
> + * Check for an HDMI or DisplayPort SST disconnect with debounce
> + * enabled. eDP and MST are intentionally excluded.
> */
> - debounce_required = (aconnector->hdmi_hpd_debounce_delay_ms > 0 &&
> - dc_is_hdmi_signal(aconnector->dc_link->connector_signal) &&
> + if (dc_is_hdmi_signal(aconnector->dc_link->connector_signal))
> + debounce_delay_ms = aconnector->hdmi_hpd_debounce_delay_ms;
> + else if (aconnector->dc_link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
> + aconnector->dc_link->type != dc_connection_mst_branch)
> + debounce_delay_ms = aconnector->dp_hpd_debounce_delay_ms;
> +
> + debounce_required = (debounce_delay_ms > 0 &&
> new_connection_type == dc_connection_none &&
> aconnector->dc_link->local_sink != NULL);
>
> @@ -1344,12 +1351,12 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
> drm_kms_helper_connector_hotplug_event(connector);
> } else if (debounce_required) {
> /*
> - * HDMI disconnect detected - schedule delayed work instead of
> + * Disconnect detected - schedule delayed work instead of
> * processing immediately. This allows us to coalesce spurious
> - * HDMI signals from physical unplugs.
> + * HDMI/DP HPD signals from physical unplugs.
> */
> - drm_dbg_kms(dev, "HDMI HPD: Disconnect detected, scheduling debounce work (%u ms)\n",
> - aconnector->hdmi_hpd_debounce_delay_ms);
> + drm_dbg_kms(dev, "HPD: Disconnect detected, scheduling debounce work (%u ms)\n",
> + debounce_delay_ms);
>
> /* Cache the current sink for later comparison */
> if (aconnector->hdmi_prev_sink)
> @@ -1361,8 +1368,8 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
> /* Schedule delayed detection. */
> if (mod_delayed_work(system_percpu_wq,
> &aconnector->hdmi_hpd_debounce_work,
> - msecs_to_jiffies(aconnector->hdmi_hpd_debounce_delay_ms)))
> - drm_dbg_kms(dev, "HDMI HPD: Re-scheduled debounce work\n");
> + msecs_to_jiffies(debounce_delay_ms)))
> + drm_dbg_kms(dev, "HPD: Re-scheduled debounce work\n");
>
> } else {
>
> --
> 2.54.0
>
--
Thanks,
Ivan Lipski
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH] drm/amd/display: extend HPD debounce filter to DisplayPort SST
2026-06-25 19:15 ` Ivan Lipski
@ 2026-06-25 19:45 ` Nick Haghiri
2026-06-26 8:53 ` Michel Dänzer
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: Nick Haghiri @ 2026-06-25 19:45 UTC (permalink / raw)
To: Ivan Lipski, amd-gfx, Alex Deucher
Cc: Harry Wentland, Leo Li, Ivan Lipski, Rodrigo Siqueira,
Christian König, dri-devel, linux-kernel
On 6/25/26 3:15 PM, Ivan Lipski wrote:
> I don't think I've encountered a situation when a monitor with DP can
> wake a system up from DPMS, so that's interesting. What distro and
> desktop environment are you using? I'd like to reproduce this issue
> and help with it.
openSUSE Tumbleweed, KDE Plasma 6.7 on Wayland (KWin). GPU is an RX 9070
XT (RDNA4), monitor is an MSI MPG 274U over DisplayPort SST.
What happens: when the output goes DPMS-off and the monitor drops into
deep sleep, it briefly de-asserts and re-asserts HPD. amdgpu forwards
that as a hotplug, KWin re-probes and re-enables the output, and the
panel comes right back on, so it never actually stays asleep while
connected.
I suspect the monitor's input auto-scan plays a part, but disabling
auto-scan on the monitor did not stop the HPD toggle, so it looks like
panel-side behavior on entering deep sleep rather than something the
user can turn off.
To watch it, enable drm logging:
echo 0x16 > /sys/module/drm/parameters/debug
then force DPMS-off on the DP output (kscreen-doctor --dpms off, or just
let it idle). On the stock driver you get a link_set_dpms_off quickly
followed by a spurious detect and a link_set_dpms_on. With the debounce
set, the toggle is coalesced and it stays off.
I am happy to send the monitor's EDID and a full drm.debug trace
off-list if that helps. Its EDID identifies as manufacturer MSI, product
code 0x3CF0, i.e. drm_edid_encode_panel_id('M', 'S', 'I', 0x3CF0) for
the apply_edid_quirks() switch.
> I think generalizing the hpd_debounce_delay for both DP and HDMI would
> be better.
If you're open to it, I will fold it into a single hpd_debounce_delay_ms
that applies to both HDMI and DP SST (eDP and MST still excluded), and
rename the internal hdmi_* field, work, and prev_sink to generic hpd_*
while I am there.
One question on the existing knob: hdmi_hpd_debounce_delay_ms already
shipped. Would you rather I keep it as a back-compat alias of the
generic one, or just replace it since it is only a couple of cycles old?
I will go with whichever you prefer.
> Maybe we can also enable hpd_debounce_delay by default for monitors,
> that are known to have this issue, using apply_edid_quirks
I like that. It could make it work out of the box instead of needing a
module param. I can add an apply_edid_quirks() case for the MSI MPG 274U
(panel id above) that sets a sane default, and keep the module param as
a global override. 1500 ms is what reliably works in the testing I've
done, but I can tune that down if you want a smaller default.
Thanks for the quick and helpful review.
--
Nick Haghiri
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH] drm/amd/display: extend HPD debounce filter to DisplayPort SST
2026-06-25 19:45 ` Nick Haghiri
@ 2026-06-26 8:53 ` Michel Dänzer
2026-07-09 11:38 ` Xaver Hugl
2026-07-09 1:20 ` [PATCH v2] drm/amd/display: unify HDMI/DP SST HPD debounce delay Nick Haghiri
2026-07-09 14:15 ` [PATCH v3] drm/amd/display: unify HDMI/DVI/DP " Nick Haghiri
2 siblings, 1 reply; 10+ messages in thread
From: Michel Dänzer @ 2026-06-26 8:53 UTC (permalink / raw)
To: Nick Haghiri, Ivan Lipski, amd-gfx, Alex Deucher
Cc: Harry Wentland, Leo Li, Ivan Lipski, Rodrigo Siqueira,
Christian König, dri-devel, linux-kernel, Xaver Hugl
[ Adding Xaver for awareness ]
On 6/25/26 21:45, Nick Haghiri wrote:
> On 6/25/26 3:15 PM, Ivan Lipski wrote:
>> I don't think I've encountered a situation when a monitor with DP can
>> wake a system up from DPMS, so that's interesting. What distro and
>> desktop environment are you using? I'd like to reproduce this issue
>> and help with it.
>
> openSUSE Tumbleweed, KDE Plasma 6.7 on Wayland (KWin). GPU is an RX 9070
> XT (RDNA4), monitor is an MSI MPG 274U over DisplayPort SST.
>
> What happens: when the output goes DPMS-off and the monitor drops into
> deep sleep, it briefly de-asserts and re-asserts HPD. amdgpu forwards
> that as a hotplug, KWin re-probes and re-enables the output, and the
> panel comes right back on, so it never actually stays asleep while
> connected.
FWIW, that the panel comes on and stays on might be a KWin bug. Mutter had a bug like that, which I fixed in https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4209/diffs?commit_id=ec73076e07640fc0752d9ecc66c5934726db2d7e.
P.S. For other reasons, mutter also has debouncing similar to this. If the kernel debounces as well, it'll take longer until mutter actually removes an unplugged display from its display configuration, hopefully not too bad though.
--
Earthling Michel Dänzer \ GNOME / Xwayland / Mesa developer
https://redhat.com \ Libre software enthusiast
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2] drm/amd/display: unify HDMI/DP SST HPD debounce delay
2026-06-25 19:45 ` Nick Haghiri
2026-06-26 8:53 ` Michel Dänzer
@ 2026-07-09 1:20 ` Nick Haghiri
2026-07-09 13:15 ` Alex Deucher
2026-07-09 14:15 ` [PATCH v3] drm/amd/display: unify HDMI/DVI/DP " Nick Haghiri
2 siblings, 1 reply; 10+ messages in thread
From: Nick Haghiri @ 2026-07-09 1:20 UTC (permalink / raw)
To: Ivan Lipski, amd-gfx, Alex Deucher
Cc: Harry Wentland, Leo Li, Ivan Lipski, Rodrigo Siqueira,
Christian König, Michel Dänzer, Xaver Hugl,
David Airlie, Simona Vetter, dri-devel, linux-kernel,
Nick Haghiri
Per review feedback on the DP SST debounce extension, fold
hdmi_hpd_debounce_delay_ms and dp_hpd_debounce_delay_ms into a single
hpd_debounce_delay_ms module parameter (eDP and MST still excluded),
and rename the shared connector fields, work, and cached sink from
hdmi_* to generic hpd_*.
Also add an apply_edid_quirks() case for the MSI MPG 274U
(drm_edid_encode_panel_id('M', 'S', 'I', 0x3CF0)) that enables a
1500ms default debounce delay for that panel, overridable by the
module parameter.
Signed-off-by: Nick Haghiri <nick@haghiri.net>
---
Ivan, generalized to a single hpd_debounce_delay_ms for both HDMI and
DP SST as suggested, and added the apply_edid_quirks() case for the
MSI MPG 274U (1500ms default, module param still overrides it).
Went with replacing hdmi_hpd_debounce_delay_ms rather than keeping a
back-compat alias, since it's only a couple cycles old. Shout if you'd
rather I keep the alias.
---
drivers/gpu/drm/amd/amdgpu/amdgpu.h | 3 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 26 +++-------
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 18 +++----
.../amd/display/amdgpu_dm/amdgpu_dm_connector.c | 29 ++++-------
.../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 8 +++
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 58 +++++++++++-----------
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h | 2 +-
7 files changed, 60 insertions(+), 84 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index c085a6cc1..af1748984 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -270,8 +270,7 @@ extern int amdgpu_wbrf;
extern int amdgpu_user_queue;
extern int amdgpu_ptl;
-extern uint amdgpu_hdmi_hpd_debounce_delay_ms;
-extern uint amdgpu_dp_hpd_debounce_delay_ms;
+extern uint amdgpu_hpd_debounce_delay_ms;
#define AMDGPU_SG_THRESHOLD (256*1024*1024)
#define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 78df53b8c..5ed415aa9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -245,8 +245,7 @@ int amdgpu_damage_clips = -1; /* auto */
int amdgpu_umsch_mm_fwlog;
int amdgpu_rebar = -1; /* auto */
int amdgpu_user_queue = -1;
-uint amdgpu_hdmi_hpd_debounce_delay_ms;
-uint amdgpu_dp_hpd_debounce_delay_ms;
+uint amdgpu_hpd_debounce_delay_ms;
int amdgpu_ptl = -1; /* auto */
DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
@@ -1105,25 +1104,12 @@ MODULE_PARM_DESC(user_queue, "Enable user queues (-1 = auto (default), 0 = disab
module_param_named(user_queue, amdgpu_user_queue, int, 0444);
/*
- * DOC: hdmi_hpd_debounce_delay_ms (uint)
- * HDMI HPD disconnect debounce delay in milliseconds.
- *
- * Used to filter short disconnect->reconnect HPD toggles some HDMI sinks
- * generate while entering/leaving power save. Set to 0 to disable by default.
- */
-MODULE_PARM_DESC(hdmi_hpd_debounce_delay_ms, "HDMI HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
-module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms, uint, 0644);
-
-/*
- * DOC: dp_hpd_debounce_delay_ms (uint)
- * DisplayPort SST HPD disconnect debounce delay in milliseconds.
- *
- * Used to filter short disconnect->reconnect HPD toggles some DisplayPort SST
- * sinks generate while entering/leaving power save. Set to 0 to disable by
- * default. eDP and MST are not affected.
+ * DOC: hpd_debounce_delay_ms (uint)
+ * HDMI/DP SST HPD disconnect debounce delay in milliseconds. eDP and MST
+ * are not affected. Overrides any per-panel default set via EDID quirks.
*/
-MODULE_PARM_DESC(dp_hpd_debounce_delay_ms, "DisplayPort SST HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
-module_param_named(dp_hpd_debounce_delay_ms, amdgpu_dp_hpd_debounce_delay_ms, uint, 0644);
+MODULE_PARM_DESC(hpd_debounce_delay_ms, "HDMI/DP SST HPD disconnect debounce delay in milliseconds (0 to disable (by default) or use the EDID quirk default, 1500 is common)");
+module_param_named(hpd_debounce_delay_ms, amdgpu_hpd_debounce_delay_ms, uint, 0644);
/**
* DOC: ptl (int)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index abc17f547..530e63321 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -61,14 +61,9 @@ enum amd_vsdb_panel_type {
#define AMDGPU_HDR_MULT_DEFAULT (0x100000000LL)
/*
- * Maximum HDMI HPD debounce delay in milliseconds
+ * Maximum HDMI/DP SST HPD debounce delay in milliseconds
*/
-#define AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS 5000
-
-/*
- * Maximum DisplayPort SST HPD debounce delay in milliseconds
- */
-#define AMDGPU_DM_MAX_DP_HPD_DEBOUNCE_MS 5000
+#define AMDGPU_DM_MAX_HPD_DEBOUNCE_MS 5000
/*
#include "include/amdgpu_dal_power_if.h"
#include "amdgpu_dm_irq.h"
@@ -878,11 +873,10 @@ struct amdgpu_dm_connector {
enum adaptive_sync_type as_type;
struct amdgpu_hdmi_vsdb_info vsdb_info;
- /* HDMI HPD debounce support */
- unsigned int hdmi_hpd_debounce_delay_ms;
- unsigned int dp_hpd_debounce_delay_ms;
- struct delayed_work hdmi_hpd_debounce_work;
- struct dc_sink *hdmi_prev_sink;
+ /* HDMI/DP SST HPD debounce support */
+ unsigned int hpd_debounce_delay_ms;
+ struct delayed_work hpd_debounce_work;
+ struct dc_sink *hpd_prev_sink;
/* HDMI compliance automation */
bool hdmi_comp_auto;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index c79a8ada8..798825ec1 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -1748,12 +1748,10 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
drm_dp_mst_topology_mgr_destroy(&aconnector->mst_mgr);
/* Cancel and flush any pending HPD debounce work */
- if (aconnector->hdmi_hpd_debounce_delay_ms || aconnector->dp_hpd_debounce_delay_ms) {
- cancel_delayed_work_sync(&aconnector->hdmi_hpd_debounce_work);
- if (aconnector->hdmi_prev_sink) {
- dc_sink_release(aconnector->hdmi_prev_sink);
- aconnector->hdmi_prev_sink = NULL;
- }
+ cancel_delayed_work_sync(&aconnector->hpd_debounce_work);
+ if (aconnector->hpd_prev_sink) {
+ dc_sink_release(aconnector->hpd_prev_sink);
+ aconnector->hpd_prev_sink = NULL;
}
if (aconnector->bl_idx != -1) {
@@ -2828,20 +2826,11 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
mutex_init(&aconnector->hpd_lock);
mutex_init(&aconnector->handle_mst_msg_ready);
- /*
- * If an HPD debounce delay is set, clamp each signal's delay to its
- * maximum. The debounce work and cached sink are shared by both the
- * HDMI and DisplayPort SST paths.
- */
- aconnector->hdmi_hpd_debounce_delay_ms = amdgpu_hdmi_hpd_debounce_delay_ms ?
- min(amdgpu_hdmi_hpd_debounce_delay_ms, AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS) : 0;
- aconnector->dp_hpd_debounce_delay_ms = amdgpu_dp_hpd_debounce_delay_ms ?
- min(amdgpu_dp_hpd_debounce_delay_ms, AMDGPU_DM_MAX_DP_HPD_DEBOUNCE_MS) : 0;
-
- if (aconnector->hdmi_hpd_debounce_delay_ms || aconnector->dp_hpd_debounce_delay_ms) {
- INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, amdgpu_dm_hdmi_hpd_debounce_work);
- aconnector->hdmi_prev_sink = NULL;
- }
+ /* May be overridden later by an EDID quirk in apply_edid_quirks() */
+ aconnector->hpd_debounce_delay_ms = amdgpu_hpd_debounce_delay_ms ?
+ min(amdgpu_hpd_debounce_delay_ms, AMDGPU_DM_MAX_HPD_DEBOUNCE_MS) : 0;
+ aconnector->hpd_prev_sink = NULL;
+ INIT_DELAYED_WORK(&aconnector->hpd_debounce_work, amdgpu_dm_hpd_debounce_work);
dm->hdmi_frl_status_polling_delay_ms = 200;
INIT_DELAYED_WORK(&dm->hdmi_frl_status_polling_work, hdmi_frl_status_polling_work);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index 9c4e0a4e2..71c897416 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -137,6 +137,14 @@ static void apply_edid_quirks(struct dc_link *link, struct edid *edid,
drm_dbg_driver(dev, "Skip PHY SSC reduction on panel id %X\n", panel_id);
link->wa_flags.skip_phy_ssc_reduction = true;
break;
+ /* Workaround for monitors that toggle HPD on entering deep sleep */
+ case drm_edid_encode_panel_id('M', 'S', 'I', 0x3CF0):
+ if (!aconnector->hpd_debounce_delay_ms) {
+ drm_dbg_driver(dev, "Enabling HPD debounce on panel id %X\n", panel_id);
+ aconnector->hpd_debounce_delay_ms =
+ min(1500U, AMDGPU_DM_MAX_HPD_DEBOUNCE_MS);
+ }
+ break;
default:
return;
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
index 2a732d19b..e423dbe9b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
@@ -1217,13 +1217,13 @@ EXPORT_IF_KUNIT(are_sinks_equal);
/**
- * DOC: amdgpu_dm_hdmi_hpd_debounce_work
+ * DOC: amdgpu_dm_hpd_debounce_work
*
- * HDMI HPD debounce delay in milliseconds. When an HDMI display toggles HPD
+ * HDMI/DP SST HPD debounce delay in milliseconds. When a display toggles HPD
* (such as during power save transitions), this delay determines how long to
* wait before processing the HPD event. This allows distinguishing between a
- * physical unplug (>hdmi_hpd_debounce_delay)
- * and a spontaneous RX HPD toggle (<hdmi_hpd_debounce_delay).
+ * physical unplug (>hpd_debounce_delay)
+ * and a spontaneous RX HPD toggle (<hpd_debounce_delay).
*
* If the toggle is less than this delay, the driver compares sink capabilities
* and permits a hotplug event if they changed.
@@ -1231,11 +1231,11 @@ EXPORT_IF_KUNIT(are_sinks_equal);
* The default value of 1500ms was chosen based on experimental testing with
* various monitors that exhibit spontaneous HPD toggling behavior.
*/
-void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work)
+void amdgpu_dm_hpd_debounce_work(struct work_struct *work)
{
struct amdgpu_dm_connector *aconnector =
container_of(to_delayed_work(work), struct amdgpu_dm_connector,
- hdmi_hpd_debounce_work);
+ hpd_debounce_work);
struct drm_connector *connector = &aconnector->base;
struct drm_device *dev = connector->dev;
struct amdgpu_device *adev = drm_to_adev(dev);
@@ -1259,11 +1259,12 @@ void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work)
/* Apply workaround delay for certain panels */
amdgpu_dm_apply_delay_after_dpcd_poweroff(adev, aconnector->dc_sink);
/* Compare sinks to determine if this was a spontaneous HPD toggle */
- if (are_sinks_equal(aconnector->dc_link->local_sink, aconnector->hdmi_prev_sink)) {
+ if (are_sinks_equal(aconnector->dc_link->local_sink, aconnector->hpd_prev_sink)) {
/*
- * Sinks match - this was a spontaneous HDMI HPD toggle.
+ * Sinks match - this was a spontaneous HPD toggle.
*/
- drm_dbg_kms(dev, "HDMI HPD: Sink unchanged after debounce, internal re-enable\n");
+ drm_dbg_kms(dev,
+ "HPD: Sink unchanged after debounce, internal re-enable\n");
fake_reconnect = true;
}
@@ -1280,9 +1281,9 @@ void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work)
}
/* Release the cached sink reference */
- if (aconnector->hdmi_prev_sink) {
- dc_sink_release(aconnector->hdmi_prev_sink);
- aconnector->hdmi_prev_sink = NULL;
+ if (aconnector->hpd_prev_sink) {
+ dc_sink_release(aconnector->hpd_prev_sink);
+ aconnector->hpd_prev_sink = NULL;
}
scoped_guard(mutex, &adev->dm.dc_lock) {
@@ -1302,7 +1303,7 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
struct dc *dc = aconnector->dc_link->ctx->dc;
bool ret = false;
bool debounce_required = false;
- unsigned int debounce_delay_ms = 0;
+ bool debounce_eligible;
if (adev->dm.disable_hpd_irq)
return;
@@ -1329,13 +1330,12 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
* Check for an HDMI or DisplayPort SST disconnect with debounce
* enabled. eDP and MST are intentionally excluded.
*/
- if (dc_is_hdmi_signal(aconnector->dc_link->connector_signal))
- debounce_delay_ms = aconnector->hdmi_hpd_debounce_delay_ms;
- else if (aconnector->dc_link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
- aconnector->dc_link->type != dc_connection_mst_branch)
- debounce_delay_ms = aconnector->dp_hpd_debounce_delay_ms;
+ debounce_eligible = dc_is_hdmi_signal(aconnector->dc_link->connector_signal) ||
+ (aconnector->dc_link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
+ aconnector->dc_link->type != dc_connection_mst_branch);
- debounce_required = (debounce_delay_ms > 0 &&
+ debounce_required = (debounce_eligible &&
+ aconnector->hpd_debounce_delay_ms > 0 &&
new_connection_type == dc_connection_none &&
aconnector->dc_link->local_sink != NULL);
@@ -1356,25 +1356,25 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
* HDMI/DP HPD signals from physical unplugs.
*/
drm_dbg_kms(dev, "HPD: Disconnect detected, scheduling debounce work (%u ms)\n",
- debounce_delay_ms);
+ aconnector->hpd_debounce_delay_ms);
/* Cache the current sink for later comparison */
- if (aconnector->hdmi_prev_sink)
- dc_sink_release(aconnector->hdmi_prev_sink);
- aconnector->hdmi_prev_sink = aconnector->dc_link->local_sink;
- if (aconnector->hdmi_prev_sink)
- dc_sink_retain(aconnector->hdmi_prev_sink);
+ if (aconnector->hpd_prev_sink)
+ dc_sink_release(aconnector->hpd_prev_sink);
+ aconnector->hpd_prev_sink = aconnector->dc_link->local_sink;
+ if (aconnector->hpd_prev_sink)
+ dc_sink_retain(aconnector->hpd_prev_sink);
/* Schedule delayed detection. */
if (mod_delayed_work(system_percpu_wq,
- &aconnector->hdmi_hpd_debounce_work,
- msecs_to_jiffies(debounce_delay_ms)))
+ &aconnector->hpd_debounce_work,
+ msecs_to_jiffies(aconnector->hpd_debounce_delay_ms)))
drm_dbg_kms(dev, "HPD: Re-scheduled debounce work\n");
} else {
- /* If the aconnector->hdmi_hpd_debounce_work is scheduled, exit early */
- if (delayed_work_pending(&aconnector->hdmi_hpd_debounce_work))
+ /* If the aconnector->hpd_debounce_work is scheduled, exit early */
+ if (delayed_work_pending(&aconnector->hpd_debounce_work))
return;
scoped_guard(mutex, &adev->dm.dc_lock) {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
index bccb5d354..66fb82961 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
@@ -113,7 +113,7 @@ void amdgpu_dm_irq_resume_late(struct amdgpu_device *adev);
struct hpd_rx_irq_offload_work_queue *amdgpu_dm_hpd_rx_irq_create_workqueue(struct amdgpu_device *adev);
void amdgpu_dm_hpd_rx_irq_work_suspend(struct amdgpu_display_manager *dm);
int amdgpu_dm_register_hpd_handlers(struct amdgpu_device *adev);
-void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work);
+void amdgpu_dm_hpd_debounce_work(struct work_struct *work);
/* IRQ handlers */
struct amdgpu_crtc *amdgpu_dm_get_crtc_by_otg_inst(struct amdgpu_device *adev,
---
base-commit: c92b5b607c1c8ab786fccf03d62352b82f6539ae
change-id: 20260708-hpd-debounce-unify-896ad367bf02
Best regards,
--
Nick Haghiri <nick@haghiri.net>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH] drm/amd/display: extend HPD debounce filter to DisplayPort SST
2026-06-26 8:53 ` Michel Dänzer
@ 2026-07-09 11:38 ` Xaver Hugl
0 siblings, 0 replies; 10+ messages in thread
From: Xaver Hugl @ 2026-07-09 11:38 UTC (permalink / raw)
To: Michel Dänzer
Cc: Nick Haghiri, Ivan Lipski, amd-gfx, Alex Deucher, Harry Wentland,
Leo Li, Ivan Lipski, Rodrigo Siqueira, Christian König,
dri-devel, linux-kernel
Am Fr., 26. Juni 2026 um 10:53 Uhr schrieb Michel Dänzer
<michel.daenzer@mailbox.org>:
>
>
> [ Adding Xaver for awareness ]
>
> On 6/25/26 21:45, Nick Haghiri wrote:
> > On 6/25/26 3:15 PM, Ivan Lipski wrote:
> >> I don't think I've encountered a situation when a monitor with DP can
> >> wake a system up from DPMS, so that's interesting. What distro and
> >> desktop environment are you using? I'd like to reproduce this issue
> >> and help with it.
> >
> > openSUSE Tumbleweed, KDE Plasma 6.7 on Wayland (KWin). GPU is an RX 9070
> > XT (RDNA4), monitor is an MSI MPG 274U over DisplayPort SST.
> >
> > What happens: when the output goes DPMS-off and the monitor drops into
> > deep sleep, it briefly de-asserts and re-asserts HPD. amdgpu forwards
> > that as a hotplug, KWin re-probes and re-enables the output, and the
> > panel comes right back on, so it never actually stays asleep while
> > connected.
>
> FWIW, that the panel comes on and stays on might be a KWin bug. Mutter had a bug like that, which I fixed in https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4209/diffs?commit_id=ec73076e07640fc0752d9ecc66c5934726db2d7e.
Yeah, I did find (and fix) a different problem with our workaround
recently, where KWin-internal pointer warps in response to the
"hotunplug" were wrongly counted as user activity in some cases.
Either way, kernel-side debouncing is very much appreciated.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2] drm/amd/display: unify HDMI/DP SST HPD debounce delay
2026-07-09 1:20 ` [PATCH v2] drm/amd/display: unify HDMI/DP SST HPD debounce delay Nick Haghiri
@ 2026-07-09 13:15 ` Alex Deucher
0 siblings, 0 replies; 10+ messages in thread
From: Alex Deucher @ 2026-07-09 13:15 UTC (permalink / raw)
To: Nick Haghiri
Cc: Ivan Lipski, amd-gfx, Alex Deucher, Harry Wentland, Leo Li,
Ivan Lipski, Rodrigo Siqueira, Christian König,
Michel Dänzer, Xaver Hugl, David Airlie, Simona Vetter,
dri-devel, linux-kernel
On Thu, Jul 9, 2026 at 3:34 AM Nick Haghiri <nick@haghiri.net> wrote:
>
> Per review feedback on the DP SST debounce extension, fold
> hdmi_hpd_debounce_delay_ms and dp_hpd_debounce_delay_ms into a single
> hpd_debounce_delay_ms module parameter (eDP and MST still excluded),
> and rename the shared connector fields, work, and cached sink from
> hdmi_* to generic hpd_*.
>
> Also add an apply_edid_quirks() case for the MSI MPG 274U
> (drm_edid_encode_panel_id('M', 'S', 'I', 0x3CF0)) that enables a
> 1500ms default debounce delay for that panel, overridable by the
> module parameter.
>
> Signed-off-by: Nick Haghiri <nick@haghiri.net>
> ---
> Ivan, generalized to a single hpd_debounce_delay_ms for both HDMI and
> DP SST as suggested, and added the apply_edid_quirks() case for the
> MSI MPG 274U (1500ms default, module param still overrides it).
Can you extend this to DVI as well?
Alex
>
> Went with replacing hdmi_hpd_debounce_delay_ms rather than keeping a
> back-compat alias, since it's only a couple cycles old. Shout if you'd
> rather I keep the alias.
> ---
> drivers/gpu/drm/amd/amdgpu/amdgpu.h | 3 +-
> drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 26 +++-------
> drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 18 +++----
> .../amd/display/amdgpu_dm/amdgpu_dm_connector.c | 29 ++++-------
> .../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 8 +++
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 58 +++++++++++-----------
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h | 2 +-
> 7 files changed, 60 insertions(+), 84 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index c085a6cc1..af1748984 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -270,8 +270,7 @@ extern int amdgpu_wbrf;
> extern int amdgpu_user_queue;
> extern int amdgpu_ptl;
>
> -extern uint amdgpu_hdmi_hpd_debounce_delay_ms;
> -extern uint amdgpu_dp_hpd_debounce_delay_ms;
> +extern uint amdgpu_hpd_debounce_delay_ms;
>
> #define AMDGPU_SG_THRESHOLD (256*1024*1024)
> #define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> index 78df53b8c..5ed415aa9 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> @@ -245,8 +245,7 @@ int amdgpu_damage_clips = -1; /* auto */
> int amdgpu_umsch_mm_fwlog;
> int amdgpu_rebar = -1; /* auto */
> int amdgpu_user_queue = -1;
> -uint amdgpu_hdmi_hpd_debounce_delay_ms;
> -uint amdgpu_dp_hpd_debounce_delay_ms;
> +uint amdgpu_hpd_debounce_delay_ms;
> int amdgpu_ptl = -1; /* auto */
>
> DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
> @@ -1105,25 +1104,12 @@ MODULE_PARM_DESC(user_queue, "Enable user queues (-1 = auto (default), 0 = disab
> module_param_named(user_queue, amdgpu_user_queue, int, 0444);
>
> /*
> - * DOC: hdmi_hpd_debounce_delay_ms (uint)
> - * HDMI HPD disconnect debounce delay in milliseconds.
> - *
> - * Used to filter short disconnect->reconnect HPD toggles some HDMI sinks
> - * generate while entering/leaving power save. Set to 0 to disable by default.
> - */
> -MODULE_PARM_DESC(hdmi_hpd_debounce_delay_ms, "HDMI HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
> -module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms, uint, 0644);
> -
> -/*
> - * DOC: dp_hpd_debounce_delay_ms (uint)
> - * DisplayPort SST HPD disconnect debounce delay in milliseconds.
> - *
> - * Used to filter short disconnect->reconnect HPD toggles some DisplayPort SST
> - * sinks generate while entering/leaving power save. Set to 0 to disable by
> - * default. eDP and MST are not affected.
> + * DOC: hpd_debounce_delay_ms (uint)
> + * HDMI/DP SST HPD disconnect debounce delay in milliseconds. eDP and MST
> + * are not affected. Overrides any per-panel default set via EDID quirks.
> */
> -MODULE_PARM_DESC(dp_hpd_debounce_delay_ms, "DisplayPort SST HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
> -module_param_named(dp_hpd_debounce_delay_ms, amdgpu_dp_hpd_debounce_delay_ms, uint, 0644);
> +MODULE_PARM_DESC(hpd_debounce_delay_ms, "HDMI/DP SST HPD disconnect debounce delay in milliseconds (0 to disable (by default) or use the EDID quirk default, 1500 is common)");
> +module_param_named(hpd_debounce_delay_ms, amdgpu_hpd_debounce_delay_ms, uint, 0644);
>
> /**
> * DOC: ptl (int)
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> index abc17f547..530e63321 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> @@ -61,14 +61,9 @@ enum amd_vsdb_panel_type {
> #define AMDGPU_HDR_MULT_DEFAULT (0x100000000LL)
>
> /*
> - * Maximum HDMI HPD debounce delay in milliseconds
> + * Maximum HDMI/DP SST HPD debounce delay in milliseconds
> */
> -#define AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS 5000
> -
> -/*
> - * Maximum DisplayPort SST HPD debounce delay in milliseconds
> - */
> -#define AMDGPU_DM_MAX_DP_HPD_DEBOUNCE_MS 5000
> +#define AMDGPU_DM_MAX_HPD_DEBOUNCE_MS 5000
> /*
> #include "include/amdgpu_dal_power_if.h"
> #include "amdgpu_dm_irq.h"
> @@ -878,11 +873,10 @@ struct amdgpu_dm_connector {
> enum adaptive_sync_type as_type;
> struct amdgpu_hdmi_vsdb_info vsdb_info;
>
> - /* HDMI HPD debounce support */
> - unsigned int hdmi_hpd_debounce_delay_ms;
> - unsigned int dp_hpd_debounce_delay_ms;
> - struct delayed_work hdmi_hpd_debounce_work;
> - struct dc_sink *hdmi_prev_sink;
> + /* HDMI/DP SST HPD debounce support */
> + unsigned int hpd_debounce_delay_ms;
> + struct delayed_work hpd_debounce_work;
> + struct dc_sink *hpd_prev_sink;
>
> /* HDMI compliance automation */
> bool hdmi_comp_auto;
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> index c79a8ada8..798825ec1 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> @@ -1748,12 +1748,10 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
> drm_dp_mst_topology_mgr_destroy(&aconnector->mst_mgr);
>
> /* Cancel and flush any pending HPD debounce work */
> - if (aconnector->hdmi_hpd_debounce_delay_ms || aconnector->dp_hpd_debounce_delay_ms) {
> - cancel_delayed_work_sync(&aconnector->hdmi_hpd_debounce_work);
> - if (aconnector->hdmi_prev_sink) {
> - dc_sink_release(aconnector->hdmi_prev_sink);
> - aconnector->hdmi_prev_sink = NULL;
> - }
> + cancel_delayed_work_sync(&aconnector->hpd_debounce_work);
> + if (aconnector->hpd_prev_sink) {
> + dc_sink_release(aconnector->hpd_prev_sink);
> + aconnector->hpd_prev_sink = NULL;
> }
>
> if (aconnector->bl_idx != -1) {
> @@ -2828,20 +2826,11 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
> mutex_init(&aconnector->hpd_lock);
> mutex_init(&aconnector->handle_mst_msg_ready);
>
> - /*
> - * If an HPD debounce delay is set, clamp each signal's delay to its
> - * maximum. The debounce work and cached sink are shared by both the
> - * HDMI and DisplayPort SST paths.
> - */
> - aconnector->hdmi_hpd_debounce_delay_ms = amdgpu_hdmi_hpd_debounce_delay_ms ?
> - min(amdgpu_hdmi_hpd_debounce_delay_ms, AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS) : 0;
> - aconnector->dp_hpd_debounce_delay_ms = amdgpu_dp_hpd_debounce_delay_ms ?
> - min(amdgpu_dp_hpd_debounce_delay_ms, AMDGPU_DM_MAX_DP_HPD_DEBOUNCE_MS) : 0;
> -
> - if (aconnector->hdmi_hpd_debounce_delay_ms || aconnector->dp_hpd_debounce_delay_ms) {
> - INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, amdgpu_dm_hdmi_hpd_debounce_work);
> - aconnector->hdmi_prev_sink = NULL;
> - }
> + /* May be overridden later by an EDID quirk in apply_edid_quirks() */
> + aconnector->hpd_debounce_delay_ms = amdgpu_hpd_debounce_delay_ms ?
> + min(amdgpu_hpd_debounce_delay_ms, AMDGPU_DM_MAX_HPD_DEBOUNCE_MS) : 0;
> + aconnector->hpd_prev_sink = NULL;
> + INIT_DELAYED_WORK(&aconnector->hpd_debounce_work, amdgpu_dm_hpd_debounce_work);
>
> dm->hdmi_frl_status_polling_delay_ms = 200;
> INIT_DELAYED_WORK(&dm->hdmi_frl_status_polling_work, hdmi_frl_status_polling_work);
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> index 9c4e0a4e2..71c897416 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> @@ -137,6 +137,14 @@ static void apply_edid_quirks(struct dc_link *link, struct edid *edid,
> drm_dbg_driver(dev, "Skip PHY SSC reduction on panel id %X\n", panel_id);
> link->wa_flags.skip_phy_ssc_reduction = true;
> break;
> + /* Workaround for monitors that toggle HPD on entering deep sleep */
> + case drm_edid_encode_panel_id('M', 'S', 'I', 0x3CF0):
> + if (!aconnector->hpd_debounce_delay_ms) {
> + drm_dbg_driver(dev, "Enabling HPD debounce on panel id %X\n", panel_id);
> + aconnector->hpd_debounce_delay_ms =
> + min(1500U, AMDGPU_DM_MAX_HPD_DEBOUNCE_MS);
> + }
> + break;
> default:
> return;
> }
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
> index 2a732d19b..e423dbe9b 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
> @@ -1217,13 +1217,13 @@ EXPORT_IF_KUNIT(are_sinks_equal);
>
>
> /**
> - * DOC: amdgpu_dm_hdmi_hpd_debounce_work
> + * DOC: amdgpu_dm_hpd_debounce_work
> *
> - * HDMI HPD debounce delay in milliseconds. When an HDMI display toggles HPD
> + * HDMI/DP SST HPD debounce delay in milliseconds. When a display toggles HPD
> * (such as during power save transitions), this delay determines how long to
> * wait before processing the HPD event. This allows distinguishing between a
> - * physical unplug (>hdmi_hpd_debounce_delay)
> - * and a spontaneous RX HPD toggle (<hdmi_hpd_debounce_delay).
> + * physical unplug (>hpd_debounce_delay)
> + * and a spontaneous RX HPD toggle (<hpd_debounce_delay).
> *
> * If the toggle is less than this delay, the driver compares sink capabilities
> * and permits a hotplug event if they changed.
> @@ -1231,11 +1231,11 @@ EXPORT_IF_KUNIT(are_sinks_equal);
> * The default value of 1500ms was chosen based on experimental testing with
> * various monitors that exhibit spontaneous HPD toggling behavior.
> */
> -void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work)
> +void amdgpu_dm_hpd_debounce_work(struct work_struct *work)
> {
> struct amdgpu_dm_connector *aconnector =
> container_of(to_delayed_work(work), struct amdgpu_dm_connector,
> - hdmi_hpd_debounce_work);
> + hpd_debounce_work);
> struct drm_connector *connector = &aconnector->base;
> struct drm_device *dev = connector->dev;
> struct amdgpu_device *adev = drm_to_adev(dev);
> @@ -1259,11 +1259,12 @@ void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work)
> /* Apply workaround delay for certain panels */
> amdgpu_dm_apply_delay_after_dpcd_poweroff(adev, aconnector->dc_sink);
> /* Compare sinks to determine if this was a spontaneous HPD toggle */
> - if (are_sinks_equal(aconnector->dc_link->local_sink, aconnector->hdmi_prev_sink)) {
> + if (are_sinks_equal(aconnector->dc_link->local_sink, aconnector->hpd_prev_sink)) {
> /*
> - * Sinks match - this was a spontaneous HDMI HPD toggle.
> + * Sinks match - this was a spontaneous HPD toggle.
> */
> - drm_dbg_kms(dev, "HDMI HPD: Sink unchanged after debounce, internal re-enable\n");
> + drm_dbg_kms(dev,
> + "HPD: Sink unchanged after debounce, internal re-enable\n");
> fake_reconnect = true;
> }
>
> @@ -1280,9 +1281,9 @@ void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work)
> }
>
> /* Release the cached sink reference */
> - if (aconnector->hdmi_prev_sink) {
> - dc_sink_release(aconnector->hdmi_prev_sink);
> - aconnector->hdmi_prev_sink = NULL;
> + if (aconnector->hpd_prev_sink) {
> + dc_sink_release(aconnector->hpd_prev_sink);
> + aconnector->hpd_prev_sink = NULL;
> }
>
> scoped_guard(mutex, &adev->dm.dc_lock) {
> @@ -1302,7 +1303,7 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
> struct dc *dc = aconnector->dc_link->ctx->dc;
> bool ret = false;
> bool debounce_required = false;
> - unsigned int debounce_delay_ms = 0;
> + bool debounce_eligible;
>
> if (adev->dm.disable_hpd_irq)
> return;
> @@ -1329,13 +1330,12 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
> * Check for an HDMI or DisplayPort SST disconnect with debounce
> * enabled. eDP and MST are intentionally excluded.
> */
> - if (dc_is_hdmi_signal(aconnector->dc_link->connector_signal))
> - debounce_delay_ms = aconnector->hdmi_hpd_debounce_delay_ms;
> - else if (aconnector->dc_link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
> - aconnector->dc_link->type != dc_connection_mst_branch)
> - debounce_delay_ms = aconnector->dp_hpd_debounce_delay_ms;
> + debounce_eligible = dc_is_hdmi_signal(aconnector->dc_link->connector_signal) ||
> + (aconnector->dc_link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
> + aconnector->dc_link->type != dc_connection_mst_branch);
>
> - debounce_required = (debounce_delay_ms > 0 &&
> + debounce_required = (debounce_eligible &&
> + aconnector->hpd_debounce_delay_ms > 0 &&
> new_connection_type == dc_connection_none &&
> aconnector->dc_link->local_sink != NULL);
>
> @@ -1356,25 +1356,25 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
> * HDMI/DP HPD signals from physical unplugs.
> */
> drm_dbg_kms(dev, "HPD: Disconnect detected, scheduling debounce work (%u ms)\n",
> - debounce_delay_ms);
> + aconnector->hpd_debounce_delay_ms);
>
> /* Cache the current sink for later comparison */
> - if (aconnector->hdmi_prev_sink)
> - dc_sink_release(aconnector->hdmi_prev_sink);
> - aconnector->hdmi_prev_sink = aconnector->dc_link->local_sink;
> - if (aconnector->hdmi_prev_sink)
> - dc_sink_retain(aconnector->hdmi_prev_sink);
> + if (aconnector->hpd_prev_sink)
> + dc_sink_release(aconnector->hpd_prev_sink);
> + aconnector->hpd_prev_sink = aconnector->dc_link->local_sink;
> + if (aconnector->hpd_prev_sink)
> + dc_sink_retain(aconnector->hpd_prev_sink);
>
> /* Schedule delayed detection. */
> if (mod_delayed_work(system_percpu_wq,
> - &aconnector->hdmi_hpd_debounce_work,
> - msecs_to_jiffies(debounce_delay_ms)))
> + &aconnector->hpd_debounce_work,
> + msecs_to_jiffies(aconnector->hpd_debounce_delay_ms)))
> drm_dbg_kms(dev, "HPD: Re-scheduled debounce work\n");
>
> } else {
>
> - /* If the aconnector->hdmi_hpd_debounce_work is scheduled, exit early */
> - if (delayed_work_pending(&aconnector->hdmi_hpd_debounce_work))
> + /* If the aconnector->hpd_debounce_work is scheduled, exit early */
> + if (delayed_work_pending(&aconnector->hpd_debounce_work))
> return;
>
> scoped_guard(mutex, &adev->dm.dc_lock) {
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
> index bccb5d354..66fb82961 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
> @@ -113,7 +113,7 @@ void amdgpu_dm_irq_resume_late(struct amdgpu_device *adev);
> struct hpd_rx_irq_offload_work_queue *amdgpu_dm_hpd_rx_irq_create_workqueue(struct amdgpu_device *adev);
> void amdgpu_dm_hpd_rx_irq_work_suspend(struct amdgpu_display_manager *dm);
> int amdgpu_dm_register_hpd_handlers(struct amdgpu_device *adev);
> -void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work);
> +void amdgpu_dm_hpd_debounce_work(struct work_struct *work);
>
> /* IRQ handlers */
> struct amdgpu_crtc *amdgpu_dm_get_crtc_by_otg_inst(struct amdgpu_device *adev,
>
> ---
> base-commit: c92b5b607c1c8ab786fccf03d62352b82f6539ae
> change-id: 20260708-hpd-debounce-unify-896ad367bf02
>
> Best regards,
> --
> Nick Haghiri <nick@haghiri.net>
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v3] drm/amd/display: unify HDMI/DVI/DP SST HPD debounce delay
2026-06-25 19:45 ` Nick Haghiri
2026-06-26 8:53 ` Michel Dänzer
2026-07-09 1:20 ` [PATCH v2] drm/amd/display: unify HDMI/DP SST HPD debounce delay Nick Haghiri
@ 2026-07-09 14:15 ` Nick Haghiri
2026-07-09 17:30 ` Ivan Lipski
2 siblings, 1 reply; 10+ messages in thread
From: Nick Haghiri @ 2026-07-09 14:15 UTC (permalink / raw)
To: Ivan Lipski, amd-gfx, Alex Deucher
Cc: Harry Wentland, Leo Li, Ivan Lipski, Rodrigo Siqueira,
Christian König, Michel Dänzer, Xaver Hugl,
David Airlie, Simona Vetter, dri-devel, linux-kernel,
Nick Haghiri
Per review feedback on the DP SST debounce extension, fold
hdmi_hpd_debounce_delay_ms and dp_hpd_debounce_delay_ms into a single
hpd_debounce_delay_ms module parameter (eDP and MST still excluded),
and rename the shared connector fields, work, and cached sink from
hdmi_* to generic hpd_*. Also extend eligibility to DVI, which shares
the same HPD toggle behavior and has no MST/eDP variants to exclude.
Also add an apply_edid_quirks() case for the MSI MPG 274U
(drm_edid_encode_panel_id('M', 'S', 'I', 0x3CF0)) that enables a
1500ms default debounce delay for that panel, overridable by the
module parameter.
Signed-off-by: Nick Haghiri <nick@haghiri.net>
---
Ivan, generalized to a single hpd_debounce_delay_ms for both HDMI and
DP SST as suggested, and added the apply_edid_quirks() case for the
MSI MPG 274U (1500ms default, module param still overrides it).
Went with replacing hdmi_hpd_debounce_delay_ms rather than keeping a
back-compat alias, since it's only a couple cycles old. Shout if you'd
rather I keep the alias.
Alex, done. debounce_eligible now also checks dc_is_dvi_signal(),
reusing the same hpd_debounce_delay_ms param. Updated text and
comments to reflect scope now being HDMI, DVI, and DP.
---
Changes in v3:
- Extend HPD debounce eligibility to DVI (dc_is_dvi_signal()), per Alex
- Update comments/docs to reflect HDMI/DVI/DP SST scope
- Link to v2: https://patch.msgid.link/20260708-hpd-debounce-unify-v2-1-d214832551b3@haghiri.net
---
drivers/gpu/drm/amd/amdgpu/amdgpu.h | 3 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 26 ++-------
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 18 ++----
.../amd/display/amdgpu_dm/amdgpu_dm_connector.c | 29 +++-------
.../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 8 +++
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 65 +++++++++++-----------
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h | 2 +-
7 files changed, 64 insertions(+), 87 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index c085a6cc1..af1748984 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -270,8 +270,7 @@ extern int amdgpu_wbrf;
extern int amdgpu_user_queue;
extern int amdgpu_ptl;
-extern uint amdgpu_hdmi_hpd_debounce_delay_ms;
-extern uint amdgpu_dp_hpd_debounce_delay_ms;
+extern uint amdgpu_hpd_debounce_delay_ms;
#define AMDGPU_SG_THRESHOLD (256*1024*1024)
#define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 78df53b8c..a82d807f7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -245,8 +245,7 @@ int amdgpu_damage_clips = -1; /* auto */
int amdgpu_umsch_mm_fwlog;
int amdgpu_rebar = -1; /* auto */
int amdgpu_user_queue = -1;
-uint amdgpu_hdmi_hpd_debounce_delay_ms;
-uint amdgpu_dp_hpd_debounce_delay_ms;
+uint amdgpu_hpd_debounce_delay_ms;
int amdgpu_ptl = -1; /* auto */
DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
@@ -1105,25 +1104,12 @@ MODULE_PARM_DESC(user_queue, "Enable user queues (-1 = auto (default), 0 = disab
module_param_named(user_queue, amdgpu_user_queue, int, 0444);
/*
- * DOC: hdmi_hpd_debounce_delay_ms (uint)
- * HDMI HPD disconnect debounce delay in milliseconds.
- *
- * Used to filter short disconnect->reconnect HPD toggles some HDMI sinks
- * generate while entering/leaving power save. Set to 0 to disable by default.
- */
-MODULE_PARM_DESC(hdmi_hpd_debounce_delay_ms, "HDMI HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
-module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms, uint, 0644);
-
-/*
- * DOC: dp_hpd_debounce_delay_ms (uint)
- * DisplayPort SST HPD disconnect debounce delay in milliseconds.
- *
- * Used to filter short disconnect->reconnect HPD toggles some DisplayPort SST
- * sinks generate while entering/leaving power save. Set to 0 to disable by
- * default. eDP and MST are not affected.
+ * DOC: hpd_debounce_delay_ms (uint)
+ * HDMI/DVI/DP SST HPD disconnect debounce delay in milliseconds. eDP and MST
+ * are not affected. Overrides any per-panel default set via EDID quirks.
*/
-MODULE_PARM_DESC(dp_hpd_debounce_delay_ms, "DisplayPort SST HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
-module_param_named(dp_hpd_debounce_delay_ms, amdgpu_dp_hpd_debounce_delay_ms, uint, 0644);
+MODULE_PARM_DESC(hpd_debounce_delay_ms, "HDMI/DVI/DP SST HPD disconnect debounce delay in milliseconds (0 to disable (by default) or use the EDID quirk default, 1500 is common)");
+module_param_named(hpd_debounce_delay_ms, amdgpu_hpd_debounce_delay_ms, uint, 0644);
/**
* DOC: ptl (int)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index abc17f547..5235a5ef6 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -61,14 +61,9 @@ enum amd_vsdb_panel_type {
#define AMDGPU_HDR_MULT_DEFAULT (0x100000000LL)
/*
- * Maximum HDMI HPD debounce delay in milliseconds
+ * Maximum HDMI/DVI/DP SST HPD debounce delay in milliseconds
*/
-#define AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS 5000
-
-/*
- * Maximum DisplayPort SST HPD debounce delay in milliseconds
- */
-#define AMDGPU_DM_MAX_DP_HPD_DEBOUNCE_MS 5000
+#define AMDGPU_DM_MAX_HPD_DEBOUNCE_MS 5000
/*
#include "include/amdgpu_dal_power_if.h"
#include "amdgpu_dm_irq.h"
@@ -878,11 +873,10 @@ struct amdgpu_dm_connector {
enum adaptive_sync_type as_type;
struct amdgpu_hdmi_vsdb_info vsdb_info;
- /* HDMI HPD debounce support */
- unsigned int hdmi_hpd_debounce_delay_ms;
- unsigned int dp_hpd_debounce_delay_ms;
- struct delayed_work hdmi_hpd_debounce_work;
- struct dc_sink *hdmi_prev_sink;
+ /* HDMI/DVI/DP SST HPD debounce support */
+ unsigned int hpd_debounce_delay_ms;
+ struct delayed_work hpd_debounce_work;
+ struct dc_sink *hpd_prev_sink;
/* HDMI compliance automation */
bool hdmi_comp_auto;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index c79a8ada8..798825ec1 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -1748,12 +1748,10 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
drm_dp_mst_topology_mgr_destroy(&aconnector->mst_mgr);
/* Cancel and flush any pending HPD debounce work */
- if (aconnector->hdmi_hpd_debounce_delay_ms || aconnector->dp_hpd_debounce_delay_ms) {
- cancel_delayed_work_sync(&aconnector->hdmi_hpd_debounce_work);
- if (aconnector->hdmi_prev_sink) {
- dc_sink_release(aconnector->hdmi_prev_sink);
- aconnector->hdmi_prev_sink = NULL;
- }
+ cancel_delayed_work_sync(&aconnector->hpd_debounce_work);
+ if (aconnector->hpd_prev_sink) {
+ dc_sink_release(aconnector->hpd_prev_sink);
+ aconnector->hpd_prev_sink = NULL;
}
if (aconnector->bl_idx != -1) {
@@ -2828,20 +2826,11 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
mutex_init(&aconnector->hpd_lock);
mutex_init(&aconnector->handle_mst_msg_ready);
- /*
- * If an HPD debounce delay is set, clamp each signal's delay to its
- * maximum. The debounce work and cached sink are shared by both the
- * HDMI and DisplayPort SST paths.
- */
- aconnector->hdmi_hpd_debounce_delay_ms = amdgpu_hdmi_hpd_debounce_delay_ms ?
- min(amdgpu_hdmi_hpd_debounce_delay_ms, AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS) : 0;
- aconnector->dp_hpd_debounce_delay_ms = amdgpu_dp_hpd_debounce_delay_ms ?
- min(amdgpu_dp_hpd_debounce_delay_ms, AMDGPU_DM_MAX_DP_HPD_DEBOUNCE_MS) : 0;
-
- if (aconnector->hdmi_hpd_debounce_delay_ms || aconnector->dp_hpd_debounce_delay_ms) {
- INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, amdgpu_dm_hdmi_hpd_debounce_work);
- aconnector->hdmi_prev_sink = NULL;
- }
+ /* May be overridden later by an EDID quirk in apply_edid_quirks() */
+ aconnector->hpd_debounce_delay_ms = amdgpu_hpd_debounce_delay_ms ?
+ min(amdgpu_hpd_debounce_delay_ms, AMDGPU_DM_MAX_HPD_DEBOUNCE_MS) : 0;
+ aconnector->hpd_prev_sink = NULL;
+ INIT_DELAYED_WORK(&aconnector->hpd_debounce_work, amdgpu_dm_hpd_debounce_work);
dm->hdmi_frl_status_polling_delay_ms = 200;
INIT_DELAYED_WORK(&dm->hdmi_frl_status_polling_work, hdmi_frl_status_polling_work);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index 9c4e0a4e2..71c897416 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -137,6 +137,14 @@ static void apply_edid_quirks(struct dc_link *link, struct edid *edid,
drm_dbg_driver(dev, "Skip PHY SSC reduction on panel id %X\n", panel_id);
link->wa_flags.skip_phy_ssc_reduction = true;
break;
+ /* Workaround for monitors that toggle HPD on entering deep sleep */
+ case drm_edid_encode_panel_id('M', 'S', 'I', 0x3CF0):
+ if (!aconnector->hpd_debounce_delay_ms) {
+ drm_dbg_driver(dev, "Enabling HPD debounce on panel id %X\n", panel_id);
+ aconnector->hpd_debounce_delay_ms =
+ min(1500U, AMDGPU_DM_MAX_HPD_DEBOUNCE_MS);
+ }
+ break;
default:
return;
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
index 2a732d19b..151db9893 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
@@ -1217,13 +1217,13 @@ EXPORT_IF_KUNIT(are_sinks_equal);
/**
- * DOC: amdgpu_dm_hdmi_hpd_debounce_work
+ * DOC: amdgpu_dm_hpd_debounce_work
*
- * HDMI HPD debounce delay in milliseconds. When an HDMI display toggles HPD
+ * HDMI/DVI/DP SST HPD debounce delay in milliseconds. When a display toggles HPD
* (such as during power save transitions), this delay determines how long to
* wait before processing the HPD event. This allows distinguishing between a
- * physical unplug (>hdmi_hpd_debounce_delay)
- * and a spontaneous RX HPD toggle (<hdmi_hpd_debounce_delay).
+ * physical unplug (>hpd_debounce_delay)
+ * and a spontaneous RX HPD toggle (<hpd_debounce_delay).
*
* If the toggle is less than this delay, the driver compares sink capabilities
* and permits a hotplug event if they changed.
@@ -1231,11 +1231,11 @@ EXPORT_IF_KUNIT(are_sinks_equal);
* The default value of 1500ms was chosen based on experimental testing with
* various monitors that exhibit spontaneous HPD toggling behavior.
*/
-void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work)
+void amdgpu_dm_hpd_debounce_work(struct work_struct *work)
{
struct amdgpu_dm_connector *aconnector =
container_of(to_delayed_work(work), struct amdgpu_dm_connector,
- hdmi_hpd_debounce_work);
+ hpd_debounce_work);
struct drm_connector *connector = &aconnector->base;
struct drm_device *dev = connector->dev;
struct amdgpu_device *adev = drm_to_adev(dev);
@@ -1259,11 +1259,12 @@ void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work)
/* Apply workaround delay for certain panels */
amdgpu_dm_apply_delay_after_dpcd_poweroff(adev, aconnector->dc_sink);
/* Compare sinks to determine if this was a spontaneous HPD toggle */
- if (are_sinks_equal(aconnector->dc_link->local_sink, aconnector->hdmi_prev_sink)) {
+ if (are_sinks_equal(aconnector->dc_link->local_sink, aconnector->hpd_prev_sink)) {
/*
- * Sinks match - this was a spontaneous HDMI HPD toggle.
+ * Sinks match - this was a spontaneous HPD toggle.
*/
- drm_dbg_kms(dev, "HDMI HPD: Sink unchanged after debounce, internal re-enable\n");
+ drm_dbg_kms(dev,
+ "HPD: Sink unchanged after debounce, internal re-enable\n");
fake_reconnect = true;
}
@@ -1280,9 +1281,9 @@ void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work)
}
/* Release the cached sink reference */
- if (aconnector->hdmi_prev_sink) {
- dc_sink_release(aconnector->hdmi_prev_sink);
- aconnector->hdmi_prev_sink = NULL;
+ if (aconnector->hpd_prev_sink) {
+ dc_sink_release(aconnector->hpd_prev_sink);
+ aconnector->hpd_prev_sink = NULL;
}
scoped_guard(mutex, &adev->dm.dc_lock) {
@@ -1302,7 +1303,7 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
struct dc *dc = aconnector->dc_link->ctx->dc;
bool ret = false;
bool debounce_required = false;
- unsigned int debounce_delay_ms = 0;
+ bool debounce_eligible;
if (adev->dm.disable_hpd_irq)
return;
@@ -1326,16 +1327,16 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n");
/*
- * Check for an HDMI or DisplayPort SST disconnect with debounce
- * enabled. eDP and MST are intentionally excluded.
+ * Check for an HDMI, DVI, or DisplayPort SST disconnect with
+ * debounce enabled. eDP and MST are intentionally excluded.
*/
- if (dc_is_hdmi_signal(aconnector->dc_link->connector_signal))
- debounce_delay_ms = aconnector->hdmi_hpd_debounce_delay_ms;
- else if (aconnector->dc_link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
- aconnector->dc_link->type != dc_connection_mst_branch)
- debounce_delay_ms = aconnector->dp_hpd_debounce_delay_ms;
+ debounce_eligible = dc_is_hdmi_signal(aconnector->dc_link->connector_signal) ||
+ dc_is_dvi_signal(aconnector->dc_link->connector_signal) ||
+ (aconnector->dc_link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
+ aconnector->dc_link->type != dc_connection_mst_branch);
- debounce_required = (debounce_delay_ms > 0 &&
+ debounce_required = (debounce_eligible &&
+ aconnector->hpd_debounce_delay_ms > 0 &&
new_connection_type == dc_connection_none &&
aconnector->dc_link->local_sink != NULL);
@@ -1353,28 +1354,28 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
/*
* Disconnect detected - schedule delayed work instead of
* processing immediately. This allows us to coalesce spurious
- * HDMI/DP HPD signals from physical unplugs.
+ * HDMI/DVI/DP HPD signals from physical unplugs.
*/
drm_dbg_kms(dev, "HPD: Disconnect detected, scheduling debounce work (%u ms)\n",
- debounce_delay_ms);
+ aconnector->hpd_debounce_delay_ms);
/* Cache the current sink for later comparison */
- if (aconnector->hdmi_prev_sink)
- dc_sink_release(aconnector->hdmi_prev_sink);
- aconnector->hdmi_prev_sink = aconnector->dc_link->local_sink;
- if (aconnector->hdmi_prev_sink)
- dc_sink_retain(aconnector->hdmi_prev_sink);
+ if (aconnector->hpd_prev_sink)
+ dc_sink_release(aconnector->hpd_prev_sink);
+ aconnector->hpd_prev_sink = aconnector->dc_link->local_sink;
+ if (aconnector->hpd_prev_sink)
+ dc_sink_retain(aconnector->hpd_prev_sink);
/* Schedule delayed detection. */
if (mod_delayed_work(system_percpu_wq,
- &aconnector->hdmi_hpd_debounce_work,
- msecs_to_jiffies(debounce_delay_ms)))
+ &aconnector->hpd_debounce_work,
+ msecs_to_jiffies(aconnector->hpd_debounce_delay_ms)))
drm_dbg_kms(dev, "HPD: Re-scheduled debounce work\n");
} else {
- /* If the aconnector->hdmi_hpd_debounce_work is scheduled, exit early */
- if (delayed_work_pending(&aconnector->hdmi_hpd_debounce_work))
+ /* If the aconnector->hpd_debounce_work is scheduled, exit early */
+ if (delayed_work_pending(&aconnector->hpd_debounce_work))
return;
scoped_guard(mutex, &adev->dm.dc_lock) {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
index bccb5d354..66fb82961 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
@@ -113,7 +113,7 @@ void amdgpu_dm_irq_resume_late(struct amdgpu_device *adev);
struct hpd_rx_irq_offload_work_queue *amdgpu_dm_hpd_rx_irq_create_workqueue(struct amdgpu_device *adev);
void amdgpu_dm_hpd_rx_irq_work_suspend(struct amdgpu_display_manager *dm);
int amdgpu_dm_register_hpd_handlers(struct amdgpu_device *adev);
-void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work);
+void amdgpu_dm_hpd_debounce_work(struct work_struct *work);
/* IRQ handlers */
struct amdgpu_crtc *amdgpu_dm_get_crtc_by_otg_inst(struct amdgpu_device *adev,
---
base-commit: c92b5b607c1c8ab786fccf03d62352b82f6539ae
change-id: 20260708-hpd-debounce-unify-896ad367bf02
Best regards,
--
Nick Haghiri <nick@haghiri.net>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3] drm/amd/display: unify HDMI/DVI/DP SST HPD debounce delay
2026-07-09 14:15 ` [PATCH v3] drm/amd/display: unify HDMI/DVI/DP " Nick Haghiri
@ 2026-07-09 17:30 ` Ivan Lipski
2026-07-13 18:42 ` Harry Wentland
0 siblings, 1 reply; 10+ messages in thread
From: Ivan Lipski @ 2026-07-09 17:30 UTC (permalink / raw)
To: Nick Haghiri, amd-gfx, Alex Deucher
Cc: Harry Wentland, Leo Li, Ivan Lipski, Rodrigo Siqueira,
Christian König, Michel Dänzer, Xaver Hugl,
David Airlie, Simona Vetter, dri-devel, linux-kernel
On 7/9/26 10:15, Nick Haghiri wrote:
> Per review feedback on the DP SST debounce extension, fold
> hdmi_hpd_debounce_delay_ms and dp_hpd_debounce_delay_ms into a single
> hpd_debounce_delay_ms module parameter (eDP and MST still excluded),
> and rename the shared connector fields, work, and cached sink from
> hdmi_* to generic hpd_*. Also extend eligibility to DVI, which shares
> the same HPD toggle behavior and has no MST/eDP variants to exclude.
>
> Also add an apply_edid_quirks() case for the MSI MPG 274U
> (drm_edid_encode_panel_id('M', 'S', 'I', 0x3CF0)) that enables a
> 1500ms default debounce delay for that panel, overridable by the
> module parameter.
>
> Signed-off-by: Nick Haghiri <nick@haghiri.net>
> ---
> Ivan, generalized to a single hpd_debounce_delay_ms for both HDMI and
> DP SST as suggested, and added the apply_edid_quirks() case for the
> MSI MPG 274U (1500ms default, module param still overrides it).
>
> Went with replacing hdmi_hpd_debounce_delay_ms rather than keeping a
> back-compat alias, since it's only a couple cycles old. Shout if you'd
> rather I keep the alias.
>
> Alex, done. debounce_eligible now also checks dc_is_dvi_signal(),
> reusing the same hpd_debounce_delay_ms param. Updated text and
> comments to reflect scope now being HDMI, DVI, and DP.
> ---
> Changes in v3:
> - Extend HPD debounce eligibility to DVI (dc_is_dvi_signal()), per Alex
> - Update comments/docs to reflect HDMI/DVI/DP SST scope
> - Link to v2: https://patch.msgid.link/20260708-hpd-debounce-unify-v2-1-d214832551b3@haghiri.net
Hey Nick,
Thank you very much for this patch.
My only concern is that a monitor that requires HPD debounce delay on
HDMI may not need it when connected via DP, a vice-versa, so I think we
should differentiate them.
I think a proper approach for this would be adding two new integer
fields to the dc_panel_patch struct for DP and HDMI each, so a delay in
ms could be explicitly set for a specific monitor and specific connector
type.
So in the apply_edid_quirks, we could have something like this in
apply_edid_quirk
/* Workaround for monitors that toggle HPD on entering deep sleep */
case drm_edid_encode_panel_id('M', 'S', 'I', 0x3CF0):
if (!aconnector->hpd_debounce_delay_ms) {
drm_dbg_driver(dev, "Enabling HPD debounce on panel id %X\n", panel_id);
edid_caps.panel_patch.dp_hpd_debounce_delay_ms =
min(1500U, AMDGPU_DM_MAX_HPD_DEBOUNCE_MS);
}
break;
That would also require changing logic of determining the
`debounce_eligible` as we'd need to check for initialized
dp_hpd_debounce_delay_ms && SIGNAL_TYPE_DISPLAY_PORT or
(hdmi_hpd_debounce_delay_ms && (HDMI || DVI)).
sunpeng.li@amd.com, alexander.deucher@amd.com, what do you think?
> ---
> drivers/gpu/drm/amd/amdgpu/amdgpu.h | 3 +-
> drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 26 ++-------
> drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 18 ++----
> .../amd/display/amdgpu_dm/amdgpu_dm_connector.c | 29 +++-------
> .../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 8 +++
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 65 +++++++++++-----------
> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h | 2 +-
> 7 files changed, 64 insertions(+), 87 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index c085a6cc1..af1748984 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -270,8 +270,7 @@ extern int amdgpu_wbrf;
> extern int amdgpu_user_queue;
> extern int amdgpu_ptl;
>
> -extern uint amdgpu_hdmi_hpd_debounce_delay_ms;
> -extern uint amdgpu_dp_hpd_debounce_delay_ms;
> +extern uint amdgpu_hpd_debounce_delay_ms;
>
> #define AMDGPU_SG_THRESHOLD (256*1024*1024)
> #define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> index 78df53b8c..a82d807f7 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> @@ -245,8 +245,7 @@ int amdgpu_damage_clips = -1; /* auto */
> int amdgpu_umsch_mm_fwlog;
> int amdgpu_rebar = -1; /* auto */
> int amdgpu_user_queue = -1;
> -uint amdgpu_hdmi_hpd_debounce_delay_ms;
> -uint amdgpu_dp_hpd_debounce_delay_ms;
> +uint amdgpu_hpd_debounce_delay_ms;
> int amdgpu_ptl = -1; /* auto */
>
> DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
> @@ -1105,25 +1104,12 @@ MODULE_PARM_DESC(user_queue, "Enable user queues (-1 = auto (default), 0 = disab
> module_param_named(user_queue, amdgpu_user_queue, int, 0444);
>
> /*
> - * DOC: hdmi_hpd_debounce_delay_ms (uint)
> - * HDMI HPD disconnect debounce delay in milliseconds.
> - *
> - * Used to filter short disconnect->reconnect HPD toggles some HDMI sinks
> - * generate while entering/leaving power save. Set to 0 to disable by default.
> - */
> -MODULE_PARM_DESC(hdmi_hpd_debounce_delay_ms, "HDMI HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
> -module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms, uint, 0644);
> -
> -/*
> - * DOC: dp_hpd_debounce_delay_ms (uint)
> - * DisplayPort SST HPD disconnect debounce delay in milliseconds.
> - *
> - * Used to filter short disconnect->reconnect HPD toggles some DisplayPort SST
> - * sinks generate while entering/leaving power save. Set to 0 to disable by
> - * default. eDP and MST are not affected.
> + * DOC: hpd_debounce_delay_ms (uint)
> + * HDMI/DVI/DP SST HPD disconnect debounce delay in milliseconds. eDP and MST
> + * are not affected. Overrides any per-panel default set via EDID quirks.
> */
> -MODULE_PARM_DESC(dp_hpd_debounce_delay_ms, "DisplayPort SST HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
> -module_param_named(dp_hpd_debounce_delay_ms, amdgpu_dp_hpd_debounce_delay_ms, uint, 0644);
> +MODULE_PARM_DESC(hpd_debounce_delay_ms, "HDMI/DVI/DP SST HPD disconnect debounce delay in milliseconds (0 to disable (by default) or use the EDID quirk default, 1500 is common)");
> +module_param_named(hpd_debounce_delay_ms, amdgpu_hpd_debounce_delay_ms, uint, 0644);
>
> /**
> * DOC: ptl (int)
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> index abc17f547..5235a5ef6 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
> @@ -61,14 +61,9 @@ enum amd_vsdb_panel_type {
> #define AMDGPU_HDR_MULT_DEFAULT (0x100000000LL)
>
> /*
> - * Maximum HDMI HPD debounce delay in milliseconds
> + * Maximum HDMI/DVI/DP SST HPD debounce delay in milliseconds
> */
> -#define AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS 5000
> -
> -/*
> - * Maximum DisplayPort SST HPD debounce delay in milliseconds
> - */
> -#define AMDGPU_DM_MAX_DP_HPD_DEBOUNCE_MS 5000
> +#define AMDGPU_DM_MAX_HPD_DEBOUNCE_MS 5000
> /*
> #include "include/amdgpu_dal_power_if.h"
> #include "amdgpu_dm_irq.h"
> @@ -878,11 +873,10 @@ struct amdgpu_dm_connector {
> enum adaptive_sync_type as_type;
> struct amdgpu_hdmi_vsdb_info vsdb_info;
>
> - /* HDMI HPD debounce support */
> - unsigned int hdmi_hpd_debounce_delay_ms;
> - unsigned int dp_hpd_debounce_delay_ms;
> - struct delayed_work hdmi_hpd_debounce_work;
> - struct dc_sink *hdmi_prev_sink;
> + /* HDMI/DVI/DP SST HPD debounce support */
> + unsigned int hpd_debounce_delay_ms;
> + struct delayed_work hpd_debounce_work;
> + struct dc_sink *hpd_prev_sink;
>
> /* HDMI compliance automation */
> bool hdmi_comp_auto;
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> index c79a8ada8..798825ec1 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
> @@ -1748,12 +1748,10 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
> drm_dp_mst_topology_mgr_destroy(&aconnector->mst_mgr);
>
> /* Cancel and flush any pending HPD debounce work */
> - if (aconnector->hdmi_hpd_debounce_delay_ms || aconnector->dp_hpd_debounce_delay_ms) {
> - cancel_delayed_work_sync(&aconnector->hdmi_hpd_debounce_work);
> - if (aconnector->hdmi_prev_sink) {
> - dc_sink_release(aconnector->hdmi_prev_sink);
> - aconnector->hdmi_prev_sink = NULL;
> - }
> + cancel_delayed_work_sync(&aconnector->hpd_debounce_work);
> + if (aconnector->hpd_prev_sink) {
> + dc_sink_release(aconnector->hpd_prev_sink);
> + aconnector->hpd_prev_sink = NULL;
> }
>
> if (aconnector->bl_idx != -1) {
> @@ -2828,20 +2826,11 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
> mutex_init(&aconnector->hpd_lock);
> mutex_init(&aconnector->handle_mst_msg_ready);
>
> - /*
> - * If an HPD debounce delay is set, clamp each signal's delay to its
> - * maximum. The debounce work and cached sink are shared by both the
> - * HDMI and DisplayPort SST paths.
> - */
> - aconnector->hdmi_hpd_debounce_delay_ms = amdgpu_hdmi_hpd_debounce_delay_ms ?
> - min(amdgpu_hdmi_hpd_debounce_delay_ms, AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS) : 0;
> - aconnector->dp_hpd_debounce_delay_ms = amdgpu_dp_hpd_debounce_delay_ms ?
> - min(amdgpu_dp_hpd_debounce_delay_ms, AMDGPU_DM_MAX_DP_HPD_DEBOUNCE_MS) : 0;
> -
> - if (aconnector->hdmi_hpd_debounce_delay_ms || aconnector->dp_hpd_debounce_delay_ms) {
> - INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, amdgpu_dm_hdmi_hpd_debounce_work);
> - aconnector->hdmi_prev_sink = NULL;
> - }
> + /* May be overridden later by an EDID quirk in apply_edid_quirks() */
> + aconnector->hpd_debounce_delay_ms = amdgpu_hpd_debounce_delay_ms ?
> + min(amdgpu_hpd_debounce_delay_ms, AMDGPU_DM_MAX_HPD_DEBOUNCE_MS) : 0;
> + aconnector->hpd_prev_sink = NULL;
> + INIT_DELAYED_WORK(&aconnector->hpd_debounce_work, amdgpu_dm_hpd_debounce_work);
>
> dm->hdmi_frl_status_polling_delay_ms = 200;
> INIT_DELAYED_WORK(&dm->hdmi_frl_status_polling_work, hdmi_frl_status_polling_work);
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> index 9c4e0a4e2..71c897416 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
> @@ -137,6 +137,14 @@ static void apply_edid_quirks(struct dc_link *link, struct edid *edid,
> drm_dbg_driver(dev, "Skip PHY SSC reduction on panel id %X\n", panel_id);
> link->wa_flags.skip_phy_ssc_reduction = true;
> break;
> + /* Workaround for monitors that toggle HPD on entering deep sleep */
> + case drm_edid_encode_panel_id('M', 'S', 'I', 0x3CF0):
> + if (!aconnector->hpd_debounce_delay_ms) {
> + drm_dbg_driver(dev, "Enabling HPD debounce on panel id %X\n", panel_id);
> + aconnector->hpd_debounce_delay_ms =
> + min(1500U, AMDGPU_DM_MAX_HPD_DEBOUNCE_MS);
> + }
> + break;
> default:
> return;
> }
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
> index 2a732d19b..151db9893 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
> @@ -1217,13 +1217,13 @@ EXPORT_IF_KUNIT(are_sinks_equal);
>
>
> /**
> - * DOC: amdgpu_dm_hdmi_hpd_debounce_work
> + * DOC: amdgpu_dm_hpd_debounce_work
> *
> - * HDMI HPD debounce delay in milliseconds. When an HDMI display toggles HPD
> + * HDMI/DVI/DP SST HPD debounce delay in milliseconds. When a display toggles HPD
> * (such as during power save transitions), this delay determines how long to
> * wait before processing the HPD event. This allows distinguishing between a
> - * physical unplug (>hdmi_hpd_debounce_delay)
> - * and a spontaneous RX HPD toggle (<hdmi_hpd_debounce_delay).
> + * physical unplug (>hpd_debounce_delay)
> + * and a spontaneous RX HPD toggle (<hpd_debounce_delay).
> *
> * If the toggle is less than this delay, the driver compares sink capabilities
> * and permits a hotplug event if they changed.
> @@ -1231,11 +1231,11 @@ EXPORT_IF_KUNIT(are_sinks_equal);
> * The default value of 1500ms was chosen based on experimental testing with
> * various monitors that exhibit spontaneous HPD toggling behavior.
> */
> -void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work)
> +void amdgpu_dm_hpd_debounce_work(struct work_struct *work)
> {
> struct amdgpu_dm_connector *aconnector =
> container_of(to_delayed_work(work), struct amdgpu_dm_connector,
> - hdmi_hpd_debounce_work);
> + hpd_debounce_work);
> struct drm_connector *connector = &aconnector->base;
> struct drm_device *dev = connector->dev;
> struct amdgpu_device *adev = drm_to_adev(dev);
> @@ -1259,11 +1259,12 @@ void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work)
> /* Apply workaround delay for certain panels */
> amdgpu_dm_apply_delay_after_dpcd_poweroff(adev, aconnector->dc_sink);
> /* Compare sinks to determine if this was a spontaneous HPD toggle */
> - if (are_sinks_equal(aconnector->dc_link->local_sink, aconnector->hdmi_prev_sink)) {
> + if (are_sinks_equal(aconnector->dc_link->local_sink, aconnector->hpd_prev_sink)) {
> /*
> - * Sinks match - this was a spontaneous HDMI HPD toggle.
> + * Sinks match - this was a spontaneous HPD toggle.
> */
> - drm_dbg_kms(dev, "HDMI HPD: Sink unchanged after debounce, internal re-enable\n");
> + drm_dbg_kms(dev,
> + "HPD: Sink unchanged after debounce, internal re-enable\n");
> fake_reconnect = true;
> }
>
> @@ -1280,9 +1281,9 @@ void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work)
> }
>
> /* Release the cached sink reference */
> - if (aconnector->hdmi_prev_sink) {
> - dc_sink_release(aconnector->hdmi_prev_sink);
> - aconnector->hdmi_prev_sink = NULL;
> + if (aconnector->hpd_prev_sink) {
> + dc_sink_release(aconnector->hpd_prev_sink);
> + aconnector->hpd_prev_sink = NULL;
> }
>
> scoped_guard(mutex, &adev->dm.dc_lock) {
> @@ -1302,7 +1303,7 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
> struct dc *dc = aconnector->dc_link->ctx->dc;
> bool ret = false;
> bool debounce_required = false;
> - unsigned int debounce_delay_ms = 0;
> + bool debounce_eligible;
>
> if (adev->dm.disable_hpd_irq)
> return;
> @@ -1326,16 +1327,16 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
> drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n");
>
> /*
> - * Check for an HDMI or DisplayPort SST disconnect with debounce
> - * enabled. eDP and MST are intentionally excluded.
> + * Check for an HDMI, DVI, or DisplayPort SST disconnect with
> + * debounce enabled. eDP and MST are intentionally excluded.
> */
> - if (dc_is_hdmi_signal(aconnector->dc_link->connector_signal))
> - debounce_delay_ms = aconnector->hdmi_hpd_debounce_delay_ms;
> - else if (aconnector->dc_link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
> - aconnector->dc_link->type != dc_connection_mst_branch)
> - debounce_delay_ms = aconnector->dp_hpd_debounce_delay_ms;
> + debounce_eligible = dc_is_hdmi_signal(aconnector->dc_link->connector_signal) ||
> + dc_is_dvi_signal(aconnector->dc_link->connector_signal) ||
> + (aconnector->dc_link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
> + aconnector->dc_link->type != dc_connection_mst_branch);
>
> - debounce_required = (debounce_delay_ms > 0 &&
> + debounce_required = (debounce_eligible &&
> + aconnector->hpd_debounce_delay_ms > 0 &&
> new_connection_type == dc_connection_none &&
> aconnector->dc_link->local_sink != NULL);
>
> @@ -1353,28 +1354,28 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
> /*
> * Disconnect detected - schedule delayed work instead of
> * processing immediately. This allows us to coalesce spurious
> - * HDMI/DP HPD signals from physical unplugs.
> + * HDMI/DVI/DP HPD signals from physical unplugs.
> */
> drm_dbg_kms(dev, "HPD: Disconnect detected, scheduling debounce work (%u ms)\n",
> - debounce_delay_ms);
> + aconnector->hpd_debounce_delay_ms);
>
> /* Cache the current sink for later comparison */
> - if (aconnector->hdmi_prev_sink)
> - dc_sink_release(aconnector->hdmi_prev_sink);
> - aconnector->hdmi_prev_sink = aconnector->dc_link->local_sink;
> - if (aconnector->hdmi_prev_sink)
> - dc_sink_retain(aconnector->hdmi_prev_sink);
> + if (aconnector->hpd_prev_sink)
> + dc_sink_release(aconnector->hpd_prev_sink);
> + aconnector->hpd_prev_sink = aconnector->dc_link->local_sink;
> + if (aconnector->hpd_prev_sink)
> + dc_sink_retain(aconnector->hpd_prev_sink);
>
> /* Schedule delayed detection. */
> if (mod_delayed_work(system_percpu_wq,
> - &aconnector->hdmi_hpd_debounce_work,
> - msecs_to_jiffies(debounce_delay_ms)))
> + &aconnector->hpd_debounce_work,
> + msecs_to_jiffies(aconnector->hpd_debounce_delay_ms)))
> drm_dbg_kms(dev, "HPD: Re-scheduled debounce work\n");
>
> } else {
>
> - /* If the aconnector->hdmi_hpd_debounce_work is scheduled, exit early */
> - if (delayed_work_pending(&aconnector->hdmi_hpd_debounce_work))
> + /* If the aconnector->hpd_debounce_work is scheduled, exit early */
> + if (delayed_work_pending(&aconnector->hpd_debounce_work))
> return;
>
> scoped_guard(mutex, &adev->dm.dc_lock) {
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
> index bccb5d354..66fb82961 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
> @@ -113,7 +113,7 @@ void amdgpu_dm_irq_resume_late(struct amdgpu_device *adev);
> struct hpd_rx_irq_offload_work_queue *amdgpu_dm_hpd_rx_irq_create_workqueue(struct amdgpu_device *adev);
> void amdgpu_dm_hpd_rx_irq_work_suspend(struct amdgpu_display_manager *dm);
> int amdgpu_dm_register_hpd_handlers(struct amdgpu_device *adev);
> -void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work);
> +void amdgpu_dm_hpd_debounce_work(struct work_struct *work);
>
> /* IRQ handlers */
> struct amdgpu_crtc *amdgpu_dm_get_crtc_by_otg_inst(struct amdgpu_device *adev,
>
> ---
> base-commit: c92b5b607c1c8ab786fccf03d62352b82f6539ae
> change-id: 20260708-hpd-debounce-unify-896ad367bf02
>
> Best regards,
> --
> Nick Haghiri <nick@haghiri.net>
>
--
Thanks,
Ivan Lipski
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3] drm/amd/display: unify HDMI/DVI/DP SST HPD debounce delay
2026-07-09 17:30 ` Ivan Lipski
@ 2026-07-13 18:42 ` Harry Wentland
0 siblings, 0 replies; 10+ messages in thread
From: Harry Wentland @ 2026-07-13 18:42 UTC (permalink / raw)
To: Ivan Lipski, Nick Haghiri, amd-gfx, Alex Deucher
Cc: Leo Li, Ivan Lipski, Rodrigo Siqueira, Christian König,
Michel Dänzer, Xaver Hugl, David Airlie, Simona Vetter,
dri-devel, linux-kernel
On 2026-07-09 13:30, Ivan Lipski wrote:
>
> On 7/9/26 10:15, Nick Haghiri wrote:
>> Per review feedback on the DP SST debounce extension, fold
>> hdmi_hpd_debounce_delay_ms and dp_hpd_debounce_delay_ms into a single
>> hpd_debounce_delay_ms module parameter (eDP and MST still excluded),
>> and rename the shared connector fields, work, and cached sink from
>> hdmi_* to generic hpd_*. Also extend eligibility to DVI, which shares
>> the same HPD toggle behavior and has no MST/eDP variants to exclude.
>>
>> Also add an apply_edid_quirks() case for the MSI MPG 274U
>> (drm_edid_encode_panel_id('M', 'S', 'I', 0x3CF0)) that enables a
>> 1500ms default debounce delay for that panel, overridable by the
>> module parameter.
>>
>> Signed-off-by: Nick Haghiri <nick@haghiri.net>
>> ---
>> Ivan, generalized to a single hpd_debounce_delay_ms for both HDMI and
>> DP SST as suggested, and added the apply_edid_quirks() case for the
>> MSI MPG 274U (1500ms default, module param still overrides it).
>>
>> Went with replacing hdmi_hpd_debounce_delay_ms rather than keeping a
>> back-compat alias, since it's only a couple cycles old. Shout if you'd
>> rather I keep the alias.
>>
>> Alex, done. debounce_eligible now also checks dc_is_dvi_signal(),
>> reusing the same hpd_debounce_delay_ms param. Updated text and
>> comments to reflect scope now being HDMI, DVI, and DP.
>> ---
>> Changes in v3:
>> - Extend HPD debounce eligibility to DVI (dc_is_dvi_signal()), per Alex
>> - Update comments/docs to reflect HDMI/DVI/DP SST scope
>> - Link to v2: https://patch.msgid.link/20260708-hpd-debounce-unify-v2-1-d214832551b3@haghiri.net
>
> Hey Nick,
>
> Thank you very much for this patch.
>
> My only concern is that a monitor that requires HPD debounce delay on HDMI may not need it when connected via DP, a vice-versa, so I think we should differentiate them.
>
> I think a proper approach for this would be adding two new integer fields to the dc_panel_patch struct for DP and HDMI each, so a delay in ms could be explicitly set for a specific monitor and specific connector type.
>
> So in the apply_edid_quirks, we could have something like this in apply_edid_quirk
>
> /* Workaround for monitors that toggle HPD on entering deep sleep */
> case drm_edid_encode_panel_id('M', 'S', 'I', 0x3CF0):
> if (!aconnector->hpd_debounce_delay_ms) {
> drm_dbg_driver(dev, "Enabling HPD debounce on panel id %X\n", panel_id);
> edid_caps.panel_patch.dp_hpd_debounce_delay_ms =
> min(1500U, AMDGPU_DM_MAX_HPD_DEBOUNCE_MS);
> }
> break;
>
> That would also require changing logic of determining the `debounce_eligible` as we'd need to check for initialized dp_hpd_debounce_delay_ms && SIGNAL_TYPE_DISPLAY_PORT or (hdmi_hpd_debounce_delay_ms && (HDMI || DVI)).
>
> sunpeng.li@amd.com, alexander.deucher@amd.com, what do you think?
IMO any EDID quirk for this should apply to a combo of display type + EDID product & manufacturer ID. But I don't think we need separate module parameters for different display types. The module param is global anyways, currently, and would apply to all displays (if I understand this correctly after skimming this work), so it's mostly useful to single-display scenarios and (likely) won't harm multi-display scenarios, other than adding some delays to unplug detection.
Harry
>
>> ---
>> drivers/gpu/drm/amd/amdgpu/amdgpu.h | 3 +-
>> drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 26 ++-------
>> drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 18 ++----
>> .../amd/display/amdgpu_dm/amdgpu_dm_connector.c | 29 +++-------
>> .../drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 8 +++
>> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 65 +++++++++++-----------
>> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h | 2 +-
>> 7 files changed, 64 insertions(+), 87 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
>> index c085a6cc1..af1748984 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
>> @@ -270,8 +270,7 @@ extern int amdgpu_wbrf;
>> extern int amdgpu_user_queue;
>> extern int amdgpu_ptl;
>> -extern uint amdgpu_hdmi_hpd_debounce_delay_ms;
>> -extern uint amdgpu_dp_hpd_debounce_delay_ms;
>> +extern uint amdgpu_hpd_debounce_delay_ms;
>> #define AMDGPU_SG_THRESHOLD (256*1024*1024)
>> #define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000
>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
>> index 78df53b8c..a82d807f7 100644
>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
>> @@ -245,8 +245,7 @@ int amdgpu_damage_clips = -1; /* auto */
>> int amdgpu_umsch_mm_fwlog;
>> int amdgpu_rebar = -1; /* auto */
>> int amdgpu_user_queue = -1;
>> -uint amdgpu_hdmi_hpd_debounce_delay_ms;
>> -uint amdgpu_dp_hpd_debounce_delay_ms;
>> +uint amdgpu_hpd_debounce_delay_ms;
>> int amdgpu_ptl = -1; /* auto */
>> DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0,
>> @@ -1105,25 +1104,12 @@ MODULE_PARM_DESC(user_queue, "Enable user queues (-1 = auto (default), 0 = disab
>> module_param_named(user_queue, amdgpu_user_queue, int, 0444);
>> /*
>> - * DOC: hdmi_hpd_debounce_delay_ms (uint)
>> - * HDMI HPD disconnect debounce delay in milliseconds.
>> - *
>> - * Used to filter short disconnect->reconnect HPD toggles some HDMI sinks
>> - * generate while entering/leaving power save. Set to 0 to disable by default.
>> - */
>> -MODULE_PARM_DESC(hdmi_hpd_debounce_delay_ms, "HDMI HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
>> -module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms, uint, 0644);
>> -
>> -/*
>> - * DOC: dp_hpd_debounce_delay_ms (uint)
>> - * DisplayPort SST HPD disconnect debounce delay in milliseconds.
>> - *
>> - * Used to filter short disconnect->reconnect HPD toggles some DisplayPort SST
>> - * sinks generate while entering/leaving power save. Set to 0 to disable by
>> - * default. eDP and MST are not affected.
>> + * DOC: hpd_debounce_delay_ms (uint)
>> + * HDMI/DVI/DP SST HPD disconnect debounce delay in milliseconds. eDP and MST
>> + * are not affected. Overrides any per-panel default set via EDID quirks.
>> */
>> -MODULE_PARM_DESC(dp_hpd_debounce_delay_ms, "DisplayPort SST HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
>> -module_param_named(dp_hpd_debounce_delay_ms, amdgpu_dp_hpd_debounce_delay_ms, uint, 0644);
>> +MODULE_PARM_DESC(hpd_debounce_delay_ms, "HDMI/DVI/DP SST HPD disconnect debounce delay in milliseconds (0 to disable (by default) or use the EDID quirk default, 1500 is common)");
>> +module_param_named(hpd_debounce_delay_ms, amdgpu_hpd_debounce_delay_ms, uint, 0644);
>> /**
>> * DOC: ptl (int)
>> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
>> index abc17f547..5235a5ef6 100644
>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
>> @@ -61,14 +61,9 @@ enum amd_vsdb_panel_type {
>> #define AMDGPU_HDR_MULT_DEFAULT (0x100000000LL)
>> /*
>> - * Maximum HDMI HPD debounce delay in milliseconds
>> + * Maximum HDMI/DVI/DP SST HPD debounce delay in milliseconds
>> */
>> -#define AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS 5000
>> -
>> -/*
>> - * Maximum DisplayPort SST HPD debounce delay in milliseconds
>> - */
>> -#define AMDGPU_DM_MAX_DP_HPD_DEBOUNCE_MS 5000
>> +#define AMDGPU_DM_MAX_HPD_DEBOUNCE_MS 5000
>> /*
>> #include "include/amdgpu_dal_power_if.h"
>> #include "amdgpu_dm_irq.h"
>> @@ -878,11 +873,10 @@ struct amdgpu_dm_connector {
>> enum adaptive_sync_type as_type;
>> struct amdgpu_hdmi_vsdb_info vsdb_info;
>> - /* HDMI HPD debounce support */
>> - unsigned int hdmi_hpd_debounce_delay_ms;
>> - unsigned int dp_hpd_debounce_delay_ms;
>> - struct delayed_work hdmi_hpd_debounce_work;
>> - struct dc_sink *hdmi_prev_sink;
>> + /* HDMI/DVI/DP SST HPD debounce support */
>> + unsigned int hpd_debounce_delay_ms;
>> + struct delayed_work hpd_debounce_work;
>> + struct dc_sink *hpd_prev_sink;
>> /* HDMI compliance automation */
>> bool hdmi_comp_auto;
>> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
>> index c79a8ada8..798825ec1 100644
>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
>> @@ -1748,12 +1748,10 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
>> drm_dp_mst_topology_mgr_destroy(&aconnector->mst_mgr);
>> /* Cancel and flush any pending HPD debounce work */
>> - if (aconnector->hdmi_hpd_debounce_delay_ms || aconnector->dp_hpd_debounce_delay_ms) {
>> - cancel_delayed_work_sync(&aconnector->hdmi_hpd_debounce_work);
>> - if (aconnector->hdmi_prev_sink) {
>> - dc_sink_release(aconnector->hdmi_prev_sink);
>> - aconnector->hdmi_prev_sink = NULL;
>> - }
>> + cancel_delayed_work_sync(&aconnector->hpd_debounce_work);
>> + if (aconnector->hpd_prev_sink) {
>> + dc_sink_release(aconnector->hpd_prev_sink);
>> + aconnector->hpd_prev_sink = NULL;
>> }
>> if (aconnector->bl_idx != -1) {
>> @@ -2828,20 +2826,11 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
>> mutex_init(&aconnector->hpd_lock);
>> mutex_init(&aconnector->handle_mst_msg_ready);
>> - /*
>> - * If an HPD debounce delay is set, clamp each signal's delay to its
>> - * maximum. The debounce work and cached sink are shared by both the
>> - * HDMI and DisplayPort SST paths.
>> - */
>> - aconnector->hdmi_hpd_debounce_delay_ms = amdgpu_hdmi_hpd_debounce_delay_ms ?
>> - min(amdgpu_hdmi_hpd_debounce_delay_ms, AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS) : 0;
>> - aconnector->dp_hpd_debounce_delay_ms = amdgpu_dp_hpd_debounce_delay_ms ?
>> - min(amdgpu_dp_hpd_debounce_delay_ms, AMDGPU_DM_MAX_DP_HPD_DEBOUNCE_MS) : 0;
>> -
>> - if (aconnector->hdmi_hpd_debounce_delay_ms || aconnector->dp_hpd_debounce_delay_ms) {
>> - INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, amdgpu_dm_hdmi_hpd_debounce_work);
>> - aconnector->hdmi_prev_sink = NULL;
>> - }
>> + /* May be overridden later by an EDID quirk in apply_edid_quirks() */
>> + aconnector->hpd_debounce_delay_ms = amdgpu_hpd_debounce_delay_ms ?
>> + min(amdgpu_hpd_debounce_delay_ms, AMDGPU_DM_MAX_HPD_DEBOUNCE_MS) : 0;
>> + aconnector->hpd_prev_sink = NULL;
>> + INIT_DELAYED_WORK(&aconnector->hpd_debounce_work, amdgpu_dm_hpd_debounce_work);
>> dm->hdmi_frl_status_polling_delay_ms = 200;
>> INIT_DELAYED_WORK(&dm->hdmi_frl_status_polling_work, hdmi_frl_status_polling_work);
>> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
>> index 9c4e0a4e2..71c897416 100644
>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
>> @@ -137,6 +137,14 @@ static void apply_edid_quirks(struct dc_link *link, struct edid *edid,
>> drm_dbg_driver(dev, "Skip PHY SSC reduction on panel id %X\n", panel_id);
>> link->wa_flags.skip_phy_ssc_reduction = true;
>> break;
>> + /* Workaround for monitors that toggle HPD on entering deep sleep */
>> + case drm_edid_encode_panel_id('M', 'S', 'I', 0x3CF0):
>> + if (!aconnector->hpd_debounce_delay_ms) {
>> + drm_dbg_driver(dev, "Enabling HPD debounce on panel id %X\n", panel_id);
>> + aconnector->hpd_debounce_delay_ms =
>> + min(1500U, AMDGPU_DM_MAX_HPD_DEBOUNCE_MS);
>> + }
>> + break;
>> default:
>> return;
>> }
>> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
>> index 2a732d19b..151db9893 100644
>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
>> @@ -1217,13 +1217,13 @@ EXPORT_IF_KUNIT(are_sinks_equal);
>> /**
>> - * DOC: amdgpu_dm_hdmi_hpd_debounce_work
>> + * DOC: amdgpu_dm_hpd_debounce_work
>> *
>> - * HDMI HPD debounce delay in milliseconds. When an HDMI display toggles HPD
>> + * HDMI/DVI/DP SST HPD debounce delay in milliseconds. When a display toggles HPD
>> * (such as during power save transitions), this delay determines how long to
>> * wait before processing the HPD event. This allows distinguishing between a
>> - * physical unplug (>hdmi_hpd_debounce_delay)
>> - * and a spontaneous RX HPD toggle (<hdmi_hpd_debounce_delay).
>> + * physical unplug (>hpd_debounce_delay)
>> + * and a spontaneous RX HPD toggle (<hpd_debounce_delay).
>> *
>> * If the toggle is less than this delay, the driver compares sink capabilities
>> * and permits a hotplug event if they changed.
>> @@ -1231,11 +1231,11 @@ EXPORT_IF_KUNIT(are_sinks_equal);
>> * The default value of 1500ms was chosen based on experimental testing with
>> * various monitors that exhibit spontaneous HPD toggling behavior.
>> */
>> -void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work)
>> +void amdgpu_dm_hpd_debounce_work(struct work_struct *work)
>> {
>> struct amdgpu_dm_connector *aconnector =
>> container_of(to_delayed_work(work), struct amdgpu_dm_connector,
>> - hdmi_hpd_debounce_work);
>> + hpd_debounce_work);
>> struct drm_connector *connector = &aconnector->base;
>> struct drm_device *dev = connector->dev;
>> struct amdgpu_device *adev = drm_to_adev(dev);
>> @@ -1259,11 +1259,12 @@ void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work)
>> /* Apply workaround delay for certain panels */
>> amdgpu_dm_apply_delay_after_dpcd_poweroff(adev, aconnector->dc_sink);
>> /* Compare sinks to determine if this was a spontaneous HPD toggle */
>> - if (are_sinks_equal(aconnector->dc_link->local_sink, aconnector->hdmi_prev_sink)) {
>> + if (are_sinks_equal(aconnector->dc_link->local_sink, aconnector->hpd_prev_sink)) {
>> /*
>> - * Sinks match - this was a spontaneous HDMI HPD toggle.
>> + * Sinks match - this was a spontaneous HPD toggle.
>> */
>> - drm_dbg_kms(dev, "HDMI HPD: Sink unchanged after debounce, internal re-enable\n");
>> + drm_dbg_kms(dev,
>> + "HPD: Sink unchanged after debounce, internal re-enable\n");
>> fake_reconnect = true;
>> }
>> @@ -1280,9 +1281,9 @@ void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work)
>> }
>> /* Release the cached sink reference */
>> - if (aconnector->hdmi_prev_sink) {
>> - dc_sink_release(aconnector->hdmi_prev_sink);
>> - aconnector->hdmi_prev_sink = NULL;
>> + if (aconnector->hpd_prev_sink) {
>> + dc_sink_release(aconnector->hpd_prev_sink);
>> + aconnector->hpd_prev_sink = NULL;
>> }
>> scoped_guard(mutex, &adev->dm.dc_lock) {
>> @@ -1302,7 +1303,7 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
>> struct dc *dc = aconnector->dc_link->ctx->dc;
>> bool ret = false;
>> bool debounce_required = false;
>> - unsigned int debounce_delay_ms = 0;
>> + bool debounce_eligible;
>> if (adev->dm.disable_hpd_irq)
>> return;
>> @@ -1326,16 +1327,16 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
>> drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n");
>> /*
>> - * Check for an HDMI or DisplayPort SST disconnect with debounce
>> - * enabled. eDP and MST are intentionally excluded.
>> + * Check for an HDMI, DVI, or DisplayPort SST disconnect with
>> + * debounce enabled. eDP and MST are intentionally excluded.
>> */
>> - if (dc_is_hdmi_signal(aconnector->dc_link->connector_signal))
>> - debounce_delay_ms = aconnector->hdmi_hpd_debounce_delay_ms;
>> - else if (aconnector->dc_link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
>> - aconnector->dc_link->type != dc_connection_mst_branch)
>> - debounce_delay_ms = aconnector->dp_hpd_debounce_delay_ms;
>> + debounce_eligible = dc_is_hdmi_signal(aconnector->dc_link->connector_signal) ||
>> + dc_is_dvi_signal(aconnector->dc_link->connector_signal) ||
>> + (aconnector->dc_link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
>> + aconnector->dc_link->type != dc_connection_mst_branch);
>> - debounce_required = (debounce_delay_ms > 0 &&
>> + debounce_required = (debounce_eligible &&
>> + aconnector->hpd_debounce_delay_ms > 0 &&
>> new_connection_type == dc_connection_none &&
>> aconnector->dc_link->local_sink != NULL);
>> @@ -1353,28 +1354,28 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector,
>> /*
>> * Disconnect detected - schedule delayed work instead of
>> * processing immediately. This allows us to coalesce spurious
>> - * HDMI/DP HPD signals from physical unplugs.
>> + * HDMI/DVI/DP HPD signals from physical unplugs.
>> */
>> drm_dbg_kms(dev, "HPD: Disconnect detected, scheduling debounce work (%u ms)\n",
>> - debounce_delay_ms);
>> + aconnector->hpd_debounce_delay_ms);
>> /* Cache the current sink for later comparison */
>> - if (aconnector->hdmi_prev_sink)
>> - dc_sink_release(aconnector->hdmi_prev_sink);
>> - aconnector->hdmi_prev_sink = aconnector->dc_link->local_sink;
>> - if (aconnector->hdmi_prev_sink)
>> - dc_sink_retain(aconnector->hdmi_prev_sink);
>> + if (aconnector->hpd_prev_sink)
>> + dc_sink_release(aconnector->hpd_prev_sink);
>> + aconnector->hpd_prev_sink = aconnector->dc_link->local_sink;
>> + if (aconnector->hpd_prev_sink)
>> + dc_sink_retain(aconnector->hpd_prev_sink);
>> /* Schedule delayed detection. */
>> if (mod_delayed_work(system_percpu_wq,
>> - &aconnector->hdmi_hpd_debounce_work,
>> - msecs_to_jiffies(debounce_delay_ms)))
>> + &aconnector->hpd_debounce_work,
>> + msecs_to_jiffies(aconnector->hpd_debounce_delay_ms)))
>> drm_dbg_kms(dev, "HPD: Re-scheduled debounce work\n");
>> } else {
>> - /* If the aconnector->hdmi_hpd_debounce_work is scheduled, exit early */
>> - if (delayed_work_pending(&aconnector->hdmi_hpd_debounce_work))
>> + /* If the aconnector->hpd_debounce_work is scheduled, exit early */
>> + if (delayed_work_pending(&aconnector->hpd_debounce_work))
>> return;
>> scoped_guard(mutex, &adev->dm.dc_lock) {
>> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
>> index bccb5d354..66fb82961 100644
>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
>> @@ -113,7 +113,7 @@ void amdgpu_dm_irq_resume_late(struct amdgpu_device *adev);
>> struct hpd_rx_irq_offload_work_queue *amdgpu_dm_hpd_rx_irq_create_workqueue(struct amdgpu_device *adev);
>> void amdgpu_dm_hpd_rx_irq_work_suspend(struct amdgpu_display_manager *dm);
>> int amdgpu_dm_register_hpd_handlers(struct amdgpu_device *adev);
>> -void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work);
>> +void amdgpu_dm_hpd_debounce_work(struct work_struct *work);
>> /* IRQ handlers */
>> struct amdgpu_crtc *amdgpu_dm_get_crtc_by_otg_inst(struct amdgpu_device *adev,
>>
>> ---
>> base-commit: c92b5b607c1c8ab786fccf03d62352b82f6539ae
>> change-id: 20260708-hpd-debounce-unify-896ad367bf02
>>
>> Best regards,
>> --
>> Nick Haghiri <nick@haghiri.net>
>>
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-07-13 18:43 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-25 15:04 [RFC PATCH] drm/amd/display: extend HPD debounce filter to DisplayPort SST Nick Haghiri
2026-06-25 19:15 ` Ivan Lipski
2026-06-25 19:45 ` Nick Haghiri
2026-06-26 8:53 ` Michel Dänzer
2026-07-09 11:38 ` Xaver Hugl
2026-07-09 1:20 ` [PATCH v2] drm/amd/display: unify HDMI/DP SST HPD debounce delay Nick Haghiri
2026-07-09 13:15 ` Alex Deucher
2026-07-09 14:15 ` [PATCH v3] drm/amd/display: unify HDMI/DVI/DP " Nick Haghiri
2026-07-09 17:30 ` Ivan Lipski
2026-07-13 18:42 ` Harry Wentland
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®