* [PATCH 01/11] drm: of: drm_of_find_panel_or_bridge: simplify freeing the remote node pointer
2026-08-14 14:05 [PATCH 00/11] drm/panel: add a panel_bridge to every panel Luca Ceresoli
@ 2026-08-14 14:05 ` Luca Ceresoli
2026-08-17 8:21 ` Maxime Ripard
2026-08-14 14:05 ` [PATCH 02/11] drm: of: drm_of_find_panel_or_bridge: simplify error return paths Luca Ceresoli
` (10 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: Luca Ceresoli @ 2026-08-14 14:05 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Jessica Zhang,
Linus Walleij, Inki Dae, Jagan Teki, Marek Szyprowski
Cc: Dmitry Baryshkov, Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel,
linux-kernel, Luca Ceresoli
In prepataion to further modify the logic of this function, simplify
putting the struct device_node pointer by using a cleanup action.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/drm_of.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c
index e495117735e1..b42a321f3052 100644
--- a/drivers/gpu/drm/drm_of.c
+++ b/drivers/gpu/drm/drm_of.c
@@ -288,7 +288,6 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
struct drm_bridge **bridge)
{
int ret = -EPROBE_DEFER;
- struct device_node *remote;
if (WARN_ON(!panel))
return -EINVAL;
@@ -304,7 +303,8 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
if (!of_graph_is_present(np))
return -ENODEV;
- remote = of_graph_get_remote_node(np, port, endpoint);
+ struct device_node *remote __free(device_node) =
+ of_graph_get_remote_node(np, port, endpoint);
if (!remote)
return -ENODEV;
@@ -326,7 +326,6 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
}
- of_node_put(remote);
return ret;
}
EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge);
--
2.55.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH 01/11] drm: of: drm_of_find_panel_or_bridge: simplify freeing the remote node pointer
2026-08-14 14:05 ` [PATCH 01/11] drm: of: drm_of_find_panel_or_bridge: simplify freeing the remote node pointer Luca Ceresoli
@ 2026-08-17 8:21 ` Maxime Ripard
0 siblings, 0 replies; 25+ messages in thread
From: Maxime Ripard @ 2026-08-17 8:21 UTC (permalink / raw)
To: Luca Ceresoli
Cc: dri-devel, linux-kernel, Andrzej Hajda, David Airlie,
Dmitry Baryshkov, Hui Pu, Ian Ray, Inki Dae, Jagan Teki,
Jernej Skrabec, Jessica Zhang, Jonas Karlman, Laurent Pinchart,
Linus Walleij, Maarten Lankhorst, Marek Szyprowski, Maxime Ripard,
Neil Armstrong, Robert Foss, Simona Vetter, Thomas Petazzoni,
Thomas Zimmermann
On Fri, 14 Aug 2026 16:05:49 +0200, Luca Ceresoli wrote:
> In prepataion to further modify the logic of this function, simplify
> putting the struct device_node pointer by using a cleanup action.
>
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Thanks!
Maxime
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 02/11] drm: of: drm_of_find_panel_or_bridge: simplify error return paths
2026-08-14 14:05 [PATCH 00/11] drm/panel: add a panel_bridge to every panel Luca Ceresoli
2026-08-14 14:05 ` [PATCH 01/11] drm: of: drm_of_find_panel_or_bridge: simplify freeing the remote node pointer Luca Ceresoli
@ 2026-08-14 14:05 ` Luca Ceresoli
2026-08-17 8:23 ` Maxime Ripard
2026-08-14 14:05 ` [PATCH 03/11] drm: of: drm_of_find_panel_or_bridge: prioritize the bridge, not the panel Luca Ceresoli
` (9 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: Luca Ceresoli @ 2026-08-14 14:05 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Jessica Zhang,
Linus Walleij, Inki Dae, Jagan Teki, Marek Szyprowski
Cc: Dmitry Baryshkov, Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel,
linux-kernel, Luca Ceresoli
In prepataion to further modify the logic of this function, simplify the
error-returning code.
With this change, on any error there is an immediate 'return -<ERRNO>;'
statement, without having to carry on the return value until the end.
Additionally, clear both the panel and the bridge pointers at the
beginning. Even though this is redundant in some code paths, it allows to
have a simpler code in the rest of the function.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/drm_of.c | 25 +++++++++++--------------
1 file changed, 11 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c
index b42a321f3052..8ec352f3df93 100644
--- a/drivers/gpu/drm/drm_of.c
+++ b/drivers/gpu/drm/drm_of.c
@@ -287,12 +287,12 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
struct drm_panel **panel,
struct drm_bridge **bridge)
{
- int ret = -EPROBE_DEFER;
-
if (WARN_ON(!panel))
return -EINVAL;
*panel = NULL;
+ if (bridge)
+ *bridge = NULL;
/*
* of_graph_get_remote_node() produces a noisy error message if port
@@ -310,23 +310,20 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
*panel = of_drm_find_panel(remote);
if (!IS_ERR(*panel))
- ret = 0;
- else
- *panel = NULL;
+ return 0;
+
+ *panel = NULL;
if (bridge) {
- if (ret) {
- /* No panel found yet, check for a bridge next. */
- *bridge = of_drm_find_bridge(remote);
- if (*bridge)
- ret = 0;
- } else {
- *bridge = NULL;
- }
+ /* No panel found yet, check for a bridge next. */
+ *bridge = of_drm_find_bridge(remote);
+ if (*bridge)
+ return 0;
+ *bridge = NULL;
}
- return ret;
+ return -EPROBE_DEFER;
}
EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge);
--
2.55.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH 02/11] drm: of: drm_of_find_panel_or_bridge: simplify error return paths
2026-08-14 14:05 ` [PATCH 02/11] drm: of: drm_of_find_panel_or_bridge: simplify error return paths Luca Ceresoli
@ 2026-08-17 8:23 ` Maxime Ripard
0 siblings, 0 replies; 25+ messages in thread
From: Maxime Ripard @ 2026-08-17 8:23 UTC (permalink / raw)
To: Luca Ceresoli
Cc: dri-devel, linux-kernel, Andrzej Hajda, David Airlie,
Dmitry Baryshkov, Hui Pu, Ian Ray, Inki Dae, Jagan Teki,
Jernej Skrabec, Jessica Zhang, Jonas Karlman, Laurent Pinchart,
Linus Walleij, Maarten Lankhorst, Marek Szyprowski, Maxime Ripard,
Neil Armstrong, Robert Foss, Simona Vetter, Thomas Petazzoni,
Thomas Zimmermann
On Fri, 14 Aug 2026 16:05:50 +0200, Luca Ceresoli wrote:
> In prepataion to further modify the logic of this function, simplify the
> error-returning code.
>
> With this change, on any error there is an immediate 'return -<ERRNO>;'
> statement, without having to carry on the return value until the end.
>
> [ ... ]
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Thanks!
Maxime
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 03/11] drm: of: drm_of_find_panel_or_bridge: prioritize the bridge, not the panel
2026-08-14 14:05 [PATCH 00/11] drm/panel: add a panel_bridge to every panel Luca Ceresoli
2026-08-14 14:05 ` [PATCH 01/11] drm: of: drm_of_find_panel_or_bridge: simplify freeing the remote node pointer Luca Ceresoli
2026-08-14 14:05 ` [PATCH 02/11] drm: of: drm_of_find_panel_or_bridge: simplify error return paths Luca Ceresoli
@ 2026-08-14 14:05 ` Luca Ceresoli
2026-08-17 8:26 ` Maxime Ripard
2026-08-14 14:05 ` [PATCH 04/11] drm/panel: merge the drm_kms_helper module into the drm module Luca Ceresoli
` (8 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: Luca Ceresoli @ 2026-08-14 14:05 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Jessica Zhang,
Linus Walleij, Inki Dae, Jagan Teki, Marek Szyprowski
Cc: Dmitry Baryshkov, Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel,
linux-kernel, Luca Ceresoli
By the documentation drm_of_find_panel_or_bridge() returns a "drm_panel or
drm_bridge", without specifying which one is returned in case both exist.
Definitely it never returns both. If both exist (and @bridge is != NULL),
the current implementation prioritizes the drm_panel pointer and returns
that. In most cases (including devm_drm_of_get_bridge() and
drmm_of_get_bridge()) this is used to implement the following logic
(simplified):
drm_of_find_panel_or_bridge(..., &panel, &bridge);
if (panel)
bridge = [devm_]drm_panel_bridge_add[_typed](panel);
Work is in progress to make every drm_panel automatically create a
panel_bridge, so a panel_bridge will always be present for every
drm_panel. This means the above logic would create a panel_bridge that
already exists. Avoid it by returning the drm_bridge when both are present,
instead of the drm_panel.
For the case where @bridge == NULL, this commit does not change anything:
the 'if (bridge)' body is never executed and the drm_panel (if found) is
always returned.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/drm_of.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c
index 8ec352f3df93..f92f02f9b202 100644
--- a/drivers/gpu/drm/drm_of.c
+++ b/drivers/gpu/drm/drm_of.c
@@ -308,14 +308,7 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
if (!remote)
return -ENODEV;
- *panel = of_drm_find_panel(remote);
- if (!IS_ERR(*panel))
- return 0;
-
- *panel = NULL;
-
if (bridge) {
- /* No panel found yet, check for a bridge next. */
*bridge = of_drm_find_bridge(remote);
if (*bridge)
return 0;
@@ -323,6 +316,13 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
*bridge = NULL;
}
+ /* No bridge found yet, check for a panel next. */
+ *panel = of_drm_find_panel(remote);
+ if (!IS_ERR(*panel))
+ return 0;
+
+ *panel = NULL;
+
return -EPROBE_DEFER;
}
EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge);
--
2.55.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH 03/11] drm: of: drm_of_find_panel_or_bridge: prioritize the bridge, not the panel
2026-08-14 14:05 ` [PATCH 03/11] drm: of: drm_of_find_panel_or_bridge: prioritize the bridge, not the panel Luca Ceresoli
@ 2026-08-17 8:26 ` Maxime Ripard
2026-08-17 12:23 ` Luca Ceresoli
0 siblings, 1 reply; 25+ messages in thread
From: Maxime Ripard @ 2026-08-17 8:26 UTC (permalink / raw)
To: Luca Ceresoli
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jessica Zhang, Linus Walleij,
Inki Dae, Jagan Teki, Marek Szyprowski, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 1577 bytes --]
Hi,
On Fri, Aug 14, 2026 at 04:05:51PM +0200, Luca Ceresoli wrote:
> By the documentation drm_of_find_panel_or_bridge() returns a "drm_panel or
> drm_bridge", without specifying which one is returned in case both exist.
>
> Definitely it never returns both. If both exist (and @bridge is != NULL),
> the current implementation prioritizes the drm_panel pointer and returns
> that. In most cases (including devm_drm_of_get_bridge() and
> drmm_of_get_bridge()) this is used to implement the following logic
> (simplified):
>
> drm_of_find_panel_or_bridge(..., &panel, &bridge);
> if (panel)
> bridge = [devm_]drm_panel_bridge_add[_typed](panel);
>
> Work is in progress to make every drm_panel automatically create a
> panel_bridge, so a panel_bridge will always be present for every
> drm_panel. This means the above logic would create a panel_bridge that
> already exists. Avoid it by returning the drm_bridge when both are present,
> instead of the drm_panel.
>
> For the case where @bridge == NULL, this commit does not change anything:
> the 'if (bridge)' body is never executed and the drm_panel (if found) is
> always returned.
>
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
I'm always a bit concerned about that kind of change, because you
basically change some part of the API we don't really know if a driver
relies on.
That being said, if we do create a panel_bridge for every panel, why do
we still need drm_of_find_panel_or_bridge()? We'll only really need
of_drm_find_bridge(), no?
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 03/11] drm: of: drm_of_find_panel_or_bridge: prioritize the bridge, not the panel
2026-08-17 8:26 ` Maxime Ripard
@ 2026-08-17 12:23 ` Luca Ceresoli
0 siblings, 0 replies; 25+ messages in thread
From: Luca Ceresoli @ 2026-08-17 12:23 UTC (permalink / raw)
To: Maxime Ripard, Luca Ceresoli
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jessica Zhang, Linus Walleij,
Inki Dae, Jagan Teki, Marek Szyprowski, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel
Hi Maxime,
thanks for the quick feedback!
On Mon Aug 17, 2026 at 10:26 AM CEST, Maxime Ripard wrote:
> Hi,
>
> On Fri, Aug 14, 2026 at 04:05:51PM +0200, Luca Ceresoli wrote:
>> By the documentation drm_of_find_panel_or_bridge() returns a "drm_panel or
>> drm_bridge", without specifying which one is returned in case both exist.
>>
>> Definitely it never returns both. If both exist (and @bridge is != NULL),
>> the current implementation prioritizes the drm_panel pointer and returns
>> that. In most cases (including devm_drm_of_get_bridge() and
>> drmm_of_get_bridge()) this is used to implement the following logic
>> (simplified):
>>
>> drm_of_find_panel_or_bridge(..., &panel, &bridge);
>> if (panel)
>> bridge = [devm_]drm_panel_bridge_add[_typed](panel);
>>
>> Work is in progress to make every drm_panel automatically create a
>> panel_bridge, so a panel_bridge will always be present for every
>> drm_panel. This means the above logic would create a panel_bridge that
>> already exists. Avoid it by returning the drm_bridge when both are present,
>> instead of the drm_panel.
>>
>> For the case where @bridge == NULL, this commit does not change anything:
>> the 'if (bridge)' body is never executed and the drm_panel (if found) is
>> always returned.
>>
>> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
>
> I'm always a bit concerned about that kind of change, because you
> basically change some part of the API we don't really know if a driver
> relies on.
Indeed, this was a pretty wild attempt to start discussion. And in fact
Sashiko found 3 drivers which would break: sun4i, fsl-dcu and tegra. I had
a look, some could possibly be fixed quite simply, but not all.
> That being said, if we do create a panel_bridge for every panel, why do
> we still need drm_of_find_panel_or_bridge()? We'll only really need
> of_drm_find_bridge(), no?
Yes, in the long term we can get rid of drm_of_find_panel_or_bridge(), but
not in the short term due to the above mentioned drivers, and others which
use it in "creative" ways.
The point is about the transition. This patch was an attempt to convert at
once all the many drivers which use the most common pattern:
| drm_of_find_panel_or_bridge(..., &panel, &bridge);
| if (panel)
| bridge = drm_panel_bridge_add();
to then fix manually the remaining drivers (patches 6-11).
But this approach doesn't fly due to the legacy users of
drm_of_find_panel_or_bridge() as mentioned above.
So what about this other approach instead:
1. leave drm_of_find_panel_or_bridge() as is (it's already deprecated anyway)
2. keep patch 5 (which "breaks" mayt drivers which would create an additional
panel_bridge)
3. perhaps add a warning when an additional bridge is created for the
some panel
4. *in the same series*, manually convert *all* drivers to use
of_drm_find_bridge() or of_drm_get_bridge_by_endpoint() -- like patches
6-11, but done on all drivers
5. apply the series atomically, because it wouldn't be bisectable between
items 2 and 4
Your opinion?
Kind regards,
Luca
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 04/11] drm/panel: merge the drm_kms_helper module into the drm module
2026-08-14 14:05 [PATCH 00/11] drm/panel: add a panel_bridge to every panel Luca Ceresoli
` (2 preceding siblings ...)
2026-08-14 14:05 ` [PATCH 03/11] drm: of: drm_of_find_panel_or_bridge: prioritize the bridge, not the panel Luca Ceresoli
@ 2026-08-14 14:05 ` Luca Ceresoli
2026-08-17 8:31 ` Maxime Ripard
2026-08-14 14:05 ` [PATCH 05/11] drm/bridge: panel: add a panel_bridge to every panel Luca Ceresoli
` (7 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: Luca Ceresoli @ 2026-08-14 14:05 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Jessica Zhang,
Linus Walleij, Inki Dae, Jagan Teki, Marek Szyprowski
Cc: Dmitry Baryshkov, Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel,
linux-kernel, Luca Ceresoli
Work is in progress to make every drm_panel automatically create a
panel_bridge [0][1].
This requires the panel code to call the drm_panel_bridge APIs. However
this would create a circular dependency loop on modular builds:
__devm_drm_panel_alloc() [drm]
-> drm_panel_bridge_add() [drm_kms_helper]
-> drm_bridge.c APIs [drm]
Moving just the panel_brige.o file from [drm_kms_helper] to [drm] does not
work because the panel bridge code uses the drm_atomic_helper and
drm_probe_helper which add further dependencies on symbols in the
[drm_kms_helper] module.
So take a simple approach, and move the entire drm_kms_helper into the
[drm] module.
Link: https://lore.kernel.org/all/emuj2innmp6zmzd7pyakqzjqpdzhly6qfhakya3ydwmd63pl26@5jwxaidpikjw/ [0]
Link: https://lore.kernel.org/lkml/20250206-hotplug-drm-bridge-v6-8-9d6f2c9c3058@bootlin.com/ [1]
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
*Note* This is just a quick implementation to open a discussion while
having a working implementation. If the approach is approved there will be
more details to polish.
---
drivers/gpu/drm/Makefile | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index e97faabcd783..945d4f117c3f 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -139,7 +139,7 @@ obj-$(CONFIG_DRM_TTM_HELPER) += drm_ttm_helper.o
# Modesetting helpers
#
-drm_kms_helper-y := \
+drm-$(CONFIG_DRM_KMS_HELPER) := \
drm_atomic_helper.o \
drm_atomic_state_helper.o \
drm_bridge_helper.o \
@@ -156,9 +156,8 @@ drm_kms_helper-y := \
drm_self_refresh_helper.o \
drm_simple_kms_helper.o \
drm_vblank_helper.o
-drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
-drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
-obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
+drm-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
+drm-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
#
# Drivers and the rest
--
2.55.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH 04/11] drm/panel: merge the drm_kms_helper module into the drm module
2026-08-14 14:05 ` [PATCH 04/11] drm/panel: merge the drm_kms_helper module into the drm module Luca Ceresoli
@ 2026-08-17 8:31 ` Maxime Ripard
2026-08-17 12:27 ` Luca Ceresoli
0 siblings, 1 reply; 25+ messages in thread
From: Maxime Ripard @ 2026-08-17 8:31 UTC (permalink / raw)
To: Luca Ceresoli
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jessica Zhang, Linus Walleij,
Inki Dae, Jagan Teki, Marek Szyprowski, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 1377 bytes --]
On Fri, Aug 14, 2026 at 04:05:52PM +0200, Luca Ceresoli wrote:
> Work is in progress to make every drm_panel automatically create a
> panel_bridge [0][1].
>
> This requires the panel code to call the drm_panel_bridge APIs. However
> this would create a circular dependency loop on modular builds:
>
> __devm_drm_panel_alloc() [drm]
> -> drm_panel_bridge_add() [drm_kms_helper]
> -> drm_bridge.c APIs [drm]
>
> Moving just the panel_brige.o file from [drm_kms_helper] to [drm] does not
> work because the panel bridge code uses the drm_atomic_helper and
> drm_probe_helper which add further dependencies on symbols in the
> [drm_kms_helper] module.
>
> So take a simple approach, and move the entire drm_kms_helper into the
> [drm] module.
>
> Link: https://lore.kernel.org/all/emuj2innmp6zmzd7pyakqzjqpdzhly6qfhakya3ydwmd63pl26@5jwxaidpikjw/ [0]
> Link: https://lore.kernel.org/lkml/20250206-hotplug-drm-bridge-v6-8-9d6f2c9c3058@bootlin.com/ [1]
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
So, that's not an option. However, why do we need drm_panel_bridge_add()
after this work is done? If we want to create a bridge for every panel,
then the bridge implementation can live in drm_panel.c, which is part of
the drm module.
And we'd essentially move drm_panel_bridge into drm_panel.c, and make it
private.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 04/11] drm/panel: merge the drm_kms_helper module into the drm module
2026-08-17 8:31 ` Maxime Ripard
@ 2026-08-17 12:27 ` Luca Ceresoli
0 siblings, 0 replies; 25+ messages in thread
From: Luca Ceresoli @ 2026-08-17 12:27 UTC (permalink / raw)
To: Maxime Ripard, Luca Ceresoli
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jessica Zhang, Linus Walleij,
Inki Dae, Jagan Teki, Marek Szyprowski, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel
Hi Maxime,
On Mon Aug 17, 2026 at 10:31 AM CEST, Maxime Ripard wrote:
> On Fri, Aug 14, 2026 at 04:05:52PM +0200, Luca Ceresoli wrote:
>> Work is in progress to make every drm_panel automatically create a
>> panel_bridge [0][1].
>>
>> This requires the panel code to call the drm_panel_bridge APIs. However
>> this would create a circular dependency loop on modular builds:
>>
>> __devm_drm_panel_alloc() [drm]
>> -> drm_panel_bridge_add() [drm_kms_helper]
>> -> drm_bridge.c APIs [drm]
>>
>> Moving just the panel_brige.o file from [drm_kms_helper] to [drm] does not
>> work because the panel bridge code uses the drm_atomic_helper and
>> drm_probe_helper which add further dependencies on symbols in the
>> [drm_kms_helper] module.
>>
>> So take a simple approach, and move the entire drm_kms_helper into the
>> [drm] module.
>>
>> Link: https://lore.kernel.org/all/emuj2innmp6zmzd7pyakqzjqpdzhly6qfhakya3ydwmd63pl26@5jwxaidpikjw/ [0]
>> Link: https://lore.kernel.org/lkml/20250206-hotplug-drm-bridge-v6-8-9d6f2c9c3058@bootlin.com/ [1]
>> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
>
> So, that's not an option. However, why do we need drm_panel_bridge_add()
> after this work is done? If we want to create a bridge for every panel,
> then the bridge implementation can live in drm_panel.c, which is part of
> the drm module.
>
> And we'd essentially move drm_panel_bridge into drm_panel.c, and make it
> private.
Yes in theory, but the panel_bridge code uses other parts of the
drm_kms_helper module: drm_atomic_helper and drm_probe_helper, maybe more,
so we'd have to move them into the drm module too.
Is it worth trying to identify only the closure of files in drm_kms_helpers
that are actually used by the panel_bridg, and move only them? That'd mean
having some *_helper.c files in the drm module and other *_helper.c files
in the drm module.
There's a licensing aspect too: drm_panel.c is MIT-licensed, bridge/panel.c
is GPL-2.0-or-later. However my understanding is that we can merge the two
into a single file and the result would all be GPL-2.0-or-later, so that is
an option.
Luca
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 05/11] drm/bridge: panel: add a panel_bridge to every panel
2026-08-14 14:05 [PATCH 00/11] drm/panel: add a panel_bridge to every panel Luca Ceresoli
` (3 preceding siblings ...)
2026-08-14 14:05 ` [PATCH 04/11] drm/panel: merge the drm_kms_helper module into the drm module Luca Ceresoli
@ 2026-08-14 14:05 ` Luca Ceresoli
2026-08-17 8:42 ` Maxime Ripard
2026-08-14 14:05 ` [PATCH 06/11] drm/bridge: tc358767: don't create a panel_bridge Luca Ceresoli
` (6 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: Luca Ceresoli @ 2026-08-14 14:05 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Jessica Zhang,
Linus Walleij, Inki Dae, Jagan Teki, Marek Szyprowski
Cc: Dmitry Baryshkov, Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel,
linux-kernel, Luca Ceresoli
Adding a panel does currently not add a panel_bridge wrapping it. Usually
the panel_bridge creation happens later, when some other driver (e.g. the
previous bridge or the encoder) calls *_of_get_bridge() and the following
element in the pipeline is a panel.
This has some drawbacks:
* hte bridge API is currently the best practice to access various
components of the pipeline, especially with complex cards where bridges
can be combined in different ways on different hardware
* the panel_bridge is not created in the context of the driver of the
underlying physical device (the panel driver), but of some other driver
* that other driver is not aware of whether the returned drm_bridge
pointer is a panel_bridge created on the fly, a pre-existing
panel_bridge or a non-panel bridge
* removal of a panel_bridge requires calling drm_panel_bridge_remove(),
but the other driver doesn't know whether this is needed because it
doesn't know whether it has created a panel_bridge or not
So far the current approach has been working because devm and drmm ensure
the panel bridge would be dealloacted at some later point. However with the
upcoming implementation of dynamic bridge lifetime this will get more
complicated.
Switch to the new approach: always create a panel_bridge with a drm_panel,
thus matching the lifetime of the drm_panel and the panel_bridge wrapping
it. This makes lifetime much more straightforward to understand and to
further develop on.
As a consequence devm_drm_of_get_bridge() and drmm_of_get_bridge() don't
need to look for a panel anymore and become simple wrappers to
of_drm_get_bridge_by_endpoint(). Also deprecate them as they can be
replaced by of_drm_get_bridge_by_endpoint() which also handles refcount.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/bridge/panel.c | 47 +++++++++++++++++++++---------------------
drivers/gpu/drm/drm_panel.c | 3 +++
include/drm/drm_panel.h | 8 +++++++
3 files changed, 34 insertions(+), 24 deletions(-)
diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 02388a3de626..d86555254aa9 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -412,6 +412,11 @@ struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
{
struct drm_bridge **ptr, *bridge;
+ if (panel->bridge) {
+ dev_dbg(dev, "returning existing bridge=%p\n", panel->bridge);
+ return panel->bridge;
+ }
+
ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),
GFP_KERNEL);
if (!ptr)
@@ -495,9 +500,12 @@ EXPORT_SYMBOL(drm_panel_bridge_connector);
* @port: port in the device tree node
* @endpoint: endpoint in the device tree node
*
+ * This function is deprecated and should not be used in new drivers. The
+ * returned bridge refcount is not incremented! Replace by
+ * of_drm_get_bridge_by_endpoint() and handle bridge refcount.
+ *
* Given a DT node's port and endpoint number, finds the connected node
- * and returns the associated bridge if any, or creates and returns a
- * drm panel bridge instance if a panel is connected.
+ * and returns the associated bridge if any.
*
* Returns a pointer to the bridge if successful, or an error pointer
* otherwise.
@@ -507,18 +515,12 @@ struct drm_bridge *devm_drm_of_get_bridge(struct device *dev,
u32 port, u32 endpoint)
{
struct drm_bridge *bridge;
- struct drm_panel *panel;
- int ret;
- ret = drm_of_find_panel_or_bridge(np, port, endpoint,
- &panel, &bridge);
- if (ret)
- return ERR_PTR(ret);
+ bridge = of_drm_get_bridge_by_endpoint(np, port, endpoint);
+ if (IS_ERR(bridge))
+ return bridge;
- if (panel) {
- bridge = devm_drm_panel_bridge_add(dev, panel);
- drm_panel_put(panel);
- }
+ drm_bridge_put(bridge);
return bridge;
}
@@ -531,9 +533,12 @@ EXPORT_SYMBOL(devm_drm_of_get_bridge);
* @port: port in the device tree node
* @endpoint: endpoint in the device tree node
*
+ * This function is deprecated and should not be used in new drivers. The
+ * returned bridge refcount is not incremented! Replace by
+ * of_drm_get_bridge_by_endpoint() and handle bridge refcount.
+ *
* Given a DT node's port and endpoint number, finds the connected node
- * and returns the associated bridge if any, or creates and returns a
- * drm panel bridge instance if a panel is connected.
+ * and returns the associated bridge if any.
*
* Returns a drmm managed pointer to the bridge if successful, or an error
* pointer otherwise.
@@ -543,18 +548,12 @@ struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm,
u32 port, u32 endpoint)
{
struct drm_bridge *bridge;
- struct drm_panel *panel;
- int ret;
- ret = drm_of_find_panel_or_bridge(np, port, endpoint,
- &panel, &bridge);
- if (ret)
- return ERR_PTR(ret);
+ bridge = of_drm_get_bridge_by_endpoint(np, port, endpoint);
+ if (IS_ERR(bridge))
+ return bridge;
- if (panel) {
- bridge = drmm_panel_bridge_add(drm, panel);
- drm_panel_put(panel);
- }
+ drm_bridge_put(bridge);
return bridge;
}
diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
index f8f6082e637f..95fc95d1b4b7 100644
--- a/drivers/gpu/drm/drm_panel.c
+++ b/drivers/gpu/drm/drm_panel.c
@@ -453,6 +453,9 @@ void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset,
drm_panel_init(panel, dev, funcs, connector_type);
+ panel->bridge = devm_drm_panel_bridge_add(dev, panel);
+ WARN_ON(!panel->bridge);
+
return container;
}
EXPORT_SYMBOL(__devm_drm_panel_alloc);
diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
index b87323443f49..9a042675eb3e 100644
--- a/include/drm/drm_panel.h
+++ b/include/drm/drm_panel.h
@@ -210,6 +210,14 @@ struct drm_panel {
*/
struct device *dev;
+ /**
+ * @bridge:
+ *
+ * Pointer to the panel bridge giving access to the panel using the
+ * DRM bridge API.
+ */
+ struct drm_bridge *bridge;
+
/**
* @backlight:
*
--
2.55.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH 05/11] drm/bridge: panel: add a panel_bridge to every panel
2026-08-14 14:05 ` [PATCH 05/11] drm/bridge: panel: add a panel_bridge to every panel Luca Ceresoli
@ 2026-08-17 8:42 ` Maxime Ripard
2026-08-17 12:30 ` Luca Ceresoli
0 siblings, 1 reply; 25+ messages in thread
From: Maxime Ripard @ 2026-08-17 8:42 UTC (permalink / raw)
To: Luca Ceresoli
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jessica Zhang, Linus Walleij,
Inki Dae, Jagan Teki, Marek Szyprowski, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 6513 bytes --]
On Fri, Aug 14, 2026 at 04:05:53PM +0200, Luca Ceresoli wrote:
> Adding a panel does currently not add a panel_bridge wrapping it. Usually
> the panel_bridge creation happens later, when some other driver (e.g. the
> previous bridge or the encoder) calls *_of_get_bridge() and the following
> element in the pipeline is a panel.
>
> This has some drawbacks:
>
> * hte bridge API is currently the best practice to access various
> components of the pipeline, especially with complex cards where bridges
> can be combined in different ways on different hardware
> * the panel_bridge is not created in the context of the driver of the
> underlying physical device (the panel driver), but of some other driver
> * that other driver is not aware of whether the returned drm_bridge
> pointer is a panel_bridge created on the fly, a pre-existing
> panel_bridge or a non-panel bridge
> * removal of a panel_bridge requires calling drm_panel_bridge_remove(),
> but the other driver doesn't know whether this is needed because it
> doesn't know whether it has created a panel_bridge or not
>
> So far the current approach has been working because devm and drmm ensure
> the panel bridge would be dealloacted at some later point. However with the
> upcoming implementation of dynamic bridge lifetime this will get more
> complicated.
>
> Switch to the new approach: always create a panel_bridge with a drm_panel,
> thus matching the lifetime of the drm_panel and the panel_bridge wrapping
> it. This makes lifetime much more straightforward to understand and to
> further develop on.
>
> As a consequence devm_drm_of_get_bridge() and drmm_of_get_bridge() don't
> need to look for a panel anymore and become simple wrappers to
> of_drm_get_bridge_by_endpoint(). Also deprecate them as they can be
> replaced by of_drm_get_bridge_by_endpoint() which also handles refcount.
>
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
> ---
> drivers/gpu/drm/bridge/panel.c | 47 +++++++++++++++++++++---------------------
> drivers/gpu/drm/drm_panel.c | 3 +++
> include/drm/drm_panel.h | 8 +++++++
> 3 files changed, 34 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
> index 02388a3de626..d86555254aa9 100644
> --- a/drivers/gpu/drm/bridge/panel.c
> +++ b/drivers/gpu/drm/bridge/panel.c
> @@ -412,6 +412,11 @@ struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
> {
> struct drm_bridge **ptr, *bridge;
>
> + if (panel->bridge) {
> + dev_dbg(dev, "returning existing bridge=%p\n", panel->bridge);
> + return panel->bridge;
> + }
> +
> ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),
> GFP_KERNEL);
> if (!ptr)
> @@ -495,9 +500,12 @@ EXPORT_SYMBOL(drm_panel_bridge_connector);
> * @port: port in the device tree node
> * @endpoint: endpoint in the device tree node
> *
> + * This function is deprecated and should not be used in new drivers. The
> + * returned bridge refcount is not incremented! Replace by
> + * of_drm_get_bridge_by_endpoint() and handle bridge refcount.
> + *
> * Given a DT node's port and endpoint number, finds the connected node
> - * and returns the associated bridge if any, or creates and returns a
> - * drm panel bridge instance if a panel is connected.
> + * and returns the associated bridge if any.
> *
> * Returns a pointer to the bridge if successful, or an error pointer
> * otherwise.
> @@ -507,18 +515,12 @@ struct drm_bridge *devm_drm_of_get_bridge(struct device *dev,
> u32 port, u32 endpoint)
> {
> struct drm_bridge *bridge;
> - struct drm_panel *panel;
> - int ret;
>
> - ret = drm_of_find_panel_or_bridge(np, port, endpoint,
> - &panel, &bridge);
> - if (ret)
> - return ERR_PTR(ret);
> + bridge = of_drm_get_bridge_by_endpoint(np, port, endpoint);
> + if (IS_ERR(bridge))
> + return bridge;
>
> - if (panel) {
> - bridge = devm_drm_panel_bridge_add(dev, panel);
> - drm_panel_put(panel);
> - }
> + drm_bridge_put(bridge);
>
> return bridge;
> }
> @@ -531,9 +533,12 @@ EXPORT_SYMBOL(devm_drm_of_get_bridge);
> * @port: port in the device tree node
> * @endpoint: endpoint in the device tree node
> *
> + * This function is deprecated and should not be used in new drivers. The
> + * returned bridge refcount is not incremented! Replace by
> + * of_drm_get_bridge_by_endpoint() and handle bridge refcount.
> + *
> * Given a DT node's port and endpoint number, finds the connected node
> - * and returns the associated bridge if any, or creates and returns a
> - * drm panel bridge instance if a panel is connected.
> + * and returns the associated bridge if any.
> *
> * Returns a drmm managed pointer to the bridge if successful, or an error
> * pointer otherwise.
> @@ -543,18 +548,12 @@ struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm,
> u32 port, u32 endpoint)
> {
> struct drm_bridge *bridge;
> - struct drm_panel *panel;
> - int ret;
>
> - ret = drm_of_find_panel_or_bridge(np, port, endpoint,
> - &panel, &bridge);
> - if (ret)
> - return ERR_PTR(ret);
> + bridge = of_drm_get_bridge_by_endpoint(np, port, endpoint);
> + if (IS_ERR(bridge))
> + return bridge;
>
> - if (panel) {
> - bridge = drmm_panel_bridge_add(drm, panel);
> - drm_panel_put(panel);
> - }
> + drm_bridge_put(bridge);
>
> return bridge;
> }
> diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
> index f8f6082e637f..95fc95d1b4b7 100644
> --- a/drivers/gpu/drm/drm_panel.c
> +++ b/drivers/gpu/drm/drm_panel.c
> @@ -453,6 +453,9 @@ void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset,
>
> drm_panel_init(panel, dev, funcs, connector_type);
>
> + panel->bridge = devm_drm_panel_bridge_add(dev, panel);
> + WARN_ON(!panel->bridge);
> +
Having two refcounted dynamic allocations yet with the exact same
lifetime makes me a bit uneasy: we'll introduce lifetime / reference
count issue because we would then have to keep the same reference count
everywhere.
I wonder if we shouldn't embed the drm_bridge struct into drm_panel, and
provide a way for the drm_panel and drm_bridge to share the same
refcount, maybe by making drm_panel_get take drm_bridge.refcount instead
of duplicating the refcount in both drm_panel and drm_bridge?
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 25+ messages in thread* Re: [PATCH 05/11] drm/bridge: panel: add a panel_bridge to every panel
2026-08-17 8:42 ` Maxime Ripard
@ 2026-08-17 12:30 ` Luca Ceresoli
0 siblings, 0 replies; 25+ messages in thread
From: Luca Ceresoli @ 2026-08-17 12:30 UTC (permalink / raw)
To: Maxime Ripard, Luca Ceresoli
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Jessica Zhang, Linus Walleij,
Inki Dae, Jagan Teki, Marek Szyprowski, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel
Hi Maxime,
On Mon Aug 17, 2026 at 10:42 AM CEST, Maxime Ripard wrote:
> On Fri, Aug 14, 2026 at 04:05:53PM +0200, Luca Ceresoli wrote:
>> Adding a panel does currently not add a panel_bridge wrapping it. Usually
>> the panel_bridge creation happens later, when some other driver (e.g. the
>> previous bridge or the encoder) calls *_of_get_bridge() and the following
>> element in the pipeline is a panel.
>>
>> This has some drawbacks:
>>
>> * hte bridge API is currently the best practice to access various
>> components of the pipeline, especially with complex cards where bridges
>> can be combined in different ways on different hardware
>> * the panel_bridge is not created in the context of the driver of the
>> underlying physical device (the panel driver), but of some other driver
>> * that other driver is not aware of whether the returned drm_bridge
>> pointer is a panel_bridge created on the fly, a pre-existing
>> panel_bridge or a non-panel bridge
>> * removal of a panel_bridge requires calling drm_panel_bridge_remove(),
>> but the other driver doesn't know whether this is needed because it
>> doesn't know whether it has created a panel_bridge or not
>>
>> So far the current approach has been working because devm and drmm ensure
>> the panel bridge would be dealloacted at some later point. However with the
>> upcoming implementation of dynamic bridge lifetime this will get more
>> complicated.
>>
>> Switch to the new approach: always create a panel_bridge with a drm_panel,
>> thus matching the lifetime of the drm_panel and the panel_bridge wrapping
>> it. This makes lifetime much more straightforward to understand and to
>> further develop on.
>>
>> As a consequence devm_drm_of_get_bridge() and drmm_of_get_bridge() don't
>> need to look for a panel anymore and become simple wrappers to
>> of_drm_get_bridge_by_endpoint(). Also deprecate them as they can be
>> replaced by of_drm_get_bridge_by_endpoint() which also handles refcount.
>>
>> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
>> ---
>> drivers/gpu/drm/bridge/panel.c | 47 +++++++++++++++++++++---------------------
>> drivers/gpu/drm/drm_panel.c | 3 +++
>> include/drm/drm_panel.h | 8 +++++++
>> 3 files changed, 34 insertions(+), 24 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
>> index 02388a3de626..d86555254aa9 100644
>> --- a/drivers/gpu/drm/bridge/panel.c
>> +++ b/drivers/gpu/drm/bridge/panel.c
>> @@ -412,6 +412,11 @@ struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
>> {
>> struct drm_bridge **ptr, *bridge;
>>
>> + if (panel->bridge) {
>> + dev_dbg(dev, "returning existing bridge=%p\n", panel->bridge);
>> + return panel->bridge;
>> + }
>> +
>> ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),
>> GFP_KERNEL);
>> if (!ptr)
>> @@ -495,9 +500,12 @@ EXPORT_SYMBOL(drm_panel_bridge_connector);
>> * @port: port in the device tree node
>> * @endpoint: endpoint in the device tree node
>> *
>> + * This function is deprecated and should not be used in new drivers. The
>> + * returned bridge refcount is not incremented! Replace by
>> + * of_drm_get_bridge_by_endpoint() and handle bridge refcount.
>> + *
>> * Given a DT node's port and endpoint number, finds the connected node
>> - * and returns the associated bridge if any, or creates and returns a
>> - * drm panel bridge instance if a panel is connected.
>> + * and returns the associated bridge if any.
>> *
>> * Returns a pointer to the bridge if successful, or an error pointer
>> * otherwise.
>> @@ -507,18 +515,12 @@ struct drm_bridge *devm_drm_of_get_bridge(struct device *dev,
>> u32 port, u32 endpoint)
>> {
>> struct drm_bridge *bridge;
>> - struct drm_panel *panel;
>> - int ret;
>>
>> - ret = drm_of_find_panel_or_bridge(np, port, endpoint,
>> - &panel, &bridge);
>> - if (ret)
>> - return ERR_PTR(ret);
>> + bridge = of_drm_get_bridge_by_endpoint(np, port, endpoint);
>> + if (IS_ERR(bridge))
>> + return bridge;
>>
>> - if (panel) {
>> - bridge = devm_drm_panel_bridge_add(dev, panel);
>> - drm_panel_put(panel);
>> - }
>> + drm_bridge_put(bridge);
>>
>> return bridge;
>> }
>> @@ -531,9 +533,12 @@ EXPORT_SYMBOL(devm_drm_of_get_bridge);
>> * @port: port in the device tree node
>> * @endpoint: endpoint in the device tree node
>> *
>> + * This function is deprecated and should not be used in new drivers. The
>> + * returned bridge refcount is not incremented! Replace by
>> + * of_drm_get_bridge_by_endpoint() and handle bridge refcount.
>> + *
>> * Given a DT node's port and endpoint number, finds the connected node
>> - * and returns the associated bridge if any, or creates and returns a
>> - * drm panel bridge instance if a panel is connected.
>> + * and returns the associated bridge if any.
>> *
>> * Returns a drmm managed pointer to the bridge if successful, or an error
>> * pointer otherwise.
>> @@ -543,18 +548,12 @@ struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm,
>> u32 port, u32 endpoint)
>> {
>> struct drm_bridge *bridge;
>> - struct drm_panel *panel;
>> - int ret;
>>
>> - ret = drm_of_find_panel_or_bridge(np, port, endpoint,
>> - &panel, &bridge);
>> - if (ret)
>> - return ERR_PTR(ret);
>> + bridge = of_drm_get_bridge_by_endpoint(np, port, endpoint);
>> + if (IS_ERR(bridge))
>> + return bridge;
>>
>> - if (panel) {
>> - bridge = drmm_panel_bridge_add(drm, panel);
>> - drm_panel_put(panel);
>> - }
>> + drm_bridge_put(bridge);
>>
>> return bridge;
>> }
>> diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
>> index f8f6082e637f..95fc95d1b4b7 100644
>> --- a/drivers/gpu/drm/drm_panel.c
>> +++ b/drivers/gpu/drm/drm_panel.c
>> @@ -453,6 +453,9 @@ void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset,
>>
>> drm_panel_init(panel, dev, funcs, connector_type);
>>
>> + panel->bridge = devm_drm_panel_bridge_add(dev, panel);
>> + WARN_ON(!panel->bridge);
>> +
>
> Having two refcounted dynamic allocations yet with the exact same
> lifetime makes me a bit uneasy: we'll introduce lifetime / reference
> count issue because we would then have to keep the same reference count
> everywhere.
It may look twisty but I don't see why it should not work.
> I wonder if we shouldn't embed the drm_bridge struct into drm_panel, and
> provide a way for the drm_panel and drm_bridge to share the same
> refcount, maybe by making drm_panel_get take drm_bridge.refcount instead
> of duplicating the refcount in both drm_panel and drm_bridge?
That is the other option I evaluated, and I must agree it makes
sense. Basically the resulting bridge refcount would be:
bridge.refcount == number of drm_bridge_get() calls
+ number of drm_panel_get() calls
- number of drm_bridge_put() calls
- number of drm_panel_put() calls
I think that's an implementation detail, even though an important one. The
API for both panel and bridge users would be the same, and with the same
guarantee: memory won't be freed before (get - put) reaches zero, but with
the second idea it could be freed even later.
I'll try implementing this, and see what happens when going into the
details.
Luca
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 06/11] drm/bridge: tc358767: don't create a panel_bridge
2026-08-14 14:05 [PATCH 00/11] drm/panel: add a panel_bridge to every panel Luca Ceresoli
` (4 preceding siblings ...)
2026-08-14 14:05 ` [PATCH 05/11] drm/bridge: panel: add a panel_bridge to every panel Luca Ceresoli
@ 2026-08-14 14:05 ` Luca Ceresoli
2026-08-14 14:05 ` [PATCH 07/11] drm/bridge: waveshare-dsi: " Luca Ceresoli
` (5 subsequent siblings)
11 siblings, 0 replies; 25+ messages in thread
From: Luca Ceresoli @ 2026-08-14 14:05 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Jessica Zhang,
Linus Walleij, Inki Dae, Jagan Teki, Marek Szyprowski
Cc: Dmitry Baryshkov, Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel,
linux-kernel, Luca Ceresoli
Now a panel_bridge is automatically created for every drm_panel, so this
panel-only call to drm_of_find_panel_or_bridge() would lead to creating a
second panel_bridge for the same panel.
Fix and simplify the code by just getting a reference to the
already-existing panel_bridge using of_drm_get_bridge_by_endpoint().
As of_drm_get_bridge_by_endpoint() returns a refcouncted bridge, take care
of putting the bridge reference on removal.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/bridge/tc358767.c | 22 +++++++---------------
1 file changed, 7 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index ac83af7902cd..d282db507d59 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -2347,24 +2347,15 @@ static int tc_probe_dpi_bridge_endpoint(struct tc_data *tc)
static int tc_probe_edp_bridge_endpoint(struct tc_data *tc)
{
struct device *dev = tc->dev;
- struct drm_panel *panel;
- int ret;
+ struct drm_bridge *bridge;
/* port@2 is the output port */
- ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &panel, NULL);
- if (ret && ret != -ENODEV)
- return dev_err_probe(dev, ret,
- "Could not find DSI panel or bridge\n");
+ bridge = of_drm_get_bridge_by_endpoint(dev->of_node, 2, 0);
+ if (IS_ERR(bridge) && PTR_ERR(bridge) != -ENODEV)
+ return dev_err_probe(dev, PTR_ERR(bridge), "Could not find DSI bridge\n");
- if (panel) {
- struct drm_bridge *panel_bridge;
-
- panel_bridge = devm_drm_panel_bridge_add(dev, panel);
- drm_panel_put(panel);
- if (IS_ERR(panel_bridge))
- return PTR_ERR(panel_bridge);
-
- tc->panel_bridge = panel_bridge;
+ if (!IS_ERR(bridge)) {
+ tc->panel_bridge = bridge;
tc->bridge.type = DRM_MODE_CONNECTOR_eDP;
} else {
tc->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
@@ -2607,6 +2598,7 @@ static void tc_remove(struct i2c_client *client)
{
struct tc_data *tc = i2c_get_clientdata(client);
+ drm_bridge_put(tc->panel_bridge);
drm_bridge_remove(&tc->bridge);
}
--
2.55.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH 07/11] drm/bridge: waveshare-dsi: don't create a panel_bridge
2026-08-14 14:05 [PATCH 00/11] drm/panel: add a panel_bridge to every panel Luca Ceresoli
` (5 preceding siblings ...)
2026-08-14 14:05 ` [PATCH 06/11] drm/bridge: tc358767: don't create a panel_bridge Luca Ceresoli
@ 2026-08-14 14:05 ` Luca Ceresoli
2026-08-14 14:05 ` [PATCH 08/11] drm/mcde: dsi: simplify device_node management using scoped for_each variant Luca Ceresoli
` (4 subsequent siblings)
11 siblings, 0 replies; 25+ messages in thread
From: Luca Ceresoli @ 2026-08-14 14:05 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Jessica Zhang,
Linus Walleij, Inki Dae, Jagan Teki, Marek Szyprowski
Cc: Dmitry Baryshkov, Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel,
linux-kernel, Luca Ceresoli
Now a panel_bridge is automatically created for every drm_panel, so this
panel-only call to drm_of_find_panel_or_bridge() would lead to creating a
second panel_bridge for the same panel.
Fix and simplify the code by just getting a reference to the
already-existing panel_bridge using of_drm_get_bridge_by_endpoint().
As of_drm_get_bridge_by_endpoint() returns a refcouncted bridge, take care
of putting the bridge reference by using bridge->next_bridge.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/bridge/waveshare-dsi.c | 16 +++++-----------
1 file changed, 5 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/bridge/waveshare-dsi.c b/drivers/gpu/drm/bridge/waveshare-dsi.c
index 420f3b870a74..b79a1d32e679 100644
--- a/drivers/gpu/drm/bridge/waveshare-dsi.c
+++ b/drivers/gpu/drm/bridge/waveshare-dsi.c
@@ -20,7 +20,6 @@
struct ws_bridge {
struct drm_bridge bridge;
- struct drm_bridge *next_bridge;
struct backlight_device *backlight;
struct device *dev;
struct regmap *reg_map;
@@ -89,7 +88,7 @@ static int ws_bridge_bridge_attach(struct drm_bridge *bridge,
{
struct ws_bridge *ws = bridge_to_ws_bridge(bridge);
- return drm_bridge_attach(encoder, ws->next_bridge,
+ return drm_bridge_attach(encoder, ws->bridge.next_bridge,
&ws->bridge, flags);
}
@@ -150,7 +149,6 @@ static struct backlight_device *ws_bridge_create_backlight(struct ws_bridge *ws)
static int ws_bridge_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
- struct drm_panel *panel;
struct ws_bridge *ws;
int ret;
@@ -164,14 +162,10 @@ static int ws_bridge_probe(struct i2c_client *i2c)
if (IS_ERR(ws->reg_map))
return dev_err_probe(dev, PTR_ERR(ws->reg_map), "Failed to allocate regmap\n");
- ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, &panel, NULL);
- if (ret)
- return dev_err_probe(dev, ret, "Failed to find remote panel\n");
-
- ws->next_bridge = devm_drm_panel_bridge_add(dev, panel);
- drm_panel_put(panel);
- if (IS_ERR(ws->next_bridge))
- return PTR_ERR(ws->next_bridge);
+ ws->bridge.next_bridge = of_drm_get_bridge_by_endpoint(dev->of_node, 1, -1);
+ if (IS_ERR(ws->bridge.next_bridge))
+ return dev_err_probe(dev, PTR_ERR(ws->bridge.next_bridge),
+ "Failed to find remote panel\n");
ws->backlight = ws_bridge_create_backlight(ws);
if (IS_ERR(ws->backlight)) {
--
2.55.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH 08/11] drm/mcde: dsi: simplify device_node management using scoped for_each variant
2026-08-14 14:05 [PATCH 00/11] drm/panel: add a panel_bridge to every panel Luca Ceresoli
` (6 preceding siblings ...)
2026-08-14 14:05 ` [PATCH 07/11] drm/bridge: waveshare-dsi: " Luca Ceresoli
@ 2026-08-14 14:05 ` Luca Ceresoli
2026-08-17 8:43 ` Maxime Ripard
2026-08-17 12:25 ` Linus Walleij
2026-08-14 14:05 ` [PATCH 09/11] drm/mcde: dsi: don't create a panel_bridge Luca Ceresoli
` (3 subsequent siblings)
11 siblings, 2 replies; 25+ messages in thread
From: Luca Ceresoli @ 2026-08-14 14:05 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Jessica Zhang,
Linus Walleij, Inki Dae, Jagan Teki, Marek Szyprowski
Cc: Dmitry Baryshkov, Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel,
linux-kernel, Luca Ceresoli
Before further modifying this function, simpify the struct device_node
management using the scoped variat of for_each_available_child_of_node().
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/mcde/mcde_dsi.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c
index 694372581840..ce078aa3910f 100644
--- a/drivers/gpu/drm/mcde/mcde_dsi.c
+++ b/drivers/gpu/drm/mcde/mcde_dsi.c
@@ -1076,7 +1076,6 @@ static int mcde_dsi_bind(struct device *dev, struct device *master,
struct drm_device *drm = data;
struct mcde *mcde = to_mcde(drm);
struct mcde_dsi *d = dev_get_drvdata(dev);
- struct device_node *child;
struct drm_panel *panel = NULL;
struct drm_bridge *bridge __free(drm_bridge_put) = NULL;
@@ -1104,7 +1103,7 @@ static int mcde_dsi_bind(struct device *dev, struct device *master,
}
/* Look for a panel as a child to this node */
- for_each_available_child_of_node(dev->of_node, child) {
+ for_each_available_child_of_node_scoped(dev->of_node, child) {
panel = of_drm_find_panel(child);
if (IS_ERR(panel)) {
dev_err(dev, "failed to find panel try bridge (%ld)\n",
@@ -1114,15 +1113,12 @@ static int mcde_dsi_bind(struct device *dev, struct device *master,
bridge = of_drm_find_and_get_bridge(child);
if (!bridge) {
dev_err(dev, "failed to find bridge\n");
- of_node_put(child);
return -EINVAL;
}
}
- if (panel || bridge) {
- of_node_put(child);
+ if (panel || bridge)
break;
- }
}
if (panel) {
bridge = drm_panel_bridge_add_typed(panel,
--
2.55.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH 08/11] drm/mcde: dsi: simplify device_node management using scoped for_each variant
2026-08-14 14:05 ` [PATCH 08/11] drm/mcde: dsi: simplify device_node management using scoped for_each variant Luca Ceresoli
@ 2026-08-17 8:43 ` Maxime Ripard
2026-08-17 12:25 ` Linus Walleij
1 sibling, 0 replies; 25+ messages in thread
From: Maxime Ripard @ 2026-08-17 8:43 UTC (permalink / raw)
To: Luca Ceresoli
Cc: dri-devel, linux-kernel, Andrzej Hajda, David Airlie,
Dmitry Baryshkov, Hui Pu, Ian Ray, Inki Dae, Jagan Teki,
Jernej Skrabec, Jessica Zhang, Jonas Karlman, Laurent Pinchart,
Linus Walleij, Maarten Lankhorst, Marek Szyprowski, Maxime Ripard,
Neil Armstrong, Robert Foss, Simona Vetter, Thomas Petazzoni,
Thomas Zimmermann
On Fri, 14 Aug 2026 16:05:56 +0200, Luca Ceresoli wrote:
> Before further modifying this function, simpify the struct device_node
> management using the scoped variat of for_each_available_child_of_node().
>
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Thanks!
Maxime
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 08/11] drm/mcde: dsi: simplify device_node management using scoped for_each variant
2026-08-14 14:05 ` [PATCH 08/11] drm/mcde: dsi: simplify device_node management using scoped for_each variant Luca Ceresoli
2026-08-17 8:43 ` Maxime Ripard
@ 2026-08-17 12:25 ` Linus Walleij
2026-08-17 12:34 ` Luca Ceresoli
1 sibling, 1 reply; 25+ messages in thread
From: Linus Walleij @ 2026-08-17 12:25 UTC (permalink / raw)
To: Luca Ceresoli
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Jessica Zhang,
Inki Dae, Jagan Teki, Marek Szyprowski, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel
On Fri, Aug 14, 2026 at 4:07 PM Luca Ceresoli <luca.ceresoli@bootlin.com> wrote:
> Before further modifying this function, simpify the struct device_node
> management using the scoped variat of for_each_available_child_of_node().
>
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
This looks like it can be queued already irrespective of other
patches,
Reviewed-by: Linus Walleij <linusw@kernel.org>
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 08/11] drm/mcde: dsi: simplify device_node management using scoped for_each variant
2026-08-17 12:25 ` Linus Walleij
@ 2026-08-17 12:34 ` Luca Ceresoli
0 siblings, 0 replies; 25+ messages in thread
From: Luca Ceresoli @ 2026-08-17 12:34 UTC (permalink / raw)
To: Linus Walleij, Luca Ceresoli
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Jessica Zhang,
Inki Dae, Jagan Teki, Marek Szyprowski, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel
Hello Linus,
On Mon Aug 17, 2026 at 2:25 PM CEST, Linus Walleij wrote:
> On Fri, Aug 14, 2026 at 4:07 PM Luca Ceresoli <luca.ceresoli@bootlin.com> wrote:
>
>> Before further modifying this function, simpify the struct device_node
>> management using the scoped variat of for_each_available_child_of_node().
>>
>> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
>
> This looks like it can be queued already irrespective of other
> patches,
Absolutely.
That's not the case for patch 9, which works only if patch 5 (or a better
future version of it) is applied.
So I'm all OK if you want to apply this patch.
> Reviewed-by: Linus Walleij <linusw@kernel.org>
Thanks!
Luca
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 09/11] drm/mcde: dsi: don't create a panel_bridge
2026-08-14 14:05 [PATCH 00/11] drm/panel: add a panel_bridge to every panel Luca Ceresoli
` (7 preceding siblings ...)
2026-08-14 14:05 ` [PATCH 08/11] drm/mcde: dsi: simplify device_node management using scoped for_each variant Luca Ceresoli
@ 2026-08-14 14:05 ` Luca Ceresoli
2026-08-17 12:23 ` Linus Walleij
2026-08-14 14:05 ` [PATCH 10/11] drm/bridge: fsl-ldb: " Luca Ceresoli
` (2 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: Luca Ceresoli @ 2026-08-14 14:05 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Jessica Zhang,
Linus Walleij, Inki Dae, Jagan Teki, Marek Szyprowski
Cc: Dmitry Baryshkov, Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel,
linux-kernel, Luca Ceresoli
Now a panel_bridge is automatically created for every drm_panel, so this
code (similar to an open-coded variant of drm_of_find_panel_or_bridge())
would lead to creating a second panel_bridge for the same panel.
Fix and simplify the code by just getting a reference to the
already-existing bridge.
Also keep the "connected to non-panel bridge (unsupported)\n" error logic
by using the drm_bridge_is_panel() function.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/mcde/mcde_dsi.c | 41 +++++++++--------------------------------
1 file changed, 9 insertions(+), 32 deletions(-)
diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c
index ce078aa3910f..ec45440d20d7 100644
--- a/drivers/gpu/drm/mcde/mcde_dsi.c
+++ b/drivers/gpu/drm/mcde/mcde_dsi.c
@@ -39,7 +39,6 @@ struct mcde_dsi {
struct device *dev;
struct mcde *mcde;
struct drm_bridge bridge;
- struct drm_panel *panel;
struct mipi_dsi_host dsi_host;
struct mipi_dsi_device *mdsi;
const struct drm_display_mode *mode;
@@ -1076,7 +1075,6 @@ static int mcde_dsi_bind(struct device *dev, struct device *master,
struct drm_device *drm = data;
struct mcde *mcde = to_mcde(drm);
struct mcde_dsi *d = dev_get_drvdata(dev);
- struct drm_panel *panel = NULL;
struct drm_bridge *bridge __free(drm_bridge_put) = NULL;
if (!of_get_available_child_count(dev->of_node)) {
@@ -1104,40 +1102,21 @@ static int mcde_dsi_bind(struct device *dev, struct device *master,
/* Look for a panel as a child to this node */
for_each_available_child_of_node_scoped(dev->of_node, child) {
- panel = of_drm_find_panel(child);
- if (IS_ERR(panel)) {
- dev_err(dev, "failed to find panel try bridge (%ld)\n",
- PTR_ERR(panel));
- panel = NULL;
-
- bridge = of_drm_find_and_get_bridge(child);
- if (!bridge) {
- dev_err(dev, "failed to find bridge\n");
- return -EINVAL;
- }
+ bridge = of_drm_find_and_get_bridge(child);
+ if (!bridge) {
+ dev_err(dev, "failed to find bridge\n");
+ return -EINVAL;
}
- if (panel || bridge)
- break;
+ break;
}
- if (panel) {
- bridge = drm_panel_bridge_add_typed(panel,
- DRM_MODE_CONNECTOR_DSI);
- drm_panel_put(panel);
- if (IS_ERR(bridge)) {
- dev_err(dev, "error adding panel bridge\n");
- return PTR_ERR(bridge);
- }
- drm_bridge_get(bridge);
- dev_info(dev, "connected to panel\n");
- d->panel = panel;
- } else if (bridge) {
+ if (!bridge) {
+ dev_err(dev, "no panel or bridge\n");
+ return -ENODEV;
+ } else if (!drm_bridge_is_panel(bridge)) {
/* TODO: AV8100 HDMI encoder goes here for example */
dev_info(dev, "connected to non-panel bridge (unsupported)\n");
return -ENODEV;
- } else {
- dev_err(dev, "no panel or bridge\n");
- return -ENODEV;
}
d->bridge.next_bridge = drm_bridge_get(bridge);
@@ -1159,8 +1138,6 @@ static void mcde_dsi_unbind(struct device *dev, struct device *master,
{
struct mcde_dsi *d = dev_get_drvdata(dev);
- if (d->panel)
- drm_panel_bridge_remove(d->bridge.next_bridge);
regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET,
PRCM_DSI_SW_RESET_DSI0_SW_RESETN, 0);
}
--
2.55.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH 09/11] drm/mcde: dsi: don't create a panel_bridge
2026-08-14 14:05 ` [PATCH 09/11] drm/mcde: dsi: don't create a panel_bridge Luca Ceresoli
@ 2026-08-17 12:23 ` Linus Walleij
0 siblings, 0 replies; 25+ messages in thread
From: Linus Walleij @ 2026-08-17 12:23 UTC (permalink / raw)
To: Luca Ceresoli
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Jessica Zhang,
Inki Dae, Jagan Teki, Marek Szyprowski, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel
On Fri, Aug 14, 2026 at 4:07 PM Luca Ceresoli <luca.ceresoli@bootlin.com> wrote:
> Now a panel_bridge is automatically created for every drm_panel, so this
> code (similar to an open-coded variant of drm_of_find_panel_or_bridge())
> would lead to creating a second panel_bridge for the same panel.
>
> Fix and simplify the code by just getting a reference to the
> already-existing bridge.
>
> Also keep the "connected to non-panel bridge (unsupported)\n" error logic
> by using the drm_bridge_is_panel() function.
>
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Looks good to me!
Reviewed-by: Linus Walleij <linusw@kernel.org>
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 10/11] drm/bridge: fsl-ldb: don't create a panel_bridge
2026-08-14 14:05 [PATCH 00/11] drm/panel: add a panel_bridge to every panel Luca Ceresoli
` (8 preceding siblings ...)
2026-08-14 14:05 ` [PATCH 09/11] drm/mcde: dsi: don't create a panel_bridge Luca Ceresoli
@ 2026-08-14 14:05 ` Luca Ceresoli
2026-08-14 14:05 ` [PATCH 11/11] drm/bridge: samsung-dsim: " Luca Ceresoli
2026-08-14 14:13 ` [PATCH 00/11] drm/panel: add a panel_bridge to every panel Luca Ceresoli
11 siblings, 0 replies; 25+ messages in thread
From: Luca Ceresoli @ 2026-08-14 14:05 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Jessica Zhang,
Linus Walleij, Inki Dae, Jagan Teki, Marek Szyprowski
Cc: Dmitry Baryshkov, Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel,
linux-kernel, Luca Ceresoli
Now a panel_bridge is automatically created for every drm_panel, so this
code, looking only for a panel and unconditionally creating a panel_bridge
for it, would lead to creating a second panel_bridge for the same panel.
Fix and simplify the code by just getting a reference to the
already-existing bridge from of_drm_find_and_get_bridge().
And since of_drm_find_and_get_bridge() returns a refcounted bridge, take
care of putting the bridge reference by using bridge->next_bridge.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/bridge/fsl-ldb.c | 18 +++++-------------
1 file changed, 5 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c
index 26cc72948f31..c289139b9273 100644
--- a/drivers/gpu/drm/bridge/fsl-ldb.c
+++ b/drivers/gpu/drm/bridge/fsl-ldb.c
@@ -86,7 +86,6 @@ static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
struct fsl_ldb {
struct device *dev;
struct drm_bridge bridge;
- struct drm_bridge *panel_bridge;
struct clk *clk;
struct regmap *regmap;
const struct fsl_ldb_devdata *devdata;
@@ -119,7 +118,7 @@ static int fsl_ldb_attach(struct drm_bridge *bridge,
{
struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
- return drm_bridge_attach(encoder, fsl_ldb->panel_bridge,
+ return drm_bridge_attach(encoder, fsl_ldb->bridge.next_bridge,
bridge, flags);
}
@@ -298,7 +297,6 @@ static int fsl_ldb_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *panel_node;
struct device_node *remote1, *remote2;
- struct drm_panel *panel;
struct fsl_ldb *fsl_ldb;
int dual_link;
@@ -339,19 +337,13 @@ static int fsl_ldb_probe(struct platform_device *pdev)
fsl_ldb_is_dual(fsl_ldb) ? "dual-link mode" :
fsl_ldb->ch0_enabled ? "channel 0" : "channel 1");
- panel = of_drm_find_panel(panel_node);
- of_node_put(panel_node);
- if (IS_ERR(panel))
- return PTR_ERR(panel);
-
if (of_property_present(dev->of_node, "nxp,enable-termination-resistor"))
fsl_ldb->use_termination_resistor = true;
- fsl_ldb->panel_bridge = devm_drm_panel_bridge_add(dev, panel);
- drm_panel_put(panel);
- if (IS_ERR(fsl_ldb->panel_bridge))
- return PTR_ERR(fsl_ldb->panel_bridge);
-
+ fsl_ldb->bridge.next_bridge = of_drm_find_and_get_bridge(panel_node);
+ of_node_put(panel_node);
+ if (!fsl_ldb->bridge.next_bridge)
+ return -ENODEV;
if (fsl_ldb_is_dual(fsl_ldb)) {
struct device_node *port1, *port2;
--
2.55.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH 11/11] drm/bridge: samsung-dsim: don't create a panel_bridge
2026-08-14 14:05 [PATCH 00/11] drm/panel: add a panel_bridge to every panel Luca Ceresoli
` (9 preceding siblings ...)
2026-08-14 14:05 ` [PATCH 10/11] drm/bridge: fsl-ldb: " Luca Ceresoli
@ 2026-08-14 14:05 ` Luca Ceresoli
2026-08-14 14:13 ` [PATCH 00/11] drm/panel: add a panel_bridge to every panel Luca Ceresoli
11 siblings, 0 replies; 25+ messages in thread
From: Luca Ceresoli @ 2026-08-14 14:05 UTC (permalink / raw)
To: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Jessica Zhang,
Linus Walleij, Inki Dae, Jagan Teki, Marek Szyprowski
Cc: Dmitry Baryshkov, Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel,
linux-kernel, Luca Ceresoli
Now a panel_bridge is automatically created for every drm_panel, so this
code (similar to an open-coded variant of drm_of_find_panel_or_bridge())
would lead to creating a second panel_bridge for the same panel.
Fix and simplify the code by just getting a reference to the
already-existing bridge.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/bridge/samsung-dsim.c | 19 +++----------------
1 file changed, 3 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c
index 5457a7b02a33..55d4e3aedb3d 100644
--- a/drivers/gpu/drm/bridge/samsung-dsim.c
+++ b/drivers/gpu/drm/bridge/samsung-dsim.c
@@ -1898,7 +1898,6 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
struct device *dev = dsi->dev;
struct device_node *np = dev->of_node;
struct device_node *remote;
- struct drm_panel *panel;
int ret = 0;
/*
@@ -1931,21 +1930,9 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
if (!remote)
return -ENODEV;
- panel = of_drm_find_panel(remote);
- if (!IS_ERR(panel)) {
- next_bridge = devm_drm_panel_bridge_add(dev, panel);
- drm_panel_put(panel);
- if (IS_ERR(next_bridge)) {
- ret = PTR_ERR(next_bridge);
- next_bridge = NULL; // Inhibit the cleanup action on an ERR_PTR
- } else {
- drm_bridge_get(next_bridge);
- }
- } else {
- next_bridge = of_drm_find_and_get_bridge(remote);
- if (!next_bridge)
- ret = -EINVAL;
- }
+ next_bridge = of_drm_find_and_get_bridge(remote);
+ if (!next_bridge)
+ ret = -EINVAL;
of_node_put(remote);
--
2.55.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH 00/11] drm/panel: add a panel_bridge to every panel
2026-08-14 14:05 [PATCH 00/11] drm/panel: add a panel_bridge to every panel Luca Ceresoli
` (10 preceding siblings ...)
2026-08-14 14:05 ` [PATCH 11/11] drm/bridge: samsung-dsim: " Luca Ceresoli
@ 2026-08-14 14:13 ` Luca Ceresoli
11 siblings, 0 replies; 25+ messages in thread
From: Luca Ceresoli @ 2026-08-14 14:13 UTC (permalink / raw)
To: Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Jessica Zhang, Linus Walleij, Inki Dae,
Jagan Teki, Marek Szyprowski
Cc: Dmitry Baryshkov, Hui Pu, Ian Ray, Thomas Petazzoni, dri-devel,
linux-kernel
Hello,
On Fri Aug 14, 2026 at 4:05 PM CEST, Luca Ceresoli wrote:
> This series makes every drm_panel create a drm_panel_bridge wrapping it, as
> previously discussed [1][2].
I'm afraid I forgot adding an [RFC] tag to this series before
sending. Sorry about that.
> == Series outline
[...]
> 2. Address circular module dependency that would arise in the following
> commit [RFC!]
>
> drm/panel: merge the drm_kms_helper module into the drm module
>
> 3. The main commit
>
> drm/bridge: panel: add a panel_bridge to every panel
FYI, these two commits are those in the biggest need for comments.
Luca
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 25+ messages in thread