* [PATCH RFC v2 01/19] drm: of: move drm_of_find_panel_or_bridge() from drm_of.c to bridge/panel.c
2026-09-03 8:11 [PATCH RFC v2 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
@ 2026-09-03 8:11 ` Luca Ceresoli
2026-09-03 9:51 ` Maxime Ripard
2026-09-03 8:11 ` [PATCH RFC v2 02/19] drm/bridge: panel: move to a new module Luca Ceresoli
` (17 subsequent siblings)
18 siblings, 1 reply; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 8:11 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: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu, Ian Ray,
Thomas Petazzoni, dri-devel, linux-kernel, Luca Ceresoli
We want to move drm_panel.o from the main drm module to a new drm_panel
module, but there is one function in the drm module that calls into
drm_panel.c code:
drm_of_find_panel_or_bridge() (in drm_of.c, drm module)
-> calls of_drm_find_panel (in drm_panel.c, would-be the new drm_panel module)
Avoid this issue by moving drm_of_find_panel_or_bridge() to bridge/panel.c
(which is currently in the drm_kms_helper module).
As a result drm_kms_helper will depend on the new drm_panel module, which
is fine because there is no dependency of drm_panel on drm_kms_helper.
After this change, all drivers using drm_of_find_panel_or_bridge() will
have to select DRM_PANEL_BRIDGE (and DRM_PANEL, recursively). Add that for
affected drivers. While there, also add DRM_PANEL on drivers selecting
DRM_PANEL_BRIDGE.
No functional changes, just moving code around.
[AI used to add 'select DRM_PANEL[_BRIDGE]' for affected drivers]
Assisted-by: opencode:deepseek-v4-flash-0731
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/bridge/Kconfig | 2 ++
drivers/gpu/drm/bridge/analogix/Kconfig | 4 +++
drivers/gpu/drm/bridge/panel.c | 63 +++++++++++++++++++++++++++++++++
drivers/gpu/drm/drm_of.c | 63 ---------------------------------
drivers/gpu/drm/fsl-dcu/Kconfig | 1 +
drivers/gpu/drm/imx/dcss/Kconfig | 2 ++
drivers/gpu/drm/ingenic/Kconfig | 1 +
drivers/gpu/drm/logicvc/Kconfig | 2 ++
drivers/gpu/drm/mcde/Kconfig | 1 +
drivers/gpu/drm/pl111/Kconfig | 1 +
drivers/gpu/drm/renesas/rcar-du/Kconfig | 1 +
drivers/gpu/drm/rockchip/Kconfig | 4 +++
drivers/gpu/drm/stm/Kconfig | 1 +
drivers/gpu/drm/sun4i/Kconfig | 1 +
drivers/gpu/drm/tegra/Kconfig | 1 +
drivers/gpu/drm/tidss/Kconfig | 2 ++
drivers/gpu/drm/tve200/Kconfig | 1 +
include/drm/drm_bridge.h | 12 +++++++
include/drm/drm_of.h | 12 -------
19 files changed, 100 insertions(+), 75 deletions(-)
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index f2db7f60d40f..89e87460aefc 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -151,6 +151,7 @@ config DRM_LONTIUM_LT8912B
config DRM_LONTIUM_LT9211
tristate "Lontium LT9211 DSI/LVDS/DPI bridge"
depends on OF
+ select DRM_PANEL
select DRM_PANEL_BRIDGE
select DRM_KMS_HELPER
select DRM_MIPI_DSI
@@ -498,6 +499,7 @@ config DRM_WAVESHARE_BRIDGE
tristate "Waveshare DSI bridge"
depends on OF
depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_PANEL
select DRM_PANEL_BRIDGE
select DRM_KMS_HELPER
select DRM_MIPI_DSI
diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig
index 57bb2daa5aaf..d07431788fcb 100644
--- a/drivers/gpu/drm/bridge/analogix/Kconfig
+++ b/drivers/gpu/drm/bridge/analogix/Kconfig
@@ -6,6 +6,8 @@ config DRM_ANALOGIX_ANX6345
select DRM_DISPLAY_DP_HELPER
select DRM_DISPLAY_HELPER
select DRM_KMS_HELPER
+ select DRM_PANEL
+ select DRM_PANEL_BRIDGE
select REGMAP_I2C
help
ANX6345 is an ultra-low power Full-HD DisplayPort/eDP
@@ -32,6 +34,8 @@ config DRM_ANALOGIX_DP
depends on DRM
depends on OF
select DRM_DISPLAY_DP_AUX_BUS
+ select DRM_PANEL
+ select DRM_PANEL_BRIDGE
config DRM_ANALOGIX_ANX7625
tristate "Analogix Anx7625 MIPI to DP interface support"
diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 02388a3de626..83be09641582 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -560,4 +560,67 @@ struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm,
}
EXPORT_SYMBOL(drmm_of_get_bridge);
+/**
+ * drm_of_find_panel_or_bridge - return connected panel or bridge device
+ * @np: device tree node containing encoder output ports
+ * @port: port in the device tree node
+ * @endpoint: endpoint in the device tree node
+ * @panel: pointer to hold returned drm_panel, must not be NULL. On success
+ * the caller must call drm_panel_put() when done with the panel
+ * @bridge: pointer to hold returned drm_bridge
+ *
+ * Given a DT node's port and endpoint number, find the connected node and
+ * return either the associated struct drm_panel or drm_bridge device.
+ *
+ * This function is deprecated and should not be used in new drivers. Use
+ * of_drm_get_bridge_by_endpoint() instead when not looking for a panel, or
+ * devm_drm_of_get_bridge() otherwise.
+ *
+ * Returns zero if successful, or one of the standard error codes if it fails.
+ */
+int drm_of_find_panel_or_bridge(const struct device_node *np,
+ int port, int endpoint,
+ struct drm_panel **panel,
+ struct drm_bridge **bridge)
+{
+ if (WARN_ON(!panel))
+ return -EINVAL;
+
+ *panel = NULL;
+ if (bridge)
+ *bridge = NULL;
+
+ /*
+ * 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 a graph is present 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;
+
+ *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;
+
+ *bridge = NULL;
+ }
+
+ return -EPROBE_DEFER;
+}
+EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge);
+
#endif
diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c
index 2b53124ded68..411f258d9f91 100644
--- a/drivers/gpu/drm/drm_of.c
+++ b/drivers/gpu/drm/drm_of.c
@@ -264,69 +264,6 @@ int drm_of_get_panel_orientation(const struct device_node *np,
}
EXPORT_SYMBOL_GPL(drm_of_get_panel_orientation);
-/**
- * drm_of_find_panel_or_bridge - return connected panel or bridge device
- * @np: device tree node containing encoder output ports
- * @port: port in the device tree node
- * @endpoint: endpoint in the device tree node
- * @panel: pointer to hold returned drm_panel, must not be NULL. On success
- * the caller must call drm_panel_put() when done with the panel
- * @bridge: pointer to hold returned drm_bridge
- *
- * Given a DT node's port and endpoint number, find the connected node and
- * return either the associated struct drm_panel or drm_bridge device.
- *
- * This function is deprecated and should not be used in new drivers. Use
- * of_drm_get_bridge_by_endpoint() instead when not looking for a panel, or
- * devm_drm_of_get_bridge() otherwise.
- *
- * Returns zero if successful, or one of the standard error codes if it fails.
- */
-int drm_of_find_panel_or_bridge(const struct device_node *np,
- int port, int endpoint,
- struct drm_panel **panel,
- struct drm_bridge **bridge)
-{
- if (WARN_ON(!panel))
- return -EINVAL;
-
- *panel = NULL;
- if (bridge)
- *bridge = NULL;
-
- /*
- * 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 a graph is present 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;
-
- *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;
-
- *bridge = NULL;
- }
-
- return -EPROBE_DEFER;
-}
-EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge);
-
enum drm_of_lvds_pixels {
DRM_OF_LVDS_EVEN = BIT(0),
DRM_OF_LVDS_ODD = BIT(1),
diff --git a/drivers/gpu/drm/fsl-dcu/Kconfig b/drivers/gpu/drm/fsl-dcu/Kconfig
index 0e0f910ceb9f..7f0e851e8508 100644
--- a/drivers/gpu/drm/fsl-dcu/Kconfig
+++ b/drivers/gpu/drm/fsl-dcu/Kconfig
@@ -7,6 +7,7 @@ config DRM_FSL_DCU
select DRM_GEM_DMA_HELPER
select DRM_KMS_HELPER
select DRM_PANEL
+ select DRM_PANEL_BRIDGE
select REGMAP_MMIO
select VIDEOMODE_HELPERS
select MFD_SYSCON if SOC_LS1021A
diff --git a/drivers/gpu/drm/imx/dcss/Kconfig b/drivers/gpu/drm/imx/dcss/Kconfig
index e014ed3ae66c..aa2a20ef5910 100644
--- a/drivers/gpu/drm/imx/dcss/Kconfig
+++ b/drivers/gpu/drm/imx/dcss/Kconfig
@@ -6,6 +6,8 @@ config DRM_IMX_DCSS
select DRM_DISPLAY_HELPER
select DRM_BRIDGE_CONNECTOR
select DRM_GEM_DMA_HELPER
+ select DRM_PANEL
+ select DRM_PANEL_BRIDGE
select VIDEOMODE_HELPERS
depends on DRM && ((ARCH_MXC && ARM64) || COMPILE_TEST)
help
diff --git a/drivers/gpu/drm/ingenic/Kconfig b/drivers/gpu/drm/ingenic/Kconfig
index 04ecfb0c5dd6..987ed42f6f7a 100644
--- a/drivers/gpu/drm/ingenic/Kconfig
+++ b/drivers/gpu/drm/ingenic/Kconfig
@@ -7,6 +7,7 @@ config DRM_INGENIC
depends on COMMON_CLK
select DRM_BRIDGE
select DRM_CLIENT_SELECTION
+ select DRM_PANEL
select DRM_PANEL_BRIDGE
select DRM_KMS_HELPER
select DRM_DISPLAY_HELPER
diff --git a/drivers/gpu/drm/logicvc/Kconfig b/drivers/gpu/drm/logicvc/Kconfig
index 579a358ed5cf..7d2c0a460eec 100644
--- a/drivers/gpu/drm/logicvc/Kconfig
+++ b/drivers/gpu/drm/logicvc/Kconfig
@@ -6,6 +6,8 @@ config DRM_LOGICVC
select DRM_KMS_HELPER
select DRM_KMS_DMA_HELPER
select DRM_GEM_DMA_HELPER
+ select DRM_PANEL
+ select DRM_PANEL_BRIDGE
select REGMAP
select REGMAP_MMIO
help
diff --git a/drivers/gpu/drm/mcde/Kconfig b/drivers/gpu/drm/mcde/Kconfig
index 3516c8d2a5d9..6ebfb930cbfa 100644
--- a/drivers/gpu/drm/mcde/Kconfig
+++ b/drivers/gpu/drm/mcde/Kconfig
@@ -9,6 +9,7 @@ config DRM_MCDE
select DRM_CLIENT_SELECTION
select DRM_MIPI_DSI
select DRM_BRIDGE
+ select DRM_PANEL
select DRM_PANEL_BRIDGE
select DRM_KMS_HELPER
select DRM_GEM_DMA_HELPER
diff --git a/drivers/gpu/drm/pl111/Kconfig b/drivers/gpu/drm/pl111/Kconfig
index 82e918820950..20201ec20aa7 100644
--- a/drivers/gpu/drm/pl111/Kconfig
+++ b/drivers/gpu/drm/pl111/Kconfig
@@ -9,6 +9,7 @@ config DRM_PL111
select DRM_KMS_HELPER
select DRM_GEM_DMA_HELPER
select DRM_BRIDGE
+ select DRM_PANEL
select DRM_PANEL_BRIDGE
help
Choose this option for DRM support for the PL111 CLCD controller.
diff --git a/drivers/gpu/drm/renesas/rcar-du/Kconfig b/drivers/gpu/drm/renesas/rcar-du/Kconfig
index 840305fdeb49..051b0967008c 100644
--- a/drivers/gpu/drm/renesas/rcar-du/Kconfig
+++ b/drivers/gpu/drm/renesas/rcar-du/Kconfig
@@ -47,6 +47,7 @@ config DRM_RCAR_LVDS
depends on PM
select DRM_KMS_HELPER
select DRM_PANEL
+ select DRM_PANEL_BRIDGE
select RESET_CONTROLLER
config DRM_RCAR_USE_MIPI_DSI
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index e7f49fe845ea..0b20f472dbd1 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -124,6 +124,8 @@ config ROCKCHIP_LVDS
depends on PINCTRL && OF
select DRM_DISPLAY_HELPER
select DRM_BRIDGE_CONNECTOR
+ select DRM_PANEL
+ select DRM_PANEL_BRIDGE
help
Choose this option to enable support for Rockchip LVDS controllers.
Rockchip rk3288 SoC has LVDS TX Controller can be used, and it
@@ -136,6 +138,8 @@ config ROCKCHIP_RGB
depends on PINCTRL
select DRM_DISPLAY_HELPER
select DRM_BRIDGE_CONNECTOR
+ select DRM_PANEL
+ select DRM_PANEL_BRIDGE
help
Choose this option to enable support for Rockchip RGB output.
Some Rockchip CRTCs, like rv1108, can directly output parallel
diff --git a/drivers/gpu/drm/stm/Kconfig b/drivers/gpu/drm/stm/Kconfig
index 635be0ac00af..1e3205aa2c7e 100644
--- a/drivers/gpu/drm/stm/Kconfig
+++ b/drivers/gpu/drm/stm/Kconfig
@@ -6,6 +6,7 @@ config DRM_STM
select DRM_CLIENT_SELECTION
select DRM_KMS_HELPER
select DRM_GEM_DMA_HELPER
+ select DRM_PANEL
select DRM_PANEL_BRIDGE
select VIDEOMODE_HELPERS
select FB_PROVIDE_GET_FB_UNMAPPED_AREA if FB
diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
index b56ba00aabca..32c30e08cf5c 100644
--- a/drivers/gpu/drm/sun4i/Kconfig
+++ b/drivers/gpu/drm/sun4i/Kconfig
@@ -7,6 +7,7 @@ config DRM_SUN4I
select DRM_GEM_DMA_HELPER
select DRM_KMS_HELPER
select DRM_PANEL
+ select DRM_PANEL_BRIDGE
select REGMAP_MMIO
select VIDEOMODE_HELPERS
help
diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig
index 8a3b16aac5d6..fdcb10a4c7b5 100644
--- a/drivers/gpu/drm/tegra/Kconfig
+++ b/drivers/gpu/drm/tegra/Kconfig
@@ -14,6 +14,7 @@ config DRM_TEGRA
select DRM_KMS_HELPER
select DRM_MIPI_DSI
select DRM_PANEL
+ select DRM_PANEL_BRIDGE
select FB_DMAMEM_HELPERS if DRM_FBDEV_EMULATION
select TEGRA_HOST1X
select INTERCONNECT
diff --git a/drivers/gpu/drm/tidss/Kconfig b/drivers/gpu/drm/tidss/Kconfig
index 31ad582b7602..863930ecda1e 100644
--- a/drivers/gpu/drm/tidss/Kconfig
+++ b/drivers/gpu/drm/tidss/Kconfig
@@ -7,6 +7,8 @@ config DRM_TIDSS
select DRM_DISPLAY_HELPER
select DRM_BRIDGE_CONNECTOR
select DRM_GEM_DMA_HELPER
+ select DRM_PANEL
+ select DRM_PANEL_BRIDGE
help
The TI Keystone family SoCs introduced a new generation of
Display SubSystem. There is currently three Keystone family
diff --git a/drivers/gpu/drm/tve200/Kconfig b/drivers/gpu/drm/tve200/Kconfig
index a9d6fe535d88..c0746ae8f703 100644
--- a/drivers/gpu/drm/tve200/Kconfig
+++ b/drivers/gpu/drm/tve200/Kconfig
@@ -7,6 +7,7 @@ config DRM_TVE200
depends on OF
select DRM_BRIDGE
select DRM_CLIENT_SELECTION
+ select DRM_PANEL
select DRM_PANEL_BRIDGE
select DRM_KMS_HELPER
select DRM_GEM_DMA_HELPER
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 58fff047f43b..c5b82e6946f5 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -1507,6 +1507,10 @@ struct drm_bridge *devm_drm_of_get_bridge(struct device *dev, struct device_node
u32 port, u32 endpoint);
struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm, struct device_node *node,
u32 port, u32 endpoint);
+int drm_of_find_panel_or_bridge(const struct device_node *np,
+ int port, int endpoint,
+ struct drm_panel **panel,
+ struct drm_bridge **bridge);
#else
static inline struct drm_bridge *devm_drm_of_get_bridge(struct device *dev,
struct device_node *node,
@@ -1523,6 +1527,14 @@ static inline struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm,
{
return ERR_PTR(-ENODEV);
}
+
+static inline int drm_of_find_panel_or_bridge(const struct device_node *np,
+ int port, int endpoint,
+ struct drm_panel **panel,
+ struct drm_bridge **bridge)
+{
+ return -EINVAL;
+}
#endif
void devm_drm_put_bridge(struct device *dev, struct drm_bridge *bridge);
diff --git a/include/drm/drm_of.h b/include/drm/drm_of.h
index ebebed14c611..402f5db11e47 100644
--- a/include/drm/drm_of.h
+++ b/include/drm/drm_of.h
@@ -51,10 +51,6 @@ int drm_of_encoder_active_endpoint(struct device_node *node,
struct of_endpoint *endpoint);
int drm_of_get_panel_orientation(const struct device_node *np,
enum drm_panel_orientation *orientation);
-int drm_of_find_panel_or_bridge(const struct device_node *np,
- int port, int endpoint,
- struct drm_panel **panel,
- struct drm_bridge **bridge);
int drm_of_lvds_get_dual_link_pixel_order(const struct device_node *port1,
const struct device_node *port2);
int drm_of_lvds_get_dual_link_pixel_order_sink(struct device_node *port1,
@@ -112,14 +108,6 @@ static inline int drm_of_get_panel_orientation(const struct device_node *np,
return -EINVAL;
}
-static inline int drm_of_find_panel_or_bridge(const struct device_node *np,
- int port, int endpoint,
- struct drm_panel **panel,
- struct drm_bridge **bridge)
-{
- return -EINVAL;
-}
-
static inline int
drm_of_lvds_get_dual_link_pixel_order(const struct device_node *port1,
const struct device_node *port2)
--
2.55.0
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH RFC v2 01/19] drm: of: move drm_of_find_panel_or_bridge() from drm_of.c to bridge/panel.c
2026-09-03 8:11 ` [PATCH RFC v2 01/19] drm: of: move drm_of_find_panel_or_bridge() from drm_of.c to bridge/panel.c Luca Ceresoli
@ 2026-09-03 9:51 ` Maxime Ripard
2026-09-03 13:42 ` Luca Ceresoli
0 siblings, 1 reply; 30+ messages in thread
From: Maxime Ripard @ 2026-09-03 9:51 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, Albert Esteve,
Anusha Srivatsa, Dmitry Baryshkov, Hui Pu, Ian Ray,
Thomas Petazzoni, dri-devel, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 1489 bytes --]
Hi,
On Thu, Sep 03, 2026 at 10:11:04AM +0200, Luca Ceresoli wrote:
> We want to move drm_panel.o from the main drm module to a new drm_panel
> module, but there is one function in the drm module that calls into
> drm_panel.c code:
>
> drm_of_find_panel_or_bridge() (in drm_of.c, drm module)
> -> calls of_drm_find_panel (in drm_panel.c, would-be the new drm_panel module)
>
> Avoid this issue by moving drm_of_find_panel_or_bridge() to bridge/panel.c
> (which is currently in the drm_kms_helper module).
>
> As a result drm_kms_helper will depend on the new drm_panel module, which
> is fine because there is no dependency of drm_panel on drm_kms_helper.
>
> After this change, all drivers using drm_of_find_panel_or_bridge() will
> have to select DRM_PANEL_BRIDGE (and DRM_PANEL, recursively). Add that for
> affected drivers. While there, also add DRM_PANEL on drivers selecting
> DRM_PANEL_BRIDGE.
>
> No functional changes, just moving code around.
>
> [AI used to add 'select DRM_PANEL[_BRIDGE]' for affected drivers]
> Assisted-by: opencode:deepseek-v4-flash-0731
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
In the previous discussion, I suggested to move it to drm_panel.c
because it's not really related to the panel_bridge stuff, like, at all.
And both drm_panel.c and drm_bridge.c are in drm.ko at this point so you
shouldn't have any issue there.
Also, you don't have to select DRM_PANEL_BRIDGE anymore.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH RFC v2 01/19] drm: of: move drm_of_find_panel_or_bridge() from drm_of.c to bridge/panel.c
2026-09-03 9:51 ` Maxime Ripard
@ 2026-09-03 13:42 ` Luca Ceresoli
0 siblings, 0 replies; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 13:42 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, Albert Esteve,
Anusha Srivatsa, Dmitry Baryshkov, Hui Pu, Ian Ray,
Thomas Petazzoni, dri-devel, linux-kernel
Hi,
On Thu Sep 3, 2026 at 11:51 AM CEST, Maxime Ripard wrote:
> Hi,
>
> On Thu, Sep 03, 2026 at 10:11:04AM +0200, Luca Ceresoli wrote:
>> We want to move drm_panel.o from the main drm module to a new drm_panel
>> module, but there is one function in the drm module that calls into
>> drm_panel.c code:
>>
>> drm_of_find_panel_or_bridge() (in drm_of.c, drm module)
>> -> calls of_drm_find_panel (in drm_panel.c, would-be the new drm_panel module)
>>
>> Avoid this issue by moving drm_of_find_panel_or_bridge() to bridge/panel.c
>> (which is currently in the drm_kms_helper module).
>>
>> As a result drm_kms_helper will depend on the new drm_panel module, which
>> is fine because there is no dependency of drm_panel on drm_kms_helper.
>>
>> After this change, all drivers using drm_of_find_panel_or_bridge() will
>> have to select DRM_PANEL_BRIDGE (and DRM_PANEL, recursively). Add that for
>> affected drivers. While there, also add DRM_PANEL on drivers selecting
>> DRM_PANEL_BRIDGE.
>>
>> No functional changes, just moving code around.
>>
>> [AI used to add 'select DRM_PANEL[_BRIDGE]' for affected drivers]
>> Assisted-by: opencode:deepseek-v4-flash-0731
>> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
>
> In the previous discussion, I suggested to move it to drm_panel.c
> because it's not really related to the panel_bridge stuff, like, at all.
> And both drm_panel.c and drm_bridge.c are in drm.ko at this point so you
> shouldn't have any issue there.
I had this other implementation done already, and I wanted to have patch 5
out ASAP so I sent as is.
I don't care much about where drm_of_find_panel_or_bridge() is moved and
the discussion about where it's more fitting, because it should just
disappear eventually anyway, hopefully soon.
I will try your idea in v3.
Luca
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH RFC v2 02/19] drm/bridge: panel: move to a new module
2026-09-03 8:11 [PATCH RFC v2 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
2026-09-03 8:11 ` [PATCH RFC v2 01/19] drm: of: move drm_of_find_panel_or_bridge() from drm_of.c to bridge/panel.c Luca Ceresoli
@ 2026-09-03 8:11 ` Luca Ceresoli
2026-09-03 9:59 ` Maxime Ripard
2026-09-03 8:11 ` [PATCH RFC v2 03/19] drm/panel: " Luca Ceresoli
` (16 subsequent siblings)
18 siblings, 1 reply; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 8:11 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: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu, Ian Ray,
Thomas Petazzoni, dri-devel, linux-kernel, Luca Ceresoli
Work is in progress for every drm_panel to embed a drm_bridge, which will
make the drm_panel code (currently in the drm module) depend on the
drm_kms_helper module.
However that would create a dependency loop:
* the panel_bridge code in bridge/panel.c [drm_kms_helper module]
already depends on the drm_panel.c code (it manipulates a drm_panel)
* additionally, the drm_panel.c code, in order to create a drm_bridge,
will depend on the helpers in drm_atomic_helper and drm_probe_helper
code [drm_kms_helper module]
Prevent the loop by moving the panel bridge out to its own module.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/Makefile | 3 ++-
drivers/gpu/drm/bridge/Kconfig | 2 +-
drivers/gpu/drm/bridge/panel.c | 3 +++
include/drm/drm_bridge.h | 4 ++--
4 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index e635fcffd379..c4509e7fd248 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -156,10 +156,11 @@ 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
+obj-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
+
#
# Drivers and the rest
#
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 89e87460aefc..0a1689f8209d 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -6,7 +6,7 @@ config DRM_BRIDGE
Bridge registration and lookup framework.
config DRM_PANEL_BRIDGE
- def_bool y
+ def_tristate y
depends on DRM_BRIDGE
select DRM_PANEL
help
diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 83be09641582..40e3970e8b76 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -624,3 +624,6 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge);
#endif
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Panel bridge helper");
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index c5b82e6946f5..9f2294957669 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -1473,7 +1473,7 @@ void drm_bridge_hpd_disable(struct drm_bridge *bridge);
void drm_bridge_hpd_notify(struct drm_bridge *bridge,
enum drm_connector_status status);
-#ifdef CONFIG_DRM_PANEL_BRIDGE
+#if IS_ENABLED(CONFIG_DRM_PANEL_BRIDGE)
bool drm_bridge_is_panel(const struct drm_bridge *bridge);
struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel);
struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
@@ -1502,7 +1502,7 @@ static inline int drm_panel_bridge_set_orientation(struct drm_connector *connect
}
#endif
-#if defined(CONFIG_OF) && defined(CONFIG_DRM_PANEL_BRIDGE)
+#if defined(CONFIG_OF) && IS_ENABLED(CONFIG_DRM_PANEL_BRIDGE)
struct drm_bridge *devm_drm_of_get_bridge(struct device *dev, struct device_node *node,
u32 port, u32 endpoint);
struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm, struct device_node *node,
--
2.55.0
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH RFC v2 02/19] drm/bridge: panel: move to a new module
2026-09-03 8:11 ` [PATCH RFC v2 02/19] drm/bridge: panel: move to a new module Luca Ceresoli
@ 2026-09-03 9:59 ` Maxime Ripard
0 siblings, 0 replies; 30+ messages in thread
From: Maxime Ripard @ 2026-09-03 9:59 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, Albert Esteve,
Anusha Srivatsa, Dmitry Baryshkov, Hui Pu, Ian Ray,
Thomas Petazzoni, dri-devel, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 1134 bytes --]
On Thu, Sep 03, 2026 at 10:11:05AM +0200, Luca Ceresoli wrote:
> Work is in progress for every drm_panel to embed a drm_bridge, which will
> make the drm_panel code (currently in the drm module) depend on the
> drm_kms_helper module.
>
> However that would create a dependency loop:
>
> * the panel_bridge code in bridge/panel.c [drm_kms_helper module]
> already depends on the drm_panel.c code (it manipulates a drm_panel)
> * additionally, the drm_panel.c code, in order to create a drm_bridge,
> will depend on the helpers in drm_atomic_helper and drm_probe_helper
> code [drm_kms_helper module]
>
> Prevent the loop by moving the panel bridge out to its own module.
>
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Again, in the previous discussion, I suggested that you moved the
drm_panel code into its own module. If you're doing everything at once,
it will break, but the only source of breakage you're talking about here
are introduced by *future* patches, not the current state.
So, what prevented you *in this patch* from moving drm_panel into its
own module?
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH RFC v2 03/19] drm/panel: move to a new module
2026-09-03 8:11 [PATCH RFC v2 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
2026-09-03 8:11 ` [PATCH RFC v2 01/19] drm: of: move drm_of_find_panel_or_bridge() from drm_of.c to bridge/panel.c Luca Ceresoli
2026-09-03 8:11 ` [PATCH RFC v2 02/19] drm/bridge: panel: move to a new module Luca Ceresoli
@ 2026-09-03 8:11 ` Luca Ceresoli
2026-09-03 9:59 ` Maxime Ripard
2026-09-03 8:11 ` [PATCH RFC v2 04/19] drm/bridge: panel: rename drm_bridge_is_panel() -> drm_bridge_is_panel_bridge() Luca Ceresoli
` (15 subsequent siblings)
18 siblings, 1 reply; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 8:11 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: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu, Ian Ray,
Thomas Petazzoni, dri-devel, linux-kernel, Luca Ceresoli
Work is in progress for every drm_panel to embed a drm_bridge, which will
make the drm_panel code (currently in the drm module) depend on the
drm_kms_helper module.
To avoid the main drm module to depend on other drm modules and create a
depepdency loop, move drm_panel.o to a new drm_panel module, so the module
dependency will be drm_panel -> drm_kms_helper instead.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/Makefile | 2 +-
drivers/gpu/drm/panel/Kconfig | 2 +-
include/drm/drm_panel.h | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index c4509e7fd248..9a8df14ef628 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -79,7 +79,6 @@ drm-$(CONFIG_DRM_CLIENT) += \
drm_client_modeset.o \
drm_client_sysrq.o
drm-$(CONFIG_COMPAT) += drm_ioc32.o
-drm-$(CONFIG_DRM_PANEL) += drm_panel.o
drm-$(CONFIG_OF) += drm_of.o
drm-$(CONFIG_PCI) += drm_pci.o
drm-$(CONFIG_DEBUG_FS) += \
@@ -96,6 +95,7 @@ drm-$(CONFIG_DRM_PANIC_SCREEN_QR_CODE) += drm_panic_qr.o
drm-$(CONFIG_DRM_RAS) += drm_ras.o drm_ras_nl.o drm_ras_genl_family.o
obj-$(CONFIG_DRM) += drm.o
+obj-$(CONFIG_DRM_PANEL) += drm_panel.o
obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
obj-$(CONFIG_DRM_PANEL_BACKLIGHT_QUIRKS) += drm_panel_backlight_quirks.o
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 747f47347521..0a79a0558101 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
config DRM_PANEL
- bool
+ tristate
depends on DRM
help
Panel registration and lookup framework.
diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
index b87323443f49..08949d41d743 100644
--- a/include/drm/drm_panel.h
+++ b/include/drm/drm_panel.h
@@ -335,7 +335,7 @@ void drm_panel_disable(struct drm_panel *panel);
int drm_panel_get_modes(struct drm_panel *panel, struct drm_connector *connector);
-#if defined(CONFIG_OF) && defined(CONFIG_DRM_PANEL)
+#if defined(CONFIG_OF) && IS_ENABLED(CONFIG_DRM_PANEL)
struct drm_panel *of_drm_find_panel(const struct device_node *np);
#else
static inline struct drm_panel *of_drm_find_panel(const struct device_node *np)
@@ -344,7 +344,7 @@ static inline struct drm_panel *of_drm_find_panel(const struct device_node *np)
}
#endif
-#if defined(CONFIG_DRM_PANEL)
+#if IS_ENABLED(CONFIG_DRM_PANEL)
bool drm_is_panel_follower(struct device *dev);
int drm_panel_add_follower(struct device *follower_dev,
struct drm_panel_follower *follower);
--
2.55.0
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH RFC v2 03/19] drm/panel: move to a new module
2026-09-03 8:11 ` [PATCH RFC v2 03/19] drm/panel: " Luca Ceresoli
@ 2026-09-03 9:59 ` Maxime Ripard
0 siblings, 0 replies; 30+ messages in thread
From: Maxime Ripard @ 2026-09-03 9:59 UTC (permalink / raw)
To: Luca Ceresoli
Cc: dri-devel, linux-kernel, Albert Esteve, Andrzej Hajda,
Anusha Srivatsa, 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 Thu, 3 Sep 2026 10:11:06 +0200, Luca Ceresoli wrote:
> Work is in progress for every drm_panel to embed a drm_bridge, which will
> make the drm_panel code (currently in the drm module) depend on the
> drm_kms_helper module.
>
> To avoid the main drm module to depend on other drm modules and create a
>
> [ ... ]
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Thanks!
Maxime
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH RFC v2 04/19] drm/bridge: panel: rename drm_bridge_is_panel() -> drm_bridge_is_panel_bridge()
2026-09-03 8:11 [PATCH RFC v2 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (2 preceding siblings ...)
2026-09-03 8:11 ` [PATCH RFC v2 03/19] drm/panel: " Luca Ceresoli
@ 2026-09-03 8:11 ` Luca Ceresoli
2026-09-03 13:59 ` Albert Esteve
2026-09-03 8:11 ` [PATCH RFC v2 05/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (14 subsequent siblings)
18 siblings, 1 reply; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 8:11 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: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu, Ian Ray,
Thomas Petazzoni, dri-devel, linux-kernel, Luca Ceresoli
Work is in progress for every drm_panel to embed a drm_bridge, and for that
a function will be needed in the drm_panel API to tell whether a bridge
represents a panel or something else. The ideal name for that will be
drm_bridge_is_panel(), which however is already in use by the panel_bridge.
Rename the current function in the panel_bridge API to
drm_bridge_is_panel_bridge(), which is more precise and frees up the
drm_bridge_is_panel() for future use in the drm_panel API.
No functional changes, just renaming a function treewide.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/bridge/panel.c | 8 ++++----
drivers/gpu/drm/display/drm_bridge_connector.c | 2 +-
include/drm/drm_bridge.h | 4 ++--
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 40e3970e8b76..0582c708957c 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -221,17 +221,17 @@ static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
};
/**
- * drm_bridge_is_panel - Checks if a drm_bridge is a panel_bridge.
+ * drm_bridge_is_panel_bridge - Checks if a drm_bridge is a panel_bridge.
*
* @bridge: The drm_bridge to be checked.
*
* Returns true if the bridge is a panel bridge, or false otherwise.
*/
-bool drm_bridge_is_panel(const struct drm_bridge *bridge)
+bool drm_bridge_is_panel_bridge(const struct drm_bridge *bridge)
{
return bridge->funcs == &panel_bridge_bridge_funcs;
}
-EXPORT_SYMBOL(drm_bridge_is_panel);
+EXPORT_SYMBOL(drm_bridge_is_panel_bridge);
/**
* drm_panel_bridge_add - Creates a &drm_bridge and &drm_connector that
@@ -321,7 +321,7 @@ void drm_panel_bridge_remove(struct drm_bridge *bridge)
if (!bridge)
return;
- if (!drm_bridge_is_panel(bridge)) {
+ if (!drm_bridge_is_panel_bridge(bridge)) {
drm_warn(bridge->dev, "%s: called on non-panel bridge!\n", __func__);
return;
}
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 00feb73e63d7..5de9b76f345b 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -983,7 +983,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
if (bridge->ddc)
ddc = bridge->ddc;
- if (drm_bridge_is_panel(bridge)) {
+ if (drm_bridge_is_panel_bridge(bridge)) {
drm_bridge_put(panel_bridge);
panel_bridge = drm_bridge_get(bridge);
}
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 9f2294957669..b29096d624d5 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -1474,7 +1474,7 @@ void drm_bridge_hpd_notify(struct drm_bridge *bridge,
enum drm_connector_status status);
#if IS_ENABLED(CONFIG_DRM_PANEL_BRIDGE)
-bool drm_bridge_is_panel(const struct drm_bridge *bridge);
+bool drm_bridge_is_panel_bridge(const struct drm_bridge *bridge);
struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel);
struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
u32 connector_type);
@@ -1490,7 +1490,7 @@ struct drm_bridge *drmm_panel_bridge_add(struct drm_device *drm,
struct drm_panel *panel);
struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge);
#else
-static inline bool drm_bridge_is_panel(const struct drm_bridge *bridge)
+static inline bool drm_bridge_is_panel_bridge(const struct drm_bridge *bridge)
{
return false;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH RFC v2 04/19] drm/bridge: panel: rename drm_bridge_is_panel() -> drm_bridge_is_panel_bridge()
2026-09-03 8:11 ` [PATCH RFC v2 04/19] drm/bridge: panel: rename drm_bridge_is_panel() -> drm_bridge_is_panel_bridge() Luca Ceresoli
@ 2026-09-03 13:59 ` Albert Esteve
2026-09-03 15:38 ` Luca Ceresoli
0 siblings, 1 reply; 30+ messages in thread
From: Albert Esteve @ 2026-09-03 13:59 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,
Linus Walleij, Inki Dae, Jagan Teki, Marek Szyprowski,
Anusha Srivatsa, Dmitry Baryshkov, Hui Pu, Ian Ray,
Thomas Petazzoni, dri-devel, linux-kernel
On Thu, Sep 3, 2026 at 10:12 AM Luca Ceresoli <luca.ceresoli@bootlin.com> wrote:
>
> Work is in progress for every drm_panel to embed a drm_bridge, and for that
> a function will be needed in the drm_panel API to tell whether a bridge
> represents a panel or something else. The ideal name for that will be
> drm_bridge_is_panel(), which however is already in use by the panel_bridge.
>
> Rename the current function in the panel_bridge API to
> drm_bridge_is_panel_bridge(), which is more precise and frees up the
> drm_bridge_is_panel() for future use in the drm_panel API.
>
> No functional changes, just renaming a function treewide.
>
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
> ---
> drivers/gpu/drm/bridge/panel.c | 8 ++++----
> drivers/gpu/drm/display/drm_bridge_connector.c | 2 +-
> include/drm/drm_bridge.h | 4 ++--
> 3 files changed, 7 insertions(+), 7 deletions(-)
Reviewed-by: Albert Esteve <aesteve@redhat.com>
Thanks for cc'ing me :)
Very curious to see how this series will unravel.
Albert
>
> diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
> index 40e3970e8b76..0582c708957c 100644
> --- a/drivers/gpu/drm/bridge/panel.c
> +++ b/drivers/gpu/drm/bridge/panel.c
> @@ -221,17 +221,17 @@ static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
> };
>
> /**
> - * drm_bridge_is_panel - Checks if a drm_bridge is a panel_bridge.
> + * drm_bridge_is_panel_bridge - Checks if a drm_bridge is a panel_bridge.
> *
> * @bridge: The drm_bridge to be checked.
> *
> * Returns true if the bridge is a panel bridge, or false otherwise.
> */
> -bool drm_bridge_is_panel(const struct drm_bridge *bridge)
> +bool drm_bridge_is_panel_bridge(const struct drm_bridge *bridge)
> {
> return bridge->funcs == &panel_bridge_bridge_funcs;
> }
> -EXPORT_SYMBOL(drm_bridge_is_panel);
> +EXPORT_SYMBOL(drm_bridge_is_panel_bridge);
>
> /**
> * drm_panel_bridge_add - Creates a &drm_bridge and &drm_connector that
> @@ -321,7 +321,7 @@ void drm_panel_bridge_remove(struct drm_bridge *bridge)
> if (!bridge)
> return;
>
> - if (!drm_bridge_is_panel(bridge)) {
> + if (!drm_bridge_is_panel_bridge(bridge)) {
> drm_warn(bridge->dev, "%s: called on non-panel bridge!\n", __func__);
> return;
> }
> diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
> index 00feb73e63d7..5de9b76f345b 100644
> --- a/drivers/gpu/drm/display/drm_bridge_connector.c
> +++ b/drivers/gpu/drm/display/drm_bridge_connector.c
> @@ -983,7 +983,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
> if (bridge->ddc)
> ddc = bridge->ddc;
>
> - if (drm_bridge_is_panel(bridge)) {
> + if (drm_bridge_is_panel_bridge(bridge)) {
> drm_bridge_put(panel_bridge);
> panel_bridge = drm_bridge_get(bridge);
> }
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index 9f2294957669..b29096d624d5 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -1474,7 +1474,7 @@ void drm_bridge_hpd_notify(struct drm_bridge *bridge,
> enum drm_connector_status status);
>
> #if IS_ENABLED(CONFIG_DRM_PANEL_BRIDGE)
> -bool drm_bridge_is_panel(const struct drm_bridge *bridge);
> +bool drm_bridge_is_panel_bridge(const struct drm_bridge *bridge);
> struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel);
> struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
> u32 connector_type);
> @@ -1490,7 +1490,7 @@ struct drm_bridge *drmm_panel_bridge_add(struct drm_device *drm,
> struct drm_panel *panel);
> struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge);
> #else
> -static inline bool drm_bridge_is_panel(const struct drm_bridge *bridge)
> +static inline bool drm_bridge_is_panel_bridge(const struct drm_bridge *bridge)
> {
> return false;
> }
>
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 30+ messages in thread* Re: [PATCH RFC v2 04/19] drm/bridge: panel: rename drm_bridge_is_panel() -> drm_bridge_is_panel_bridge()
2026-09-03 13:59 ` Albert Esteve
@ 2026-09-03 15:38 ` Luca Ceresoli
0 siblings, 0 replies; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 15:38 UTC (permalink / raw)
To: Albert Esteve, 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,
Linus Walleij, Inki Dae, Jagan Teki, Marek Szyprowski,
Anusha Srivatsa, Dmitry Baryshkov, Hui Pu, Ian Ray,
Thomas Petazzoni, dri-devel, linux-kernel
Hello Albert,
On Thu Sep 3, 2026 at 3:59 PM CEST, Albert Esteve wrote:
> On Thu, Sep 3, 2026 at 10:12 AM Luca Ceresoli <luca.ceresoli@bootlin.com> wrote:
>>
>> Work is in progress for every drm_panel to embed a drm_bridge, and for that
>> a function will be needed in the drm_panel API to tell whether a bridge
>> represents a panel or something else. The ideal name for that will be
>> drm_bridge_is_panel(), which however is already in use by the panel_bridge.
>>
>> Rename the current function in the panel_bridge API to
>> drm_bridge_is_panel_bridge(), which is more precise and frees up the
>> drm_bridge_is_panel() for future use in the drm_panel API.
>>
>> No functional changes, just renaming a function treewide.
>>
>> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
>> ---
>> drivers/gpu/drm/bridge/panel.c | 8 ++++----
>> drivers/gpu/drm/display/drm_bridge_connector.c | 2 +-
>> include/drm/drm_bridge.h | 4 ++--
>> 3 files changed, 7 insertions(+), 7 deletions(-)
>
> Reviewed-by: Albert Esteve <aesteve@redhat.com>
>
> Thanks for cc'ing me :)
You're welcome. Sorry for not having done it since v1.
Luca
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH RFC v2 05/19] drm/panel: embed a drm_bridge into every drm_panel
2026-09-03 8:11 [PATCH RFC v2 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (3 preceding siblings ...)
2026-09-03 8:11 ` [PATCH RFC v2 04/19] drm/bridge: panel: rename drm_bridge_is_panel() -> drm_bridge_is_panel_bridge() Luca Ceresoli
@ 2026-09-03 8:11 ` Luca Ceresoli
2026-09-03 10:22 ` Maxime Ripard
2026-09-03 8:11 ` [PATCH RFC v2 06/19] drm/bridge: tc358767: don't create a panel_bridge Luca Ceresoli
` (13 subsequent siblings)
18 siblings, 1 reply; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 8:11 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: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu, Ian Ray,
Thomas Petazzoni, dri-devel, linux-kernel, Luca Ceresoli
Adding a drm_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:
* the 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 that other driver doesn't know whether this is needed because it
doesn't know whether it has created a panel_bridge or not
Other drivers call [a variant of] drm_panel_bridge_add(), which also has
some of the above drawbacks.
So far the current approach was working mostly because devm and drmm ensure
the panel bridge would be dealloacted at some later point. However with the
upcoming implementation of bridge hotplug and dynamic bridge lifetime this
will get more complicated.
Switch to the new approach: embed a drm_bridge inside every drm_panel,
which behaves just like the current drm_panel_bridge.
Do this by copying and adapting the code from bridge/panel.c, using
function names that are more suitable within drm_panel.c and doing the
minimal adaptation needed.
Currently drm_bridge and drm_panel have independent refcounted
allocation. As they now become a single struct, just change
drm_panel_get/put() to get/put the bridge. As a result, the refcount for a
drm_bridge embedded in a drm_panel is:
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
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
This patch is new in v2, and replaces "drm/bridge: panel: add a
panel_bridge to every panel" which was based on a different approach.
---
drivers/gpu/drm/drm_panel.c | 258 +++++++++++++++++++++++++++++++++++++++++---
include/drm/drm_panel.h | 33 ++++--
2 files changed, 266 insertions(+), 25 deletions(-)
diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
index f8f6082e637f..9b86195f9f66 100644
--- a/drivers/gpu/drm/drm_panel.c
+++ b/drivers/gpu/drm/drm_panel.c
@@ -22,15 +22,19 @@
*/
#include <linux/backlight.h>
+#include <linux/debugfs.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
static DEFINE_MUTEX(panel_lock);
static LIST_HEAD(panel_list);
@@ -46,6 +50,18 @@ static LIST_HEAD(panel_list);
* take look at drm_panel_bridge_add() and devm_drm_panel_bridge_add().
*/
+static inline struct drm_panel *
+drm_bridge_to_panel(const struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct drm_panel, bridge);
+}
+
+static inline struct drm_panel *
+drm_connector_to_panel(const struct drm_connector *connector)
+{
+ return container_of(connector, struct drm_panel, connector);
+}
+
/**
* drm_panel_init - initialize a panel
* @panel: DRM panel
@@ -86,6 +102,7 @@ void drm_panel_add(struct drm_panel *panel)
mutex_lock(&panel_lock);
list_add_tail(&panel->list, &panel_list);
mutex_unlock(&panel_lock);
+ drm_bridge_add(&panel->bridge);
}
EXPORT_SYMBOL(drm_panel_add);
@@ -97,6 +114,7 @@ EXPORT_SYMBOL(drm_panel_add);
*/
void drm_panel_remove(struct drm_panel *panel)
{
+ drm_bridge_remove(&panel->bridge);
mutex_lock(&panel_lock);
list_del_init(&panel->list);
mutex_unlock(&panel_lock);
@@ -370,13 +388,198 @@ int drm_panel_get_modes(struct drm_panel *panel,
}
EXPORT_SYMBOL(drm_panel_get_modes);
-static void __drm_panel_free(struct kref *kref)
+static int drm_panel_bridge_connector_get_modes(struct drm_connector *connector)
+{
+ struct drm_panel *drm_panel = drm_connector_to_panel(connector);
+
+ return drm_panel_get_modes(drm_panel, connector);
+}
+
+/**
+ * drm_bridge_set_connector_orientation - Set the connector panel
+ * orientation from the bridge that can be transformed to drm_panel.
+ *
+ * @bridge: The drm_bridge for a drm_panel.
+ * @connector: The connector to be set panel orientation.
+ *
+ * Returns 0 on success, negative errno on failure.
+ */
+int drm_bridge_set_connector_orientation(const struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+
+ return drm_connector_set_orientation_from_panel(connector, panel);
+}
+EXPORT_SYMBOL(drm_bridge_set_connector_orientation);
+
+static const struct drm_connector_helper_funcs
+drm_panel_bridge_connector_helper_funcs = {
+ .get_modes = drm_panel_bridge_connector_get_modes,
+};
+
+static const struct drm_connector_funcs drm_panel_bridge_connector_funcs = {
+ .reset = drm_atomic_helper_connector_reset,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = drm_connector_cleanup,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int drm_panel_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
+ enum drm_bridge_attach_flags flags)
+{
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+ struct drm_connector *connector = &panel->connector;
+ int ret;
+
+ if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
+ return 0;
+
+ drm_connector_helper_add(connector,
+ &drm_panel_bridge_connector_helper_funcs);
+
+ ret = drm_connector_init(bridge->dev, connector,
+ &drm_panel_bridge_connector_funcs,
+ panel->connector_type);
+ if (ret) {
+ DRM_ERROR("Failed to initialize connector\n");
+ return ret;
+ }
+
+ drm_bridge_set_connector_orientation(bridge, connector);
+
+ drm_connector_attach_encoder(connector, encoder);
+
+ if (bridge->dev->registered) {
+ if (connector->funcs->reset)
+ connector->funcs->reset(connector);
+ drm_connector_register(connector);
+ }
+
+ return 0;
+}
+
+static void drm_panel_bridge_detach(struct drm_bridge *bridge)
+{
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+ struct drm_connector *connector = &panel->connector;
+
+ /* Cleanup the connector if we know it was initialized */
+ if (connector->dev)
+ drm_connector_cleanup(connector);
+}
+
+static void drm_panel_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+ struct drm_atomic_commit *atomic_commit)
+{
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+ struct drm_encoder *encoder = bridge->encoder;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *old_crtc_state;
+
+ crtc = drm_atomic_get_new_crtc_for_encoder(atomic_commit, encoder);
+ if (!crtc)
+ return;
+
+ old_crtc_state = drm_atomic_get_old_crtc_state(atomic_commit, crtc);
+ if (old_crtc_state && old_crtc_state->self_refresh_active)
+ return;
+
+ drm_panel_prepare(panel);
+}
+
+static void drm_panel_bridge_atomic_enable(struct drm_bridge *bridge,
+ struct drm_atomic_commit *atomic_commit)
{
- struct drm_panel *panel = container_of(kref, struct drm_panel, refcount);
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+ struct drm_encoder *encoder = bridge->encoder;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *old_crtc_state;
- kfree(panel->container);
+ crtc = drm_atomic_get_new_crtc_for_encoder(atomic_commit, encoder);
+ if (!crtc)
+ return;
+
+ old_crtc_state = drm_atomic_get_old_crtc_state(atomic_commit, crtc);
+ if (old_crtc_state && old_crtc_state->self_refresh_active)
+ return;
+
+ drm_panel_enable(panel);
+}
+
+static void drm_panel_bridge_atomic_disable(struct drm_bridge *bridge,
+ struct drm_atomic_commit *atomic_commit)
+{
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+ struct drm_encoder *encoder = bridge->encoder;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *new_crtc_state;
+
+ crtc = drm_atomic_get_old_crtc_for_encoder(atomic_commit, encoder);
+ if (!crtc)
+ return;
+
+ new_crtc_state = drm_atomic_get_new_crtc_state(atomic_commit, crtc);
+ if (new_crtc_state && new_crtc_state->self_refresh_active)
+ return;
+
+ drm_panel_disable(panel);
}
+static void drm_panel_bridge_atomic_post_disable(struct drm_bridge *bridge,
+ struct drm_atomic_commit *atomic_commit)
+{
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+ struct drm_encoder *encoder = bridge->encoder;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *new_crtc_state;
+
+ crtc = drm_atomic_get_old_crtc_for_encoder(atomic_commit, encoder);
+ if (!crtc)
+ return;
+
+ new_crtc_state = drm_atomic_get_new_crtc_state(atomic_commit, crtc);
+ if (new_crtc_state && new_crtc_state->self_refresh_active)
+ return;
+
+ drm_panel_unprepare(panel);
+}
+
+static int drm_panel_bridge_get_modes(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+
+ return drm_panel_get_modes(panel, connector);
+}
+
+static void drm_panel_bridge_debugfs_init(struct drm_bridge *bridge,
+ struct dentry *root)
+{
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+
+ root = debugfs_create_dir("panel", root);
+ if (panel->funcs->debugfs_init)
+ panel->funcs->debugfs_init(panel, root);
+}
+
+static const struct drm_bridge_funcs drm_panel_bridge_funcs = {
+ .attach = drm_panel_bridge_attach,
+ .detach = drm_panel_bridge_detach,
+ .atomic_pre_enable = drm_panel_bridge_atomic_pre_enable,
+ .atomic_enable = drm_panel_bridge_atomic_enable,
+ .atomic_disable = drm_panel_bridge_atomic_disable,
+ .atomic_post_disable = drm_panel_bridge_atomic_post_disable,
+ .get_modes = drm_panel_bridge_get_modes,
+ .atomic_create_state = drm_atomic_helper_bridge_create_state,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt,
+ .debugfs_init = drm_panel_bridge_debugfs_init,
+};
+
/**
* drm_panel_get - Acquire a panel reference
* @panel: DRM panel
@@ -387,10 +590,8 @@ static void __drm_panel_free(struct kref *kref)
*/
struct drm_panel *drm_panel_get(struct drm_panel *panel)
{
- if (!panel)
- return panel;
-
- kref_get(&panel->refcount);
+ if (panel)
+ drm_bridge_get(&panel->bridge);
return panel;
}
@@ -406,7 +607,7 @@ EXPORT_SYMBOL(drm_panel_get);
void drm_panel_put(struct drm_panel *panel)
{
if (panel)
- kref_put(&panel->refcount, __drm_panel_free);
+ drm_bridge_put(&panel->bridge);
}
EXPORT_SYMBOL(drm_panel_put);
@@ -429,8 +630,22 @@ void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset,
const struct drm_panel_funcs *funcs,
int connector_type)
{
- void *container;
+ /*
+ * Struct embedding and offsets:
+ *
+ * |--------------- user container struct ------------|
+ * : |---------- struct drm_panel ------------|
+ * : : |----- struct drm_bridge ------|
+ * A B C
+ *
+ * B - A = offset (passed as argument)
+ * C - B = panel_bridge_offset
+ * C - A = alloc_bridge_offset
+ */
+ const size_t panel_bridge_offset = offsetof(struct drm_panel, bridge);
+ const size_t alloc_bridge_offset = offset + panel_bridge_offset;
struct drm_panel *panel;
+ void *container;
int err;
if (!funcs) {
@@ -438,14 +653,16 @@ void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset,
return ERR_PTR(-EINVAL);
}
- container = kzalloc(size, GFP_KERNEL);
- if (!container)
- return ERR_PTR(-ENOMEM);
+ container = __devm_drm_bridge_alloc(dev, size, alloc_bridge_offset,
+ &drm_panel_bridge_funcs);
+ if (IS_ERR(container))
+ return container;
panel = container + offset;
- panel->container = container;
panel->funcs = funcs;
- kref_init(&panel->refcount);
+ panel->bridge.of_node = dev->of_node;
+
+ drm_panel_get(panel);
err = devm_add_action_or_reset(dev, drm_panel_put_void, panel);
if (err)
@@ -457,6 +674,19 @@ void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset,
}
EXPORT_SYMBOL(__devm_drm_panel_alloc);
+/**
+ * drm_bridge_is_panel - Tell if a drm_bridge is a panel.
+ *
+ * @bridge: The drm_bridge to be checked.
+ *
+ * Returns true if the bridge is a panel, or false otherwise.
+ */
+bool drm_bridge_is_panel(const struct drm_bridge *bridge)
+{
+ return bridge->funcs == &drm_panel_bridge_funcs;
+}
+EXPORT_SYMBOL(drm_bridge_is_panel);
+
#ifdef CONFIG_OF
/**
* of_drm_find_panel - look up and reference a panel by device tree node
diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
index 08949d41d743..7fe2f3160b2a 100644
--- a/include/drm/drm_panel.h
+++ b/include/drm/drm_panel.h
@@ -30,6 +30,8 @@
#include <linux/mutex.h>
#include <linux/kref.h>
+#include <drm/drm_bridge.h>
+
struct backlight_device;
struct dentry;
struct device_node;
@@ -228,6 +230,22 @@ struct drm_panel {
*/
const struct drm_panel_funcs *funcs;
+ /**
+ * @bridge:
+ *
+ * Bridge to access the panel features through the drm_bridge API.
+ */
+ struct drm_bridge bridge;
+
+ /**
+ * @connector:
+ *
+ * Connector instantiated by the bridge (only for legacy code not
+ * yet using the drm_bridge_connector and
+ * DRM_BRIDGE_ATTACH_NO_CONNECTOR).
+ */
+ struct drm_connector connector;
+
/**
* @connector_type:
*
@@ -281,17 +299,6 @@ struct drm_panel {
* If true then the panel has been enabled.
*/
bool enabled;
-
- /**
- * @container: Pointer to the private driver struct embedding this
- * @struct drm_panel.
- */
- void *container;
-
- /**
- * @refcount: reference count of users referencing this panel.
- */
- struct kref refcount;
};
void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset,
@@ -327,6 +334,10 @@ void drm_panel_add(struct drm_panel *panel);
void drm_panel_remove(struct drm_panel *panel);
int devm_drm_panel_add(struct device *dev, struct drm_panel *panel);
+bool drm_bridge_is_panel(const struct drm_bridge *bridge);
+int drm_bridge_set_connector_orientation(const struct drm_bridge *bridge,
+ struct drm_connector *connector);
+
void drm_panel_prepare(struct drm_panel *panel);
void drm_panel_unprepare(struct drm_panel *panel);
--
2.55.0
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH RFC v2 05/19] drm/panel: embed a drm_bridge into every drm_panel
2026-09-03 8:11 ` [PATCH RFC v2 05/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
@ 2026-09-03 10:22 ` Maxime Ripard
2026-09-03 13:37 ` Luca Ceresoli
0 siblings, 1 reply; 30+ messages in thread
From: Maxime Ripard @ 2026-09-03 10:22 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, Albert Esteve,
Anusha Srivatsa, Dmitry Baryshkov, Hui Pu, Ian Ray,
Thomas Petazzoni, dri-devel, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 6142 bytes --]
On Thu, Sep 03, 2026 at 10:11:08AM +0200, Luca Ceresoli wrote:
> Adding a drm_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:
>
> * the 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 that other driver doesn't know whether this is needed because it
> doesn't know whether it has created a panel_bridge or not
>
> Other drivers call [a variant of] drm_panel_bridge_add(), which also has
> some of the above drawbacks.
>
> So far the current approach was working mostly because devm and drmm ensure
> the panel bridge would be dealloacted at some later point. However with the
> upcoming implementation of bridge hotplug and dynamic bridge lifetime this
> will get more complicated.
>
> Switch to the new approach: embed a drm_bridge inside every drm_panel,
> which behaves just like the current drm_panel_bridge.
>
> Do this by copying and adapting the code from bridge/panel.c, using
> function names that are more suitable within drm_panel.c and doing the
> minimal adaptation needed.
>
> Currently drm_bridge and drm_panel have independent refcounted
> allocation. As they now become a single struct, just change
> drm_panel_get/put() to get/put the bridge. As a result, the refcount for a
> drm_bridge embedded in a drm_panel is:
>
> 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
>
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
So there's a lot to unravel, and I wished you had split it, but I can't
find a good way to split it either.
> This patch is new in v2, and replaces "drm/bridge: panel: add a
> panel_bridge to every panel" which was based on a different approach.
> ---
> drivers/gpu/drm/drm_panel.c | 258 +++++++++++++++++++++++++++++++++++++++++---
> include/drm/drm_panel.h | 33 ++++--
> 2 files changed, 266 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
> index f8f6082e637f..9b86195f9f66 100644
> --- a/drivers/gpu/drm/drm_panel.c
> +++ b/drivers/gpu/drm/drm_panel.c
> @@ -22,15 +22,19 @@
> */
>
> #include <linux/backlight.h>
> +#include <linux/debugfs.h>
> #include <linux/err.h>
> #include <linux/export.h>
> #include <linux/module.h>
> #include <linux/of.h>
>
> +#include <drm/drm_atomic_helper.h>
> #include <drm/drm_crtc.h>
> +#include <drm/drm_modeset_helper_vtables.h>
> #include <drm/drm_of.h>
> #include <drm/drm_panel.h>
> #include <drm/drm_print.h>
> +#include <drm/drm_probe_helper.h>
>
> static DEFINE_MUTEX(panel_lock);
> static LIST_HEAD(panel_list);
> @@ -46,6 +50,18 @@ static LIST_HEAD(panel_list);
> * take look at drm_panel_bridge_add() and devm_drm_panel_bridge_add().
> */
>
> +static inline struct drm_panel *
> +drm_bridge_to_panel(const struct drm_bridge *bridge)
> +{
> + return container_of(bridge, struct drm_panel, bridge);
> +}
> +
> +static inline struct drm_panel *
> +drm_connector_to_panel(const struct drm_connector *connector)
> +{
> + return container_of(connector, struct drm_panel, connector);
> +}
> +
> /**
> * drm_panel_init - initialize a panel
> * @panel: DRM panel
> @@ -86,6 +102,7 @@ void drm_panel_add(struct drm_panel *panel)
> mutex_lock(&panel_lock);
> list_add_tail(&panel->list, &panel_list);
> mutex_unlock(&panel_lock);
> + drm_bridge_add(&panel->bridge);
> }
> EXPORT_SYMBOL(drm_panel_add);
>
> @@ -97,6 +114,7 @@ EXPORT_SYMBOL(drm_panel_add);
> */
> void drm_panel_remove(struct drm_panel *panel)
> {
> + drm_bridge_remove(&panel->bridge);
> mutex_lock(&panel_lock);
> list_del_init(&panel->list);
> mutex_unlock(&panel_lock);
> @@ -370,13 +388,198 @@ int drm_panel_get_modes(struct drm_panel *panel,
> }
> EXPORT_SYMBOL(drm_panel_get_modes);
>
> -static void __drm_panel_free(struct kref *kref)
> +static int drm_panel_bridge_connector_get_modes(struct drm_connector *connector)
> +{
> + struct drm_panel *drm_panel = drm_connector_to_panel(connector);
> +
> + return drm_panel_get_modes(drm_panel, connector);
> +}
> +
> +/**
> + * drm_bridge_set_connector_orientation - Set the connector panel
> + * orientation from the bridge that can be transformed to drm_panel.
> + *
> + * @bridge: The drm_bridge for a drm_panel.
> + * @connector: The connector to be set panel orientation.
> + *
> + * Returns 0 on success, negative errno on failure.
> + */
> +int drm_bridge_set_connector_orientation(const struct drm_bridge *bridge,
> + struct drm_connector *connector)
> +{
> + struct drm_panel *panel = drm_bridge_to_panel(bridge);
> +
> + return drm_connector_set_orientation_from_panel(connector, panel);
> +}
> +EXPORT_SYMBOL(drm_bridge_set_connector_orientation);
I don't think we should create new ones. Just move the code from
bridge/panel here and remove it there. The only thing left will be the
panel_bridge_add() variants that become almost trivial now, and you can
cleanup the drivers in later patches.
This also allows to get rid of all the symbol renaming, which isn't
great in itself, but also the existing names were good so it's hard to
come with better ones.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 30+ messages in thread* Re: [PATCH RFC v2 05/19] drm/panel: embed a drm_bridge into every drm_panel
2026-09-03 10:22 ` Maxime Ripard
@ 2026-09-03 13:37 ` Luca Ceresoli
0 siblings, 0 replies; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 13:37 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, Albert Esteve,
Anusha Srivatsa, Dmitry Baryshkov, Hui Pu, Ian Ray,
Thomas Petazzoni, dri-devel, linux-kernel
Hi Maxime,
thanks for keeping the round-trip time short for this discussion!
On Thu Sep 3, 2026 at 12:22 PM CEST, Maxime Ripard wrote:
> On Thu, Sep 03, 2026 at 10:11:08AM +0200, Luca Ceresoli wrote:
>> Adding a drm_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:
>>
>> * the 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 that other driver doesn't know whether this is needed because it
>> doesn't know whether it has created a panel_bridge or not
>>
>> Other drivers call [a variant of] drm_panel_bridge_add(), which also has
>> some of the above drawbacks.
>>
>> So far the current approach was working mostly because devm and drmm ensure
>> the panel bridge would be dealloacted at some later point. However with the
>> upcoming implementation of bridge hotplug and dynamic bridge lifetime this
>> will get more complicated.
>>
>> Switch to the new approach: embed a drm_bridge inside every drm_panel,
>> which behaves just like the current drm_panel_bridge.
>>
>> Do this by copying and adapting the code from bridge/panel.c, using
>> function names that are more suitable within drm_panel.c and doing the
>> minimal adaptation needed.
>>
>> Currently drm_bridge and drm_panel have independent refcounted
>> allocation. As they now become a single struct, just change
>> drm_panel_get/put() to get/put the bridge. As a result, the refcount for a
>> drm_bridge embedded in a drm_panel is:
>>
>> 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
>>
>> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
>
> So there's a lot to unravel, and I wished you had split it, but I can't
> find a good way to split it either.
As I see it, this could be maybe split in 2:
- copy all needed symbols from bridge/panel.c (or move or whatever, see
discussion below) without using them
- change _alloc, _get, _put etc to actually embed the bridge and start
using the copied/moved symbols
Would you prefer that?
Note the second bullet, which is the core change, is pretty small, I think
a <100 lines diff, but I don't think it can be split further.
>> This patch is new in v2, and replaces "drm/bridge: panel: add a
>> panel_bridge to every panel" which was based on a different approach.
>> ---
>> drivers/gpu/drm/drm_panel.c | 258 +++++++++++++++++++++++++++++++++++++++++---
>> include/drm/drm_panel.h | 33 ++++--
>> 2 files changed, 266 insertions(+), 25 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
>> index f8f6082e637f..9b86195f9f66 100644
>> --- a/drivers/gpu/drm/drm_panel.c
>> +++ b/drivers/gpu/drm/drm_panel.c
>> @@ -22,15 +22,19 @@
>> */
>>
>> #include <linux/backlight.h>
>> +#include <linux/debugfs.h>
>> #include <linux/err.h>
>> #include <linux/export.h>
>> #include <linux/module.h>
>> #include <linux/of.h>
>>
>> +#include <drm/drm_atomic_helper.h>
>> #include <drm/drm_crtc.h>
>> +#include <drm/drm_modeset_helper_vtables.h>
>> #include <drm/drm_of.h>
>> #include <drm/drm_panel.h>
>> #include <drm/drm_print.h>
>> +#include <drm/drm_probe_helper.h>
>>
>> static DEFINE_MUTEX(panel_lock);
>> static LIST_HEAD(panel_list);
>> @@ -46,6 +50,18 @@ static LIST_HEAD(panel_list);
>> * take look at drm_panel_bridge_add() and devm_drm_panel_bridge_add().
>> */
>>
>> +static inline struct drm_panel *
>> +drm_bridge_to_panel(const struct drm_bridge *bridge)
>> +{
>> + return container_of(bridge, struct drm_panel, bridge);
>> +}
>> +
>> +static inline struct drm_panel *
>> +drm_connector_to_panel(const struct drm_connector *connector)
>> +{
>> + return container_of(connector, struct drm_panel, connector);
>> +}
>> +
>> /**
>> * drm_panel_init - initialize a panel
>> * @panel: DRM panel
>> @@ -86,6 +102,7 @@ void drm_panel_add(struct drm_panel *panel)
>> mutex_lock(&panel_lock);
>> list_add_tail(&panel->list, &panel_list);
>> mutex_unlock(&panel_lock);
>> + drm_bridge_add(&panel->bridge);
>> }
>> EXPORT_SYMBOL(drm_panel_add);
>>
>> @@ -97,6 +114,7 @@ EXPORT_SYMBOL(drm_panel_add);
>> */
>> void drm_panel_remove(struct drm_panel *panel)
>> {
>> + drm_bridge_remove(&panel->bridge);
>> mutex_lock(&panel_lock);
>> list_del_init(&panel->list);
>> mutex_unlock(&panel_lock);
>> @@ -370,13 +388,198 @@ int drm_panel_get_modes(struct drm_panel *panel,
>> }
>> EXPORT_SYMBOL(drm_panel_get_modes);
>>
>> -static void __drm_panel_free(struct kref *kref)
>> +static int drm_panel_bridge_connector_get_modes(struct drm_connector *connector)
>> +{
>> + struct drm_panel *drm_panel = drm_connector_to_panel(connector);
>> +
>> + return drm_panel_get_modes(drm_panel, connector);
>> +}
>> +
>> +/**
>> + * drm_bridge_set_connector_orientation - Set the connector panel
>> + * orientation from the bridge that can be transformed to drm_panel.
>> + *
>> + * @bridge: The drm_bridge for a drm_panel.
>> + * @connector: The connector to be set panel orientation.
>> + *
>> + * Returns 0 on success, negative errno on failure.
>> + */
>> +int drm_bridge_set_connector_orientation(const struct drm_bridge *bridge,
>> + struct drm_connector *connector)
>> +{
>> + struct drm_panel *panel = drm_bridge_to_panel(bridge);
>> +
>> + return drm_connector_set_orientation_from_panel(connector, panel);
>> +}
>> +EXPORT_SYMBOL(drm_bridge_set_connector_orientation);
>
> I don't think we should create new ones. Just move the code from
> bridge/panel here and remove it there. The only thing left will be the
> panel_bridge_add() variants that become almost trivial now, and you can
> cleanup the drivers in later patches.
What do you mean by "move" exactly? Really move all relevant functions from
bridge/panel.c into drm_panel.c, so evey user driver will depend on the new
drm_panel module instead of the old one for these symbols?
> This also allows to get rid of all the symbol renaming, which isn't
> great in itself, but also the existing names were good so it's hard to
> come with better ones.
I think the names in bridge/panel.c make sense there, but not in
drm_panel.c. Here's my interpretation (using atomic_enable as an example):
- panel_bridge_atomic_enable
^^^^^^^^^^^^ <- this is about the panel_bridge
- drm_panel_bridge_atomic_enable
^^^^^^^^^ <- this is drm_panel stuff
^^^^^^ <- and specifically about the bridge embedded in drm_panel
Does it make sense to you too in this perspective?
Luca
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH RFC v2 06/19] drm/bridge: tc358767: don't create a panel_bridge
2026-09-03 8:11 [PATCH RFC v2 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (4 preceding siblings ...)
2026-09-03 8:11 ` [PATCH RFC v2 05/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
@ 2026-09-03 8:11 ` Luca Ceresoli
2026-09-03 8:11 ` [PATCH RFC v2 07/19] drm/bridge: waveshare-dsi: " Luca Ceresoli
` (12 subsequent siblings)
18 siblings, 0 replies; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 8:11 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: Albert Esteve, Anusha Srivatsa, 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 calls
to devm_drm_panel_bridge_add() would lead to creating a second panel_bridge
for the same panel.
Update and simplify the code by just getting a reference to the
already-existing bridge using of_drm_get_bridge_by_endpoint().
As of_drm_get_bridge_by_endpoint() 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/Kconfig | 2 --
drivers/gpu/drm/bridge/tc358767.c | 64 ++++++++++++---------------------------
2 files changed, 20 insertions(+), 46 deletions(-)
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 0a1689f8209d..30f71654eaeb 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -402,8 +402,6 @@ config DRM_TOSHIBA_TC358767
select DRM_KMS_HELPER
select REGMAP_I2C
select DRM_MIPI_DSI
- select DRM_PANEL
- select DRM_PANEL_BRIDGE
help
Toshiba TC358767 eDP bridge chip driver.
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index ac83af7902cd..51f4baa62a53 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -35,7 +35,6 @@
#include <drm/drm_edid.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -370,7 +369,6 @@ struct tc_data {
struct drm_dp_aux aux;
struct drm_bridge bridge;
- struct drm_bridge *panel_bridge;
struct drm_connector connector;
struct mipi_dsi_device *dsi;
@@ -1742,8 +1740,8 @@ static int tc_connector_get_modes(struct drm_connector *connector)
return 0;
}
- if (tc->panel_bridge) {
- num_modes = drm_bridge_get_modes(tc->panel_bridge, connector);
+ if (tc->bridge.next_bridge) {
+ num_modes = drm_bridge_get_modes(tc->bridge.next_bridge, connector);
if (num_modes > 0)
return num_modes;
}
@@ -1788,7 +1786,7 @@ tc_connector_detect(struct drm_connector *connector, bool force)
if (tc->hpd_pin >= 0)
return tc_bridge_detect(&tc->bridge, connector);
- if (tc->panel_bridge)
+ if (tc->bridge.next_bridge)
return connector_status_connected;
else
return connector_status_unknown;
@@ -1809,10 +1807,10 @@ static int tc_dpi_bridge_attach(struct drm_bridge *bridge,
{
struct tc_data *tc = bridge_to_tc(bridge);
- if (!tc->panel_bridge)
+ if (!tc->bridge.next_bridge)
return 0;
- return drm_bridge_attach(tc->bridge.encoder, tc->panel_bridge,
+ return drm_bridge_attach(tc->bridge.encoder, tc->bridge.next_bridge,
&tc->bridge, flags);
}
@@ -1825,9 +1823,9 @@ static int tc_edp_bridge_attach(struct drm_bridge *bridge,
struct drm_device *drm = bridge->dev;
int ret;
- if (tc->panel_bridge) {
+ if (tc->bridge.next_bridge) {
/* If a connector is required then this driver shall create it */
- ret = drm_bridge_attach(tc->bridge.encoder, tc->panel_bridge,
+ ret = drm_bridge_attach(tc->bridge.encoder, tc->bridge.next_bridge,
&tc->bridge, flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret)
return ret;
@@ -2318,53 +2316,31 @@ static int tc_probe_dpi_bridge_endpoint(struct tc_data *tc)
{
struct device *dev = tc->dev;
struct drm_bridge *bridge;
- struct drm_panel *panel;
- int ret;
/* port@1 is the DPI input/output port */
- ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, &bridge);
- if (ret && ret != -ENODEV)
- return dev_err_probe(dev, ret,
- "Could not find DPI panel or bridge\n");
-
- if (panel) {
- bridge = devm_drm_panel_bridge_add(dev, panel);
- drm_panel_put(panel);
- if (IS_ERR(bridge))
- return PTR_ERR(bridge);
- }
-
- if (bridge) {
- tc->panel_bridge = bridge;
- tc->bridge.type = DRM_MODE_CONNECTOR_DPI;
+ bridge = of_drm_get_bridge_by_endpoint(dev->of_node, 1, 0);
+ if (IS_ERR(bridge))
+ return dev_err_probe(dev, PTR_ERR(bridge),
+ "Could not find DPI bridge\n");
- return 0;
- }
+ tc->bridge.next_bridge = bridge;
+ tc->bridge.type = DRM_MODE_CONNECTOR_DPI;
- return ret;
+ return 0;
}
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");
-
- 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);
+ 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");
- tc->panel_bridge = panel_bridge;
+ if (!IS_ERR(bridge)) {
+ tc->bridge.next_bridge = bridge;
tc->bridge.type = DRM_MODE_CONNECTOR_eDP;
} else {
tc->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
--
2.55.0
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH RFC v2 07/19] drm/bridge: waveshare-dsi: don't create a panel_bridge
2026-09-03 8:11 [PATCH RFC v2 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (5 preceding siblings ...)
2026-09-03 8:11 ` [PATCH RFC v2 06/19] drm/bridge: tc358767: don't create a panel_bridge Luca Ceresoli
@ 2026-09-03 8:11 ` Luca Ceresoli
2026-09-03 8:11 ` [PATCH RFC v2 08/19] drm/mcde: dsi: simplify device_node management using scoped for_each variant Luca Ceresoli
` (11 subsequent siblings)
18 siblings, 0 replies; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 8:11 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: Albert Esteve, Anusha Srivatsa, 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
call to devm_drm_panel_bridge_add() would lead to creating a second
panel_bridge for the same panel.
Update and simplify the code by just getting a reference to the
already-existing bridge using of_drm_get_bridge_by_endpoint().
As of_drm_get_bridge_by_endpoint() 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/waveshare-dsi.c | 17 +++++------------
1 file changed, 5 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/bridge/waveshare-dsi.c b/drivers/gpu/drm/bridge/waveshare-dsi.c
index 420f3b870a74..2c40bfef2b45 100644
--- a/drivers/gpu/drm/bridge/waveshare-dsi.c
+++ b/drivers/gpu/drm/bridge/waveshare-dsi.c
@@ -16,11 +16,9 @@
#include <drm/drm_bridge.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
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 +87,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 +148,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 +161,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 bridge\n");
ws->backlight = ws_bridge_create_backlight(ws);
if (IS_ERR(ws->backlight)) {
--
2.55.0
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH RFC v2 08/19] drm/mcde: dsi: simplify device_node management using scoped for_each variant
2026-09-03 8:11 [PATCH RFC v2 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (6 preceding siblings ...)
2026-09-03 8:11 ` [PATCH RFC v2 07/19] drm/bridge: waveshare-dsi: " Luca Ceresoli
@ 2026-09-03 8:11 ` Luca Ceresoli
2026-09-03 8:11 ` [PATCH RFC v2 09/19] drm/mcde: dsi: remove unused includes Luca Ceresoli
` (10 subsequent siblings)
18 siblings, 0 replies; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 8:11 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: Albert Esteve, Anusha Srivatsa, 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().
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Linus Walleij <linusw@kernel.org>
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] 30+ messages in thread* [PATCH RFC v2 09/19] drm/mcde: dsi: remove unused includes
2026-09-03 8:11 [PATCH RFC v2 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (7 preceding siblings ...)
2026-09-03 8:11 ` [PATCH RFC v2 08/19] drm/mcde: dsi: simplify device_node management using scoped for_each variant Luca Ceresoli
@ 2026-09-03 8:11 ` Luca Ceresoli
2026-09-03 8:11 ` [PATCH RFC v2 10/19] drm/mcde: dsi: don't create a panel_bridge Luca Ceresoli
` (9 subsequent siblings)
18 siblings, 0 replies; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 8:11 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: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu, Ian Ray,
Thomas Petazzoni, dri-devel, linux-kernel, Luca Ceresoli
The helpers are included but unused.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
New patch in v2
---
drivers/gpu/drm/mcde/mcde_dsi.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c
index ce078aa3910f..747886dfa17a 100644
--- a/drivers/gpu/drm/mcde/mcde_dsi.c
+++ b/drivers/gpu/drm/mcde/mcde_dsi.c
@@ -11,17 +11,14 @@
#include <linux/regulator/consumer.h>
#include <video/mipi_display.h>
-#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_encoder.h>
#include <drm/drm_mipi_dsi.h>
-#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
-#include <drm/drm_probe_helper.h>
#include "mcde_drm.h"
#include "mcde_dsi_regs.h"
--
2.55.0
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH RFC v2 10/19] drm/mcde: dsi: don't create a panel_bridge
2026-09-03 8:11 [PATCH RFC v2 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (8 preceding siblings ...)
2026-09-03 8:11 ` [PATCH RFC v2 09/19] drm/mcde: dsi: remove unused includes Luca Ceresoli
@ 2026-09-03 8:11 ` Luca Ceresoli
2026-09-03 8:11 ` [PATCH RFC v2 11/19] drm/bridge: fsl-ldb: " Luca Ceresoli
` (8 subsequent siblings)
18 siblings, 0 replies; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 8:11 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: Albert Esteve, Anusha Srivatsa, 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 bridge for the same panel.
Update 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/Kconfig | 1 -
drivers/gpu/drm/mcde/mcde_dsi.c | 41 +++++++++--------------------------------
2 files changed, 9 insertions(+), 33 deletions(-)
diff --git a/drivers/gpu/drm/mcde/Kconfig b/drivers/gpu/drm/mcde/Kconfig
index 6ebfb930cbfa..81e7d3796c06 100644
--- a/drivers/gpu/drm/mcde/Kconfig
+++ b/drivers/gpu/drm/mcde/Kconfig
@@ -10,7 +10,6 @@ config DRM_MCDE
select DRM_MIPI_DSI
select DRM_BRIDGE
select DRM_PANEL
- select DRM_PANEL_BRIDGE
select DRM_KMS_HELPER
select DRM_GEM_DMA_HELPER
help
diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c
index 747886dfa17a..c36885f5f275 100644
--- a/drivers/gpu/drm/mcde/mcde_dsi.c
+++ b/drivers/gpu/drm/mcde/mcde_dsi.c
@@ -36,7 +36,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;
@@ -1073,7 +1072,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)) {
@@ -1101,40 +1099,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 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);
@@ -1156,8 +1135,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] 30+ messages in thread* [PATCH RFC v2 11/19] drm/bridge: fsl-ldb: don't create a panel_bridge
2026-09-03 8:11 [PATCH RFC v2 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (9 preceding siblings ...)
2026-09-03 8:11 ` [PATCH RFC v2 10/19] drm/mcde: dsi: don't create a panel_bridge Luca Ceresoli
@ 2026-09-03 8:11 ` Luca Ceresoli
2026-09-03 8:11 ` [PATCH RFC v2 12/19] drm/bridge: samsung-dsim: " Luca Ceresoli
` (7 subsequent siblings)
18 siblings, 0 replies; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 8:11 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: Albert Esteve, Anusha Srivatsa, 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 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/Kconfig | 1 -
drivers/gpu/drm/bridge/fsl-ldb.c | 19 +++++--------------
2 files changed, 5 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 30f71654eaeb..0a1e617b3007 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -87,7 +87,6 @@ config DRM_FSL_LDB
depends on OF
depends on ARCH_MXC || COMPILE_TEST
select DRM_KMS_HELPER
- select DRM_PANEL_BRIDGE
help
Support for i.MX8MP DPI-to-LVDS on-SoC encoder.
diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c
index 26cc72948f31..7ec84c81cd78 100644
--- a/drivers/gpu/drm/bridge/fsl-ldb.c
+++ b/drivers/gpu/drm/bridge/fsl-ldb.c
@@ -15,7 +15,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
#define LDB_CTRL_CH0_ENABLE BIT(0)
#define LDB_CTRL_CH0_DI_SELECT BIT(1)
@@ -86,7 +85,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 +117,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 +296,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 +336,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] 30+ messages in thread* [PATCH RFC v2 12/19] drm/bridge: samsung-dsim: don't create a panel_bridge
2026-09-03 8:11 [PATCH RFC v2 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (10 preceding siblings ...)
2026-09-03 8:11 ` [PATCH RFC v2 11/19] drm/bridge: fsl-ldb: " Luca Ceresoli
@ 2026-09-03 8:11 ` Luca Ceresoli
2026-09-03 8:11 ` [PATCH RFC v2 13/19] drm/bridge: tc358768: " Luca Ceresoli
` (6 subsequent siblings)
18 siblings, 0 replies; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 8:11 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: Albert Esteve, Anusha Srivatsa, 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 bridge for the same panel.
Update 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/Kconfig | 1 -
drivers/gpu/drm/bridge/samsung-dsim.c | 24 +++++-------------------
2 files changed, 5 insertions(+), 20 deletions(-)
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 0a1e617b3007..eb16f858459d 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -302,7 +302,6 @@ config DRM_SAMSUNG_DSIM
depends on OF && HAS_IOMEM
select DRM_KMS_HELPER
select DRM_MIPI_DSI
- select DRM_PANEL_BRIDGE
select GENERIC_PHY
select GENERIC_PHY_MIPI_DPHY
help
diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c
index 5457a7b02a33..ea2837384774 100644
--- a/drivers/gpu/drm/bridge/samsung-dsim.c
+++ b/drivers/gpu/drm/bridge/samsung-dsim.c
@@ -25,7 +25,6 @@
#include <video/mipi_display.h>
#include <drm/bridge/samsung-dsim.h>
-#include <drm/drm_panel.h>
#include <drm/drm_print.h>
/* returns true iff both arguments logically differs */
@@ -1898,7 +1897,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;
/*
@@ -1913,7 +1911,7 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
of_node_name_eq(remote, "ports"))
continue;
- goto of_find_panel_or_bridge;
+ goto of_find_bridge;
}
/*
@@ -1927,25 +1925,13 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
remote = of_graph_get_remote_node(np, 1, 0);
-of_find_panel_or_bridge:
+of_find_bridge:
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] 30+ messages in thread* [PATCH RFC v2 13/19] drm/bridge: tc358768: don't create a panel_bridge
2026-09-03 8:11 [PATCH RFC v2 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (11 preceding siblings ...)
2026-09-03 8:11 ` [PATCH RFC v2 12/19] drm/bridge: samsung-dsim: " Luca Ceresoli
@ 2026-09-03 8:11 ` Luca Ceresoli
2026-09-03 8:11 ` [PATCH RFC v2 14/19] drm/bridge: ssd2825: " Luca Ceresoli
` (5 subsequent siblings)
18 siblings, 0 replies; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 8:11 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: Albert Esteve, Anusha Srivatsa, 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
call to drm_panel_bridge_add_typed() would lead to creating a second
bridge for the same panel.
Update and simplify the code by just getting a reference to the
already-existing bridge.
As of_drm_get_bridge_by_endpoint() 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/Kconfig | 2 --
drivers/gpu/drm/bridge/tc358768.c | 25 ++++++-------------------
2 files changed, 6 insertions(+), 21 deletions(-)
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index eb16f858459d..f897058462c8 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -408,8 +408,6 @@ config DRM_TOSHIBA_TC358768
depends on OF
select DRM_KMS_HELPER
select REGMAP_I2C
- select DRM_PANEL
- select DRM_PANEL_BRIDGE
select DRM_MIPI_DSI
select VIDEOMODE_HELPERS
help
diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c
index d1fc6af37cc5..cc989ab5cf25 100644
--- a/drivers/gpu/drm/bridge/tc358768.c
+++ b/drivers/gpu/drm/bridge/tc358768.c
@@ -22,7 +22,6 @@
#include <drm/drm_drv.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
#include <video/mipi_display.h>
#include <video/videomode.h>
@@ -137,7 +136,6 @@ static const char * const tc358768_supplies[] = {
struct tc358768_dsi_output {
struct mipi_dsi_device *dev;
- struct drm_panel *panel;
struct drm_bridge *bridge;
};
@@ -443,7 +441,6 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host,
{
struct tc358768_priv *priv = dsi_host_to_tc358768(host);
struct drm_bridge *bridge;
- struct drm_panel *panel;
struct device_node *ep;
int ret;
@@ -471,24 +468,15 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host,
return -ENOTSUPP;
}
- ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, &panel,
- &bridge);
- if (ret)
- return ret;
+ bridge = of_drm_get_bridge_by_endpoint(host->dev->of_node, 1, 0);
+ if (IS_ERR(bridge))
+ return PTR_ERR(bridge);
- if (panel) {
- bridge = drm_panel_bridge_add_typed(panel,
- DRM_MODE_CONNECTOR_DSI);
- drm_panel_put(panel);
- if (IS_ERR(bridge))
- return PTR_ERR(bridge);
-
- bridge->pre_enable_prev_first = true;
- }
+ bridge->type = DRM_MODE_CONNECTOR_DSI;
+ bridge->pre_enable_prev_first = true;
priv->output.dev = dev;
priv->output.bridge = bridge;
- priv->output.panel = panel;
priv->dsi_lanes = dev->lanes;
priv->dsi_bpp = mipi_dsi_pixel_format_to_bpp(dev->format);
@@ -518,8 +506,7 @@ static int tc358768_dsi_host_detach(struct mipi_dsi_host *host,
struct tc358768_priv *priv = dsi_host_to_tc358768(host);
drm_bridge_remove(&priv->bridge);
- if (priv->output.panel)
- drm_panel_bridge_remove(priv->output.bridge);
+ drm_bridge_put(priv->output.bridge);
return 0;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH RFC v2 14/19] drm/bridge: ssd2825: don't create a panel_bridge
2026-09-03 8:11 [PATCH RFC v2 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (12 preceding siblings ...)
2026-09-03 8:11 ` [PATCH RFC v2 13/19] drm/bridge: tc358768: " Luca Ceresoli
@ 2026-09-03 8:11 ` Luca Ceresoli
2026-09-03 8:11 ` [PATCH RFC v2 15/19] drm/omap: dsi: remove unused includes Luca Ceresoli
` (4 subsequent siblings)
18 siblings, 0 replies; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 8:11 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: Albert Esteve, Anusha Srivatsa, 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
call to drm_panel_bridge_add_typed() would lead to creating a second bridge
for the same panel.
Update and simplify the code by just getting a reference to the
already-existing bridge.
As of_drm_get_bridge_by_endpoint() returns a refcounted bridge, take care
of putting the bridge reference.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/bridge/Kconfig | 2 --
drivers/gpu/drm/bridge/ssd2825.c | 23 +++++------------------
2 files changed, 5 insertions(+), 20 deletions(-)
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index f897058462c8..7de5abc47b54 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -349,8 +349,6 @@ config DRM_SOLOMON_SSD2825
depends on SPI_MASTER && OF
select DRM_MIPI_DSI
select DRM_KMS_HELPER
- select DRM_PANEL
- select DRM_PANEL_BRIDGE
help
Say Y here if you want support for the Solomon SSD2825 RGB/DSI
SPI bridge driver.
diff --git a/drivers/gpu/drm/bridge/ssd2825.c b/drivers/gpu/drm/bridge/ssd2825.c
index b0142d6d40dc..71877699dfab 100644
--- a/drivers/gpu/drm/bridge/ssd2825.c
+++ b/drivers/gpu/drm/bridge/ssd2825.c
@@ -17,7 +17,6 @@
#include <drm/drm_drv.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
#include <video/mipi_display.h>
#define SSD2825_DEVICE_ID_REG 0xb0
@@ -114,7 +113,6 @@ static const struct regulator_bulk_data ssd2825_supplies[] = {
struct ssd2825_dsi_output {
struct mipi_dsi_device *dev;
- struct drm_panel *panel;
struct drm_bridge *bridge;
};
@@ -277,7 +275,6 @@ static int ssd2825_dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_d
{
struct ssd2825_priv *priv = dsi_host_to_ssd2825(host);
struct drm_bridge *bridge;
- struct drm_panel *panel;
struct device_node *ep;
int ret;
@@ -295,20 +292,14 @@ static int ssd2825_dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_d
return -EOPNOTSUPP;
}
- ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, &panel, &bridge);
- if (ret)
- return ret;
+ bridge = of_drm_get_bridge_by_endpoint(host->dev->of_node, 1, 0);
+ if (IS_ERR(bridge))
+ return PTR_ERR(bridge);
- if (panel) {
- bridge = drm_panel_bridge_add_typed(panel, DRM_MODE_CONNECTOR_DSI);
- drm_panel_put(panel);
- if (IS_ERR(bridge))
- return PTR_ERR(bridge);
- }
+ bridge->type = DRM_MODE_CONNECTOR_DSI;
priv->output.dev = dev;
priv->output.bridge = bridge;
- priv->output.panel = panel;
priv->dsi_lanes = dev->lanes;
@@ -333,8 +324,7 @@ static int ssd2825_dsi_host_detach(struct mipi_dsi_host *host, struct mipi_dsi_d
struct ssd2825_priv *priv = dsi_host_to_ssd2825(host);
drm_bridge_remove(&priv->bridge);
- if (priv->output.panel)
- drm_panel_bridge_remove(priv->output.bridge);
+ drm_bridge_put(priv->output.bridge);
return 0;
}
@@ -579,9 +569,6 @@ static void ssd2825_bridge_atomic_pre_enable(struct drm_bridge *bridge,
/* Initial DSI configuration register set */
ssd2825_write_reg(priv, SSD2825_CONFIGURATION_REG, config);
ssd2825_write_reg(priv, SSD2825_VC_CTRL_REG, 0);
-
- if (priv->output.panel)
- drm_panel_enable(priv->output.panel);
}
static void ssd2825_bridge_atomic_enable(struct drm_bridge *bridge,
--
2.55.0
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH RFC v2 15/19] drm/omap: dsi: remove unused includes
2026-09-03 8:11 [PATCH RFC v2 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (13 preceding siblings ...)
2026-09-03 8:11 ` [PATCH RFC v2 14/19] drm/bridge: ssd2825: " Luca Ceresoli
@ 2026-09-03 8:11 ` Luca Ceresoli
2026-09-03 10:24 ` Maxime Ripard
2026-09-03 8:11 ` [PATCH RFC v2 16/19] drm/omap: dss: don't create a panel_bridge Luca Ceresoli
` (3 subsequent siblings)
18 siblings, 1 reply; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 8:11 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: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu, Ian Ray,
Thomas Petazzoni, dri-devel, linux-kernel, Luca Ceresoli
The drm_panel API is completely unused in these two files.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/omapdrm/dss/dsi.c | 1 -
drivers/gpu/drm/omapdrm/omap_drv.c | 1 -
2 files changed, 2 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c
index a57f5df5c830..6723c3d422c9 100644
--- a/drivers/gpu/drm/omapdrm/dss/dsi.c
+++ b/drivers/gpu/drm/omapdrm/dss/dsi.c
@@ -38,7 +38,6 @@
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_mipi_dsi.h>
-#include <drm/drm_panel.h>
#include <video/mipi_display.h>
#include "omapdss.h"
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 92d6a1f9c0a1..89a6d3b4aa6f 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -17,7 +17,6 @@
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_ioctl.h>
-#include <drm/drm_panel.h>
#include <drm/drm_prime.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
--
2.55.0
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH RFC v2 15/19] drm/omap: dsi: remove unused includes
2026-09-03 8:11 ` [PATCH RFC v2 15/19] drm/omap: dsi: remove unused includes Luca Ceresoli
@ 2026-09-03 10:24 ` Maxime Ripard
0 siblings, 0 replies; 30+ messages in thread
From: Maxime Ripard @ 2026-09-03 10:24 UTC (permalink / raw)
To: Luca Ceresoli
Cc: dri-devel, linux-kernel, Albert Esteve, Andrzej Hajda,
Anusha Srivatsa, 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 Thu, 3 Sep 2026 10:11:18 +0200, Luca Ceresoli wrote:
> The drm_panel API is completely unused in these two files.
>
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Thanks!
Maxime
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH RFC v2 16/19] drm/omap: dss: don't create a panel_bridge
2026-09-03 8:11 [PATCH RFC v2 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (14 preceding siblings ...)
2026-09-03 8:11 ` [PATCH RFC v2 15/19] drm/omap: dsi: remove unused includes Luca Ceresoli
@ 2026-09-03 8:11 ` Luca Ceresoli
2026-09-03 8:11 ` [PATCH RFC v2 17/19] drm/tve200: remove unused includes Luca Ceresoli
` (2 subsequent siblings)
18 siblings, 0 replies; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 8:11 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: Albert Esteve, Anusha Srivatsa, 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 bridge for the same panel.
Update 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/omapdrm/dss/omapdss.h | 1 -
drivers/gpu/drm/omapdrm/dss/output.c | 42 ++++-------------------------------
2 files changed, 4 insertions(+), 39 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h
index 4c22c09c93d5..e3e685c931f1 100644
--- a/drivers/gpu/drm/omapdrm/dss/omapdss.h
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h
@@ -204,7 +204,6 @@ struct omap_dss_device {
struct dss_device *dss;
struct drm_bridge *bridge;
struct drm_bridge *next_bridge;
- struct drm_panel *panel;
struct list_head list;
diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c
index 6e9bc605ee22..36d37deac802 100644
--- a/drivers/gpu/drm/omapdrm/dss/output.c
+++ b/drivers/gpu/drm/omapdrm/dss/output.c
@@ -12,7 +12,6 @@
#include <linux/of_graph.h>
#include <drm/drm_bridge.h>
-#include <drm/drm_panel.h>
#include "dss.h"
#include "omapdss.h"
@@ -20,40 +19,16 @@
int omapdss_device_init_output(struct omap_dss_device *out,
struct drm_bridge *local_bridge)
{
- struct device_node *remote_node;
+ struct drm_bridge *bridge;
int ret;
- remote_node = of_graph_get_remote_node(out->dev->of_node,
- out->of_port, 0);
- if (!remote_node) {
+ bridge = of_drm_get_bridge_by_endpoint(out->dev->of_node, out->of_port, 0);
+ if (IS_ERR(bridge)) {
dev_dbg(out->dev, "failed to find video sink\n");
return 0;
}
- out->panel = of_drm_find_panel(remote_node);
- if (IS_ERR(out->panel))
- out->panel = NULL;
-
- if (!out->panel)
- out->bridge = of_drm_find_and_get_bridge(remote_node);
-
- of_node_put(remote_node);
-
- if (out->panel) {
- struct drm_bridge *bridge;
-
- bridge = drm_panel_bridge_add(out->panel);
- drm_panel_put(out->panel);
- if (IS_ERR(bridge)) {
- dev_err(out->dev,
- "unable to create panel bridge (%ld)\n",
- PTR_ERR(bridge));
- ret = PTR_ERR(bridge);
- goto error;
- }
-
- out->bridge = drm_bridge_get(bridge);
- }
+ out->bridge = bridge;
if (local_bridge) {
if (!out->bridge) {
@@ -65,11 +40,6 @@ int omapdss_device_init_output(struct omap_dss_device *out,
out->bridge = drm_bridge_get(local_bridge);
}
- if (!out->bridge) {
- ret = -EPROBE_DEFER;
- goto error;
- }
-
return 0;
error:
@@ -79,10 +49,6 @@ int omapdss_device_init_output(struct omap_dss_device *out,
void omapdss_device_cleanup_output(struct omap_dss_device *out)
{
- if (out->bridge && out->panel)
- drm_panel_bridge_remove(out->next_bridge ?
- out->next_bridge : out->bridge);
-
drm_bridge_put(out->next_bridge);
drm_bridge_put(out->bridge);
}
--
2.55.0
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH RFC v2 17/19] drm/tve200: remove unused includes
2026-09-03 8:11 [PATCH RFC v2 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (15 preceding siblings ...)
2026-09-03 8:11 ` [PATCH RFC v2 16/19] drm/omap: dss: don't create a panel_bridge Luca Ceresoli
@ 2026-09-03 8:11 ` Luca Ceresoli
2026-09-03 10:25 ` Maxime Ripard
2026-09-03 8:11 ` [PATCH RFC v2 18/19] drm/tve200: don't create a panel_bridge Luca Ceresoli
2026-09-03 8:11 ` [PATCH RFC v2 19/19] drm/bridge: analogix_dp: " Luca Ceresoli
18 siblings, 1 reply; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 8:11 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: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu, Ian Ray,
Thomas Petazzoni, dri-devel, linux-kernel, Luca Ceresoli
The drm_panel API is completely unused in this file.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/tve200/tve200_display.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/gpu/drm/tve200/tve200_display.c b/drivers/gpu/drm/tve200/tve200_display.c
index 26b6c65ef6fd..7f8c7756671c 100644
--- a/drivers/gpu/drm/tve200/tve200_display.c
+++ b/drivers/gpu/drm/tve200/tve200_display.c
@@ -20,7 +20,6 @@
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_dma_helper.h>
-#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
--
2.55.0
^ permalink raw reply related [flat|nested] 30+ messages in thread* Re: [PATCH RFC v2 17/19] drm/tve200: remove unused includes
2026-09-03 8:11 ` [PATCH RFC v2 17/19] drm/tve200: remove unused includes Luca Ceresoli
@ 2026-09-03 10:25 ` Maxime Ripard
0 siblings, 0 replies; 30+ messages in thread
From: Maxime Ripard @ 2026-09-03 10:25 UTC (permalink / raw)
To: Luca Ceresoli
Cc: dri-devel, linux-kernel, Albert Esteve, Andrzej Hajda,
Anusha Srivatsa, 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 Thu, 3 Sep 2026 10:11:20 +0200, Luca Ceresoli wrote:
> The drm_panel API is completely unused in this file.
>
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Thanks!
Maxime
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH RFC v2 18/19] drm/tve200: don't create a panel_bridge
2026-09-03 8:11 [PATCH RFC v2 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (16 preceding siblings ...)
2026-09-03 8:11 ` [PATCH RFC v2 17/19] drm/tve200: remove unused includes Luca Ceresoli
@ 2026-09-03 8:11 ` Luca Ceresoli
2026-09-03 8:11 ` [PATCH RFC v2 19/19] drm/bridge: analogix_dp: " Luca Ceresoli
18 siblings, 0 replies; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 8:11 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: Albert Esteve, Anusha Srivatsa, 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 bridge for the same panel.
Update and simplify the code by just getting a reference to the
already-existing bridge.
And since of_drm_find_and_get_bridge() returns a refcounted bridge, take
care of putting the bridge reference.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/tve200/Kconfig | 1 -
drivers/gpu/drm/tve200/tve200_drm.h | 1 -
drivers/gpu/drm/tve200/tve200_drv.c | 31 +++++++------------------------
3 files changed, 7 insertions(+), 26 deletions(-)
diff --git a/drivers/gpu/drm/tve200/Kconfig b/drivers/gpu/drm/tve200/Kconfig
index c0746ae8f703..afe243df4ebb 100644
--- a/drivers/gpu/drm/tve200/Kconfig
+++ b/drivers/gpu/drm/tve200/Kconfig
@@ -8,7 +8,6 @@ config DRM_TVE200
select DRM_BRIDGE
select DRM_CLIENT_SELECTION
select DRM_PANEL
- select DRM_PANEL_BRIDGE
select DRM_KMS_HELPER
select DRM_GEM_DMA_HELPER
help
diff --git a/drivers/gpu/drm/tve200/tve200_drm.h b/drivers/gpu/drm/tve200/tve200_drm.h
index 5420b52ea16b..426c936819fd 100644
--- a/drivers/gpu/drm/tve200/tve200_drm.h
+++ b/drivers/gpu/drm/tve200/tve200_drm.h
@@ -105,7 +105,6 @@ struct tve200_drm_dev_private {
struct drm_device *drm;
struct drm_connector *connector;
- struct drm_panel *panel;
struct drm_bridge *bridge;
struct drm_simple_display_pipe pipe;
diff --git a/drivers/gpu/drm/tve200/tve200_drv.c b/drivers/gpu/drm/tve200/tve200_drv.c
index 8d0e7c7c82e8..d5afed45cf43 100644
--- a/drivers/gpu/drm/tve200/tve200_drv.c
+++ b/drivers/gpu/drm/tve200/tve200_drv.c
@@ -65,7 +65,6 @@ static int tve200_modeset_init(struct drm_device *dev)
{
struct drm_mode_config *mode_config;
struct tve200_drm_dev_private *priv = dev->dev_private;
- struct drm_panel *panel;
struct drm_bridge *bridge;
int ret;
@@ -77,19 +76,10 @@ static int tve200_modeset_init(struct drm_device *dev)
mode_config->min_height = 240;
mode_config->max_height = 576;
- ret = drm_of_find_panel_or_bridge(dev->dev->of_node,
- 0, 0, &panel, &bridge);
- if (ret && ret != -ENODEV)
- return ret;
- if (panel) {
- bridge = drm_panel_bridge_add_typed(panel,
- DRM_MODE_CONNECTOR_Unknown);
- drm_panel_put(panel);
- if (IS_ERR(bridge)) {
- ret = PTR_ERR(bridge);
- goto out_bridge;
- }
- } else {
+ bridge = of_drm_get_bridge_by_endpoint(dev->dev->of_node, 0, 0);
+ if (IS_ERR(bridge) && PTR_ERR(bridge) != -ENODEV)
+ return PTR_ERR(bridge);
+ if (IS_ERR(bridge) || !drm_bridge_is_panel(bridge)) {
/*
* TODO: when we are using a different bridge than a panel
* (such as a dumb VGA connector) we need to devise a different
@@ -100,6 +90,8 @@ static int tve200_modeset_init(struct drm_device *dev)
goto out_bridge;
}
+ bridge->type = DRM_MODE_CONNECTOR_Unknown;
+
ret = tve200_display_init(dev);
if (ret) {
dev_err(dev->dev, "failed to init display\n");
@@ -113,13 +105,9 @@ static int tve200_modeset_init(struct drm_device *dev)
goto out_bridge;
}
- priv->panel = panel;
priv->connector = drm_panel_bridge_connector(bridge);
priv->bridge = bridge;
- dev_info(dev->dev, "attached to panel %s\n",
- dev_name(panel->dev));
-
ret = drm_vblank_init(dev, 1);
if (ret) {
dev_err(dev->dev, "failed to init vblank\n");
@@ -132,8 +120,6 @@ static int tve200_modeset_init(struct drm_device *dev)
goto finish;
out_bridge:
- if (panel)
- drm_panel_bridge_remove(bridge);
drm_mode_config_cleanup(dev);
finish:
return ret;
@@ -229,8 +215,6 @@ static int tve200_probe(struct platform_device *pdev)
return 0;
mode_config_cleanup:
- if (priv->panel)
- drm_panel_bridge_remove(priv->bridge);
drm_mode_config_cleanup(drm);
clk_disable:
clk_disable_unprepare(priv->pclk);
@@ -244,10 +228,9 @@ static void tve200_remove(struct platform_device *pdev)
struct drm_device *drm = platform_get_drvdata(pdev);
struct tve200_drm_dev_private *priv = drm->dev_private;
+ drm_bridge_put(priv->bridge);
drm_dev_unregister(drm);
drm_atomic_helper_shutdown(drm);
- if (priv->panel)
- drm_panel_bridge_remove(priv->bridge);
drm_mode_config_cleanup(drm);
clk_disable_unprepare(priv->pclk);
drm_dev_put(drm);
--
2.55.0
^ permalink raw reply related [flat|nested] 30+ messages in thread* [PATCH RFC v2 19/19] drm/bridge: analogix_dp: don't create a panel_bridge
2026-09-03 8:11 [PATCH RFC v2 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (17 preceding siblings ...)
2026-09-03 8:11 ` [PATCH RFC v2 18/19] drm/tve200: don't create a panel_bridge Luca Ceresoli
@ 2026-09-03 8:11 ` Luca Ceresoli
18 siblings, 0 replies; 30+ messages in thread
From: Luca Ceresoli @ 2026-09-03 8:11 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: Albert Esteve, Anusha Srivatsa, 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
call to devm_drm_panel_bridge_add() would lead to creating a second bridge
for the same panel.
Update and simplify the code by just getting a reference to the
already-existing bridge.
as of_drm_get_bridge_by_endpoint() returns a refcounted bridge, take care
of putting the bridge reference. This is not easily done in the remove path
due to the different probe paths of the user drivers, so add a devm action
to ensure the reference is put only when it was taken.
Assisted-by: opencode:deepseek-v4-flash-0731
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/bridge/analogix/Kconfig | 2 --
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 40 +++++++++++++---------
drivers/gpu/drm/exynos/exynos_dp.c | 36 ++-----------------
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 9 -----
include/drm/bridge/analogix_dp.h | 1 -
5 files changed, 25 insertions(+), 63 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig
index d07431788fcb..1e7726c76361 100644
--- a/drivers/gpu/drm/bridge/analogix/Kconfig
+++ b/drivers/gpu/drm/bridge/analogix/Kconfig
@@ -34,8 +34,6 @@ config DRM_ANALOGIX_DP
depends on DRM
depends on OF
select DRM_DISPLAY_DP_AUX_BUS
- select DRM_PANEL
- select DRM_PANEL_BRIDGE
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 566f1e5eb8cd..233bdaea8012 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -29,7 +29,6 @@
#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>
@@ -1491,15 +1490,6 @@ int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev)
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(dp->plat_data->next_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);
@@ -1571,6 +1561,11 @@ struct drm_dp_aux *analogix_dp_get_aux(struct analogix_dp_device *dp)
}
EXPORT_SYMBOL_GPL(analogix_dp_get_aux);
+static void analogix_dp_put_bridge(void *data)
+{
+ drm_bridge_put(data);
+}
+
static int analogix_dp_aux_done_probing(struct drm_dp_aux *aux)
{
struct analogix_dp_device *dp = to_dp(aux);
@@ -1579,14 +1574,25 @@ static int analogix_dp_aux_done_probing(struct drm_dp_aux *aux)
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.
+ * If of_drm_get_bridge_by_endpoint() 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;
+ plat_data->next_bridge = of_drm_get_bridge_by_endpoint(dp->dev->of_node,
+ port, 0);
+ if (IS_ERR(plat_data->next_bridge)) {
+ if (PTR_ERR(plat_data->next_bridge) == -ENODEV)
+ plat_data->next_bridge = NULL;
+ else
+ return PTR_ERR(plat_data->next_bridge);
+ }
+
+ if (plat_data->next_bridge) {
+ ret = devm_add_action_or_reset(dp->dev, analogix_dp_put_bridge,
+ plat_data->next_bridge);
+ if (ret)
+ return ret;
+ }
return component_add(dp->dev, plat_data->ops);
}
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index e1c9e2946b8a..82c238829921 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -26,7 +26,6 @@
#include <drm/drm_crtc.h>
#include <drm/drm_encoder.h>
#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/exynos_drm.h>
@@ -147,7 +146,6 @@ static const struct component_ops exynos_dp_ops = {
static int exynos_dp_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *np;
struct exynos_dp_device *dp;
dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
@@ -163,18 +161,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
*/
platform_set_drvdata(pdev, dp);
- /* This is for the backward compatibility. */
- np = of_parse_phandle(dev->of_node, "panel", 0);
- if (np) {
- dp->plat_data.panel = of_drm_find_panel(np);
-
- of_node_put(np);
- if (IS_ERR(dp->plat_data.panel))
- return PTR_ERR(dp->plat_data.panel);
-
- goto out;
- }
-
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,
@@ -189,19 +175,11 @@ static int exynos_dp_probe(struct platform_device *pdev)
dp->plat_data.power_off = exynos_dp_poweroff;
dp->plat_data.ops = &exynos_dp_ops;
-out:
dp->adp = analogix_dp_probe(dev, &dp->plat_data);
- if (IS_ERR(dp->adp)) {
- /*
- * The driver core does not invoke remove() for failed probes,
- * so release the probe-time panel reference here.
- */
- if (dp->plat_data.panel)
- drm_panel_put(dp->plat_data.panel);
+ if (IS_ERR(dp->adp))
return PTR_ERR(dp->adp);
- }
- if (dp->plat_data.panel || dp->plat_data.next_bridge)
+ if (dp->plat_data.next_bridge)
return component_add(&pdev->dev, &exynos_dp_ops);
else
return analogix_dp_finish_probe(dp->adp);
@@ -209,16 +187,6 @@ static int exynos_dp_probe(struct platform_device *pdev)
static void exynos_dp_remove(struct platform_device *pdev)
{
- struct exynos_dp_device *dp = platform_get_drvdata(pdev);
-
- /*
- * Release the probe-time reference from of_drm_find_panel(). If bind
- * ran, the panel_bridge holds a second reference that devm cleanup
- * will release when the bridge is destroyed after remove() returns.
- */
- if (dp->plat_data.panel)
- drm_panel_put(dp->plat_data.panel);
-
component_del(&pdev->dev, &exynos_dp_ops);
}
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 587e60232ec7..071d31aa5288 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -28,7 +28,6 @@
#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>
@@ -488,14 +487,6 @@ static void rockchip_dp_remove(struct platform_device *pdev)
{
struct rockchip_dp_device *dp = platform_get_drvdata(pdev);
- /*
- * Release the probe-time reference from of_drm_find_panel(). If bind
- * ran, the panel_bridge holds a second reference that devm cleanup
- * will release when the bridge is destroyed after remove() returns.
- */
- if (dp->plat_data.panel)
- drm_panel_put(dp->plat_data.panel);
-
component_del(&pdev->dev, &rockchip_dp_component_ops);
}
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index 0e0b87abee59..6033137b651e 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -35,7 +35,6 @@ static inline bool analogix_dp_is_rockchip(enum analogix_dp_devtype type)
struct analogix_dp_plat_data {
enum analogix_dp_devtype dev_type;
- struct drm_panel *panel;
struct drm_bridge *next_bridge;
struct drm_encoder *encoder;
struct drm_connector *connector;
--
2.55.0
^ permalink raw reply related [flat|nested] 30+ messages in thread