[PATCH 05/10] drm/bridge: synopsys: dw-dp: Support software triggered OOB HPD
Sebastian Reichel
sebastian.reichel at collabora.com
Thu Mar 26 10:31:29 PDT 2026
Add support for USB-C DP AltMode out-of-band hotplug handling. The
handling itself is implemented in the platform specific driver as the
registers to force HPD state are not part of the Designware DisplayPort
IP itself. Instead the platform integration might provide the necessary
functionality to mux the HPD signal.
Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
drivers/gpu/drm/bridge/synopsys/dw-dp.c | 38 ++++++++++++++++++++++++++++++++-
include/drm/bridge/dw_dp.h | 3 +++
2 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-dp.c b/drivers/gpu/drm/bridge/synopsys/dw-dp.c
index c3a108f1faa9..df2d629287fd 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-dp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-dp.c
@@ -1824,6 +1824,19 @@ static struct drm_bridge_state *dw_dp_bridge_atomic_duplicate_state(struct drm_b
return &state->base;
}
+static void dw_dp_bridge_oob_notify(struct drm_bridge *bridge,
+ struct drm_connector *connector,
+ enum drm_connector_status status)
+{
+ bool hpd_high = status != connector_status_disconnected;
+ struct dw_dp *dp = bridge_to_dp(bridge);
+
+ if (dp->plat_data.hpd_sw_cfg)
+ dp->plat_data.hpd_sw_cfg(dp->plat_data.data, hpd_high);
+ else
+ dev_err_once(dp->dev, "Missing platform handler for OOB HPD handling\n");
+}
+
static const struct drm_bridge_funcs dw_dp_bridge_funcs = {
.atomic_duplicate_state = dw_dp_bridge_atomic_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
@@ -1837,6 +1850,7 @@ static const struct drm_bridge_funcs dw_dp_bridge_funcs = {
.detect = dw_dp_bridge_detect,
.edid_read = dw_dp_bridge_edid_read,
.detach = dw_dp_bridge_detach,
+ .oob_notify = dw_dp_bridge_oob_notify,
};
static int dw_dp_link_retrain(struct dw_dp *dp)
@@ -1973,6 +1987,19 @@ static void dw_dp_phy_exit(void *data)
phy_exit(dp->phy);
}
+static bool dw_dp_is_routed_to_usb_c(struct drm_encoder *encoder)
+{
+ struct drm_bridge *last_bridge __free(drm_bridge_put) = NULL;
+ struct fwnode_handle *fwnode;
+
+ last_bridge = drm_bridge_chain_get_last_bridge(encoder);
+ if (!last_bridge)
+ return false;
+
+ fwnode = of_fwnode_handle(last_bridge->of_node);
+ return fwnode_device_is_compatible(fwnode, "usb-c-connector");
+}
+
struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder,
const struct dw_dp_plat_data *plat_data)
{
@@ -1988,7 +2015,9 @@ struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder,
dp->dev = dev;
dp->pixel_mode = plat_data->pixel_mode;
-
+ dp->plat_data.hpd_sw_sel = plat_data->hpd_sw_sel;
+ dp->plat_data.hpd_sw_cfg = plat_data->hpd_sw_cfg;
+ dp->plat_data.data = plat_data->data;
dp->plat_data.max_link_rate = plat_data->max_link_rate;
bridge = &dp->bridge;
mutex_init(&dp->irq_lock);
@@ -2086,6 +2115,13 @@ struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder,
goto unregister_aux;
}
+ if (dw_dp_is_routed_to_usb_c(encoder)) {
+ dev_dbg(dev, "USB-C mode\n");
+
+ if (dp->plat_data.hpd_sw_sel)
+ dp->plat_data.hpd_sw_sel(dp->plat_data.data, 1);
+ }
+
dw_dp_init_hw(dp);
ret = phy_init(dp->phy);
diff --git a/include/drm/bridge/dw_dp.h b/include/drm/bridge/dw_dp.h
index 25363541e69d..4aacd0e56f50 100644
--- a/include/drm/bridge/dw_dp.h
+++ b/include/drm/bridge/dw_dp.h
@@ -20,6 +20,9 @@ enum {
struct dw_dp_plat_data {
u32 max_link_rate;
u8 pixel_mode;
+ void *data;
+ void (*hpd_sw_sel)(void *data, bool hpd);
+ void (*hpd_sw_cfg)(void *data, bool hpd);
};
struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder,
--
2.53.0
More information about the Linux-rockchip
mailing list