* [PATCH v12 01/16] drm/bridge: dw-hdmi-qp: Demote i2c bus error messages to debug level
2026-10-05 0:38 [PATCH v12 00/16] Add HDMI 2.0 support to DW HDMI QP TX Cristian Ciocaltea
@ 2026-10-05 0:38 ` Cristian Ciocaltea
2026-10-07 9:05 ` Diederik de Haas
2026-10-05 0:38 ` [PATCH v12 02/16] drm/bridge: dw-hdmi-qp: Provide .{enable,disable}_hpd() PHY ops Cristian Ciocaltea
` (14 subsequent siblings)
15 siblings, 1 reply; 18+ messages in thread
From: Cristian Ciocaltea @ 2026-10-05 0:38 UTC (permalink / raw)
To: Sandy Huang, Heiko Stübner, Andy Yan, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Algea Cao,
Daniel Stone
Cc: kernel, dri-devel, linux-rockchip, linux-kernel,
linux-arm-kernel, Diederik de Haas
A NACK or timeout on the DDC bus is a normal condition when the sink is
absent or unpowered. Some displays keep HPD asserted and the EDID
EEPROM readable while in standby, but leave the SCDC slave unpowered.
This results in i2c-related error messages on every boot during
scrambling setup, even though the condition is handled gracefully and
the SCDC configuration is restored on the next hotplug event.
Log the i2c bus level failures with dev_dbg_ratelimited() instead,
matching the silent behaviour of the non-QP dw-hdmi i2c bus algorithm.
The DDC users already report failures at the appropriate level, e.g. the
SCDC helpers via drm_scdc_dbg(). This also makes the no-hpd special
casing of the read path messages redundant, so drop it.
Reported-by: Diederik de Haas <diederik@cknow-tech.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index c9568aea98dc..9abcea92b720 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -350,22 +350,14 @@ static int dw_hdmi_qp_i2c_read(struct dw_hdmi_qp *hdmi,
stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10);
if (!stat) {
- if (hdmi->no_hpd)
- dev_dbg_ratelimited(hdmi->dev,
- "i2c read timed out\n");
- else
- dev_err(hdmi->dev, "i2c read timed out\n");
+ dev_dbg_ratelimited(hdmi->dev, "i2c read timed out\n");
dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
return -EAGAIN;
}
/* Check for error condition on the bus */
if (i2c->stat & I2CM_NACK_RCVD_IRQ) {
- if (hdmi->no_hpd)
- dev_dbg_ratelimited(hdmi->dev,
- "i2c read error\n");
- else
- dev_err(hdmi->dev, "i2c read error\n");
+ dev_dbg_ratelimited(hdmi->dev, "i2c read error\n");
dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
return -EIO;
}
@@ -404,14 +396,14 @@ static int dw_hdmi_qp_i2c_write(struct dw_hdmi_qp *hdmi,
stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10);
if (!stat) {
- dev_err(hdmi->dev, "i2c write time out!\n");
+ dev_dbg_ratelimited(hdmi->dev, "i2c write time out!\n");
dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
return -EAGAIN;
}
/* Check for error condition on the bus */
if (i2c->stat & I2CM_NACK_RCVD_IRQ) {
- dev_err(hdmi->dev, "i2c write nack!\n");
+ dev_dbg_ratelimited(hdmi->dev, "i2c write nack!\n");
dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
return -EIO;
}
--
2.55.0
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PATCH v12 01/16] drm/bridge: dw-hdmi-qp: Demote i2c bus error messages to debug level
2026-10-05 0:38 ` [PATCH v12 01/16] drm/bridge: dw-hdmi-qp: Demote i2c bus error messages to debug level Cristian Ciocaltea
@ 2026-10-07 9:05 ` Diederik de Haas
0 siblings, 0 replies; 18+ messages in thread
From: Diederik de Haas @ 2026-10-07 9:05 UTC (permalink / raw)
To: Cristian Ciocaltea, Sandy Huang, Heiko Stübner, Andy Yan,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Algea Cao, Daniel Stone
Cc: kernel, dri-devel, linux-rockchip, linux-kernel,
linux-arm-kernel, Diederik de Haas
Hi Cristian,
On Mon Oct 5, 2026 at 2:38 AM CEST, Cristian Ciocaltea wrote:
> A NACK or timeout on the DDC bus is a normal condition when the sink is
> absent or unpowered. Some displays keep HPD asserted and the EDID
> EEPROM readable while in standby, but leave the SCDC slave unpowered.
> This results in i2c-related error messages on every boot during
> scrambling setup, even though the condition is handled gracefully and
> the SCDC configuration is restored on the next hotplug event.
>
> Log the i2c bus level failures with dev_dbg_ratelimited() instead,
> matching the silent behaviour of the non-QP dw-hdmi i2c bus algorithm.
I can confirm that with this patch I no longer see warnings like this:
dwhdmiqp-rockchip fde80000.hdmi: i2c read error
dwhdmiqp-rockchip fde80000.hdmi: i2c write nack!
When I add ``dw_hdmi_qp.dyndbg`` to the kernel command line, I do see
them at debug level.
This is when I boot up my NanoPC-T6 LTS connected to my 4K TV while it
is turned OFF.
When I boot up my NanoPC-T6 LTS connected to my 4K TV while it is
turned ON, dmesg is rather clean wrt dw_hdmi_qp both with and without
``dw_hdmi_qp.dyndbg`` in my kernel command line.
So it acts exactly as intended :-) Thus feel free to include my:
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS
Thanks!
Cheers,
Diederik
> The DDC users already report failures at the appropriate level, e.g. the
> SCDC helpers via drm_scdc_dbg(). This also makes the no-hpd special
> casing of the read path messages redundant, so drop it.
>
> Reported-by: Diederik de Haas <diederik@cknow-tech.com>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
> ---
> drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 16 ++++------------
> 1 file changed, 4 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
> index c9568aea98dc..9abcea92b720 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
> @@ -350,22 +350,14 @@ static int dw_hdmi_qp_i2c_read(struct dw_hdmi_qp *hdmi,
>
> stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10);
> if (!stat) {
> - if (hdmi->no_hpd)
> - dev_dbg_ratelimited(hdmi->dev,
> - "i2c read timed out\n");
> - else
> - dev_err(hdmi->dev, "i2c read timed out\n");
> + dev_dbg_ratelimited(hdmi->dev, "i2c read timed out\n");
> dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
> return -EAGAIN;
> }
>
> /* Check for error condition on the bus */
> if (i2c->stat & I2CM_NACK_RCVD_IRQ) {
> - if (hdmi->no_hpd)
> - dev_dbg_ratelimited(hdmi->dev,
> - "i2c read error\n");
> - else
> - dev_err(hdmi->dev, "i2c read error\n");
> + dev_dbg_ratelimited(hdmi->dev, "i2c read error\n");
> dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
> return -EIO;
> }
> @@ -404,14 +396,14 @@ static int dw_hdmi_qp_i2c_write(struct dw_hdmi_qp *hdmi,
>
> stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10);
> if (!stat) {
> - dev_err(hdmi->dev, "i2c write time out!\n");
> + dev_dbg_ratelimited(hdmi->dev, "i2c write time out!\n");
> dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
> return -EAGAIN;
> }
>
> /* Check for error condition on the bus */
> if (i2c->stat & I2CM_NACK_RCVD_IRQ) {
> - dev_err(hdmi->dev, "i2c write nack!\n");
> + dev_dbg_ratelimited(hdmi->dev, "i2c write nack!\n");
> dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
> return -EIO;
> }
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v12 02/16] drm/bridge: dw-hdmi-qp: Provide .{enable,disable}_hpd() PHY ops
2026-10-05 0:38 [PATCH v12 00/16] Add HDMI 2.0 support to DW HDMI QP TX Cristian Ciocaltea
2026-10-05 0:38 ` [PATCH v12 01/16] drm/bridge: dw-hdmi-qp: Demote i2c bus error messages to debug level Cristian Ciocaltea
@ 2026-10-05 0:38 ` Cristian Ciocaltea
2026-10-05 0:38 ` [PATCH v12 03/16] drm/bridge: dw-hdmi-qp: Remove unused workqueue include and define Cristian Ciocaltea
` (13 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Cristian Ciocaltea @ 2026-10-05 0:38 UTC (permalink / raw)
To: Sandy Huang, Heiko Stübner, Andy Yan, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Algea Cao,
Daniel Stone
Cc: kernel, dri-devel, linux-rockchip, linux-kernel,
linux-arm-kernel, Maud Spierings, Diederik de Haas,
Robin Räber, Igor Paunovic
Implement the .hpd_enable() and .hpd_disable() bridge callbacks and
extend dw_hdmi_qp_phy_ops with corresponding hooks.
This enables the DRM core to control when HPD interrupts are armed,
which is needed to prevent premature interrupt delivery before the
connector is fully initialized, and to properly quiesce HPD during
suspend.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Tested-by: Robin Räber <robin.raebi@gmail.com>
Tested-by: Igor Paunovic <royalnet026@gmail.com> # RK3588 Orange Pi 5 Plus, dual HDMI
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 18 ++++++++++++++++++
include/drm/bridge/dw_hdmi_qp.h | 2 ++
2 files changed, 20 insertions(+)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 9abcea92b720..bed743ce3909 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -974,6 +974,22 @@ static int dw_hdmi_qp_cec_transmit(struct drm_bridge *bridge, u8 attempts,
#define dw_hdmi_qp_cec_transmit NULL
#endif /* CONFIG_DRM_DW_HDMI_QP_CEC */
+static void dw_hdmi_qp_bridge_hpd_enable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+ if (hdmi->phy.ops->enable_hpd)
+ hdmi->phy.ops->enable_hpd(hdmi, hdmi->phy.data);
+}
+
+static void dw_hdmi_qp_bridge_hpd_disable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+ if (hdmi->phy.ops->disable_hpd)
+ hdmi->phy.ops->disable_hpd(hdmi, hdmi->phy.data);
+}
+
static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
.atomic_get_output_bus_fmts = drm_atomic_helper_bridge_get_hdmi_output_bus_fmts,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
@@ -982,6 +998,8 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
.atomic_enable = dw_hdmi_qp_bridge_atomic_enable,
.atomic_disable = dw_hdmi_qp_bridge_atomic_disable,
.detect = dw_hdmi_qp_bridge_detect,
+ .hpd_enable = dw_hdmi_qp_bridge_hpd_enable,
+ .hpd_disable = dw_hdmi_qp_bridge_hpd_disable,
.edid_read = dw_hdmi_qp_bridge_edid_read,
.hdmi_tmds_char_rate_valid = dw_hdmi_qp_bridge_tmds_char_rate_valid,
.hdmi_clear_avi_infoframe = dw_hdmi_qp_bridge_clear_avi_infoframe,
diff --git a/include/drm/bridge/dw_hdmi_qp.h b/include/drm/bridge/dw_hdmi_qp.h
index 6ea9c561cfef..b80fceffc315 100644
--- a/include/drm/bridge/dw_hdmi_qp.h
+++ b/include/drm/bridge/dw_hdmi_qp.h
@@ -17,6 +17,8 @@ struct dw_hdmi_qp_phy_ops {
void (*disable)(struct dw_hdmi_qp *hdmi, void *data);
enum drm_connector_status (*read_hpd)(struct dw_hdmi_qp *hdmi, void *data);
void (*setup_hpd)(struct dw_hdmi_qp *hdmi, void *data);
+ void (*enable_hpd)(struct dw_hdmi_qp *hdmi, void *data);
+ void (*disable_hpd)(struct dw_hdmi_qp *hdmi, void *data);
};
struct dw_hdmi_qp_plat_data {
--
2.55.0
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH v12 03/16] drm/bridge: dw-hdmi-qp: Remove unused workqueue include and define
2026-10-05 0:38 [PATCH v12 00/16] Add HDMI 2.0 support to DW HDMI QP TX Cristian Ciocaltea
2026-10-05 0:38 ` [PATCH v12 01/16] drm/bridge: dw-hdmi-qp: Demote i2c bus error messages to debug level Cristian Ciocaltea
2026-10-05 0:38 ` [PATCH v12 02/16] drm/bridge: dw-hdmi-qp: Provide .{enable,disable}_hpd() PHY ops Cristian Ciocaltea
@ 2026-10-05 0:38 ` Cristian Ciocaltea
2026-10-05 0:38 ` [PATCH v12 04/16] drm/bridge: dw-hdmi-qp: Add HDMI 2.0 scrambling support Cristian Ciocaltea
` (12 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Cristian Ciocaltea @ 2026-10-05 0:38 UTC (permalink / raw)
To: Sandy Huang, Heiko Stübner, Andy Yan, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Algea Cao,
Daniel Stone
Cc: kernel, dri-devel, linux-rockchip, linux-kernel, linux-arm-kernel
linux/workqueue.h is no longer needed, and SCRAMB_POLL_DELAY_MS is
unused.
Remove them.
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index bed743ce3909..4b55bed42ab7 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -15,7 +15,6 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/workqueue.h>
#include <drm/bridge/dw_hdmi_qp.h>
#include <drm/display/drm_hdmi_helper.h>
@@ -38,8 +37,6 @@
#define DDC_CI_ADDR 0x37
#define DDC_SEGMENT_ADDR 0x30
-#define SCRAMB_POLL_DELAY_MS 3000
-
struct dw_hdmi_qp_i2c {
struct i2c_adapter adap;
--
2.55.0
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH v12 04/16] drm/bridge: dw-hdmi-qp: Add HDMI 2.0 scrambling support
2026-10-05 0:38 [PATCH v12 00/16] Add HDMI 2.0 support to DW HDMI QP TX Cristian Ciocaltea
` (2 preceding siblings ...)
2026-10-05 0:38 ` [PATCH v12 03/16] drm/bridge: dw-hdmi-qp: Remove unused workqueue include and define Cristian Ciocaltea
@ 2026-10-05 0:38 ` Cristian Ciocaltea
2026-10-05 0:38 ` [PATCH v12 05/16] drm/bridge: dw-hdmi-qp: Provide dw_hdmi_qp_hpd_notify() helper Cristian Ciocaltea
` (11 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Cristian Ciocaltea @ 2026-10-05 0:38 UTC (permalink / raw)
To: Sandy Huang, Heiko Stübner, Andy Yan, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Algea Cao,
Daniel Stone
Cc: kernel, dri-devel, linux-rockchip, linux-kernel,
linux-arm-kernel, Maud Spierings, Diederik de Haas,
Robin Räber, Igor Paunovic
Add support for SCDC scrambling and the high TMDS clock ratio required
by HDMI 2.0 modes with TMDS character rates above 340 MHz, such as
4K@60Hz.
Hook the bridge into the DRM HDMI connector scrambling helpers so the
sink-side SCDC state and the controller scrambler are updated together
as part of the atomic enable and disable paths. This allows the driver
to advertise HDMI 2.0 support when HPD is available.
Keep no-HPD configurations limited to HDMI 1.4, since SCDC access
requires a connected HDMI sink.
Modes above the HDMI 2.0 600 MHz TMDS character-rate limit are now
implicitly rejected by the DRM HDMI connector/bridge infrastructure,
making the dw_hdmi_qp_bridge_tmds_char_rate_valid() callback redundant.
Drop it.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Acked-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Robin Räber <robin.raebi@gmail.com>
Tested-by: Igor Paunovic <royalnet026@gmail.com> # RK3588 Orange Pi 5 Plus, dual HDMI
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 60 ++++++++++++++++++----------
1 file changed, 39 insertions(+), 21 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 4b55bed42ab7..14723ee5cb05 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd.
* Copyright (c) 2024 Collabora Ltd.
+ * Copyright (c) 2025 Amazon.com, Inc. or its affiliates.
*
* Author: Algea Cao <algea.cao@rock-chips.com>
* Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
@@ -536,6 +537,7 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
struct drm_connector_state *conn_state;
struct drm_connector *connector;
unsigned int op_mode;
+ int ret;
connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
if (WARN_ON(!connector))
@@ -546,14 +548,20 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
return;
if (connector->display_info.is_hdmi) {
- dev_dbg(hdmi->dev, "%s mode=HDMI %s rate=%llu bpc=%u\n", __func__,
- drm_hdmi_connector_get_output_format_name(conn_state->hdmi.output_format),
- conn_state->hdmi.tmds_char_rate, conn_state->hdmi.output_bpc);
op_mode = 0;
hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate;
+
+ ret = drm_connector_hdmi_enable_scrambling(connector, conn_state);
+ if (ret)
+ dev_warn(hdmi->dev, "Failed to enable scrambling: %d\n", ret);
+
+ dev_dbg(hdmi->dev, "%s mode=HDMI %s rate=%llu bpc=%u scramb=%d\n", __func__,
+ drm_hdmi_connector_get_output_format_name(conn_state->hdmi.output_format),
+ conn_state->hdmi.tmds_char_rate, conn_state->hdmi.output_bpc,
+ connector->hdmi.scrambler_enabled);
} else {
- dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__);
op_mode = OPMODE_DVI;
+ dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__);
}
hdmi->phy.ops->init(hdmi, hdmi->phy.data);
@@ -568,9 +576,13 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
struct drm_atomic_commit *state)
{
struct dw_hdmi_qp *hdmi = bridge->driver_private;
+ struct drm_connector *connector;
hdmi->tmds_char_rate = 0;
+ connector = drm_atomic_get_old_connector_for_encoder(state, bridge->encoder);
+ drm_connector_hdmi_disable_scrambling(connector);
+
hdmi->phy.ops->disable(hdmi, hdmi->phy.data);
}
@@ -605,24 +617,24 @@ dw_hdmi_qp_bridge_edid_read(struct drm_bridge *bridge,
return drm_edid;
}
-static enum drm_mode_status
-dw_hdmi_qp_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,
- const struct drm_display_mode *mode,
- unsigned long long rate)
+static int dw_hdmi_qp_bridge_scrambler_enable(struct drm_bridge *bridge)
{
struct dw_hdmi_qp *hdmi = bridge->driver_private;
- /*
- * TODO: when hdmi->no_hpd is 1 we must not support modes that
- * require scrambling, including every mode with a clock above
- * HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ.
- */
- if (rate > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ) {
- dev_dbg(hdmi->dev, "Unsupported TMDS char rate: %lld\n", rate);
- return MODE_CLOCK_HIGH;
- }
+ dw_hdmi_qp_write(hdmi, 1, SCRAMB_CONFIG0);
+ dev_dbg(hdmi->dev, "scrambler enabled\n");
- return MODE_OK;
+ return 0;
+}
+
+static int dw_hdmi_qp_bridge_scrambler_disable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+ dw_hdmi_qp_write(hdmi, 0, SCRAMB_CONFIG0);
+ dev_dbg(hdmi->dev, "scrambler disabled\n");
+
+ return 0;
}
static int dw_hdmi_qp_bridge_clear_avi_infoframe(struct drm_bridge *bridge)
@@ -998,7 +1010,8 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
.hpd_enable = dw_hdmi_qp_bridge_hpd_enable,
.hpd_disable = dw_hdmi_qp_bridge_hpd_disable,
.edid_read = dw_hdmi_qp_bridge_edid_read,
- .hdmi_tmds_char_rate_valid = dw_hdmi_qp_bridge_tmds_char_rate_valid,
+ .hdmi_scrambler_enable = dw_hdmi_qp_bridge_scrambler_enable,
+ .hdmi_scrambler_disable = dw_hdmi_qp_bridge_scrambler_disable,
.hdmi_clear_avi_infoframe = dw_hdmi_qp_bridge_clear_avi_infoframe,
.hdmi_write_avi_infoframe = dw_hdmi_qp_bridge_write_avi_infoframe,
.hdmi_clear_hdmi_infoframe = dw_hdmi_qp_bridge_clear_hdmi_infoframe,
@@ -1126,13 +1139,18 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
DRM_BRIDGE_OP_HDMI_AUDIO |
DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME |
DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME;
- if (!hdmi->no_hpd)
- hdmi->bridge.ops |= DRM_BRIDGE_OP_HPD;
hdmi->bridge.of_node = pdev->dev.of_node;
hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
hdmi->bridge.vendor = "Synopsys";
hdmi->bridge.product = "DW HDMI QP TX";
+ if (hdmi->no_hpd) {
+ hdmi->bridge.supported_hdmi_ver = HDMI_VERSION_1_4;
+ } else {
+ hdmi->bridge.supported_hdmi_ver = HDMI_VERSION_2_0;
+ hdmi->bridge.ops |= DRM_BRIDGE_OP_HPD;
+ }
+
if (plat_data->supported_formats)
hdmi->bridge.supported_formats = plat_data->supported_formats;
--
2.55.0
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH v12 05/16] drm/bridge: dw-hdmi-qp: Provide dw_hdmi_qp_hpd_notify() helper
2026-10-05 0:38 [PATCH v12 00/16] Add HDMI 2.0 support to DW HDMI QP TX Cristian Ciocaltea
` (3 preceding siblings ...)
2026-10-05 0:38 ` [PATCH v12 04/16] drm/bridge: dw-hdmi-qp: Add HDMI 2.0 scrambling support Cristian Ciocaltea
@ 2026-10-05 0:38 ` Cristian Ciocaltea
2026-10-05 0:38 ` [PATCH v12 06/16] drm/rockchip: dw_hdmi_qp: Fix invalid drvdata access in PM ops Cristian Ciocaltea
` (10 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Cristian Ciocaltea @ 2026-10-05 0:38 UTC (permalink / raw)
To: Sandy Huang, Heiko Stübner, Andy Yan, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Algea Cao,
Daniel Stone
Cc: kernel, dri-devel, linux-rockchip, linux-kernel,
linux-arm-kernel, Maud Spierings, Diederik de Haas,
Robin Räber, Igor Paunovic
Export dw_hdmi_qp_hpd_notify() for platform drivers to report hot-plug
detection events. Unlike drm_helper_hpd_irq_event() which polls all
connectors, this helper targets only the affected connector and ensures
.detect_ctx() is invoked on reconnection events to trigger SCDC state
recovery.
Track the connector in use in curr_conn, set and cleared by the atomic
enable/disable hooks. Since the helper runs asynchronously from
IRQ/work context, hold a reference on that connector for as long as the
bridge is enabled, so that the pointer is always safe to dereference.
Otherwise validity would rest on the platform glue quiescing HPD before
the DRM-managed connector is freed during teardown, risking a
use-after-free on a late HPD event.
The helper must take its own temporary reference while running, because
the long-lived reference above only guarantees the pointer is valid at
the time it is read, not that the connector survives a concurrent
atomic_disable dropping that reference while the helper is still using
it. Moreover, reading the pointer and acquiring the temporary reference
must be atomic with respect to atomic_disable, otherwise a window exists
where drm_connector_get() is called on a connector whose refcount
already reached zero, hence guard curr_conn with a mutex for this
purpose. Holding the mutex across the whole helper instead is not an
option, as it takes modeset locks while atomic_disable is called with
them held.
Also note that this helper may sleep, so it must only be called from a
threaded HPD interrupt handler or a work function.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Tested-by: Robin Räber <robin.raebi@gmail.com>
Tested-by: Igor Paunovic <royalnet026@gmail.com> # RK3588 Orange Pi 5 Plus, dual HDMI
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 59 ++++++++++++++++++++++++++++
include/drm/bridge/dw_hdmi_qp.h | 1 +
2 files changed, 60 insertions(+)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 14723ee5cb05..54181b052fe2 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -28,6 +28,7 @@
#include <drm/drm_edid.h>
#include <drm/drm_modes.h>
#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
#include <media/cec.h>
@@ -81,6 +82,9 @@ struct dw_hdmi_qp {
struct regmap *regm;
int main_irq;
+ /* Guards curr_conn between atomic hooks and HPD notify readers */
+ struct mutex mutex;
+ struct drm_connector *curr_conn;
unsigned long tmds_char_rate;
bool no_hpd;
};
@@ -564,6 +568,10 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__);
}
+ drm_connector_get(connector);
+ scoped_guard(mutex, &hdmi->mutex)
+ hdmi->curr_conn = connector;
+
hdmi->phy.ops->init(hdmi, hdmi->phy.data);
dw_hdmi_qp_mod(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0);
@@ -578,6 +586,13 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
struct dw_hdmi_qp *hdmi = bridge->driver_private;
struct drm_connector *connector;
+ scoped_guard(mutex, &hdmi->mutex) {
+ if (hdmi->curr_conn) {
+ drm_connector_put(hdmi->curr_conn);
+ hdmi->curr_conn = NULL;
+ }
+ }
+
hdmi->tmds_char_rate = 0;
connector = drm_atomic_get_old_connector_for_encoder(state, bridge->encoder);
@@ -1099,6 +1114,10 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
if (IS_ERR(hdmi))
return ERR_CAST(hdmi);
+ ret = devm_mutex_init(dev, &hdmi->mutex);
+ if (ret)
+ return ERR_PTR(ret);
+
hdmi->dev = dev;
regs = devm_platform_ioremap_resource(pdev, 0);
@@ -1194,6 +1213,46 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
}
EXPORT_SYMBOL_GPL(dw_hdmi_qp_bind);
+/**
+ * dw_hdmi_qp_hpd_notify() - Notify a hot-plug detection event
+ * @hdmi: pointer to the DW HDMI QP controller
+ *
+ * Platform drivers should call this from their threaded IRQ handler or work
+ * function to notify the bridge of a connection status change.
+ * The bridge's .read_hpd() phy_ops callback is used to read the current
+ * connection status.
+ */
+void dw_hdmi_qp_hpd_notify(struct dw_hdmi_qp *hdmi)
+{
+ enum drm_connector_status status;
+ struct drm_connector *conn;
+
+ scoped_guard(mutex, &hdmi->mutex) {
+ conn = hdmi->curr_conn;
+ if (conn)
+ drm_connector_get(conn);
+ }
+
+ status = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);
+ dev_dbg(hdmi->dev, "%s status=%d\n", __func__, status);
+
+ /*
+ * When the display pipeline has been already active, switch to
+ * drm_connector_helper_hpd_irq_event() to ensure .detect_ctx()
+ * gets invoked, i.e. via drm_helper_probe_detect(), because
+ * drm_bridge_hpd_notify() defers to a delayed hotplug path in
+ * this case.
+ */
+ if (conn && status == connector_status_connected)
+ drm_connector_helper_hpd_irq_event(conn);
+ else
+ drm_bridge_hpd_notify(&hdmi->bridge, status);
+
+ if (conn)
+ drm_connector_put(conn);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_qp_hpd_notify);
+
void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi)
{
disable_irq(hdmi->main_irq);
diff --git a/include/drm/bridge/dw_hdmi_qp.h b/include/drm/bridge/dw_hdmi_qp.h
index b80fceffc315..b4fb1c578a5b 100644
--- a/include/drm/bridge/dw_hdmi_qp.h
+++ b/include/drm/bridge/dw_hdmi_qp.h
@@ -36,6 +36,7 @@ struct dw_hdmi_qp_plat_data {
struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
struct drm_encoder *encoder,
const struct dw_hdmi_qp_plat_data *plat_data);
+void dw_hdmi_qp_hpd_notify(struct dw_hdmi_qp *hdmi);
void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi);
void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi);
#endif /* __DW_HDMI_QP__ */
--
2.55.0
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH v12 06/16] drm/rockchip: dw_hdmi_qp: Fix invalid drvdata access in PM ops
2026-10-05 0:38 [PATCH v12 00/16] Add HDMI 2.0 support to DW HDMI QP TX Cristian Ciocaltea
` (4 preceding siblings ...)
2026-10-05 0:38 ` [PATCH v12 05/16] drm/bridge: dw-hdmi-qp: Provide dw_hdmi_qp_hpd_notify() helper Cristian Ciocaltea
@ 2026-10-05 0:38 ` Cristian Ciocaltea
2026-10-05 0:38 ` [PATCH v12 07/16] drm/rockchip: dw_hdmi_qp: Cancel pending HPD work on suspend Cristian Ciocaltea
` (9 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Cristian Ciocaltea @ 2026-10-05 0:38 UTC (permalink / raw)
To: Sandy Huang, Heiko Stübner, Andy Yan, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Algea Cao,
Daniel Stone
Cc: kernel, dri-devel, linux-rockchip, linux-kernel,
linux-arm-kernel, Sashiko, Robin Räber, Igor Paunovic
The system-sleep PM callbacks fetch the driver state via
dev_get_drvdata() and dereference it unconditionally. However, the
platform device is bound by ->probe(), which merely registers a
component, hence the callbacks may well run when no valid state is
available:
- Before the aggregate driver calls ->bind(), e.g. when the system
suspends while probing is still deferred waiting for the VOP,
dev_get_drvdata() returns NULL.
- After ->unbind(), or when ->bind() fails past platform_set_drvdata(),
drvdata is left pointing to memory obtained via drmm_kzalloc(), which
is released together with the DRM device, while this platform device
remains bound and PM-capable.
Publish the driver data only after ->bind() completes successfully, and
clear it in ->unbind(). This ensures that a non-NULL drvdata always
represents live state, allowing each PM callback to rely on a single
NULL check.
Fixes: 128a9bf8ace2 ("drm/rockchip: Add basic RK3588 HDMI output support")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260702151550.8E14D1F000E9@smtp.kernel.org/
Closes: https://lore.kernel.org/all/20260723014811.1F9F01F000E9@smtp.kernel.org/
Tested-by: Robin Räber <robin.raebi@gmail.com>
Tested-by: Igor Paunovic <royalnet026@gmail.com> # RK3588 Orange Pi 5 Plus, dual HDMI
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 9c4cf68d79d5..646a4cb96830 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -683,8 +683,6 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
if (ret)
return dev_err_probe(hdmi->dev, ret, "Failed to init encoder");
- platform_set_drvdata(pdev, hdmi);
-
hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data);
if (IS_ERR(hdmi->hdmi))
return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hdmi),
@@ -695,6 +693,8 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
return dev_err_probe(hdmi->dev, PTR_ERR(connector),
"Failed to init bridge connector\n");
+ platform_set_drvdata(pdev, hdmi);
+
return 0;
}
@@ -704,6 +704,8 @@ static void dw_hdmi_qp_rockchip_unbind(struct device *dev,
{
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
+ dev_set_drvdata(dev, NULL);
+
cancel_delayed_work_sync(&hdmi->hpd_work);
}
@@ -726,7 +728,8 @@ static int __maybe_unused dw_hdmi_qp_rockchip_suspend(struct device *dev)
{
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
- dw_hdmi_qp_suspend(dev, hdmi->hdmi);
+ if (hdmi)
+ dw_hdmi_qp_suspend(dev, hdmi->hdmi);
return 0;
}
@@ -735,6 +738,9 @@ static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev)
{
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
+ if (!hdmi)
+ return 0;
+
hdmi->ctrl_ops->io_init(hdmi);
dw_hdmi_qp_resume(dev, hdmi->hdmi);
--
2.55.0
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH v12 07/16] drm/rockchip: dw_hdmi_qp: Cancel pending HPD work on suspend
2026-10-05 0:38 [PATCH v12 00/16] Add HDMI 2.0 support to DW HDMI QP TX Cristian Ciocaltea
` (5 preceding siblings ...)
2026-10-05 0:38 ` [PATCH v12 06/16] drm/rockchip: dw_hdmi_qp: Fix invalid drvdata access in PM ops Cristian Ciocaltea
@ 2026-10-05 0:38 ` Cristian Ciocaltea
2026-10-05 0:38 ` [PATCH v12 08/16] drm/rockchip: dw_hdmi_qp: Add missing newlines in dev_err_probe() messages Cristian Ciocaltea
` (8 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Cristian Ciocaltea @ 2026-10-05 0:38 UTC (permalink / raw)
To: Sandy Huang, Heiko Stübner, Andy Yan, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Algea Cao,
Daniel Stone
Cc: kernel, dri-devel, linux-rockchip, linux-kernel,
linux-arm-kernel, Sashiko, Robin Räber, Igor Paunovic
The HPD threaded handler debounces hotplug events by delaying
hdmi->hpd_work for 150 ms. Nothing discards that work when the system
goes to sleep: drm_kms_helper_poll_disable() only disables the HPD IRQ
line via the bridge .hpd_disable() op, and disable_irq() merely waits
for the threaded handler, which has already returned after arming the
timer.
If the debounce expires during suspend, its non-freezable work may probe
the connector and read the EDID over DDC. Since genpd powers off the
HDMI controller's power domain in ->suspend_noirq(), this access may
hit unpowered hardware and hang the system.
Cancel the work in the suspend callback. The DRM device is registered
as a consumer of the HDMI device, so it always suspends first and the
HPD IRQ is already disabled by that point, meaning nothing can re-arm
the work behind our back. No counterpart is needed on resume, as the
work gets scheduled again on the next hotplug interrupt.
Fixes: 128a9bf8ace2 ("drm/rockchip: Add basic RK3588 HDMI output support")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260723015909.7F79A1F000E9@smtp.kernel.org/
Tested-by: Robin Räber <robin.raebi@gmail.com>
Tested-by: Igor Paunovic <royalnet026@gmail.com> # RK3588 Orange Pi 5 Plus, dual HDMI
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 646a4cb96830..42f2627e1a05 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -728,8 +728,12 @@ static int __maybe_unused dw_hdmi_qp_rockchip_suspend(struct device *dev)
{
struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
- if (hdmi)
- dw_hdmi_qp_suspend(dev, hdmi->hdmi);
+ if (!hdmi)
+ return 0;
+
+ cancel_delayed_work_sync(&hdmi->hpd_work);
+
+ dw_hdmi_qp_suspend(dev, hdmi->hdmi);
return 0;
}
--
2.55.0
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH v12 08/16] drm/rockchip: dw_hdmi_qp: Add missing newlines in dev_err_probe() messages
2026-10-05 0:38 [PATCH v12 00/16] Add HDMI 2.0 support to DW HDMI QP TX Cristian Ciocaltea
` (6 preceding siblings ...)
2026-10-05 0:38 ` [PATCH v12 07/16] drm/rockchip: dw_hdmi_qp: Cancel pending HPD work on suspend Cristian Ciocaltea
@ 2026-10-05 0:38 ` Cristian Ciocaltea
2026-10-05 0:38 ` [PATCH v12 09/16] drm/rockchip: dw_hdmi_qp: Use local dev variable consistently in bind() Cristian Ciocaltea
` (7 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Cristian Ciocaltea @ 2026-10-05 0:38 UTC (permalink / raw)
To: Sandy Huang, Heiko Stübner, Andy Yan, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Algea Cao,
Daniel Stone
Cc: kernel, dri-devel, linux-rockchip, linux-kernel,
linux-arm-kernel, Maud Spierings, Diederik de Haas,
Robin Räber, Igor Paunovic
Add the missing trailing newlines to a couple of dev_err_probe() calls
in dw_hdmi_qp_rockchip_bind().
Fixes: b6736a4ea3fa ("drm/rockchip: dw_hdmi_qp: Improve error handling with dev_err_probe()")
Fixes: e1f7b7cbd74c ("drm/rockchip: dw_hdmi_qp: Switch to drmm_encoder_init()")
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Tested-by: Robin Räber <robin.raebi@gmail.com>
Tested-by: Igor Paunovic <royalnet026@gmail.com> # RK3588 Orange Pi 5 Plus, dual HDMI
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 42f2627e1a05..df0e2bb1eedc 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -681,12 +681,12 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs);
ret = drmm_encoder_init(drm, encoder, NULL, DRM_MODE_ENCODER_TMDS, NULL);
if (ret)
- return dev_err_probe(hdmi->dev, ret, "Failed to init encoder");
+ return dev_err_probe(hdmi->dev, ret, "Failed to init encoder\n");
hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data);
if (IS_ERR(hdmi->hdmi))
return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hdmi),
- "Failed to bind dw-hdmi-qp");
+ "Failed to bind dw-hdmi-qp\n");
connector = drm_bridge_connector_init(drm, encoder);
if (IS_ERR(connector))
--
2.55.0
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH v12 09/16] drm/rockchip: dw_hdmi_qp: Use local dev variable consistently in bind()
2026-10-05 0:38 [PATCH v12 00/16] Add HDMI 2.0 support to DW HDMI QP TX Cristian Ciocaltea
` (7 preceding siblings ...)
2026-10-05 0:38 ` [PATCH v12 08/16] drm/rockchip: dw_hdmi_qp: Add missing newlines in dev_err_probe() messages Cristian Ciocaltea
@ 2026-10-05 0:38 ` Cristian Ciocaltea
2026-10-05 0:38 ` [PATCH v12 10/16] drm/rockchip: dw_hdmi_qp: Avoid spurious HPD IRQ thread wakeups Cristian Ciocaltea
` (6 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Cristian Ciocaltea @ 2026-10-05 0:38 UTC (permalink / raw)
To: Sandy Huang, Heiko Stübner, Andy Yan, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Algea Cao,
Daniel Stone
Cc: kernel, dri-devel, linux-rockchip, linux-kernel,
linux-arm-kernel, Maud Spierings, Diederik de Haas,
Robin Räber, Igor Paunovic
Replace indirect struct device accesses via hdmi->dev and pdev->dev with
the local dev parameter already available in dw_hdmi_qp_rockchip_bind(),
for consistency and readability.
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Tested-by: Robin Räber <robin.raebi@gmail.com>
Tested-by: Igor Paunovic <royalnet026@gmail.com> # RK3588 Orange Pi 5 Plus, dual HDMI
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 33 +++++++++++++-------------
1 file changed, 16 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index df0e2bb1eedc..456bf2f194d7 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -563,7 +563,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
struct clk *ref_clk;
int ret, irq, i;
- if (!pdev->dev.of_node)
+ if (!dev->of_node)
return -ENODEV;
hdmi = drmm_kzalloc(drm, sizeof(*hdmi), GFP_KERNEL);
@@ -583,7 +583,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
return dev_err_probe(dev, -ENODEV, "Missing platform ctrl ops\n");
hdmi->ctrl_ops = cfg->ctrl_ops;
- hdmi->dev = &pdev->dev;
+ hdmi->dev = dev;
hdmi->port_id = -ENODEV;
/* Identify port ID by matching base IO address */
@@ -594,7 +594,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
}
}
if (hdmi->port_id < 0)
- return dev_err_probe(hdmi->dev, hdmi->port_id,
+ return dev_err_probe(dev, hdmi->port_id,
"Failed to match HDMI port ID\n");
plat_data.phy_ops = cfg->phy_ops;
@@ -622,37 +622,36 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
hdmi->regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
"rockchip,grf");
if (IS_ERR(hdmi->regmap))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->regmap),
+ return dev_err_probe(dev, PTR_ERR(hdmi->regmap),
"Unable to get rockchip,grf\n");
hdmi->vo_regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
"rockchip,vo-grf");
if (IS_ERR(hdmi->vo_regmap))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->vo_regmap),
+ return dev_err_probe(dev, PTR_ERR(hdmi->vo_regmap),
"Unable to get rockchip,vo-grf\n");
- ret = devm_clk_bulk_get_all_enabled(hdmi->dev, &clks);
+ ret = devm_clk_bulk_get_all_enabled(dev, &clks);
if (ret < 0)
- return dev_err_probe(hdmi->dev, ret, "Failed to get clocks\n");
+ return dev_err_probe(dev, ret, "Failed to get clocks\n");
- ref_clk = clk_get(hdmi->dev, "ref");
+ ref_clk = clk_get(dev, "ref");
if (IS_ERR(ref_clk))
- return dev_err_probe(hdmi->dev, PTR_ERR(ref_clk),
+ return dev_err_probe(dev, PTR_ERR(ref_clk),
"Failed to get ref clock\n");
plat_data.ref_clk_rate = clk_get_rate(ref_clk);
clk_put(ref_clk);
- hdmi->frl_enable_gpio = devm_gpiod_get_optional(hdmi->dev, "frl-enable",
+ hdmi->frl_enable_gpio = devm_gpiod_get_optional(dev, "frl-enable",
GPIOD_OUT_LOW);
if (IS_ERR(hdmi->frl_enable_gpio))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->frl_enable_gpio),
+ return dev_err_probe(dev, PTR_ERR(hdmi->frl_enable_gpio),
"Failed to request FRL enable GPIO\n");
hdmi->phy = devm_of_phy_get_by_index(dev, dev->of_node, 0);
if (IS_ERR(hdmi->phy))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->phy),
- "Failed to get phy\n");
+ return dev_err_probe(dev, PTR_ERR(hdmi->phy), "Failed to get phy\n");
cfg->ctrl_ops->io_init(hdmi);
@@ -670,7 +669,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
if (irq < 0)
return irq;
- ret = devm_request_threaded_irq(hdmi->dev, irq,
+ ret = devm_request_threaded_irq(dev, irq,
cfg->ctrl_ops->hardirq_callback,
cfg->ctrl_ops->irq_callback,
IRQF_SHARED, "dw-hdmi-qp-hpd",
@@ -681,16 +680,16 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs);
ret = drmm_encoder_init(drm, encoder, NULL, DRM_MODE_ENCODER_TMDS, NULL);
if (ret)
- return dev_err_probe(hdmi->dev, ret, "Failed to init encoder\n");
+ return dev_err_probe(dev, ret, "Failed to init encoder\n");
hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data);
if (IS_ERR(hdmi->hdmi))
- return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hdmi),
+ return dev_err_probe(dev, PTR_ERR(hdmi->hdmi),
"Failed to bind dw-hdmi-qp\n");
connector = drm_bridge_connector_init(drm, encoder);
if (IS_ERR(connector))
- return dev_err_probe(hdmi->dev, PTR_ERR(connector),
+ return dev_err_probe(dev, PTR_ERR(connector),
"Failed to init bridge connector\n");
platform_set_drvdata(pdev, hdmi);
--
2.55.0
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH v12 10/16] drm/rockchip: dw_hdmi_qp: Avoid spurious HPD IRQ thread wakeups
2026-10-05 0:38 [PATCH v12 00/16] Add HDMI 2.0 support to DW HDMI QP TX Cristian Ciocaltea
` (8 preceding siblings ...)
2026-10-05 0:38 ` [PATCH v12 09/16] drm/rockchip: dw_hdmi_qp: Use local dev variable consistently in bind() Cristian Ciocaltea
@ 2026-10-05 0:38 ` Cristian Ciocaltea
2026-10-05 0:38 ` [PATCH v12 11/16] drm/rockchip: dw_hdmi_qp: Mask RK3576 HPD IRQ in io_init Cristian Ciocaltea
` (5 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Cristian Ciocaltea @ 2026-10-05 0:38 UTC (permalink / raw)
To: Sandy Huang, Heiko Stübner, Andy Yan, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Algea Cao,
Daniel Stone
Cc: kernel, dri-devel, linux-rockchip, linux-kernel,
linux-arm-kernel, Sashiko, Diederik de Haas, Robin Räber,
Igor Paunovic
The RK3576 and RK3588 HPD hardirq handlers read shared status registers
and currently wake the threaded handler whenever any bit in those
registers is set. This can wake the HDMI IRQ thread for unrelated
status bits, and on RK3588 can also wake the thread for the other HDMI
port.
Mask the status value with the SoC-specific HPD interrupt bit before
deciding whether to wake the threaded handler. On RK3588, select the
HDMI0 or HDMI1 HPD bit according to the instance port id.
No stable backport is needed. The issue may only cause spurious IRQ
thread wakeups and does not cause functional breakage.
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260702151346.5A4EC1F000E9@smtp.kernel.org/
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Tested-by: Robin Räber <robin.raebi@gmail.com>
Tested-by: Igor Paunovic <royalnet026@gmail.com> # RK3588 Orange Pi 5 Plus, dual HDMI
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 456bf2f194d7..dff400233154 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -34,6 +34,7 @@
#define RK3576_IOC_HDMI_HPD_STATUS 0xa440
#define RK3576_HDMI_LEVEL_INT BIT(3)
+#define RK3576_HDMI_OHPD_INT BIT(4)
#define RK3576_VO0_GRF_SOC_CON1 0x0004
#define RK3576_HDMI_FRL_MOD BIT(0)
@@ -64,7 +65,9 @@
#define RK3588_HPD_HDMI1_IO_EN_MASK BIT(13)
#define RK3588_GRF_SOC_STATUS1 0x0384
#define RK3588_HDMI0_LEVEL_INT BIT(16)
+#define RK3588_HDMI0_OHPD_INT BIT(17)
#define RK3588_HDMI1_LEVEL_INT BIT(24)
+#define RK3588_HDMI1_OHPD_INT BIT(25)
#define RK3588_GRF_VO1_CON3 0x000c
#define RK3588_GRF_VO1_CON6 0x0018
#define RK3588_COLOR_DEPTH_MASK GENMASK(7, 4)
@@ -348,7 +351,7 @@ static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
u32 intr_stat, val;
regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat);
- if (intr_stat) {
+ if (intr_stat & RK3576_HDMI_OHPD_INT) {
val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
@@ -381,6 +384,8 @@ static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
+ intr_stat &= hdmi->port_id ? RK3588_HDMI1_OHPD_INT : RK3588_HDMI0_OHPD_INT;
+
if (intr_stat) {
if (hdmi->port_id)
val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
--
2.55.0
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH v12 11/16] drm/rockchip: dw_hdmi_qp: Mask RK3576 HPD IRQ in io_init
2026-10-05 0:38 [PATCH v12 00/16] Add HDMI 2.0 support to DW HDMI QP TX Cristian Ciocaltea
` (9 preceding siblings ...)
2026-10-05 0:38 ` [PATCH v12 10/16] drm/rockchip: dw_hdmi_qp: Avoid spurious HPD IRQ thread wakeups Cristian Ciocaltea
@ 2026-10-05 0:38 ` Cristian Ciocaltea
2026-10-05 0:38 ` [PATCH v12 12/16] drm/rockchip: dw_hdmi_qp: Implement .{enable,disable}_hpd() PHY ops Cristian Ciocaltea
` (4 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Cristian Ciocaltea @ 2026-10-05 0:38 UTC (permalink / raw)
To: Sandy Huang, Heiko Stübner, Andy Yan, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Algea Cao,
Daniel Stone
Cc: kernel, dri-devel, linux-rockchip, linux-kernel, linux-arm-kernel
Start with HPD masked, matching RK3588, so the bridge framework controls
when interrupts are armed via hpd_enable().
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index dff400233154..bcfa6646546e 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -432,7 +432,7 @@ static void dw_hdmi_qp_rk3576_io_init(struct rockchip_hdmi_qp *hdmi)
regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON14, val);
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0);
+ val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
}
--
2.55.0
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH v12 12/16] drm/rockchip: dw_hdmi_qp: Implement .{enable,disable}_hpd() PHY ops
2026-10-05 0:38 [PATCH v12 00/16] Add HDMI 2.0 support to DW HDMI QP TX Cristian Ciocaltea
` (10 preceding siblings ...)
2026-10-05 0:38 ` [PATCH v12 11/16] drm/rockchip: dw_hdmi_qp: Mask RK3576 HPD IRQ in io_init Cristian Ciocaltea
@ 2026-10-05 0:38 ` Cristian Ciocaltea
2026-10-05 0:38 ` [PATCH v12 13/16] drm/rockchip: dw_hdmi_qp: Factor out HPD interrupt (un)mask helpers Cristian Ciocaltea
` (3 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Cristian Ciocaltea @ 2026-10-05 0:38 UTC (permalink / raw)
To: Sandy Huang, Heiko Stübner, Andy Yan, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Algea Cao,
Daniel Stone
Cc: kernel, dri-devel, linux-rockchip, linux-kernel,
linux-arm-kernel, Maud Spierings, Diederik de Haas,
Robin Räber, Igor Paunovic
Implement .enable_hpd() and .disable_hpd() phy ops for RK3576 and RK3588
SoCs, used by the corresponding bridge callbacks for HPD activation
control.
Consolidate the interrupt clear-and-unmask sequence into enable_hpd()
and the mask-only operation into disable_hpd(), replacing the open-coded
register writes in the interrupt handlers and io_init().
The .setup_hpd() phy op, which was previously called from
dw_hdmi_qp_init_hw(), is no longer needed and its users are removed.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Tested-by: Robin Räber <robin.raebi@gmail.com>
Tested-by: Igor Paunovic <royalnet026@gmail.com> # RK3588 Orange Pi 5 Plus, dual HDMI
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 78 +++++++++++++-------------
1 file changed, 38 insertions(+), 40 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index bcfa6646546e..9e48ec06eb66 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -277,7 +277,7 @@ dw_hdmi_qp_rk3588_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
return val ? connector_status_connected : connector_status_disconnected;
}
-static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+static void dw_hdmi_qp_rk3588_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
{
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
u32 val;
@@ -292,11 +292,25 @@ static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
}
+static void dw_hdmi_qp_rk3588_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+{
+ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
+ u32 val;
+
+ if (hdmi->port_id)
+ val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
+ else
+ val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
+
+ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+}
+
static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = {
.init = dw_hdmi_qp_rk3588_phy_init,
.disable = dw_hdmi_qp_rk3588_phy_disable,
.read_hpd = dw_hdmi_qp_rk3588_read_hpd,
- .setup_hpd = dw_hdmi_qp_rk3588_setup_hpd,
+ .enable_hpd = dw_hdmi_qp_rk3588_enable_hpd,
+ .disable_hpd = dw_hdmi_qp_rk3588_disable_hpd,
};
static enum drm_connector_status
@@ -311,7 +325,7 @@ dw_hdmi_qp_rk3576_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
connector_status_connected : connector_status_disconnected;
}
-static void dw_hdmi_qp_rk3576_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+static void dw_hdmi_qp_rk3576_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
{
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
u32 val;
@@ -320,14 +334,22 @@ static void dw_hdmi_qp_rk3576_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0));
regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
- regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
+}
+
+static void dw_hdmi_qp_rk3576_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+{
+ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
+
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0,
+ FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1));
}
static const struct dw_hdmi_qp_phy_ops rk3576_hdmi_phy_ops = {
.init = dw_hdmi_qp_rk3588_phy_init,
.disable = dw_hdmi_qp_rk3588_phy_disable,
.read_hpd = dw_hdmi_qp_rk3576_read_hpd,
- .setup_hpd = dw_hdmi_qp_rk3576_setup_hpd,
+ .enable_hpd = dw_hdmi_qp_rk3576_enable_hpd,
+ .disable_hpd = dw_hdmi_qp_rk3576_disable_hpd,
};
static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
@@ -348,13 +370,12 @@ static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 intr_stat, val;
+ u32 intr_stat;
regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat);
- if (intr_stat & RK3576_HDMI_OHPD_INT) {
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ if (intr_stat & RK3576_HDMI_OHPD_INT) {
+ dw_hdmi_qp_rk3576_disable_hpd(NULL, hdmi);
return IRQ_WAKE_THREAD;
}
@@ -364,15 +385,11 @@ static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 val;
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ dw_hdmi_qp_rk3576_enable_hpd(NULL, hdmi);
return IRQ_HANDLED;
}
@@ -380,18 +397,14 @@ static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 intr_stat, val;
+ u32 intr_stat;
regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
intr_stat &= hdmi->port_id ? RK3588_HDMI1_OHPD_INT : RK3588_HDMI0_OHPD_INT;
if (intr_stat) {
- if (hdmi->port_id)
- val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
- else
- val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+ dw_hdmi_qp_rk3588_disable_hpd(NULL, hdmi);
return IRQ_WAKE_THREAD;
}
@@ -401,22 +414,11 @@ static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id)
{
struct rockchip_hdmi_qp *hdmi = dev_id;
- u32 val;
-
- if (hdmi->port_id)
- val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_CLR, 1);
- else
- val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_CLR, 1);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
- if (hdmi->port_id)
- val |= FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 0);
- else
- val |= FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 0);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+ dw_hdmi_qp_rk3588_enable_hpd(NULL, hdmi);
return IRQ_HANDLED;
}
@@ -429,11 +431,11 @@ static void dw_hdmi_qp_rk3576_io_init(struct rockchip_hdmi_qp *hdmi)
FIELD_PREP_WM16(RK3576_SDAIN_MASK, 1) |
FIELD_PREP_WM16(RK3576_HDMI_GRANT_SEL, 1) |
FIELD_PREP_WM16(RK3576_I2S_SEL_MASK, 1);
-
regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON14, val);
- val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
+
+ dw_hdmi_qp_rk3576_disable_hpd(NULL, hdmi);
}
static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
@@ -458,11 +460,7 @@ static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
val = FIELD_PREP_WM16(RK3588_HDMI0_GRANT_SEL, 1);
regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val);
- if (hdmi->port_id)
- val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
- else
- val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
- regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+ dw_hdmi_qp_rk3588_disable_hpd(NULL, hdmi);
}
static void dw_hdmi_qp_rk3576_enc_init(struct rockchip_hdmi_qp *hdmi,
--
2.55.0
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH v12 13/16] drm/rockchip: dw_hdmi_qp: Factor out HPD interrupt (un)mask helpers
2026-10-05 0:38 [PATCH v12 00/16] Add HDMI 2.0 support to DW HDMI QP TX Cristian Ciocaltea
` (11 preceding siblings ...)
2026-10-05 0:38 ` [PATCH v12 12/16] drm/rockchip: dw_hdmi_qp: Implement .{enable,disable}_hpd() PHY ops Cristian Ciocaltea
@ 2026-10-05 0:38 ` Cristian Ciocaltea
2026-10-05 0:38 ` [PATCH v12 14/16] drm/rockchip: dw_hdmi_qp: Control the HPD IRQ line via the bridge HPD ops Cristian Ciocaltea
` (2 subsequent siblings)
15 siblings, 0 replies; 18+ messages in thread
From: Cristian Ciocaltea @ 2026-10-05 0:38 UTC (permalink / raw)
To: Sandy Huang, Heiko Stübner, Andy Yan, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Algea Cao,
Daniel Stone
Cc: kernel, dri-devel, linux-rockchip, linux-kernel,
linux-arm-kernel, Diederik de Haas, Robin Räber,
Igor Paunovic
Extract the GRF-level HPD interrupt mask/unmask register writes into
dedicated dw_hdmi_qp_rk35{88,76}_{mask,unmask}_hpd() helpers, and use
them from the .enable_hpd()/.disable_hpd() phy ops as well as the
hardirq, threaded re-arm and io_init() paths.
This is a preparatory refactor that separates the SoC-level HPD mask
from the phy op entry points, so a subsequent change can gate the
platform HPD IRQ line without affecting the debounce paths.
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Tested-by: Robin Räber <robin.raebi@gmail.com>
Tested-by: Igor Paunovic <royalnet026@gmail.com> # RK3588 Orange Pi 5 Plus, dual HDMI
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 54 ++++++++++++++++++--------
1 file changed, 37 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 9e48ec06eb66..ecf12403101d 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -277,9 +277,8 @@ dw_hdmi_qp_rk3588_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
return val ? connector_status_connected : connector_status_disconnected;
}
-static void dw_hdmi_qp_rk3588_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+static void dw_hdmi_qp_rk3588_unmask_hpd(struct rockchip_hdmi_qp *hdmi)
{
- struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
u32 val;
if (hdmi->port_id)
@@ -292,9 +291,8 @@ static void dw_hdmi_qp_rk3588_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
}
-static void dw_hdmi_qp_rk3588_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+static void dw_hdmi_qp_rk3588_mask_hpd(struct rockchip_hdmi_qp *hdmi)
{
- struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
u32 val;
if (hdmi->port_id)
@@ -305,6 +303,20 @@ static void dw_hdmi_qp_rk3588_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data
regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
}
+static void dw_hdmi_qp_rk3588_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+{
+ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
+
+ dw_hdmi_qp_rk3588_unmask_hpd(hdmi);
+}
+
+static void dw_hdmi_qp_rk3588_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+{
+ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
+
+ dw_hdmi_qp_rk3588_mask_hpd(hdmi);
+}
+
static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = {
.init = dw_hdmi_qp_rk3588_phy_init,
.disable = dw_hdmi_qp_rk3588_phy_disable,
@@ -325,23 +337,31 @@ dw_hdmi_qp_rk3576_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
connector_status_connected : connector_status_disconnected;
}
+static void dw_hdmi_qp_rk3576_unmask_hpd(struct rockchip_hdmi_qp *hdmi)
+{
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0,
+ FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1) |
+ FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0));
+}
+
+static void dw_hdmi_qp_rk3576_mask_hpd(struct rockchip_hdmi_qp *hdmi)
+{
+ regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0,
+ FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1));
+}
+
static void dw_hdmi_qp_rk3576_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
{
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
- u32 val;
- val = (FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1) |
- FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0));
-
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+ dw_hdmi_qp_rk3576_unmask_hpd(hdmi);
}
static void dw_hdmi_qp_rk3576_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
{
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
- regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0,
- FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1));
+ dw_hdmi_qp_rk3576_mask_hpd(hdmi);
}
static const struct dw_hdmi_qp_phy_ops rk3576_hdmi_phy_ops = {
@@ -375,7 +395,7 @@ static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat);
if (intr_stat & RK3576_HDMI_OHPD_INT) {
- dw_hdmi_qp_rk3576_disable_hpd(NULL, hdmi);
+ dw_hdmi_qp_rk3576_mask_hpd(hdmi);
return IRQ_WAKE_THREAD;
}
@@ -389,7 +409,7 @@ static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
- dw_hdmi_qp_rk3576_enable_hpd(NULL, hdmi);
+ dw_hdmi_qp_rk3576_unmask_hpd(hdmi);
return IRQ_HANDLED;
}
@@ -404,7 +424,7 @@ static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
intr_stat &= hdmi->port_id ? RK3588_HDMI1_OHPD_INT : RK3588_HDMI0_OHPD_INT;
if (intr_stat) {
- dw_hdmi_qp_rk3588_disable_hpd(NULL, hdmi);
+ dw_hdmi_qp_rk3588_mask_hpd(hdmi);
return IRQ_WAKE_THREAD;
}
@@ -418,7 +438,7 @@ static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id)
mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
- dw_hdmi_qp_rk3588_enable_hpd(NULL, hdmi);
+ dw_hdmi_qp_rk3588_unmask_hpd(hdmi);
return IRQ_HANDLED;
}
@@ -435,7 +455,7 @@ static void dw_hdmi_qp_rk3576_io_init(struct rockchip_hdmi_qp *hdmi)
regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
- dw_hdmi_qp_rk3576_disable_hpd(NULL, hdmi);
+ dw_hdmi_qp_rk3576_mask_hpd(hdmi);
}
static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
@@ -460,7 +480,7 @@ static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
val = FIELD_PREP_WM16(RK3588_HDMI0_GRANT_SEL, 1);
regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val);
- dw_hdmi_qp_rk3588_disable_hpd(NULL, hdmi);
+ dw_hdmi_qp_rk3588_mask_hpd(hdmi);
}
static void dw_hdmi_qp_rk3576_enc_init(struct rockchip_hdmi_qp *hdmi,
--
2.55.0
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH v12 14/16] drm/rockchip: dw_hdmi_qp: Control the HPD IRQ line via the bridge HPD ops
2026-10-05 0:38 [PATCH v12 00/16] Add HDMI 2.0 support to DW HDMI QP TX Cristian Ciocaltea
` (12 preceding siblings ...)
2026-10-05 0:38 ` [PATCH v12 13/16] drm/rockchip: dw_hdmi_qp: Factor out HPD interrupt (un)mask helpers Cristian Ciocaltea
@ 2026-10-05 0:38 ` Cristian Ciocaltea
2026-10-05 0:38 ` [PATCH v12 15/16] drm/rockchip: dw_hdmi_qp: Use dw_hdmi_qp_hpd_notify() for HPD reports Cristian Ciocaltea
2026-10-05 0:38 ` [PATCH v12 16/16] drm/bridge: dw-hdmi-qp: Drop unused .setup_hpd() phy op Cristian Ciocaltea
15 siblings, 0 replies; 18+ messages in thread
From: Cristian Ciocaltea @ 2026-10-05 0:38 UTC (permalink / raw)
To: Sandy Huang, Heiko Stübner, Andy Yan, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Algea Cao,
Daniel Stone
Cc: kernel, dri-devel, linux-rockchip, linux-kernel,
linux-arm-kernel, Diederik de Haas, Robin Räber,
Igor Paunovic
The HPD interrupt must not be delivered before the DRM connector is fully
set up, and it should be quiesced while the display pipeline is suspended.
On top of that, the threaded handler re-arms HPD unconditionally after the
hotplug debounce, which must not override an explicit disable requested by
the DRM core.
Request the HPD IRQ in bind() with IRQF_NO_AUTOEN so it stays disabled
until the core arms it, and drive enable_irq()/disable_irq() from the
phy ops invoked by the bridge through its hpd_{enable,disable}()
callbacks. This ensures the line is only armed after the connector is
ready. disable_irq() additionally waits for the threaded handler to
finish, so its GRF re-arm can no longer race with and override a
core-requested disable.
Masking the line is not enough on its own, though: the threaded handler
merely queues hpd_work with a 150 ms debounce, so an event taken shortly
before the disable would still probe the connector and read the EDID
long after the core considers HPD quiesced. Since disable_irq() has
drained the threaded handler, which is the only site arming the work, it
can no longer be requeued and dropping it is race-free.
Use the non-syncing cancel_delayed_work() for that: waiting on a running
callback would pull mode_config.mutex, taken by the work through
drm_connector_helper_hpd_irq_event(), under the hpd_state_mutex held by
drm_bridge_hpd_disable(). That inverts the order of the connector probe
path, which holds mode_config.mutex while reaching hpd_state_mutex via
drm_kms_helper_poll_enable(). A callback already in progress is drained
by the system-sleep and unbind paths instead.
Note that IRQF_NO_AUTOEN is incompatible with IRQF_SHARED; the latter is
dropped as this IRQ has no other users.
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Tested-by: Robin Räber <robin.raebi@gmail.com>
Tested-by: Igor Paunovic <royalnet026@gmail.com> # RK3588 Orange Pi 5 Plus, dual HDMI
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 33 +++++++++++++++++++++-----
1 file changed, 27 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index ecf12403101d..1c547016ee00 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -99,6 +99,7 @@ struct rockchip_hdmi_qp {
struct phy *phy;
struct gpio_desc *frl_enable_gpio;
struct delayed_work hpd_work;
+ int hpd_irq;
int port_id;
const struct rockchip_hdmi_qp_ctrl_ops *ctrl_ops;
unsigned long long tmds_char_rate;
@@ -308,13 +309,23 @@ static void dw_hdmi_qp_rk3588_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
dw_hdmi_qp_rk3588_unmask_hpd(hdmi);
+ enable_irq(hdmi->hpd_irq);
}
static void dw_hdmi_qp_rk3588_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
{
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
+ disable_irq(hdmi->hpd_irq);
dw_hdmi_qp_rk3588_mask_hpd(hdmi);
+
+ /*
+ * Cannot use the _sync() variant: the work takes mode_config.mutex,
+ * which the connector probe path already holds when acquiring the
+ * hpd_state_mutex this caller runs under. Requeuing is already ruled
+ * out by disable_irq().
+ */
+ cancel_delayed_work(&hdmi->hpd_work);
}
static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = {
@@ -355,13 +366,23 @@ static void dw_hdmi_qp_rk3576_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
dw_hdmi_qp_rk3576_unmask_hpd(hdmi);
+ enable_irq(hdmi->hpd_irq);
}
static void dw_hdmi_qp_rk3576_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
{
struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
+ disable_irq(hdmi->hpd_irq);
dw_hdmi_qp_rk3576_mask_hpd(hdmi);
+
+ /*
+ * Cannot use the _sync() variant: the work takes mode_config.mutex,
+ * which the connector probe path already holds when acquiring the
+ * hpd_state_mutex this caller runs under. Requeuing is already ruled
+ * out by disable_irq().
+ */
+ cancel_delayed_work(&hdmi->hpd_work);
}
static const struct dw_hdmi_qp_phy_ops rk3576_hdmi_phy_ops = {
@@ -584,7 +605,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
struct resource *res;
struct clk_bulk_data *clks;
struct clk *ref_clk;
- int ret, irq, i;
+ int ret, i;
if (!dev->of_node)
return -ENODEV;
@@ -688,14 +709,14 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
if (plat_data.cec_irq < 0)
return plat_data.cec_irq;
- irq = platform_get_irq_byname(pdev, "hpd");
- if (irq < 0)
- return irq;
+ hdmi->hpd_irq = platform_get_irq_byname(pdev, "hpd");
+ if (hdmi->hpd_irq < 0)
+ return hdmi->hpd_irq;
- ret = devm_request_threaded_irq(dev, irq,
+ ret = devm_request_threaded_irq(dev, hdmi->hpd_irq,
cfg->ctrl_ops->hardirq_callback,
cfg->ctrl_ops->irq_callback,
- IRQF_SHARED, "dw-hdmi-qp-hpd",
+ IRQF_NO_AUTOEN, "dw-hdmi-qp-hpd",
hdmi);
if (ret)
return ret;
--
2.55.0
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH v12 15/16] drm/rockchip: dw_hdmi_qp: Use dw_hdmi_qp_hpd_notify() for HPD reports
2026-10-05 0:38 [PATCH v12 00/16] Add HDMI 2.0 support to DW HDMI QP TX Cristian Ciocaltea
` (13 preceding siblings ...)
2026-10-05 0:38 ` [PATCH v12 14/16] drm/rockchip: dw_hdmi_qp: Control the HPD IRQ line via the bridge HPD ops Cristian Ciocaltea
@ 2026-10-05 0:38 ` Cristian Ciocaltea
2026-10-05 0:38 ` [PATCH v12 16/16] drm/bridge: dw-hdmi-qp: Drop unused .setup_hpd() phy op Cristian Ciocaltea
15 siblings, 0 replies; 18+ messages in thread
From: Cristian Ciocaltea @ 2026-10-05 0:38 UTC (permalink / raw)
To: Sandy Huang, Heiko Stübner, Andy Yan, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Algea Cao,
Daniel Stone
Cc: kernel, dri-devel, linux-rockchip, linux-kernel,
linux-arm-kernel, Maud Spierings, Diederik de Haas,
Robin Räber, Igor Paunovic
Notify only the affected connector instead of polling all of them, and
ensure .detect_ctx() runs on reconnect to recover SCDC state.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Tested-by: Robin Räber <robin.raebi@gmail.com>
Tested-by: Igor Paunovic <royalnet026@gmail.com> # RK3588 Orange Pi 5 Plus, dual HDMI
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 12 ++----------
1 file changed, 2 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 1c547016ee00..f2a1ea8dfefa 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -24,7 +24,6 @@
#include <drm/drm_bridge_connector.h>
#include <drm/drm_managed.h>
#include <drm/drm_of.h>
-#include <drm/drm_probe_helper.h>
#include "rockchip_drm_drv.h"
@@ -398,14 +397,8 @@ static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
struct rockchip_hdmi_qp *hdmi = container_of(work,
struct rockchip_hdmi_qp,
hpd_work.work);
- struct drm_device *drm = hdmi->encoder.encoder.dev;
- bool changed;
- if (drm) {
- changed = drm_helper_hpd_irq_event(drm);
- if (changed)
- dev_dbg(hdmi->dev, "connector status changed\n");
- }
+ dw_hdmi_qp_hpd_notify(hdmi->hdmi);
}
static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
@@ -792,8 +785,7 @@ static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev)
dw_hdmi_qp_resume(dev, hdmi->hdmi);
- if (hdmi->encoder.encoder.dev)
- drm_helper_hpd_irq_event(hdmi->encoder.encoder.dev);
+ dw_hdmi_qp_hpd_notify(hdmi->hdmi);
return 0;
}
--
2.55.0
^ permalink raw reply [flat|nested] 18+ messages in thread* [PATCH v12 16/16] drm/bridge: dw-hdmi-qp: Drop unused .setup_hpd() phy op
2026-10-05 0:38 [PATCH v12 00/16] Add HDMI 2.0 support to DW HDMI QP TX Cristian Ciocaltea
` (14 preceding siblings ...)
2026-10-05 0:38 ` [PATCH v12 15/16] drm/rockchip: dw_hdmi_qp: Use dw_hdmi_qp_hpd_notify() for HPD reports Cristian Ciocaltea
@ 2026-10-05 0:38 ` Cristian Ciocaltea
15 siblings, 0 replies; 18+ messages in thread
From: Cristian Ciocaltea @ 2026-10-05 0:38 UTC (permalink / raw)
To: Sandy Huang, Heiko Stübner, Andy Yan, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Algea Cao,
Daniel Stone
Cc: kernel, dri-devel, linux-rockchip, linux-kernel,
linux-arm-kernel, Maud Spierings, Diederik de Haas,
Robin Räber, Igor Paunovic
With the transition to .{enable|disable}_hpd() phy ops complete in both
the bridge and platform drivers, .setup_hpd() has no remaining callers.
Drop it.
Tested-by: Maud Spierings <maud_spierings@hotmail.com>
Tested-by: Diederik de Haas <diederik@cknow-tech.com> # NanoPC-T6 LTS, Rock 5B
Tested-by: Robin Räber <robin.raebi@gmail.com>
Tested-by: Igor Paunovic <royalnet026@gmail.com> # RK3588 Orange Pi 5 Plus, dual HDMI
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 3 ---
include/drm/bridge/dw_hdmi_qp.h | 1 -
2 files changed, 4 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 54181b052fe2..b268c9376087 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -1089,9 +1089,6 @@ static void dw_hdmi_qp_init_hw(struct dw_hdmi_qp *hdmi)
/* Clear DONE and ERROR interrupts */
dw_hdmi_qp_write(hdmi, I2CM_OP_DONE_CLEAR | I2CM_NACK_RCVD_CLEAR,
MAINUNIT_1_INT_CLEAR);
-
- if (hdmi->phy.ops->setup_hpd)
- hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data);
}
struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
diff --git a/include/drm/bridge/dw_hdmi_qp.h b/include/drm/bridge/dw_hdmi_qp.h
index b4fb1c578a5b..ad33f9cafdeb 100644
--- a/include/drm/bridge/dw_hdmi_qp.h
+++ b/include/drm/bridge/dw_hdmi_qp.h
@@ -16,7 +16,6 @@ struct dw_hdmi_qp_phy_ops {
int (*init)(struct dw_hdmi_qp *hdmi, void *data);
void (*disable)(struct dw_hdmi_qp *hdmi, void *data);
enum drm_connector_status (*read_hpd)(struct dw_hdmi_qp *hdmi, void *data);
- void (*setup_hpd)(struct dw_hdmi_qp *hdmi, void *data);
void (*enable_hpd)(struct dw_hdmi_qp *hdmi, void *data);
void (*disable_hpd)(struct dw_hdmi_qp *hdmi, void *data);
};
--
2.55.0
^ permalink raw reply [flat|nested] 18+ messages in thread