* [PATCH 07/10] drm/bridge: adv7511: switch to of_drm_get_bridge_by_endpoint()
From: Luca Ceresoli @ 2026-04-13 13:58 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Rob Clark, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, Xinliang Liu, Tian Tao,
Xinwei Kong, Sumit Semwal, Yongqin Liu, John Stultz,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Tomi Valkeinen, Michal Simek
Cc: Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel,
linux-arm-msm, freedreno, linux-arm-kernel, Luca Ceresoli
In-Reply-To: <20260413-drm-bridge-alloc-getput-panel_or_bridge-v1-0-acd01cd79a1f@bootlin.com>
This driver calls drm_of_find_panel_or_bridge() with a NULL pointer in the
@panel parameter, thus using a reduced feature set of that function.
Replace this call with the simpler of_drm_get_bridge_by_endpoint().
Since of_drm_get_bridge_by_endpoint() increases the refcount of the
returned bridge, ensure it is put on removal. To achieve this, instead of
adding an explicit drm_bridge_put(), migrate to the bridge::next_bridge
pointer which is automatically put when the bridge is eventually freed.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/bridge/adv7511/adv7511.h | 1 -
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 8 ++++----
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h
index 8be7266fd4f4..12c95198d9a4 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
@@ -354,7 +354,6 @@ struct adv7511 {
enum drm_connector_status status;
bool powered;
- struct drm_bridge *next_bridge;
struct drm_display_mode curr_mode;
unsigned int f_tmds;
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index 6bd76c1fb007..6d2923a2ef19 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -851,8 +851,8 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge,
struct adv7511 *adv = bridge_to_adv7511(bridge);
int ret = 0;
- if (adv->next_bridge) {
- ret = drm_bridge_attach(encoder, adv->next_bridge, bridge,
+ if (adv->bridge.next_bridge) {
+ ret = drm_bridge_attach(encoder, adv->bridge.next_bridge, bridge,
flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret)
return ret;
@@ -1251,8 +1251,8 @@ static int adv7511_probe(struct i2c_client *i2c)
memset(&link_config, 0, sizeof(link_config));
- ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, NULL,
- &adv7511->next_bridge);
+ ret = of_drm_get_bridge_by_endpoint(dev->of_node, 1, -1,
+ &adv7511->bridge.next_bridge);
if (ret && ret != -ENODEV)
return ret;
--
2.53.0
^ permalink raw reply related
* [PATCH 06/10] drm/bridge: lt9611: switch to of_drm_get_bridge_by_endpoint()
From: Luca Ceresoli @ 2026-04-13 13:58 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Rob Clark, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, Xinliang Liu, Tian Tao,
Xinwei Kong, Sumit Semwal, Yongqin Liu, John Stultz,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Tomi Valkeinen, Michal Simek
Cc: Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel,
linux-arm-msm, freedreno, linux-arm-kernel, Luca Ceresoli
In-Reply-To: <20260413-drm-bridge-alloc-getput-panel_or_bridge-v1-0-acd01cd79a1f@bootlin.com>
This driver calls drm_of_find_panel_or_bridge() with a NULL pointer in the
@panel parameter, thus using a reduced feature set of that function.
Replace this call with the simpler of_drm_get_bridge_by_endpoint().
Since of_drm_get_bridge_by_endpoint() increases the refcount of the
returned bridge, ensure it is put on removal. To achieve this, instead of
adding an explicit drm_bridge_put(), migrate to the bridge::next_bridge
pointer which is automatically put when the bridge is eventually freed.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/bridge/lontium-lt9611.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c
index 4517aee83332..6aeaf248d7fe 100644
--- a/drivers/gpu/drm/bridge/lontium-lt9611.c
+++ b/drivers/gpu/drm/bridge/lontium-lt9611.c
@@ -37,7 +37,6 @@
struct lt9611 {
struct device *dev;
struct drm_bridge bridge;
- struct drm_bridge *next_bridge;
struct regmap *regmap;
@@ -761,7 +760,7 @@ static int lt9611_bridge_attach(struct drm_bridge *bridge,
{
struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
- return drm_bridge_attach(encoder, lt9611->next_bridge,
+ return drm_bridge_attach(encoder, lt9611->bridge.next_bridge,
bridge, flags);
}
@@ -1058,7 +1057,7 @@ static int lt9611_parse_dt(struct device *dev,
lt9611->ac_mode = of_property_read_bool(dev->of_node, "lt,ac-mode");
- return drm_of_find_panel_or_bridge(dev->of_node, 2, -1, NULL, <9611->next_bridge);
+ return of_drm_get_bridge_by_endpoint(dev->of_node, 2, -1, <9611->bridge.next_bridge);
}
static int lt9611_gpio_init(struct lt9611 *lt9611)
--
2.53.0
^ permalink raw reply related
* [PATCH 05/10] drm/bridge: lontium-lt9611uxc: switch to of_drm_get_bridge_by_endpoint()
From: Luca Ceresoli @ 2026-04-13 13:58 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Rob Clark, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, Xinliang Liu, Tian Tao,
Xinwei Kong, Sumit Semwal, Yongqin Liu, John Stultz,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Tomi Valkeinen, Michal Simek
Cc: Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel,
linux-arm-msm, freedreno, linux-arm-kernel, Luca Ceresoli
In-Reply-To: <20260413-drm-bridge-alloc-getput-panel_or_bridge-v1-0-acd01cd79a1f@bootlin.com>
This driver calls drm_of_find_panel_or_bridge() with a NULL pointer in the
@panel parameter, thus using a reduced feature set of that function.
Replace this call with the simpler of_drm_get_bridge_by_endpoint().
Since of_drm_get_bridge_by_endpoint() increases the refcount of the
returned bridge, ensure it is put on removal. To achieve this, instead of
adding an explicit drm_bridge_put(), migrate to the bridge::next_bridge
pointer which is automatically put when the bridge is eventually freed.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
index 11aab07d88df..55b80a488c33 100644
--- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
+++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
@@ -35,7 +35,6 @@
struct lt9611uxc {
struct device *dev;
struct drm_bridge bridge;
- struct drm_bridge *next_bridge;
struct regmap *regmap;
/* Protects all accesses to registers by stopping the on-chip MCU */
@@ -284,7 +283,7 @@ static int lt9611uxc_bridge_attach(struct drm_bridge *bridge,
{
struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
- return drm_bridge_attach(encoder, lt9611uxc->next_bridge,
+ return drm_bridge_attach(encoder, lt9611uxc->bridge.next_bridge,
bridge, flags);
}
@@ -487,7 +486,7 @@ static int lt9611uxc_parse_dt(struct device *dev,
lt9611uxc->dsi1_node = of_graph_get_remote_node(dev->of_node, 1, -1);
- return drm_of_find_panel_or_bridge(dev->of_node, 2, -1, NULL, <9611uxc->next_bridge);
+ return of_drm_get_bridge_by_endpoint(dev->of_node, 2, -1, <9611uxc->bridge.next_bridge);
}
static int lt9611uxc_gpio_init(struct lt9611uxc *lt9611uxc)
--
2.53.0
^ permalink raw reply related
* [PATCH 04/10] drm/bridge: chrontel-ch7033: switch to of_drm_get_bridge_by_endpoint()
From: Luca Ceresoli @ 2026-04-13 13:58 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Rob Clark, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, Xinliang Liu, Tian Tao,
Xinwei Kong, Sumit Semwal, Yongqin Liu, John Stultz,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Tomi Valkeinen, Michal Simek
Cc: Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel,
linux-arm-msm, freedreno, linux-arm-kernel, Luca Ceresoli
In-Reply-To: <20260413-drm-bridge-alloc-getput-panel_or_bridge-v1-0-acd01cd79a1f@bootlin.com>
This driver calls drm_of_find_panel_or_bridge() with a NULL pointer in the
@panel parameter, thus using a reduced feature set of that function.
Replace this call with the simpler of_drm_get_bridge_by_endpoint().
Since of_drm_get_bridge_by_endpoint() increases the refcount of the
returned bridge, ensure it is put on removal. To achieve this, instead of
adding an explicit drm_bridge_put(), migrate to the bridge::next_bridge
pointer which is automatically put when the bridge is eventually freed.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/bridge/chrontel-ch7033.c | 24 +++++++++++-------------
1 file changed, 11 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/bridge/chrontel-ch7033.c b/drivers/gpu/drm/bridge/chrontel-ch7033.c
index 54d49d4882c8..1d14f62d2d52 100644
--- a/drivers/gpu/drm/bridge/chrontel-ch7033.c
+++ b/drivers/gpu/drm/bridge/chrontel-ch7033.c
@@ -199,7 +199,6 @@ enum {
struct ch7033_priv {
struct regmap *regmap;
- struct drm_bridge *next_bridge;
struct drm_bridge bridge;
struct drm_connector connector;
};
@@ -215,7 +214,7 @@ static enum drm_connector_status ch7033_connector_detect(
{
struct ch7033_priv *priv = conn_to_ch7033_priv(connector);
- return drm_bridge_detect(priv->next_bridge, connector);
+ return drm_bridge_detect(priv->bridge.next_bridge, connector);
}
static const struct drm_connector_funcs ch7033_connector_funcs = {
@@ -233,7 +232,7 @@ static int ch7033_connector_get_modes(struct drm_connector *connector)
const struct drm_edid *drm_edid;
int ret;
- drm_edid = drm_bridge_edid_read(priv->next_bridge, connector);
+ drm_edid = drm_bridge_edid_read(priv->bridge.next_bridge, connector);
drm_edid_connector_update(connector, drm_edid);
if (drm_edid) {
ret = drm_edid_connector_add_modes(connector);
@@ -275,7 +274,7 @@ static int ch7033_bridge_attach(struct drm_bridge *bridge,
struct drm_connector *connector = &priv->connector;
int ret;
- ret = drm_bridge_attach(encoder, priv->next_bridge, bridge,
+ ret = drm_bridge_attach(encoder, priv->bridge.next_bridge, bridge,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret)
return ret;
@@ -283,15 +282,15 @@ static int ch7033_bridge_attach(struct drm_bridge *bridge,
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
return 0;
- if (priv->next_bridge->ops & DRM_BRIDGE_OP_DETECT) {
+ if (priv->bridge.next_bridge->ops & DRM_BRIDGE_OP_DETECT) {
connector->polled = DRM_CONNECTOR_POLL_HPD;
} else {
connector->polled = DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT;
}
- if (priv->next_bridge->ops & DRM_BRIDGE_OP_HPD) {
- drm_bridge_hpd_enable(priv->next_bridge, ch7033_hpd_event,
+ if (priv->bridge.next_bridge->ops & DRM_BRIDGE_OP_HPD) {
+ drm_bridge_hpd_enable(priv->bridge.next_bridge, ch7033_hpd_event,
priv);
}
@@ -299,8 +298,8 @@ static int ch7033_bridge_attach(struct drm_bridge *bridge,
&ch7033_connector_helper_funcs);
ret = drm_connector_init_with_ddc(bridge->dev, &priv->connector,
&ch7033_connector_funcs,
- priv->next_bridge->type,
- priv->next_bridge->ddc);
+ priv->bridge.next_bridge->type,
+ priv->bridge.next_bridge->ddc);
if (ret) {
DRM_ERROR("Failed to initialize connector\n");
return ret;
@@ -313,8 +312,8 @@ static void ch7033_bridge_detach(struct drm_bridge *bridge)
{
struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
- if (priv->next_bridge->ops & DRM_BRIDGE_OP_HPD)
- drm_bridge_hpd_disable(priv->next_bridge);
+ if (priv->bridge.next_bridge->ops & DRM_BRIDGE_OP_HPD)
+ drm_bridge_hpd_disable(priv->bridge.next_bridge);
drm_connector_cleanup(&priv->connector);
}
@@ -543,8 +542,7 @@ static int ch7033_probe(struct i2c_client *client)
dev_set_drvdata(dev, priv);
- ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, NULL,
- &priv->next_bridge);
+ ret = of_drm_get_bridge_by_endpoint(dev->of_node, 1, -1, &priv->bridge.next_bridge);
if (ret)
return ret;
--
2.53.0
^ permalink raw reply related
* [PATCH 03/10] drm/hisilicon/kirin: switch to of_drm_get_bridge_by_endpoint()
From: Luca Ceresoli @ 2026-04-13 13:58 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Rob Clark, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, Xinliang Liu, Tian Tao,
Xinwei Kong, Sumit Semwal, Yongqin Liu, John Stultz,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Tomi Valkeinen, Michal Simek
Cc: Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel,
linux-arm-msm, freedreno, linux-arm-kernel, Luca Ceresoli
In-Reply-To: <20260413-drm-bridge-alloc-getput-panel_or_bridge-v1-0-acd01cd79a1f@bootlin.com>
This driver calls drm_of_find_panel_or_bridge() with a NULL pointer in the
@panel parameter, thus using a reduced feature set of that function.
Replace this call with the simpler of_drm_get_bridge_by_endpoint().
Since of_drm_get_bridge_by_endpoint() increases the refcount of the
returned bridge, ensure it is put on removal. Here the bridge pointer is
only stored in a temporary variable, so a cleanup action is enough.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
index e80debdc4176..7b2ef5ed2c40 100644
--- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
+++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
@@ -778,7 +778,7 @@ static int dsi_host_init(struct device *dev, struct dw_dsi *dsi)
static int dsi_bridge_init(struct drm_device *dev, struct dw_dsi *dsi)
{
struct drm_encoder *encoder = &dsi->encoder;
- struct drm_bridge *bridge;
+ struct drm_bridge *bridge __free(drm_bridge_put) = NULL;
struct device_node *np = dsi->dev->of_node;
int ret;
@@ -786,7 +786,7 @@ static int dsi_bridge_init(struct drm_device *dev, struct dw_dsi *dsi)
* Get the endpoint node. In our case, dsi has one output port1
* to which the external HDMI bridge is connected.
*/
- ret = drm_of_find_panel_or_bridge(np, 1, 0, NULL, &bridge);
+ ret = of_drm_get_bridge_by_endpoint(np, 1, 0, &bridge);
if (ret)
return ret;
--
2.53.0
^ permalink raw reply related
* [PATCH 02/10] drm/msm/hdmi: switch to of_drm_get_bridge_by_endpoint()
From: Luca Ceresoli @ 2026-04-13 13:58 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Rob Clark, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, Xinliang Liu, Tian Tao,
Xinwei Kong, Sumit Semwal, Yongqin Liu, John Stultz,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Tomi Valkeinen, Michal Simek
Cc: Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel,
linux-arm-msm, freedreno, linux-arm-kernel, Luca Ceresoli
In-Reply-To: <20260413-drm-bridge-alloc-getput-panel_or_bridge-v1-0-acd01cd79a1f@bootlin.com>
This driver calls drm_of_find_panel_or_bridge() with a NULL pointer in the
@panel parameter, thus using a reduced feature set of that function.
Replace this call with the simpler of_drm_get_bridge_by_endpoint().
Since of_drm_get_bridge_by_endpoint() increases the refcount of the
returned bridge, ensure it is put on removal.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/msm/hdmi/hdmi.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 852abb2466f0..90e529b3d0c8 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -287,7 +287,7 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev)
spin_lock_init(&hdmi->reg_lock);
mutex_init(&hdmi->state_mutex);
- ret = drm_of_find_panel_or_bridge(dev_of_node(dev), 1, 0, NULL, &hdmi->next_bridge);
+ ret = of_drm_get_bridge_by_endpoint(dev_of_node(dev), 1, 0, &hdmi->next_bridge);
if (ret && ret != -ENODEV)
return ret;
@@ -383,6 +383,7 @@ static void msm_hdmi_dev_remove(struct platform_device *pdev)
component_del(&pdev->dev, &msm_hdmi_ops);
msm_hdmi_put_phy(hdmi);
+ drm_bridge_put(hdmi->next_bridge);
}
static int msm_hdmi_runtime_suspend(struct device *dev)
--
2.53.0
^ permalink raw reply related
* [PATCH 00/10] drm/bridge: handle refcounting for bridge-only callers of drm_of_find_panel_or_bridge()
From: Luca Ceresoli @ 2026-04-13 13:58 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Rob Clark, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, Xinliang Liu, Tian Tao,
Xinwei Kong, Sumit Semwal, Yongqin Liu, John Stultz,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Tomi Valkeinen, Michal Simek
Cc: Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel,
linux-arm-msm, freedreno, linux-arm-kernel, Luca Ceresoli
This series converts all the bridge-only callers of the deprecated
drm_of_find_panel_or_bridge() API to a new, simpler API that handles bridge
refcounting.
== Series description
* The first patch introduces of_drm_get_bridge_by_endpoint() as a
replacement for bridge-only calls to drm_of_find_panel_or_bridge(); the
new function is simpler and returns a refcounted bridge
* The following patches convert all bridge-only users to the new API
* The last patch forbids new bridge-only calls to
drm_of_find_panel_or_bridge()
== Grand plan
This is part of the work to support hotplug of DRM bridges. The grand plan
was discussed in [0].
Here's the work breakdown (➜ marks the current series):
1. ➜ add refcounting to DRM bridges struct drm_bridge,
based on devm_drm_bridge_alloc()
A. ✔ add new alloc API and refcounting (v6.16)
B. ✔ convert all bridge drivers to new API (v6.17)
C. ✔ kunit tests (v6.17)
D. ✔ add get/put to drm_bridge_add/remove() + attach/detach()
and warn on old allocation pattern (v6.17)
E. ➜ add get/put on drm_bridge accessors
1. ✔ drm_bridge_chain_get_first_bridge(), add cleanup action (v6.18)
2. ✔ drm_bridge_get_prev_bridge() (v6.18)
3. ✔ drm_bridge_get_next_bridge() (v6.19)
4. ✔ drm_for_each_bridge_in_chain() (v6.19)
5. ✔ drm_bridge_connector_init (v6.19)
6. … protect encoder bridge chain with a mutex
7. ➜ of_drm_find_bridge
a. ✔ add of_drm_get_bridge() (v7.0),
convert basic direct users (v7.0-v7.1)
b. ✔ convert direct of_drm_get_bridge() users, part 2 (v7.0)
c. ✔ convert direct of_drm_get_bridge() users, part 3 (v7.0)
d. ✔… convert direct of_drm_get_bridge() users, part 4
(some v7.1, some pending)
e. ➜ convert bridge-only drm_of_find_panel_or_bridge() users
8. drm_of_find_panel_or_bridge, *_of_get_bridge
9. ✔ enforce drm_bridge_add before drm_bridge_attach (v6.19)
F. ✔ debugfs improvements
1. ✔ add top-level 'bridges' file (v6.16)
2. ✔ show refcount and list lingering bridges (v6.19)
2. … handle gracefully atomic updates during bridge removal
A. ✔ Add drm_bridge_enter/exit() to protect device resources (v7.0)
B. … protect private_obj removal from list
C. ✔ Add drm_bridge_clear_and_put() (v7.1)
3. … DSI host-device driver interaction
4. ✔ removing the need for the "always-disconnected" connector
5. … Migrate i.MX LCDIF driver to bridge-connector
6. DRM bridge hotplug
A. Bridge hotplug management in the DRM core
B. Device tree description
[0] https://lore.kernel.org/lkml/20250206-hotplug-drm-bridge-v6-0-9d6f2c9c3058@bootlin.com/#t
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
Luca Ceresoli (10):
drm/bridge: add of_drm_get_bridge_by_endpoint()
drm/msm/hdmi: switch to of_drm_get_bridge_by_endpoint()
drm/hisilicon/kirin: switch to of_drm_get_bridge_by_endpoint()
drm/bridge: chrontel-ch7033: switch to of_drm_get_bridge_by_endpoint()
drm/bridge: lontium-lt9611uxc: switch to of_drm_get_bridge_by_endpoint()
drm/bridge: lt9611: switch to of_drm_get_bridge_by_endpoint()
drm/bridge: adv7511: switch to of_drm_get_bridge_by_endpoint()
drm/bridge: lt8713sx: switch to of_drm_get_bridge_by_endpoint()
drm: zynqmp_dp: switch to of_drm_get_bridge_by_endpoint()
drm: of: forbid bridge-only calls to drm_of_find_panel_or_bridge()
drivers/gpu/drm/bridge/adv7511/adv7511.h | 1 -
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 8 ++---
drivers/gpu/drm/bridge/chrontel-ch7033.c | 24 +++++++--------
drivers/gpu/drm/bridge/lontium-lt8713sx.c | 7 ++---
drivers/gpu/drm/bridge/lontium-lt9611.c | 5 ++-
drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 5 ++-
drivers/gpu/drm/drm_bridge.c | 46 ++++++++++++++++++++++++++++
drivers/gpu/drm/drm_of.c | 26 ++++++++--------
drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 4 +--
drivers/gpu/drm/msm/hdmi/hdmi.c | 3 +-
drivers/gpu/drm/xlnx/zynqmp_dp.c | 10 +++---
include/drm/drm_bridge.h | 9 ++++++
12 files changed, 97 insertions(+), 51 deletions(-)
---
base-commit: f9ef69563cc82e908e1ce84fd135d3290fb65cde
change-id: 20260410-drm-bridge-alloc-getput-panel_or_bridge-42501b38eaad
Best regards,
--
Luca Ceresoli <luca.ceresoli@bootlin.com>
^ permalink raw reply
* [PATCH 01/10] drm/bridge: add of_drm_get_bridge_by_endpoint()
From: Luca Ceresoli @ 2026-04-13 13:58 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Rob Clark, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Sean Paul, Marijn Suijten, Xinliang Liu, Tian Tao,
Xinwei Kong, Sumit Semwal, Yongqin Liu, John Stultz,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Tomi Valkeinen, Michal Simek
Cc: Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel,
linux-arm-msm, freedreno, linux-arm-kernel, Luca Ceresoli
In-Reply-To: <20260413-drm-bridge-alloc-getput-panel_or_bridge-v1-0-acd01cd79a1f@bootlin.com>
drm_of_find_panel_or_bridge() is widely used, but many callers pass NULL
into the @panel or the @bridge arguments, thus making a very partial usage
of this rather complex function.
Besides, the bridge returned in @bridge is not refcounted, thus making this
API unsafe when DRM bridge hotplug will be introduced.
Solve both issues for the cases of calls to drm_of_find_panel_or_bridge()
with a NULL @panel pointer by adding a new function that only looks for
bridges (and is thus much simpler) and increments the refcount of the
returned bridge.
The new function is identical to drm_of_find_panel_or_bridge() except it:
- handles bridge refcounting: uses of_drm_find_and_get_bridge() instead of
of_drm_find_bridge() internally to return a refcounted bridge
- is slightly simpler to use: just takes no @panel parameter
- has a simpler implementation: it is equal to
drm_of_find_panel_or_bridge() after removing the code that becomes dead
when @panel == NULL
Also add this function to drm_bridge.c and not drm_of.c because it returns
bridges only.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/drm_bridge.c | 46 ++++++++++++++++++++++++++++++++++++++++++++
include/drm/drm_bridge.h | 9 +++++++++
2 files changed, 55 insertions(+)
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index ba80bebb5685..e51990b74417 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -1581,6 +1581,52 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np)
return bridge;
}
EXPORT_SYMBOL(of_drm_find_bridge);
+
+/**
+ * of_drm_get_bridge_by_endpoint - return DRM bridge connected to a port/endpoint
+ * @np: device tree node containing output ports
+ * @port: port in the device tree node, or -1 for the first port found
+ * @endpoint: endpoint in the device tree node, or -1 for the first endpoint found
+ * @bridge: pointer to hold returned drm_bridge, must not be NULL
+ *
+ * Given a DT node's port and endpoint number, find the connected node and
+ * return the associated drm_bridge device.
+ *
+ * The refcount of the returned bridge is incremented. Use drm_bridge_put()
+ * when done with it.
+ *
+ * Returns zero (and sets *bridge to a valid bridge pointer) if successful,
+ * or one of the standard error codes (and the value in *bridge is
+ * unspecified) if it fails.
+ */
+int of_drm_get_bridge_by_endpoint(const struct device_node *np,
+ int port, int endpoint,
+ struct drm_bridge **bridge)
+{
+ if (!bridge)
+ return -EINVAL;
+
+ /*
+ * of_graph_get_remote_node() produces a noisy error message if port
+ * node isn't found and the absence of the port is a legit case here,
+ * so at first we silently check whether graph presents in the
+ * device-tree node.
+ */
+ if (!of_graph_is_present(np))
+ return -ENODEV;
+
+ struct device_node *remote __free(device_node) =
+ of_graph_get_remote_node(np, port, endpoint);
+ if (!remote)
+ return -ENODEV;
+
+ *bridge = of_drm_find_and_get_bridge(remote);
+ if (*bridge)
+ return 0;
+
+ return -EPROBE_DEFER;
+}
+EXPORT_SYMBOL_GPL(of_drm_get_bridge_by_endpoint);
#endif
/**
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index a8d67bd9ee50..ad93597cd622 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -1327,6 +1327,9 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
#ifdef CONFIG_OF
struct drm_bridge *of_drm_find_and_get_bridge(struct device_node *np);
struct drm_bridge *of_drm_find_bridge(struct device_node *np);
+int of_drm_get_bridge_by_endpoint(const struct device_node *np,
+ int port, int endpoint,
+ struct drm_bridge **bridge);
#else
static inline struct drm_bridge *of_drm_find_and_get_bridge(struct device_node *np)
{
@@ -1336,6 +1339,12 @@ static inline struct drm_bridge *of_drm_find_bridge(struct device_node *np)
{
return NULL;
}
+static inline int of_drm_get_bridge_by_endpoint(const struct device_node *np,
+ int port, int endpoint,
+ struct drm_bridge **bridge)
+{
+ return -ENODEV;
+}
#endif
static inline bool drm_bridge_is_last(struct drm_bridge *bridge)
--
2.53.0
^ permalink raw reply related
* Re: [PATCH 4/4] ARM: realtek: MAINTAINERS: Include pin controller drivers
From: Yu-Chun Lin @ 2026-04-13 13:57 UTC (permalink / raw)
To: krzysztof.kozlowski
Cc: afaerber, andrew, eleanor.lin, james.tai, joel, linusw,
linux-arm-kernel, linux-aspeed, linux-gpio, linux-kernel,
linux-realtek-soc, openbmc
In-Reply-To: <e483acb6-af9d-4bc4-9aa6-c4841ff0a8dc@oss.qualcomm.com>
> On 13/04/2026 11:23, Yu-Chun Lin [林祐君] wrote:
>>> No dedicated maintainers are shown for Realtek SoC pin controllers, except
>>> pinctrl subsystem maintainer, which means reduced review and impression of
>>> abandoned drivers. Pin controller drivers are essential part of an SoC, so in
>>> case of lack of dedicated entry at least cover it by the SoC platform
>>> maintainers.
>>>
>>> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
>>>
>>> ---
>>>
>>> This patch should go via Realtek SoC maintainers, not pinctrl.
>>> ---
>>> MAINTAINERS | 1 +
>>> 1 file changed, 1 insertion(+)
>>>
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index 10d12b51b1f6..374ce55e4fb6 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -3373,6 +3373,7 @@ F:
>>> Documentation/devicetree/bindings/arm/realtek.yaml
>>> F: arch/arm/boot/dts/realtek/
>>> F: arch/arm/mach-realtek/
>>> F: arch/arm64/boot/dts/realtek/
>>> +F: drivers/pinctrl/realtek/
>>>
>>> ARM/RISC-V/RENESAS ARCHITECTURE
>>> M: Geert Uytterhoeven <geert+renesas@glider.be>
>>>
>>> --
>>> 2.51.0
>>
>> Acked-by: Yu-Chun Lin <eleanor.lin@realtek.com>
>
> So James will pick it up?
>
> Best regards,
> Krzysztof
Sorry for the confusion. I'll pick up this patch and include it in a series
along with the maintainer updates and other DTS changes. I plan to submit
the series to soc@ during the v7.1-rc1 to v7.1-rc5 window.
Best regards,
Yu-Chun
^ permalink raw reply
* Re: [PATCH bpf-next v14 1/5] bpf: Move constants blinding out of arch-specific JITs
From: bot+bpf-ci @ 2026-04-13 13:47 UTC (permalink / raw)
To: xukuohai, bpf, linux-kernel, linux-arm-kernel
Cc: ast, daniel, andrii, martin.lau, eddyz87, memxor, yonghong.song,
puranjay, a.s.protopopov, alexis.lothore, list+bpf, linux,
yangtiezhu, hengqi.chen, johan.almbladh, paulburton, hbathini,
chleroy, naveen, luke.r.nels, xi.wang, bjorn, pulehui, iii, hca,
gor, davem, udknight, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, clm, ihor.solodrai
In-Reply-To: <7d88904b4028cbe124bbaba5739c525663bedc64.1776062885.git.xukuohai@hotmail.com>
[-- Attachment #1: Type: text/plain, Size: 2333 bytes --]
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index 066b86e7233c..fc9fb3c07866 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
[ ... ]
> /**
> * bpf_prog_select_runtime - select exec runtime for BPF program
> * @fp: bpf_prog populated with BPF program
[ ... ]
> - /* eBPF JITs can rewrite the program in case constant
> - * blinding is active. However, in case of error during
> - * blinding, bpf_int_jit_compile() must always return a
> - * valid program, which in this case would simply not
> - * be JITed, but falls back to the interpreter.
> - */
> + /* eBPF JITs can rewrite the program in case constant
> + * blinding is active. However, in case of error during
> + * blinding, bpf_int_jit_compile() must always return a
> + * valid program, which in this case would simply not
> + * be JITed, but falls back to the interpreter.
> + */
This isn't a bug, but this comment still references bpf_int_jit_compile()
even though the code now calls bpf_prog_jit_compile(). Should this be
updated to match?
> - fp = bpf_int_jit_compile(fp);
> + fp = bpf_prog_jit_compile(fp);
> diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c
> index 67c9b28767e1..ec8afd6a9369 100644
> --- a/kernel/bpf/fixups.c
> +++ b/kernel/bpf/fixups.c
[ ... ]
> +out_jit_err:
> + if (blinded) {
> + bpf_jit_prog_release_other(orig_prog, prog);
> + /* roll back to the clean original prog */
> + prog = env->prog = orig_prog;
> + goto out_restore;
> + } else {
> + if (err != -EFAULT) {
> + /*
> + * We will fall back to interpreter mode when err is not -EFAULT, before
> + * that, insn->off and insn->imm should be restored to their original
> + * values since they were modified by __jit_subprogs.
> + */
The comment references __jit_subprogs, but the function is named
jit_subprogs (no double underscore prefix). Should this be updated?
> + for (i = 0, insn = prog->insnsi; i < prog->len; i++, insn++) {
> + if (!bpf_pseudo_call(insn))
> + continue;
> + insn->off = 0;
> + insn->imm = env->insn_aux_data[i].call_imm;
> + }
> + }
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/24345549165
^ permalink raw reply
* Re: [PATCH] drm: mxsfb: lcdif: enforce 64-byte pitch alignment for scanout
From: Philipp Zabel @ 2026-04-13 13:46 UTC (permalink / raw)
To: Advait Dhamorikar, marex
Cc: simona, imx, festevam, kernel, dri-devel, Frank.Li, s.hauer,
maarten.lankhorst, linux-kernel, mripard, stefan, tzimmermann,
airlied, linux-arm-kernel
In-Reply-To: <20260413114456.173485-1-advaitd@mechasystems.com>
Hi,
On Mo, 2026-04-13 at 17:14 +0530, Advait Dhamorikar wrote:
> The LCDIF controller expects framebuffer pitch to be aligned to a
> 64 byte boundary for reliable scanout.
>
> While byte-granular pitches are
> supported by the interface, the i.MX8MP reference manual
> recommends 64-byte alignment for optimal operation.
>
> Corrupted output was observed with XR24 framebuffers where a pitch of
> 4320 bytes caused visible corruption and choppy display, while an aligned
> pitch of 4352 bytes worked correctly.
This happens to be divisible by 256, which is is the burst size
currently set in the undocumented CTRLDESCL0_3 register fields,
according to the comment in lcdif_set_mode().
I wonder if setting 4320 bytes stride works if you reduce the burst
size, for example by reverting commit 2215cb3be5c2 ("drm: lcdif: change
burst size to 256B") to test.
If that is the case, it might be better to allow unaligned pitches but
configure the burst size depending on pitch alignment.
regards
Philipp
^ permalink raw reply
* Re: [PATCH RFC 10/12] drm/i915/display/dp: Adopt dp_connector helpers to expose link training state
From: Jani Nikula @ 2026-04-13 13:44 UTC (permalink / raw)
To: Kory Maincent
Cc: Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin, David Airlie,
Simona Vetter, Dave Airlie, Jesse Barnes, Eric Anholt,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson,
Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
linux-arm-kernel, Simona Vetter
In-Reply-To: <20260413153436.2a08be28@kmaincent-XPS-13-7390>
On Mon, 13 Apr 2026, Kory Maincent <kory.maincent@bootlin.com> wrote:
> On Mon, 13 Apr 2026 16:05:53 +0300
> Jani Nikula <jani.nikula@linux.intel.com> wrote:
>
>> On Mon, 13 Apr 2026, Kory Maincent <kory.maincent@bootlin.com> wrote:
>> > On Fri, 10 Apr 2026 19:26:53 +0300
>> > Jani Nikula <jani.nikula@linux.intel.com> wrote:
>> >
>> >> On Thu, 09 Apr 2026, Kory Maincent <kory.maincent@bootlin.com> wrote:
>> >> > Switch the i915 DP connector initialization from drmm_connector_init()
>> >> > to drmm_connector_dp_init(), providing the source link capabilities
>> >> > (supported lane counts, link rates, DSC support, voltage swing and
>> >> > pre-emphasis levels).
>> >> >
>> >> > Add intel_dp_report_link_train() to collect the negotiated link
>> >> > parameters (rate, lane count, DSC enable, per-lane voltage swing and
>> >> > pre-emphasis) and report them via
>> >> > drm_connector_dp_set_link_train_properties() once link training completes
>> >> > successfully.
>> >> >
>> >> > Reset the link training properties via
>> >> > drm_connector_dp_reset_link_train_properties() when the connector is
>> >> > reported as disconnected or when the display device is disabled, so
>> >> > the exposed state always reflects the current link status.
>> >> >
>> >> > Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
>> >> > ---
>> >> > drivers/gpu/drm/i915/display/intel_dp.c | 31
>> >> > +++++++++++++++++++--- .../gpu/drm/i915/display/intel_dp_link_training.c
>> >> > | 25 +++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-)
>> >> >
>> >> > diff --git a/drivers/gpu/drm/i915/display/intel_dp.c
>> >> > b/drivers/gpu/drm/i915/display/intel_dp.c index
>> >> > 2af64de9c81de..641406bdc0cc9 100644 ---
>> >> > a/drivers/gpu/drm/i915/display/intel_dp.c +++
>> >> > b/drivers/gpu/drm/i915/display/intel_dp.c @@ -45,6 +45,7 @@
>> >> > #include <drm/display/drm_hdmi_helper.h>
>> >> > #include <drm/drm_atomic_helper.h>
>> >> > #include <drm/drm_crtc.h>
>> >> > +#include <drm/drm_dp_connector.h>
>> >> > #include <drm/drm_edid.h>
>> >> > #include <drm/drm_fixed.h>
>> >> > #include <drm/drm_managed.h>
>> >> > @@ -6337,8 +6338,10 @@ intel_dp_detect(struct drm_connector *_connector,
>> >> > drm_WARN_ON(display->drm,
>> >> > !drm_modeset_is_locked(&display->drm->mode_config.connection_mutex));
>> >> >
>> >> > - if (!intel_display_device_enabled(display))
>> >> > + if (!intel_display_device_enabled(display)) {
>> >> > +
>> >> > drm_connector_dp_reset_link_train_properties(_connector); return
>> >> > connector_status_disconnected;
>> >> > + }
>> >> >
>> >> > if (!intel_display_driver_check_access(display))
>> >> > return connector->base.status;
>> >> > @@ -6388,6 +6391,8 @@ intel_dp_detect(struct drm_connector *_connector,
>> >> >
>> >> > intel_dp_tunnel_disconnect(intel_dp);
>> >> >
>> >> > +
>> >> > drm_connector_dp_reset_link_train_properties(_connector); +
>> >> > goto out_unset_edid;
>> >> > }
>> >> >
>> >> > @@ -7162,10 +7167,12 @@ intel_dp_init_connector(struct intel_digital_port
>> >> > *dig_port, struct intel_connector *connector)
>> >> > {
>> >> > struct intel_display *display = to_intel_display(dig_port);
>> >> > + struct drm_connector_dp_link_train_caps link_caps;
>> >> > struct intel_dp *intel_dp = &dig_port->dp;
>> >> > struct intel_encoder *encoder = &dig_port->base;
>> >> > struct drm_device *dev = encoder->base.dev;
>> >> > enum port port = encoder->port;
>> >> > + u32 *rates;
>> >> > int type;
>> >> >
>> >> > if (drm_WARN(dev, dig_port->max_lanes < 1,
>> >> > @@ -7213,8 +7220,25 @@ intel_dp_init_connector(struct intel_digital_port
>> >> > *dig_port, type == DRM_MODE_CONNECTOR_eDP ? "eDP" : "DP",
>> >> > encoder->base.base.id, encoder->base.name);
>> >> >
>> >> > - drmm_connector_init(dev, &connector->base,
>> >> > &intel_dp_connector_funcs,
>> >> > - type, &intel_dp->aux.ddc);
>> >> > + intel_dp_set_source_rates(intel_dp);
>> >> > + link_caps.nlanes = DRM_DP_1LANE | DRM_DP_2LANE | DRM_DP_4LANE;
>> >> > + link_caps.nrates = intel_dp->num_source_rates;
>> >> > + rates = kzalloc_objs(*rates, intel_dp->num_source_rates);
>> >> > + if (!rates)
>> >> > + goto fail;
>> >> > +
>> >> > + for (int i = 0; i < intel_dp->num_source_rates; i++)
>> >> > + rates[i] = intel_dp->source_rates[i];
>> >> > +
>> >> > + link_caps.rates = rates;
>> >> > + link_caps.dsc = true;
>> >>
>> >> You have a source, you have a sink, and you have a link between the two.
>> >>
>> >> Source rates do not reflect the link rates common between source and
>> >> sink.
>> >>
>> >> DSC depends on source and sink, and it's not statically "true" for
>> >> either, and depends on a bunch of things.
>> >
>> > At init, we are reporting the capabilities of the source. So we list every
>> > link rates that the source can achieve and we report that the source is DSC
>> > capable which it is IIUC the code. Or maybe I am missing something?
>>
>> IMO link caps is the intersection of the source and sink caps. If the
>> sink is unknown, i.e. its caps are the empty set, then the link caps
>> should also be the empty set.
>
> Ok thanks, I am rather new to the DiplayPort world so thank you for sharing
> your knowledge.
>
> IIUC currently the drivers are not testing all the capabilities of the link,
> they try the more "powerful" link and decrease the link parameters until it
> works right? So there is currently no way to now the full capabilities between a
> sink and a source.
It's at the discretion of the driver, and e.g. for i915 it depends on
whether it's eDP or regular DP, and whether you plug in an SST sink or
an MST branch device. At least that's how it was the last I checked,
there's been changes. ;)
>> If you need to know the source caps, then they need to be presented
>> separately.
>
> With DRM properties we can see possible values and the value set.
> My though was that the possible value are matching the source capabilities and
> value set was the one negotiated between the source and the sink.
> This was straightforward to me but it indeed can confuse between source
> capabilities and link capabilities. Have you a better idea?
Ah, in that sense the property might work, indicating the possible
values for the source.
But do see my other reply elsewhere in the thread. The chosen values
might not be as helpful as you may think.
BR,
Jani.
>
>> Moreover, the source does not unconditionally support DSC. See
>> intel_dp_has_dsc().
>
> Indeed thanks, I need to investigate that function.
>
> Regards,
--
Jani Nikula, Intel
^ permalink raw reply
* Re: [PATCH RFC 10/12] drm/i915/display/dp: Adopt dp_connector helpers to expose link training state
From: Kory Maincent @ 2026-04-13 13:34 UTC (permalink / raw)
To: Jani Nikula
Cc: Rodrigo Vivi, Joonas Lahtinen, Tvrtko Ursulin, David Airlie,
Simona Vetter, Dave Airlie, Jesse Barnes, Eric Anholt,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu, Philipp Zabel,
Matthias Brugger, AngeloGioacchino Del Regno, Chris Wilson,
Thomas Petazzoni, Mark Yacoub, Sean Paul, Louis Chauvet,
intel-gfx, intel-xe, dri-devel, linux-kernel, linux-mediatek,
linux-arm-kernel, Simona Vetter
In-Reply-To: <9f4bb4501c4885f432cbe9b6a10b7d27e40b0876@intel.com>
On Mon, 13 Apr 2026 16:05:53 +0300
Jani Nikula <jani.nikula@linux.intel.com> wrote:
> On Mon, 13 Apr 2026, Kory Maincent <kory.maincent@bootlin.com> wrote:
> > On Fri, 10 Apr 2026 19:26:53 +0300
> > Jani Nikula <jani.nikula@linux.intel.com> wrote:
> >
> >> On Thu, 09 Apr 2026, Kory Maincent <kory.maincent@bootlin.com> wrote:
> >> > Switch the i915 DP connector initialization from drmm_connector_init()
> >> > to drmm_connector_dp_init(), providing the source link capabilities
> >> > (supported lane counts, link rates, DSC support, voltage swing and
> >> > pre-emphasis levels).
> >> >
> >> > Add intel_dp_report_link_train() to collect the negotiated link
> >> > parameters (rate, lane count, DSC enable, per-lane voltage swing and
> >> > pre-emphasis) and report them via
> >> > drm_connector_dp_set_link_train_properties() once link training completes
> >> > successfully.
> >> >
> >> > Reset the link training properties via
> >> > drm_connector_dp_reset_link_train_properties() when the connector is
> >> > reported as disconnected or when the display device is disabled, so
> >> > the exposed state always reflects the current link status.
> >> >
> >> > Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
> >> > ---
> >> > drivers/gpu/drm/i915/display/intel_dp.c | 31
> >> > +++++++++++++++++++--- .../gpu/drm/i915/display/intel_dp_link_training.c
> >> > | 25 +++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-)
> >> >
> >> > diff --git a/drivers/gpu/drm/i915/display/intel_dp.c
> >> > b/drivers/gpu/drm/i915/display/intel_dp.c index
> >> > 2af64de9c81de..641406bdc0cc9 100644 ---
> >> > a/drivers/gpu/drm/i915/display/intel_dp.c +++
> >> > b/drivers/gpu/drm/i915/display/intel_dp.c @@ -45,6 +45,7 @@
> >> > #include <drm/display/drm_hdmi_helper.h>
> >> > #include <drm/drm_atomic_helper.h>
> >> > #include <drm/drm_crtc.h>
> >> > +#include <drm/drm_dp_connector.h>
> >> > #include <drm/drm_edid.h>
> >> > #include <drm/drm_fixed.h>
> >> > #include <drm/drm_managed.h>
> >> > @@ -6337,8 +6338,10 @@ intel_dp_detect(struct drm_connector *_connector,
> >> > drm_WARN_ON(display->drm,
> >> > !drm_modeset_is_locked(&display->drm->mode_config.connection_mutex));
> >> >
> >> > - if (!intel_display_device_enabled(display))
> >> > + if (!intel_display_device_enabled(display)) {
> >> > +
> >> > drm_connector_dp_reset_link_train_properties(_connector); return
> >> > connector_status_disconnected;
> >> > + }
> >> >
> >> > if (!intel_display_driver_check_access(display))
> >> > return connector->base.status;
> >> > @@ -6388,6 +6391,8 @@ intel_dp_detect(struct drm_connector *_connector,
> >> >
> >> > intel_dp_tunnel_disconnect(intel_dp);
> >> >
> >> > +
> >> > drm_connector_dp_reset_link_train_properties(_connector); +
> >> > goto out_unset_edid;
> >> > }
> >> >
> >> > @@ -7162,10 +7167,12 @@ intel_dp_init_connector(struct intel_digital_port
> >> > *dig_port, struct intel_connector *connector)
> >> > {
> >> > struct intel_display *display = to_intel_display(dig_port);
> >> > + struct drm_connector_dp_link_train_caps link_caps;
> >> > struct intel_dp *intel_dp = &dig_port->dp;
> >> > struct intel_encoder *encoder = &dig_port->base;
> >> > struct drm_device *dev = encoder->base.dev;
> >> > enum port port = encoder->port;
> >> > + u32 *rates;
> >> > int type;
> >> >
> >> > if (drm_WARN(dev, dig_port->max_lanes < 1,
> >> > @@ -7213,8 +7220,25 @@ intel_dp_init_connector(struct intel_digital_port
> >> > *dig_port, type == DRM_MODE_CONNECTOR_eDP ? "eDP" : "DP",
> >> > encoder->base.base.id, encoder->base.name);
> >> >
> >> > - drmm_connector_init(dev, &connector->base,
> >> > &intel_dp_connector_funcs,
> >> > - type, &intel_dp->aux.ddc);
> >> > + intel_dp_set_source_rates(intel_dp);
> >> > + link_caps.nlanes = DRM_DP_1LANE | DRM_DP_2LANE | DRM_DP_4LANE;
> >> > + link_caps.nrates = intel_dp->num_source_rates;
> >> > + rates = kzalloc_objs(*rates, intel_dp->num_source_rates);
> >> > + if (!rates)
> >> > + goto fail;
> >> > +
> >> > + for (int i = 0; i < intel_dp->num_source_rates; i++)
> >> > + rates[i] = intel_dp->source_rates[i];
> >> > +
> >> > + link_caps.rates = rates;
> >> > + link_caps.dsc = true;
> >>
> >> You have a source, you have a sink, and you have a link between the two.
> >>
> >> Source rates do not reflect the link rates common between source and
> >> sink.
> >>
> >> DSC depends on source and sink, and it's not statically "true" for
> >> either, and depends on a bunch of things.
> >
> > At init, we are reporting the capabilities of the source. So we list every
> > link rates that the source can achieve and we report that the source is DSC
> > capable which it is IIUC the code. Or maybe I am missing something?
>
> IMO link caps is the intersection of the source and sink caps. If the
> sink is unknown, i.e. its caps are the empty set, then the link caps
> should also be the empty set.
Ok thanks, I am rather new to the DiplayPort world so thank you for sharing
your knowledge.
IIUC currently the drivers are not testing all the capabilities of the link,
they try the more "powerful" link and decrease the link parameters until it
works right? So there is currently no way to now the full capabilities between a
sink and a source.
> If you need to know the source caps, then they need to be presented
> separately.
With DRM properties we can see possible values and the value set.
My though was that the possible value are matching the source capabilities and
value set was the one negotiated between the source and the sink.
This was straightforward to me but it indeed can confuse between source
capabilities and link capabilities. Have you a better idea?
> Moreover, the source does not unconditionally support DSC. See
> intel_dp_has_dsc().
Indeed thanks, I need to investigate that function.
Regards,
--
Köry Maincent, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH RFC 00/12] Add support for DisplayPort link training information report
From: Jani Nikula @ 2026-04-13 13:29 UTC (permalink / raw)
To: Kory Maincent, Dmitry Baryshkov
Cc: Ville Syrjälä, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, David Airlie, Simona Vetter, Dave Airlie,
Jesse Barnes, Eric Anholt, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Chun-Kuang Hu,
Philipp Zabel, Matthias Brugger, AngeloGioacchino Del Regno,
Chris Wilson, Thomas Petazzoni, Mark Yacoub, Sean Paul,
Louis Chauvet, intel-gfx, intel-xe, dri-devel, linux-kernel,
linux-mediatek, linux-arm-kernel, Simona Vetter
In-Reply-To: <20260413141000.0e190dcc@kmaincent-XPS-13-7390>
On Mon, 13 Apr 2026, Kory Maincent <kory.maincent@bootlin.com> wrote:
> On Fri, 10 Apr 2026 00:36:09 +0300
> Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> wrote:
>
>> On Thu, Apr 09, 2026 at 11:36:21PM +0300, Ville Syrjälä wrote:
>> > On Thu, Apr 09, 2026 at 07:08:16PM +0200, Kory Maincent wrote:
>> > > DisplayPort link training negotiates the physical-layer parameters needed
>> > > for a reliable connection: lane count, link rate, voltage swing,
>> > > pre-emphasis, and optionally Display Stream Compression (DSC). Currently,
>> > > each driver exposes this state in its own way, often through
>> > > driver-specific debugfs entries, with no standard interface for userspace
>> > > diagnostic and monitoring tools.
>> > >
>> > > This series introduces a generic, DRM-managed framework for exposing DP
>> > > link training state as standard connector properties, modeled after the
>> > > existing HDMI helper drmm_connector_hdmi_init().
>> > >
>> > > The new drmm_connector_dp_init() helper initializes a DP connector and
>> > > registers the following connector properties to expose the negotiated link
>> > > state to userspace:
>> > >
>> > > - num_lanes: negotiated lane count (1, 2 or 4)
>> > > - link_rate: negotiated link rate
>> > > - dsc_en: whether Display Stream Compression is active
>> > > - voltage_swingN: per-lane voltage swing level (lanes 0-3)
>> > > - pre_emphasisN: per-lane pre-emphasis level (lanes 0-3)
>> >
>> > I don't see why any real userspace would be interested in those (apart
>> > from maybe DSC). If this is just for diagnostics and whatnot then I
>> > think sysfs/debugfs could be a better fit.
>>
>> I'd agree here. Please consider implementing it as a debugfs interface,
>> possibly reusing the Intel's format.
>
> Sorry, I completely forgot to include a paragraph explaining the rationale
> behind using DRM properties.
>
> This DisplayPort link information report was requested by OSes to allow them to
> assess the capabilities of each DisplayPort connector on the system, and to
> guide users from the most to least capable ones. It will also enable the OS to
> warn the user when a cable is too long or experiencing noise (indicated by high
> voltage swing and pre-emphasis levels).
The selection of the number of lanes or link rate are at the discretion
of the driver, or link policy manager in DP spec terms. It does not
really convey the capabilities of the *connectors* but rather the
current *link*. Ditto for enabling DSC.
I don't think the voltage swing and pre-emphasis are really diagnostic
measures either, but a response to measuring and adapting to the
link. And if the link training failed, the driver may have already
reduced the number of lanes and link rate to compensate. So you could
appear to have the perfect link only because it was so bad at high link
rate that it was reduced already.
The policies may also vary from driver to driver, and possibly depending
on what makes sense for the hardware (e.g. power consumption with or
without DSC).
I think "link information report ... requested by OSs" is vague, and I
don't think the concept has been completely thought through. I can't see
how you could present reliable and actionable information to the user
with what the patch at hand provides. Or how it could work in a generic
manner across drivers.
Overall sounds like an XY problem [1]. We should focus on what you're
trying to achieve first, in userspace, and only then think about what
the appropriate kernel mechanism should be.
I don't think this is it.
BR,
Jani.
[1] https://en.wikipedia.org/wiki/XY_problem
>
> Since this is information that OSes will consume on a regular basis, exposing
> it directly as DRM properties seems the most appropriate approach.
--
Jani Nikula, Intel
^ permalink raw reply
* [PATCH v14 8/8] drm/bridge: analogix_dp: Apply panel_bridge helper
From: Damon Ding @ 2026-04-13 13:25 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, maarten.lankhorst, mripard,
tzimmermann, airlied, simona, inki.dae, sw0312.kim, kyungmin.park,
krzk, jingoohan1, hjc, heiko, andy.yan
Cc: Laurent.pinchart, jonas, jernej.skrabec, alim.akhtar,
dmitry.baryshkov, luca.ceresoli, nicolas.frattaroli, dianders,
m.szyprowski, linux-kernel, dri-devel, linux-arm-kernel,
linux-samsung-soc, linux-rockchip, Damon Ding
In-Reply-To: <20260413132551.1049307-1-damon.ding@rock-chips.com>
In order to unify the handling of the panel and bridge, apply
panel_bridge helpers for Analogix DP driver. With this patch, the
bridge support will also become available.
The following changes have ben made:
- Apply plane_bridge helper to wrap the panel as the bridge.
- Remove the explicit panel APIs calls, which can be replaced with
the automic bridge APIs calls wrapped by the panel.
- Remove the unnecessary analogix_dp_bridge_get_modes().
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Tested-by: Heiko Stuebner <heiko@sntech.de> # rk3588
---
Changes in v4:
- Rename the &analogix_dp_plat_data.bridge to
&analogix_dp_plat_data.next_bridge.
Changes in v5:
- Move panel_bridge addition a little forward.
- Move next_bridge attachment from Analogix side to Rockchip/Exynos
side.
Changes in v6
- Remove the unnecessary analogix_dp_bridge_get_modes().
- Not to set DRM_BRIDGE_OP_MODES if the next is a panel.
- Squash [PATCH v5 15/17]drm/bridge: analogix_dp: Remove panel
disabling and enabling in analogix_dp_set_bridge() into this
commit.
- Fix the &drm_bridge->ops to DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT.
Changes in v9:
- Add Tested-by tag.
Changes in v13:
- Modify '(on rk3588)' to '# rk3588' for Tested-by tag.
---
.../drm/bridge/analogix/analogix_dp_core.c | 41 +++++--------------
1 file changed, 11 insertions(+), 30 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index ec56d900f899..460729fdcecd 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -750,9 +750,6 @@ static int analogix_dp_commit(struct analogix_dp_device *dp)
{
int ret;
- /* Keep the panel disabled while we configure video */
- drm_panel_disable(dp->plat_data->panel);
-
ret = analogix_dp_train_link(dp);
if (ret) {
dev_err(dp->dev, "unable to do link train, ret=%d\n", ret);
@@ -772,9 +769,6 @@ static int analogix_dp_commit(struct analogix_dp_device *dp)
return ret;
}
- /* Safe to enable the panel now */
- drm_panel_enable(dp->plat_data->panel);
-
/* Check whether panel supports fast training */
ret = analogix_dp_fast_link_train_detection(dp);
if (ret)
@@ -859,17 +853,6 @@ static int analogix_dp_disable_psr(struct analogix_dp_device *dp)
return analogix_dp_send_psr_spd(dp, &psr_vsc, true);
}
-static int analogix_dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector *connector)
-{
- struct analogix_dp_device *dp = to_dp(bridge);
- int num_modes = 0;
-
- if (dp->plat_data->panel)
- num_modes += drm_panel_get_modes(dp->plat_data->panel, connector);
-
- return num_modes;
-}
-
static const struct drm_edid *analogix_dp_bridge_edid_read(struct drm_bridge *bridge,
struct drm_connector *connector)
{
@@ -910,7 +893,7 @@ analogix_dp_bridge_detect(struct drm_bridge *bridge, struct drm_connector *conne
struct analogix_dp_device *dp = to_dp(bridge);
enum drm_connector_status status = connector_status_disconnected;
- if (dp->plat_data->panel || dp->plat_data->next_bridge)
+ if (dp->plat_data->next_bridge)
return connector_status_connected;
if (!analogix_dp_detect_hpd(dp))
@@ -996,8 +979,6 @@ static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge,
/* Don't touch the panel if we're coming back from PSR */
if (old_crtc_state && old_crtc_state->self_refresh_active)
return;
-
- drm_panel_prepare(dp->plat_data->panel);
}
static int analogix_dp_set_bridge(struct analogix_dp_device *dp)
@@ -1169,16 +1150,12 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
if (dp->dpms_mode != DRM_MODE_DPMS_ON)
return;
- drm_panel_disable(dp->plat_data->panel);
-
disable_irq(dp->irq);
analogix_dp_set_analog_power_down(dp, POWER_ALL, 1);
pm_runtime_put_sync(dp->dev);
- drm_panel_unprepare(dp->plat_data->panel);
-
dp->fast_train_enable = false;
dp->psr_supported = false;
dp->dpms_mode = DRM_MODE_DPMS_OFF;
@@ -1253,7 +1230,6 @@ static const struct drm_bridge_funcs analogix_dp_bridge_funcs = {
.atomic_post_disable = analogix_dp_bridge_atomic_post_disable,
.atomic_check = analogix_dp_bridge_atomic_check,
.attach = analogix_dp_bridge_attach,
- .get_modes = analogix_dp_bridge_get_modes,
.edid_read = analogix_dp_bridge_edid_read,
.detect = analogix_dp_bridge_detect,
};
@@ -1499,17 +1475,22 @@ int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev)
return ret;
}
- if (dp->plat_data->panel)
- bridge->ops = DRM_BRIDGE_OP_MODES | DRM_BRIDGE_OP_DETECT;
- else
- bridge->ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT;
-
+ bridge->ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT;
bridge->of_node = dp->dev->of_node;
bridge->type = DRM_MODE_CONNECTOR_eDP;
ret = devm_drm_bridge_add(dp->dev, &dp->bridge);
if (ret)
goto err_unregister_aux;
+ if (dp->plat_data->panel) {
+ dp->plat_data->next_bridge = devm_drm_panel_bridge_add(dp->dev,
+ dp->plat_data->panel);
+ if (IS_ERR(dp->plat_data->next_bridge)) {
+ ret = PTR_ERR(bridge);
+ goto err_unregister_aux;
+ }
+ }
+
ret = drm_bridge_attach(dp->encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret) {
DRM_ERROR("failed to create bridge (%d)\n", ret);
--
2.34.1
^ permalink raw reply related
* [PATCH v14 2/8] drm/bridge: analogix_dp: Apply drm_bridge_connector helper
From: Damon Ding @ 2026-04-13 13:25 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, maarten.lankhorst, mripard,
tzimmermann, airlied, simona, inki.dae, sw0312.kim, kyungmin.park,
krzk, jingoohan1, hjc, heiko, andy.yan
Cc: Laurent.pinchart, jonas, jernej.skrabec, alim.akhtar,
dmitry.baryshkov, luca.ceresoli, nicolas.frattaroli, dianders,
m.szyprowski, linux-kernel, dri-devel, linux-arm-kernel,
linux-samsung-soc, linux-rockchip, Damon Ding
In-Reply-To: <20260413132551.1049307-1-damon.ding@rock-chips.com>
Initialize bridge_connector for both Rockchip and Exynos encoder sides.
Then, make DRM_BRIDGE_ATTACH_NO_CONNECTOR mandatory for Analogix bridge
side, as the private &drm_connector is no longer created.
The previous &drm_connector_funcs and &drm_connector_helper_funcs APIs
are replaced by the corresponding &drm_bridge_funcs APIs:
analogix_dp_atomic_check() -> analogix_dp_bridge_atomic_check()
analogix_dp_detect() -> analogix_dp_bridge_detect()
analogix_dp_get_modes() -> analogix_dp_bridge_get_modes()
analogix_dp_bridge_edid_read()
Additionally, the compatibilities of Analogix DP bridge based on whether
the next bridge is a 'panel'. If it is, OP_MODES and OP_DETECT are
supported; If not (the next bridge is a 'monitor' or a bridge chip),
OP_EDID and OP_DETECT are supported.
The devm_drm_bridge_add() is placed in analogix_dp_bind() instead of
analogix_dp_probe(), because the type of next bridge (the panel, monitor
or bridge chip) can only be determined after the probe process has fully
completed.
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Tested-by: Heiko Stuebner <heiko@sntech.de> # rk3588
---
Changes in v2:
- For &drm_bridge.ops, remove DRM_BRIDGE_OP_HPD and add
DRM_BRIDGE_OP_EDID.
- Add analogix_dp_bridge_edid_read().
- Move &analogix_dp_plat_data.skip_connector deletion to the previous
patches.
Changes in v3:
- Rebase with the new devm_drm_bridge_alloc() related commit
48f05c3b4b70 ("drm/bridge: analogix_dp: Use devm_drm_bridge_alloc()
API").
- Expand the commit message.
- Call drm_bridge_get_modes() in analogix_dp_bridge_get_modes() if the
bridge is available.
- Remove unnecessary parameter struct drm_connector* for callback
&analogix_dp_plat_data.attach.
- In order to decouple the connector driver and the bridge driver, move
the bridge connector initilization to the Rockchip and Exynos sides.
Changes in v4:
- Expand analogix_dp_bridge_detect() parameters to &drm_bridge and
&drm_connector.
- Rename the &analogix_dp_plat_data.bridge to
&analogix_dp_plat_data.next_bridge.
Changes in v5:
- Set the flag fo drm_bridge_attach() to DRM_BRIDGE_ATTACH_NO_CONNECTOR
for next bridge attachment of Exynos side.
- Distinguish the &drm_bridge->ops of Analogix bridge based on whether
the downstream device is a panel, a bridge or neither.
- Remove the calls to &analogix_dp_plat_data.get_modes().
Changes in v6:
- Select DRM_BRIDGE_CONNECTOR for both Rockchip and Exynos sides.
- Remove unnecessary drm_bridge_get_modes() in
analogix_dp_bridge_get_modes().
- Simplify analogix_dp_bridge_edid_read().
- If the next is a bridge, set DRM_BRIDGE_OP_DETECT and return
connector_status_connected in analogix_dp_bridge_detect().
- Set flag DRM_BRIDGE_ATTACH_NO_CONNECTOR for bridge attachment while
binding. Meanwhile, make DRM_BRIDGE_ATTACH_NO_CONNECTOR unsuppported
in analogix_dp_bridge_attach().
- Simplify the check of bridge capabilities.
Changes in v7:
- Remove temporary flag &exynos_dp_device.has_of_bridge.
Changes in v9
- Add Tested-by tag.
Changes in v10:
- Split this commit into serval smaller ones.
- Simplify the commit message.
Changes in v11:
- Move the removal of &analogix_dp_device.connector to this commit.
- In exynos_dp_bridge_attach(), set the bridge flag to 'flags |
DRM_BRIDGE_ATTACH_NO_CONNECTOR' instead of fixed
'DRM_BRIDGE_ATTACH_NO_CONNECTOR' for extensibility.
Changes in v12:
- Restore accidentally removed DRM_BRIDGE_CONNECTOR Kconfig in v10.
Changes in v13:
- Rebase after commit 01962a191242 ("drm/rockchip: analogix: Convert
to drm_output_color_format")
- Modify '(on rk3588)' to '# rk3588' for Tested-by tag.
Changes in v14:
- Add Reviewed-by tags.
- Apply __free() to call drm_bridge_put() in CRC ralted functions.
---
.../drm/bridge/analogix/analogix_dp_core.c | 136 +++++++-----------
.../drm/bridge/analogix/analogix_dp_core.h | 1 -
drivers/gpu/drm/exynos/Kconfig | 1 +
drivers/gpu/drm/exynos/exynos_dp.c | 25 ++--
drivers/gpu/drm/rockchip/Kconfig | 1 +
.../gpu/drm/rockchip/analogix_dp-rockchip.c | 11 +-
6 files changed, 79 insertions(+), 96 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 84b994cce900..3c6eed9279d2 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -6,6 +6,7 @@
* Author: Jingoo Han <jg1.han@samsung.com>
*/
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/err.h>
@@ -856,44 +857,32 @@ static int analogix_dp_disable_psr(struct analogix_dp_device *dp)
return analogix_dp_send_psr_spd(dp, &psr_vsc, true);
}
-static int analogix_dp_get_modes(struct drm_connector *connector)
+static int analogix_dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector *connector)
{
- struct analogix_dp_device *dp = to_dp(connector);
- const struct drm_edid *drm_edid;
+ struct analogix_dp_device *dp = to_dp(bridge);
int num_modes = 0;
- if (dp->plat_data->panel) {
+ if (dp->plat_data->panel)
num_modes += drm_panel_get_modes(dp->plat_data->panel, connector);
- } else {
- drm_edid = drm_edid_read_ddc(connector, &dp->aux.ddc);
-
- drm_edid_connector_update(&dp->connector, drm_edid);
-
- if (drm_edid) {
- num_modes += drm_edid_connector_add_modes(&dp->connector);
- drm_edid_free(drm_edid);
- }
- }
return num_modes;
}
-static struct drm_encoder *
-analogix_dp_best_encoder(struct drm_connector *connector)
+static const struct drm_edid *analogix_dp_bridge_edid_read(struct drm_bridge *bridge,
+ struct drm_connector *connector)
{
- struct analogix_dp_device *dp = to_dp(connector);
+ struct analogix_dp_device *dp = to_dp(bridge);
- return dp->encoder;
+ return drm_edid_read_ddc(connector, &dp->aux.ddc);
}
-
-static int analogix_dp_atomic_check(struct drm_connector *connector,
- struct drm_atomic_state *state)
+static int analogix_dp_bridge_atomic_check(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
{
- struct analogix_dp_device *dp = to_dp(connector);
- struct drm_display_info *di = &connector->display_info;
- struct drm_connector_state *conn_state;
- struct drm_crtc_state *crtc_state;
+ struct analogix_dp_device *dp = to_dp(bridge);
+ struct drm_display_info *di = &conn_state->connector->display_info;
u32 mask = BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) | BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422);
if (is_rockchip(dp->plat_data->dev_type)) {
@@ -905,38 +894,21 @@ static int analogix_dp_atomic_check(struct drm_connector *connector,
}
}
- conn_state = drm_atomic_get_new_connector_state(state, connector);
- if (WARN_ON(!conn_state))
- return -ENODEV;
-
conn_state->self_refresh_aware = true;
- if (!conn_state->crtc)
- return 0;
-
- crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
- if (!crtc_state)
- return 0;
-
if (crtc_state->self_refresh_active && !dp->psr_supported)
return -EINVAL;
return 0;
}
-static const struct drm_connector_helper_funcs analogix_dp_connector_helper_funcs = {
- .get_modes = analogix_dp_get_modes,
- .best_encoder = analogix_dp_best_encoder,
- .atomic_check = analogix_dp_atomic_check,
-};
-
static enum drm_connector_status
-analogix_dp_detect(struct drm_connector *connector, bool force)
+analogix_dp_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector)
{
- struct analogix_dp_device *dp = to_dp(connector);
+ struct analogix_dp_device *dp = to_dp(bridge);
enum drm_connector_status status = connector_status_disconnected;
- if (dp->plat_data->panel)
+ if (dp->plat_data->panel || dp->plat_data->next_bridge)
return connector_status_connected;
if (!analogix_dp_detect_hpd(dp))
@@ -945,51 +917,18 @@ analogix_dp_detect(struct drm_connector *connector, bool force)
return status;
}
-static const struct drm_connector_funcs analogix_dp_connector_funcs = {
- .fill_modes = drm_helper_probe_single_connector_modes,
- .detect = analogix_dp_detect,
- .destroy = drm_connector_cleanup,
- .reset = drm_atomic_helper_connector_reset,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
static int analogix_dp_bridge_attach(struct drm_bridge *bridge,
struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct analogix_dp_device *dp = to_dp(bridge);
- struct drm_connector *connector = NULL;
int ret = 0;
- if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
- DRM_ERROR("Fix bridge driver to make connector optional!");
+ if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
+ DRM_ERROR("Unsupported connector creation\n");
return -EINVAL;
}
- if (!dp->plat_data->next_bridge) {
- connector = &dp->connector;
- connector->polled = DRM_CONNECTOR_POLL_HPD;
-
- ret = drm_connector_init(dp->drm_dev, connector,
- &analogix_dp_connector_funcs,
- DRM_MODE_CONNECTOR_eDP);
- if (ret) {
- DRM_ERROR("Failed to initialize connector with drm\n");
- return ret;
- }
-
- drm_connector_helper_add(connector,
- &analogix_dp_connector_helper_funcs);
- drm_connector_attach_encoder(connector, encoder);
- }
-
- /*
- * NOTE: the connector registration is implemented in analogix
- * platform driver, that to say connector would be exist after
- * plat_data->attch return, that's why we record the connector
- * point after plat attached.
- */
if (dp->plat_data->attach) {
ret = dp->plat_data->attach(dp->plat_data, bridge);
if (ret) {
@@ -1309,7 +1248,11 @@ static const struct drm_bridge_funcs analogix_dp_bridge_funcs = {
.atomic_enable = analogix_dp_bridge_atomic_enable,
.atomic_disable = analogix_dp_bridge_atomic_disable,
.atomic_post_disable = analogix_dp_bridge_atomic_post_disable,
+ .atomic_check = analogix_dp_bridge_atomic_check,
.attach = analogix_dp_bridge_attach,
+ .get_modes = analogix_dp_bridge_get_modes,
+ .edid_read = analogix_dp_bridge_edid_read,
+ .detect = analogix_dp_bridge_detect,
};
static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
@@ -1539,6 +1482,7 @@ EXPORT_SYMBOL_GPL(analogix_dp_resume);
int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev)
{
+ struct drm_bridge *bridge = &dp->bridge;
int ret;
dp->drm_dev = drm_dev;
@@ -1552,7 +1496,18 @@ int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev)
return ret;
}
- ret = drm_bridge_attach(dp->encoder, &dp->bridge, NULL, 0);
+ if (dp->plat_data->panel)
+ bridge->ops = DRM_BRIDGE_OP_MODES | DRM_BRIDGE_OP_DETECT;
+ else
+ bridge->ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT;
+
+ bridge->of_node = dp->dev->of_node;
+ bridge->type = DRM_MODE_CONNECTOR_eDP;
+ ret = devm_drm_bridge_add(dp->dev, &dp->bridge);
+ if (ret)
+ goto err_unregister_aux;
+
+ ret = drm_bridge_attach(dp->encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret) {
DRM_ERROR("failed to create bridge (%d)\n", ret);
goto err_unregister_aux;
@@ -1570,7 +1525,6 @@ EXPORT_SYMBOL_GPL(analogix_dp_bind);
void analogix_dp_unbind(struct analogix_dp_device *dp)
{
analogix_dp_bridge_disable(&dp->bridge);
- dp->connector.funcs->destroy(&dp->connector);
drm_panel_unprepare(dp->plat_data->panel);
@@ -1580,7 +1534,9 @@ EXPORT_SYMBOL_GPL(analogix_dp_unbind);
int analogix_dp_start_crc(struct drm_connector *connector)
{
- struct analogix_dp_device *dp = to_dp(connector);
+ struct analogix_dp_device *dp;
+ struct drm_bridge *bridge __free(drm_bridge_put) =
+ drm_bridge_chain_get_first_bridge(connector->encoder);
if (!connector->state->crtc) {
DRM_ERROR("Connector %s doesn't currently have a CRTC.\n",
@@ -1588,13 +1544,25 @@ int analogix_dp_start_crc(struct drm_connector *connector)
return -EINVAL;
}
+ if (!bridge || bridge->type != DRM_MODE_CONNECTOR_eDP)
+ return -EINVAL;
+
+ dp = to_dp(bridge);
+
return drm_dp_start_crc(&dp->aux, connector->state->crtc);
}
EXPORT_SYMBOL_GPL(analogix_dp_start_crc);
int analogix_dp_stop_crc(struct drm_connector *connector)
{
- struct analogix_dp_device *dp = to_dp(connector);
+ struct analogix_dp_device *dp;
+ struct drm_bridge *bridge __free(drm_bridge_put) =
+ drm_bridge_chain_get_first_bridge(connector->encoder);
+
+ if (!bridge || bridge->type != DRM_MODE_CONNECTOR_eDP)
+ return -EINVAL;
+
+ dp = to_dp(bridge);
return drm_dp_stop_crc(&dp->aux);
}
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index 91b215c6a0cf..17347448c6b0 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -154,7 +154,6 @@ struct analogix_dp_device {
struct drm_encoder *encoder;
struct device *dev;
struct drm_device *drm_dev;
- struct drm_connector connector;
struct drm_bridge bridge;
struct drm_dp_aux aux;
struct clk *clock;
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 380d9a8ce259..38bf070866f6 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -70,6 +70,7 @@ config DRM_EXYNOS_DP
bool "Exynos specific extensions for Analogix DP driver"
depends on DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON
select DRM_ANALOGIX_DP
+ select DRM_BRIDGE_CONNECTOR
select DRM_DISPLAY_DP_HELPER
default DRM_EXYNOS
select DRM_OF_DISPLAY_MODE_BRIDGE
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 71a00ee97782..b2597fafd73d 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -22,6 +22,7 @@
#include <drm/bridge/of-display-mode-bridge.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
+#include <drm/drm_bridge_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
@@ -41,8 +42,6 @@ struct exynos_dp_device {
struct analogix_dp_device *adp;
struct analogix_dp_plat_data plat_data;
-
- bool has_of_bridge;
};
static int exynos_dp_crtc_clock_enable(struct analogix_dp_plat_data *plat_data,
@@ -78,10 +77,8 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
/* Pre-empt DP connector creation if there's a bridge */
if (plat_data->next_bridge) {
- if (dp->has_of_bridge)
- flags = DRM_BRIDGE_ATTACH_NO_CONNECTOR;
-
- ret = drm_bridge_attach(&dp->encoder, plat_data->next_bridge, bridge, flags);
+ ret = drm_bridge_attach(&dp->encoder, plat_data->next_bridge, bridge,
+ flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret)
return ret;
}
@@ -111,6 +108,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
struct exynos_dp_device *dp = dev_get_drvdata(dev);
struct drm_encoder *encoder = &dp->encoder;
struct drm_device *drm_dev = data;
+ struct drm_connector *connector;
int ret;
dp->drm_dev = drm_dev;
@@ -126,10 +124,19 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
dp->plat_data.encoder = encoder;
ret = analogix_dp_bind(dp->adp, dp->drm_dev);
- if (ret)
+ if (ret) {
dp->encoder.funcs->destroy(&dp->encoder);
+ return ret;
+ }
+
+ connector = drm_bridge_connector_init(dp->drm_dev, dp->plat_data.encoder);
+ if (IS_ERR(connector)) {
+ ret = PTR_ERR(connector);
+ dev_err(dp->dev, "Failed to initialize bridge_connector\n");
+ return ret;
+ }
- return ret;
+ return drm_connector_attach_encoder(connector, dp->plat_data.encoder);
}
static void exynos_dp_unbind(struct device *dev, struct device *master,
@@ -186,8 +193,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
dp->dev->of_node,
DRM_MODE_CONNECTOR_eDP);
ret = IS_ERR(dp->plat_data.next_bridge) ? PTR_ERR(dp->plat_data.next_bridge) : 0;
- if (!ret)
- dp->has_of_bridge = true;
}
if (ret)
return ret;
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 1479b8c4ed40..e7f49fe845ea 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -46,6 +46,7 @@ config ROCKCHIP_VOP2
config ROCKCHIP_ANALOGIX_DP
bool "Rockchip specific extensions for Analogix DP driver"
depends on ROCKCHIP_VOP
+ select DRM_BRIDGE_CONNECTOR
select DRM_DISPLAY_HELPER
select DRM_DISPLAY_DP_HELPER
help
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 48206a7b767f..99e739f4f583 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -25,6 +25,7 @@
#include <drm/display/drm_dp_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge_connector.h>
#include <drm/bridge/analogix_dp.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
@@ -369,6 +370,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
{
struct rockchip_dp_device *dp = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
+ struct drm_connector *connector;
int ret;
dp->drm_dev = drm_dev;
@@ -388,7 +390,14 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
if (ret)
goto err_cleanup_encoder;
- return 0;
+ connector = drm_bridge_connector_init(dp->drm_dev, dp->plat_data.encoder);
+ if (IS_ERR(connector)) {
+ ret = PTR_ERR(connector);
+ dev_err(dp->dev, "Failed to initialize bridge_connector\n");
+ goto err_cleanup_encoder;
+ }
+
+ return drm_connector_attach_encoder(connector, dp->plat_data.encoder);
err_cleanup_encoder:
dp->encoder.encoder.funcs->destroy(&dp->encoder.encoder);
return ret;
--
2.34.1
^ permalink raw reply related
* [PATCH v14 7/8] drm/bridge: analogix_dp: Remove bridge disabing and panel unpreparing in analogix_dp_unbind()
From: Damon Ding @ 2026-04-13 13:25 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, maarten.lankhorst, mripard,
tzimmermann, airlied, simona, inki.dae, sw0312.kim, kyungmin.park,
krzk, jingoohan1, hjc, heiko, andy.yan
Cc: Laurent.pinchart, jonas, jernej.skrabec, alim.akhtar,
dmitry.baryshkov, luca.ceresoli, nicolas.frattaroli, dianders,
m.szyprowski, linux-kernel, dri-devel, linux-arm-kernel,
linux-samsung-soc, linux-rockchip, Damon Ding
In-Reply-To: <20260413132551.1049307-1-damon.ding@rock-chips.com>
The analogix_dp_unbind() should be balanced with analogix_dp_bind().
There are no bridge enabling and panel preparing in analogix_dp_bind(),
so it should be reasonable to remove the bridge disabing and panel
unpreparing in analogix_dp_unbind().
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Tested-by: Heiko Stuebner <heiko@sntech.de> # rk3588
---
Changes in v9:
- Add Tested-by tag.
Changes in v11:
- Add Reviewed-by tag.
Changes in v13:
- Modify '(on rk3588)' to '# rk3588' for Tested-by tag.
---
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 85033a8ab146..ec56d900f899 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1527,10 +1527,6 @@ EXPORT_SYMBOL_GPL(analogix_dp_bind);
void analogix_dp_unbind(struct analogix_dp_device *dp)
{
- analogix_dp_bridge_disable(&dp->bridge);
-
- drm_panel_unprepare(dp->plat_data->panel);
-
drm_dp_aux_unregister(&dp->aux);
}
EXPORT_SYMBOL_GPL(analogix_dp_unbind);
--
2.34.1
^ permalink raw reply related
* [PATCH v14 6/8] drm/bridge: analogix_dp: Attach the next bridge in analogix_dp_bridge_attach()
From: Damon Ding @ 2026-04-13 13:25 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, maarten.lankhorst, mripard,
tzimmermann, airlied, simona, inki.dae, sw0312.kim, kyungmin.park,
krzk, jingoohan1, hjc, heiko, andy.yan
Cc: Laurent.pinchart, jonas, jernej.skrabec, alim.akhtar,
dmitry.baryshkov, luca.ceresoli, nicolas.frattaroli, dianders,
m.szyprowski, linux-kernel, dri-devel, linux-arm-kernel,
linux-samsung-soc, linux-rockchip, Damon Ding
In-Reply-To: <20260413132551.1049307-1-damon.ding@rock-chips.com>
Uniformly, move the next bridge attachment to the Analogix side
rather than scattered on Rockchip and Exynos sides. It can also
help get rid of the callback &analogix_dp_plat_data.attach() and
make codes more concise.
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Tested-by: Heiko Stuebner <heiko@sntech.de> # rk3588
---
Changes in v6:
- Move the next bridge attachment to the Analogix side rather than
scattered on Rockchip and Exynos sides.
Changes in v9:
- Add Tested-by tag.
Changes in v11:
- Add Reviewed-by tag.
Changes in v13:
- Modify '(on rk3588)' to '# rk3588' for Tested-by tag.
---
.../drm/bridge/analogix/analogix_dp_core.c | 7 ++++---
drivers/gpu/drm/exynos/exynos_dp.c | 19 -------------------
include/drm/bridge/analogix_dp.h | 1 -
3 files changed, 4 insertions(+), 23 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 50415a98acb7..85033a8ab146 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -931,10 +931,11 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge,
return -EINVAL;
}
- if (dp->plat_data->attach) {
- ret = dp->plat_data->attach(dp->plat_data, bridge);
+ if (dp->plat_data->next_bridge) {
+ ret = drm_bridge_attach(dp->encoder, dp->plat_data->next_bridge, bridge,
+ DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret) {
- DRM_ERROR("Failed at platform attach func\n");
+ dev_err(dp->dev, "failed to attach following panel or bridge (%d)\n", ret);
return ret;
}
}
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 9f3d4d4c7352..6884ea6d04eb 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -68,24 +68,6 @@ static int exynos_dp_poweroff(struct analogix_dp_plat_data *plat_data)
return exynos_dp_crtc_clock_enable(plat_data, false);
}
-static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
- struct drm_bridge *bridge)
-{
- struct exynos_dp_device *dp = to_dp(plat_data);
- enum drm_bridge_attach_flags flags = 0;
- int ret;
-
- /* Pre-empt DP connector creation if there's a bridge */
- if (plat_data->next_bridge) {
- ret = drm_bridge_attach(&dp->encoder, plat_data->next_bridge, bridge,
- flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
static void exynos_dp_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -196,7 +178,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
dp->plat_data.dev_type = EXYNOS_DP;
dp->plat_data.power_on = exynos_dp_poweron;
dp->plat_data.power_off = exynos_dp_poweroff;
- dp->plat_data.attach = exynos_dp_bridge_attach;
dp->plat_data.ops = &exynos_dp_ops;
out:
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index bae969dec63a..854af692229b 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -34,7 +34,6 @@ struct analogix_dp_plat_data {
int (*power_on)(struct analogix_dp_plat_data *);
int (*power_off)(struct analogix_dp_plat_data *);
- int (*attach)(struct analogix_dp_plat_data *, struct drm_bridge *);
};
int analogix_dp_resume(struct analogix_dp_device *dp);
--
2.34.1
^ permalink raw reply related
* [PATCH v14 4/8] drm/rockchip: analogix_dp: Apply analogix_dp_finish_probe()
From: Damon Ding @ 2026-04-13 13:25 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, maarten.lankhorst, mripard,
tzimmermann, airlied, simona, inki.dae, sw0312.kim, kyungmin.park,
krzk, jingoohan1, hjc, heiko, andy.yan
Cc: Laurent.pinchart, jonas, jernej.skrabec, alim.akhtar,
dmitry.baryshkov, luca.ceresoli, nicolas.frattaroli, dianders,
m.szyprowski, linux-kernel, dri-devel, linux-arm-kernel,
linux-samsung-soc, linux-rockchip, Damon Ding
In-Reply-To: <20260413132551.1049307-1-damon.ding@rock-chips.com>
Apply analogix_dp_finish_probe() in order to move the panel/bridge
parsing from Rockchip side to the Analogix side.
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Tested-by: Heiko Stuebner <heiko@sntech.de> # rk3588
---
Changes in v4:
- Rename analogix_dp_find_panel_or_bridge() to
analogix_dp_finish_probe().
Changes in v5:
- Remove DRM_DISPLAY_DP_AUX_BUS for ROCKCHIP_ANALOGIX_DP
Changes in v9:
- Add Tested-by tag.
Changes in v13:
- Modify '(on rk3588)' to '# rk3588' for Tested-by tag.
---
.../gpu/drm/rockchip/analogix_dp-rockchip.c | 38 +------------------
1 file changed, 2 insertions(+), 36 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 99e739f4f583..eea230f0227a 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -21,14 +21,12 @@
#include <video/of_videomode.h>
#include <video/videomode.h>
-#include <drm/display/drm_dp_aux_bus.h>
#include <drm/display/drm_dp_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge_connector.h>
#include <drm/bridge/analogix_dp.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
@@ -417,24 +415,6 @@ static const struct component_ops rockchip_dp_component_ops = {
.unbind = rockchip_dp_unbind,
};
-static int rockchip_dp_link_panel(struct drm_dp_aux *aux)
-{
- struct analogix_dp_plat_data *plat_data = analogix_dp_aux_to_plat_data(aux);
- struct rockchip_dp_device *dp = pdata_encoder_to_dp(plat_data);
- int ret;
-
- /*
- * If drm_of_find_panel_or_bridge() returns -ENODEV, there may be no valid panel
- * or bridge nodes. The driver should go on for the driver-free bridge or the DP
- * mode applications.
- */
- ret = drm_of_find_panel_or_bridge(dp->dev->of_node, 1, 0, &plat_data->panel, NULL);
- if (ret && ret != -ENODEV)
- return ret;
-
- return component_add(dp->dev, &rockchip_dp_component_ops);
-}
-
static int rockchip_dp_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -475,6 +455,7 @@ static int rockchip_dp_probe(struct platform_device *pdev)
dp->plat_data.dev_type = dp->data->chip_type;
dp->plat_data.power_on = rockchip_dp_poweron;
dp->plat_data.power_off = rockchip_dp_powerdown;
+ dp->plat_data.ops = &rockchip_dp_component_ops;
ret = rockchip_dp_of_probe(dp);
if (ret < 0)
@@ -486,22 +467,7 @@ static int rockchip_dp_probe(struct platform_device *pdev)
if (IS_ERR(dp->adp))
return PTR_ERR(dp->adp);
- ret = devm_of_dp_aux_populate_bus(analogix_dp_get_aux(dp->adp), rockchip_dp_link_panel);
- if (ret) {
- /*
- * If devm_of_dp_aux_populate_bus() returns -ENODEV, the done_probing() will not
- * be called because there are no EP devices. Then the rockchip_dp_link_panel()
- * will be called directly in order to support the other valid DT configurations.
- *
- * NOTE: The devm_of_dp_aux_populate_bus() is allowed to return -EPROBE_DEFER.
- */
- if (ret != -ENODEV)
- return dev_err_probe(dp->dev, ret, "failed to populate aux bus\n");
-
- return rockchip_dp_link_panel(analogix_dp_get_aux(dp->adp));
- }
-
- return 0;
+ return analogix_dp_finish_probe(dp->adp);
}
static void rockchip_dp_remove(struct platform_device *pdev)
--
2.34.1
^ permalink raw reply related
* [PATCH v14 1/8] drm/bridge: analogix_dp: Pass struct drm_atomic_state* for analogix_dp_bridge_mode_set()
From: Damon Ding @ 2026-04-13 13:25 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, maarten.lankhorst, mripard,
tzimmermann, airlied, simona, inki.dae, sw0312.kim, kyungmin.park,
krzk, jingoohan1, hjc, heiko, andy.yan
Cc: Laurent.pinchart, jonas, jernej.skrabec, alim.akhtar,
dmitry.baryshkov, luca.ceresoli, nicolas.frattaroli, dianders,
m.szyprowski, linux-kernel, dri-devel, linux-arm-kernel,
linux-samsung-soc, linux-rockchip, Damon Ding
In-Reply-To: <20260413132551.1049307-1-damon.ding@rock-chips.com>
To avoid using &analogix_dp_device.connector for compatibility
with the bridge connector framework, get &drm_connector from
&drm_atomic_state instead.
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
Changes in v14:
- Add Reviewed-by tags.
---
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 840c1963e60e..84b994cce900 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1095,14 +1095,21 @@ static int analogix_dp_set_bridge(struct analogix_dp_device *dp)
}
static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge,
+ struct drm_atomic_state *state,
const struct drm_display_mode *mode)
{
struct analogix_dp_device *dp = to_dp(bridge);
- struct drm_display_info *display_info = &dp->connector.display_info;
struct video_info *video = &dp->video_info;
struct device_node *dp_node = dp->dev->of_node;
+ struct drm_connector *connector;
+ struct drm_display_info *display_info;
int vic;
+ connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
+ if (!connector)
+ return;
+ display_info = &connector->display_info;
+
/* Input video interlaces & hsync pol & vsync pol */
video->interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
@@ -1186,7 +1193,7 @@ static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge,
new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc);
if (!new_crtc_state)
return;
- analogix_dp_bridge_mode_set(bridge, &new_crtc_state->adjusted_mode);
+ analogix_dp_bridge_mode_set(bridge, old_state, &new_crtc_state->adjusted_mode);
old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc);
/* Not a full enable, just disable PSR and continue */
--
2.34.1
^ permalink raw reply related
* [PATCH v14 5/8] drm/exynos: exynos_dp: Apply analogix_dp_finish_probe()
From: Damon Ding @ 2026-04-13 13:25 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, maarten.lankhorst, mripard,
tzimmermann, airlied, simona, inki.dae, sw0312.kim, kyungmin.park,
krzk, jingoohan1, hjc, heiko, andy.yan
Cc: Laurent.pinchart, jonas, jernej.skrabec, alim.akhtar,
dmitry.baryshkov, luca.ceresoli, nicolas.frattaroli, dianders,
m.szyprowski, linux-kernel, dri-devel, linux-arm-kernel,
linux-samsung-soc, linux-rockchip, Damon Ding
In-Reply-To: <20260413132551.1049307-1-damon.ding@rock-chips.com>
Apply analogix_dp_finish_probe() in order to move the panel/bridge
parsing from Exynos side to the Analogix side.
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Tested-by: Heiko Stuebner <heiko@sntech.de> # rk3588
---
Changes in v4:
- Rename analogix_dp_find_panel_or_bridge() to
analogix_dp_finish_probe().
Changes in v7:
- Remove exynos_dp_legacy_bridge_init() and inline API
devm_drm_of_display_mode_bridge().
- If the panel or the next_bridge is parsed from DT, use ptr validity
to check whether to call component_add() directly at the end of
probing.
Changes in v9:
- Add Tested-by tag.
Changes in v13:
- Modify '(on rk3588)' to '# rk3588' for Tested-by tag.
---
drivers/gpu/drm/exynos/exynos_dp.c | 19 ++++++++-----------
1 file changed, 8 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index b2597fafd73d..9f3d4d4c7352 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -158,9 +158,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np;
struct exynos_dp_device *dp;
- struct drm_panel *panel;
- struct drm_bridge *bridge;
- int ret;
dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
GFP_KERNEL);
@@ -187,30 +184,30 @@ static int exynos_dp_probe(struct platform_device *pdev)
goto out;
}
- ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, &panel, &bridge);
- if (ret == -ENODEV) {
+ if (of_get_display_timings(dev->of_node)) {
dp->plat_data.next_bridge = devm_drm_of_display_mode_bridge(dp->dev,
dp->dev->of_node,
DRM_MODE_CONNECTOR_eDP);
- ret = IS_ERR(dp->plat_data.next_bridge) ? PTR_ERR(dp->plat_data.next_bridge) : 0;
+ if (IS_ERR(dp->plat_data.next_bridge))
+ return PTR_ERR(dp->plat_data.next_bridge);
}
- if (ret)
- return ret;
/* The remote port can be either a panel or a bridge */
- dp->plat_data.panel = panel;
- dp->plat_data.next_bridge = bridge;
dp->plat_data.dev_type = EXYNOS_DP;
dp->plat_data.power_on = exynos_dp_poweron;
dp->plat_data.power_off = exynos_dp_poweroff;
dp->plat_data.attach = exynos_dp_bridge_attach;
+ dp->plat_data.ops = &exynos_dp_ops;
out:
dp->adp = analogix_dp_probe(dev, &dp->plat_data);
if (IS_ERR(dp->adp))
return PTR_ERR(dp->adp);
- return component_add(&pdev->dev, &exynos_dp_ops);
+ if (dp->plat_data.panel || dp->plat_data.next_bridge)
+ return component_add(&pdev->dev, &exynos_dp_ops);
+ else
+ return analogix_dp_finish_probe(dp->adp);
}
static void exynos_dp_remove(struct platform_device *pdev)
--
2.34.1
^ permalink raw reply related
* [PATCH v14 0/8] Apply drm_bridge_connector and panel_bridge helper for the Analogix DP driver
From: Damon Ding @ 2026-04-13 13:25 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, maarten.lankhorst, mripard,
tzimmermann, airlied, simona, inki.dae, sw0312.kim, kyungmin.park,
krzk, jingoohan1, hjc, heiko, andy.yan
Cc: Laurent.pinchart, jonas, jernej.skrabec, alim.akhtar,
dmitry.baryshkov, luca.ceresoli, nicolas.frattaroli, dianders,
m.szyprowski, linux-kernel, dri-devel, linux-arm-kernel,
linux-samsung-soc, linux-rockchip, Damon Ding
Picked from:
https://lore.kernel.org/all/20260409065301.446670-1-damon.ding@rock-chips.com/
PATCH 1 is the preparation for apply drm_bridge_connector helper.
PATCH 2 is to apply the drm_bridge_connector helper.
PATCH 3-5 are to move the panel/bridge parsing to the Analogix side.
PATCH 6 is to attach the next bridge on Analogix side uniformly.
PATCH 7-8 are to apply the panel_bridge helper.
Damon Ding (8):
drm/bridge: analogix_dp: Pass struct drm_atomic_state* for
analogix_dp_bridge_mode_set()
drm/bridge: analogix_dp: Apply drm_bridge_connector helper
drm/bridge: analogix_dp: Add new API analogix_dp_finish_probe()
drm/rockchip: analogix_dp: Apply analogix_dp_finish_probe()
drm/exynos: exynos_dp: Apply analogix_dp_finish_probe()
drm/bridge: analogix_dp: Attach the next bridge in
analogix_dp_bridge_attach()
drm/bridge: analogix_dp: Remove bridge disabing and panel unpreparing
in analogix_dp_unbind()
drm/bridge: analogix_dp: Apply panel_bridge helper
drivers/gpu/drm/bridge/analogix/Kconfig | 1 +
.../drm/bridge/analogix/analogix_dp_core.c | 225 +++++++++---------
.../drm/bridge/analogix/analogix_dp_core.h | 1 -
drivers/gpu/drm/exynos/Kconfig | 1 +
drivers/gpu/drm/exynos/exynos_dp.c | 59 ++---
drivers/gpu/drm/rockchip/Kconfig | 1 +
.../gpu/drm/rockchip/analogix_dp-rockchip.c | 49 +---
include/drm/bridge/analogix_dp.h | 3 +-
8 files changed, 150 insertions(+), 190 deletions(-)
---
Changes in v2:
- Update Exynos DP driver synchronously.
- Move the panel/bridge parsing to the Analogix side.
Changes in v3:
- Rebase for the existing devm_drm_bridge_alloc() applying commit.
- Fix the typographical error of panel/bridge check in exynos_dp_bind().
- Squash all commits related to skip_connector deletion in both Exynos and
Analogix code into one.
- Apply panel_bridge helper to make the codes more concise.
- Fix the handing of bridge in analogix_dp_bridge_get_modes().
- Remove unnecessary parameter struct drm_connector* for callback
&analogix_dp_plat_data.attach().
- In order to decouple the connector driver and the bridge driver, move
the bridge connector initilization to the Rockchip and Exynos sides.
Changes in v4:
- Rebase for the applied &drm_bridge_funcs.detect() modification commit.
- Rename analogix_dp_find_panel_or_bridge() to analogix_dp_finish_probe().
- Drop the drmm_encoder_init() modification commit.
- Rename the &analogix_dp_plat_data.bridge to
&analogix_dp_plat_data.next_bridge.
Changes in v5:
- Add legacy bridge to parse the display-timings node under the dp node
for Exynos side.
- Move color format check to &drm_connector_helper_funcs.atomic_check()
in order to get rid of &analogix_dp_plat_data.get_modes().
- Remove unused callback &analogix_dp_plat_data.get_modes().
- Distinguish the &drm_bridge->ops of Analogix bridge based on whether
the downstream device is a panel, a bridge or neither.
- Select DRM_DISPLAY_DP_AUX_BUS for DRM_ANALOGIX_DP, and remove it for
ROCKCHIP_ANALOGIX_DP.
- Apply rockchip_dp_attach() to support the next bridge attachment for
the Rockchip side.
- Move next_bridge attachment from Analogix side to Rockchip/Exynos sides.
Changes in v6:
- Move legacy bridge driver out of imx directory for multi-platform use.
- Apply DRM legacy bridge to parse display timings intead of implementing
the same codes only for Exynos DP.
- Ensure last bridge determines EDID/modes detection capabilities in DRM
bridge_connector driver.
- Remove unnecessary drm_bridge_get_modes() in
analogix_dp_bridge_get_modes().
- Simplify analogix_dp_bridge_edid_read().
- If the next is a bridge, set DRM_BRIDGE_OP_DETECT and return
connector_status_connected in analogix_dp_bridge_detect().
- Set flag DRM_BRIDGE_ATTACH_NO_CONNECTOR for bridge attachment while
binding. Meanwhile, make DRM_BRIDGE_ATTACH_NO_CONNECTOR unsuppported
in analogix_dp_bridge_attach().
- Move the next bridge attachment to the Analogix side rather than
scattered on Rockchip and Exynos sides.
- Remove the unnecessary analogix_dp_bridge_get_modes().
- Squash [PATCH v5 15/17] into [PATCH v5 17/17].
- Fix the &drm_bridge->ops to DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT.
Changes in v7:
- As Luca suggested, simplify the code and related comment for bridge_connector
modifications. Additionally, move the commit related to bridge_connector to
the top of this patch series.
- Rename legacy-bridge driver to of-display-mode-bridge driver.
- Remove unnecessary API drm_bridge_is_legacy() and apply a temporary flag
&exynos_dp_device.has_of_bridge instead, which will be removed finally.
- Remove exynos_dp_legacy_bridge_init() and inline API
devm_drm_of_display_mode_bridge().
Changes in v8:
- Adapt the related modifications to the newest bridge_connector driver.
Changes in v9:
- Fix the Kconfig help text for CONFIG_DRM_OF_DISPLAY_MODE_BRIDGE.
- Add Tested-by tag from Heiko.
Changes in v10:
- Fix to use dev_err_probe() in newly added API analogix_dp_finish_probe().
- Expaned commit message for [PATCH v9 9/15] and [PATCH v9 10/15].
- Split [PATCH v9 9/15] into serval smaller commits.
- Add Reviewed-by tags from Luca.
Changes in v11:
- Merge [PATCH v10 12/18] into [PATCH v10 11/18].
- Fix the bridge flag to 'flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR' in
[PATCH v10 11/18].
- Add Reviewed-by tags from Luca.
Changes in v12:
- Restore accidentally removed DRM_BRIDGE_CONNECTOR Kconfig in v10.
Changes in v13:
- Modify '(on rk3588)' to '# rk3588' for Tested-by tag as discussed in
https://lore.kernel.org/all/571cc85a-3310-4b56-a3ef-3aab698192f6@rock-chips.com/
- Rebase [PATCH v12 2/17] after commit 02df94d98ff8 ("drm/imx: parallel-display:
add DRM_DISPLAY_HELPER for DRM_IMX_PARALLEL_DISPLAY")
- Rebase [PATCH v12 7/17] and [PATCH v12 11/17] after commit 01962a191242
("drm/rockchip: analogix: Convert to drm_output_color_format")
Changes in v14:
- Picked from
https://lore.kernel.org/all/20260409065301.446670-1-damon.ding@rock-chips.com/
- Add Reviewed-by tags.
- Apply __free() to call drm_bridge_put() in CRC ralted functions of Analogix
side.
--
2.34.1
^ permalink raw reply
* [PATCH v14 3/8] drm/bridge: analogix_dp: Add new API analogix_dp_finish_probe()
From: Damon Ding @ 2026-04-13 13:25 UTC (permalink / raw)
To: andrzej.hajda, neil.armstrong, rfoss, maarten.lankhorst, mripard,
tzimmermann, airlied, simona, inki.dae, sw0312.kim, kyungmin.park,
krzk, jingoohan1, hjc, heiko, andy.yan
Cc: Laurent.pinchart, jonas, jernej.skrabec, alim.akhtar,
dmitry.baryshkov, luca.ceresoli, nicolas.frattaroli, dianders,
m.szyprowski, linux-kernel, dri-devel, linux-arm-kernel,
linux-samsung-soc, linux-rockchip, Damon Ding
In-Reply-To: <20260413132551.1049307-1-damon.ding@rock-chips.com>
Since the panel/bridge should logically be positioned behind the
Analogix bridge in the display pipeline, it makes sense to handle
the panel/bridge parsing on the Analogix side. Therefore, we add
a new API analogix_dp_finish_probe(), which combines the panel/bridge
parsing with component addition, to do it.
In order to process component binding right after the probe completes,
the &analogix_dp_plat_data.ops is newly added to pass &component_ops,
for which the &dp_aux_ep_device_with_data.done_probing() of DP AUX bus
only supports passing &drm_dp_aux.
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Tested-by: Heiko Stuebner <heiko@sntech.de> # rk3588
---
Changes in v4:
- Rename the &analogix_dp_plat_data.bridge to
&analogix_dp_plat_data.next_bridge.
- Remame API analogix_dp_find_panel_or_bridge() to
analogix_dp_finish_probe().
Changes in v5:
- Select DRM_DISPLAY_DP_AUX_BUS for DRM_ANALOGIX_DP.
Changes in v9:
- Add Tested-by tag.
Changes in v10:
- Fix to use dev_err_probe() in analogix_dp_finish_probe().
- Expand the commit message.
Changes in v13:
- Modify '(on rk3588)' to '# rk3588' for Tested-by tag.
---
drivers/gpu/drm/bridge/analogix/Kconfig | 1 +
.../drm/bridge/analogix/analogix_dp_core.c | 46 +++++++++++++++++++
include/drm/bridge/analogix_dp.h | 2 +
3 files changed, 49 insertions(+)
diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig
index 03dc7ffe824a..8a6136cd675f 100644
--- a/drivers/gpu/drm/bridge/analogix/Kconfig
+++ b/drivers/gpu/drm/bridge/analogix/Kconfig
@@ -29,6 +29,7 @@ config DRM_ANALOGIX_ANX78XX
config DRM_ANALOGIX_DP
tristate
depends on DRM
+ select DRM_DISPLAY_DP_AUX_BUS
config DRM_ANALOGIX_ANX7625
tristate "Analogix Anx7625 MIPI to DP interface support"
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 3c6eed9279d2..50415a98acb7 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -21,12 +21,14 @@
#include <linux/platform_device.h>
#include <drm/bridge/analogix_dp.h>
+#include <drm/display/drm_dp_aux_bus.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
#include <drm/drm_edid.h>
+#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -1582,6 +1584,50 @@ struct drm_dp_aux *analogix_dp_get_aux(struct analogix_dp_device *dp)
}
EXPORT_SYMBOL_GPL(analogix_dp_get_aux);
+static int analogix_dp_aux_done_probing(struct drm_dp_aux *aux)
+{
+ struct analogix_dp_device *dp = to_dp(aux);
+ struct analogix_dp_plat_data *plat_data = dp->plat_data;
+ int port = plat_data->dev_type == EXYNOS_DP ? 0 : 1;
+ int ret;
+
+ /*
+ * If drm_of_find_panel_or_bridge() returns -ENODEV, there may be no valid panel
+ * or bridge nodes. The driver should go on for the driver-free bridge or the DP
+ * mode applications.
+ */
+ ret = drm_of_find_panel_or_bridge(dp->dev->of_node, port, 0,
+ &plat_data->panel, &plat_data->next_bridge);
+ if (ret && ret != -ENODEV)
+ return ret;
+
+ return component_add(dp->dev, plat_data->ops);
+}
+
+int analogix_dp_finish_probe(struct analogix_dp_device *dp)
+{
+ int ret;
+
+ ret = devm_of_dp_aux_populate_bus(&dp->aux, analogix_dp_aux_done_probing);
+ if (ret) {
+ /*
+ * If devm_of_dp_aux_populate_bus() returns -ENODEV, the done_probing() will
+ * not be called because there are no EP devices. Then the callback function
+ * analogix_dp_aux_done_probing() will be called directly in order to support
+ * the other valid DT configurations.
+ *
+ * NOTE: The devm_of_dp_aux_populate_bus() is allowed to return -EPROBE_DEFER.
+ */
+ if (ret != -ENODEV)
+ return dev_err_probe(dp->dev, ret, "failed to populate aux bus\n");
+
+ return analogix_dp_aux_done_probing(&dp->aux);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_finish_probe);
+
MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
MODULE_DESCRIPTION("Analogix DP Core Driver");
MODULE_LICENSE("GPL v2");
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index 3428ffff24c5..bae969dec63a 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -30,6 +30,7 @@ struct analogix_dp_plat_data {
struct drm_bridge *next_bridge;
struct drm_encoder *encoder;
struct drm_connector *connector;
+ const struct component_ops *ops;
int (*power_on)(struct analogix_dp_plat_data *);
int (*power_off)(struct analogix_dp_plat_data *);
@@ -49,5 +50,6 @@ int analogix_dp_stop_crc(struct drm_connector *connector);
struct analogix_dp_plat_data *analogix_dp_aux_to_plat_data(struct drm_dp_aux *aux);
struct drm_dp_aux *analogix_dp_get_aux(struct analogix_dp_device *dp);
+int analogix_dp_finish_probe(struct analogix_dp_device *dp);
#endif /* _ANALOGIX_DP_H_ */
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v2 3/4] perf/arm64: Add BRBE support for bpf_get_branch_snapshot()
From: Puranjay Mohan @ 2026-04-13 13:15 UTC (permalink / raw)
To: Rob Herring
Cc: bpf, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Martin KaFai Lau, Eduard Zingerman, Kumar Kartikeya Dwivedi,
Will Deacon, Mark Rutland, Catalin Marinas, Leo Yan, Breno Leitao,
linux-arm-kernel, linux-perf-users, kernel-team
In-Reply-To: <20260410192300.GA1050337-robh@kernel.org>
On Fri, Apr 10, 2026 at 8:23 PM Rob Herring <robh@kernel.org> wrote:
>
> On Wed, Mar 18, 2026 at 10:16:57AM -0700, Puranjay Mohan wrote:
> > Enable the bpf_get_branch_snapshot() BPF helper on ARM64 by implementing
> > the perf_snapshot_branch_stack static call for ARM's Branch Record Buffer
> > Extension (BRBE).
> >
> > The BPF helper bpf_get_branch_snapshot() allows BPF programs to capture
> > hardware branch records on-demand. This was previously only available on
> > x86 (Intel LBR) but not on ARM64 despite BRBE being available since
> > ARMv9.
> >
> > BRBE is paused before disabling interrupts because local_irq_save() can
> > trigger trace_hardirqs_off() which performs stack walking and pollutes
> > the branch buffer. The sysreg read/write and ISB used to pause BRBE are
> > branchless, so pausing first avoids this pollution.
> >
> > All exceptions are masked after pausing BRBE using local_daif_save() to
> > prevent pseudo-NMI from PMU counter overflow from interfering with the
> > snapshot read. A PMU overflow arriving between the pause and
> > local_daif_save() can re-enable BRBE via the interrupt handler; the
> > snapshot detects this by re-checking BRBFCR_EL1.PAUSED and bailing out.
> >
> > Branch records are read using the existing perf_entry_from_brbe_regset()
> > helper with a NULL event pointer, which bypasses event-specific filtering
> > and captures all recorded branches. The BPF program is responsible for
> > filtering entries based on its own criteria. The BRBE buffer is
> > invalidated after reading to maintain contiguity for other consumers.
> >
> > On heterogeneous big.LITTLE systems, only some CPUs may implement
> > FEAT_BRBE. The perf_snapshot_branch_stack static call is system-wide, so
> > a per-CPU brbe_active flag is used to prevent BRBE sysreg access on CPUs
> > that do not implement FEAT_BRBE, where such access would be UNDEFINED.
>
> Is this something you've seen? IIRC, the existing assumption is all CPUs
> have FEAT_BRBE or that perf has been limited to those CPUs. It is
> allowed that the number of records can vary.
I just added it as a safeguard, but if you say that it is not
possible, I will remove this in the next version.
>
> >
> > Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
> > ---
> > drivers/perf/arm_brbe.c | 79 +++++++++++++++++++++++++++++++++++++++-
> > drivers/perf/arm_brbe.h | 9 +++++
> > drivers/perf/arm_pmuv3.c | 5 ++-
> > 3 files changed, 90 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/perf/arm_brbe.c b/drivers/perf/arm_brbe.c
> > index ba554e0c846c..527c2d5ebba6 100644
> > --- a/drivers/perf/arm_brbe.c
> > +++ b/drivers/perf/arm_brbe.c
> > @@ -8,9 +8,13 @@
> > */
> > #include <linux/types.h>
> > #include <linux/bitmap.h>
> > +#include <linux/percpu.h>
> > #include <linux/perf/arm_pmu.h>
> > +#include <asm/daifflags.h>
> > #include "arm_brbe.h"
> >
> > +static DEFINE_PER_CPU(bool, brbe_active);
> > +
> > #define BRBFCR_EL1_BRANCH_FILTERS (BRBFCR_EL1_DIRECT | \
> > BRBFCR_EL1_INDIRECT | \
> > BRBFCR_EL1_RTN | \
> > @@ -533,6 +537,8 @@ void brbe_enable(const struct arm_pmu *arm_pmu)
> > /* Finally write SYS_BRBFCR_EL to unpause BRBE */
> > write_sysreg_s(brbfcr, SYS_BRBFCR_EL1);
> > /* Synchronization in PMCR write ensures ordering WRT PMU enabling */
> > +
> > + this_cpu_write(brbe_active, true);
> > }
> >
> > void brbe_disable(void)
> > @@ -544,6 +550,7 @@ void brbe_disable(void)
> > */
> > write_sysreg_s(BRBFCR_EL1_PAUSED, SYS_BRBFCR_EL1);
> > write_sysreg_s(0, SYS_BRBCR_EL1);
> > + this_cpu_write(brbe_active, false);
> > }
> >
> > static const int brbe_type_to_perf_type_map[BRBINFx_EL1_TYPE_DEBUG_EXIT + 1][2] = {
> > @@ -618,10 +625,10 @@ static bool perf_entry_from_brbe_regset(int index, struct perf_branch_entry *ent
> >
> > brbe_set_perf_entry_type(entry, brbinf);
> >
> > - if (!branch_sample_no_cycles(event))
> > + if (!event || !branch_sample_no_cycles(event))
> > entry->cycles = brbinf_get_cycles(brbinf);
> >
> > - if (!branch_sample_no_flags(event)) {
> > + if (!event || !branch_sample_no_flags(event)) {
> > /* Mispredict info is available for source only and complete branch records. */
> > if (!brbe_record_is_target_only(brbinf)) {
> > entry->mispred = brbinf_get_mispredict(brbinf);
> > @@ -803,3 +810,71 @@ void brbe_read_filtered_entries(struct perf_branch_stack *branch_stack,
> > done:
> > branch_stack->nr = nr_filtered;
> > }
> > +
> > +/*
> > + * Best-effort BRBE snapshot for BPF tracing. Pause BRBE to avoid
> > + * self-recording and return 0 if the snapshot state appears disturbed.
> > + */
> > +int arm_brbe_snapshot_branch_stack(struct perf_branch_entry *entries, unsigned int cnt)
> > +{
> > + unsigned long flags;
> > + int nr_hw, nr_banks, nr_copied = 0;
> > + u64 brbidr, brbfcr, brbcr;
> > +
> > + if (!cnt || !__this_cpu_read(brbe_active))
> > + return 0;
> > +
> > + /* Pause BRBE first to avoid recording our own branches. */
> > + brbfcr = read_sysreg_s(SYS_BRBFCR_EL1);
> > + brbcr = read_sysreg_s(SYS_BRBCR_EL1);
> > + write_sysreg_s(brbfcr | BRBFCR_EL1_PAUSED, SYS_BRBFCR_EL1);
> > + isb();
>
> Is there something that guarantees BRBE is enabled when you enter this
> function and that it is not disabled in this window? A context switch
> could disable it unless it's a global event for example.
The user space program handling this BPF program should create a
system wide event in the expected use case. But you are right that it
is not guaranteed to be enabled, I will check and return early in that
case.
>
> > +
> > + /* Block local exception delivery while reading the buffer. */
> > + flags = local_daif_save();
> > +
> > + /*
> > + * A PMU overflow before local_daif_save() could have re-enabled
> > + * BRBE, clearing the PAUSED bit. The overflow handler already
> > + * restored BRBE to its correct state, so just bail out.
> > + */
> > + if (!(read_sysreg_s(SYS_BRBFCR_EL1) & BRBFCR_EL1_PAUSED)) {
> > + local_daif_restore(flags);
> > + return 0;
> > + }
> > +
> > + brbidr = read_sysreg_s(SYS_BRBIDR0_EL1);
> > + if (!valid_brbidr(brbidr))
>
> This is not possibly true if brbe_active is true. If BRBIDR is not
> valid, then we would have rejected any event requesting branch stack.
Will remove it in the next version.
>
> > + goto out;
> > +
> > + nr_hw = FIELD_GET(BRBIDR0_EL1_NUMREC_MASK, brbidr);
> > + nr_banks = DIV_ROUND_UP(nr_hw, BRBE_BANK_MAX_ENTRIES);
> > +
> > + for (int bank = 0; bank < nr_banks; bank++) {
> > + int nr_remaining = nr_hw - (bank * BRBE_BANK_MAX_ENTRIES);
> > + int nr_this_bank = min(nr_remaining, BRBE_BANK_MAX_ENTRIES);
> > +
> > + select_brbe_bank(bank);
> > +
> > + for (int i = 0; i < nr_this_bank; i++) {
>
> I don't love all this being duplicated. Perhaps an iterator would help
> here (and the other copy):
>
> static void next_slot(int *bank, int *bank_idx, int nr_hw)
> {
> *bank_idx++;
> if (*bank_idx + (*bank * BRBE_BANK_MAX_ENTRIES) == nr_hw)
> bank = BRBE_MAX_BANKS;
> else if ((*bank_idx % BRBE_BANK_MAX_ENTRIES) == 0) {
> *bank_idx = 0;
> select_brbe_bank(++(*bank));
> }
>
> }
>
> #define for_each_bank_slot(i, nr_hw) \
> for (int bank = 0, int i = 0; bank < BRBE_MAX_BANKS; next_slot(&bank,
> &i))
>
> Then here you just have:
>
> for_each_bank_slot(i, FIELD_GET(BRBIDR0_EL1_NUMREC_MASK, brbidr)) {
> ...
> }
>
> Feel free to come up with better naming. :)
Will add this to the next version, thanks
>
> > + if (nr_copied >= cnt)
> > + goto done;
> > +
> > + if (!perf_entry_from_brbe_regset(i, &entries[nr_copied], NULL))
> > + goto done;
> > +
> > + nr_copied++;
> > + }
> > + }
> > +
> > +done:
> > + brbe_invalidate();
> > +out:
> > + /* Restore BRBCR before unpausing via BRBFCR, matching brbe_enable(). */
> > + write_sysreg_s(brbcr, SYS_BRBCR_EL1);
> > + isb();
> > + write_sysreg_s(brbfcr, SYS_BRBFCR_EL1);
> > + local_daif_restore(flags);
> > +
> > + return nr_copied;
> > +}
^ permalink raw reply
* Re: [PATCH v2] pmdomain: imx: Make IMX8M/IMX9 BLK_CTRL tristate
From: Marco Felsch @ 2026-04-13 13:11 UTC (permalink / raw)
To: Zhipeng Wang
Cc: ulfh, Frank.Li, s.hauer, imx, linux-pm, xuegang.liu, jindong.yue,
linux-kernel, kernel, festevam, linux-arm-kernel
In-Reply-To: <20260413053049.3041177-1-zhipeng.wang_1@nxp.com>
On 26-04-13, Zhipeng Wang wrote:
> Convert IMX8M_BLK_CTRL and IMX9_BLK_CTRL from bool to tristate
> to allow building as loadable modules.
Out of curiosity, why do you want to have a PM driver to be buildable as
module?
Regards,
Marco
> Add prompt strings to make these options visible and configurable
> in menuconfig, keeping them enabled by default on appropriate platforms.
>
> Also remove the IMX_GPCV2_PM_DOMAINS dependency from IMX9_BLK_CTRL.
> This dependency was incorrect from the beginning - i.MX93 uses a
> different power domain architecture compared to i.MX8M series:
>
> - i.MX8M uses GPCv2 (General Power Controller v2) for power domain
> management, hence IMX8M_BLK_CTRL correctly depends on it.
>
> - i.MX93 uses BLK_CTRL directly without GPCv2. The hardware doesn't
> have GPCv2 at all.
>
> Signed-off-by: Zhipeng Wang <zhipeng.wang_1@nxp.com>
> ---
> drivers/pmdomain/imx/Kconfig | 11 +++++++----
> 1 file changed, 7 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/pmdomain/imx/Kconfig b/drivers/pmdomain/imx/Kconfig
> index 00203615c65e..9168d183b0c5 100644
> --- a/drivers/pmdomain/imx/Kconfig
> +++ b/drivers/pmdomain/imx/Kconfig
> @@ -10,15 +10,18 @@ config IMX_GPCV2_PM_DOMAINS
> default y if SOC_IMX7D
>
> config IMX8M_BLK_CTRL
> - bool
> - default SOC_IMX8M && IMX_GPCV2_PM_DOMAINS
> + tristate "i.MX8M BLK CTRL driver"
> + depends on SOC_IMX8M
> + depends on IMX_GPCV2_PM_DOMAINS
> depends on PM_GENERIC_DOMAINS
> depends on COMMON_CLK
> + default y
>
> config IMX9_BLK_CTRL
> - bool
> - default SOC_IMX9 && IMX_GPCV2_PM_DOMAINS
> + tristate "i.MX93 BLK CTRL driver"
> + depends on SOC_IMX9
> depends on PM_GENERIC_DOMAINS
> + default y
>
> config IMX_SCU_PD
> bool "IMX SCU Power Domain driver"
> --
> 2.34.1
>
>
>
--
#gernperDu
#CallMeByMyFirstName
Pengutronix e.K. | |
Steuerwalder Str. 21 | https://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 |
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox