* [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel
@ 2026-09-16 13:45 Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 01/19] drm: of: move drm_of_find_panel_or_bridge() from drm_of.c to drm_panel.c Luca Ceresoli
` (18 more replies)
0 siblings, 19 replies; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, Luca Ceresoli
This series embeds a drm_bridge into every drm_panel, as previously
discussed [1][2] and in previous iterations.
This will allow bridges and encoders to interact with the next pipeline
component always with the bridge API, not caring whether it is a panel or
another device (e.g. a bridge from a bus to another bus).
Currently a drm_panel does not have a corresponding drm_bridge when it is
created. A panel_bridge is often created afterwards by the component
accessing it (typically the previous bridge or encoder). This creates a
mismatch between the drm_panel and the drm_bridge (part of the
panel_bridge), in terms of lifetime and devm ownership. It also makes
implementing bridge hotplug close to impossible in some cases.
This work leverages the work done by Anusha Srivatsa and Albert Esteve to
implement drm_panel lifetime.
== panel_bridge API impact
This series moves the panel_bridge code inside drm_panel.c and changes it
to be reusable by the panel code. However this implies the old panel_bridge
behaviour (drm_panel_bridge_add() and derivatives create a panel_bridge, to
name one) cannot coexist with the new behaviour (devm_drm_panel_alloc()
allocates an embedded drm_bridge and initializes it).
To handle this, the old panel_bridge API is kept to not break its users,
but now behaves differently:
* drm_panel_bridge_add() and derivatives don't create a bridge, they
just drm_bridge_get() and return a pointer to the existing one
* drm_panel_bridge_remove() and devm_drm_panel_bridge_release() don't
remove the bridge, they just drm-bridge_put() it
* The other panel_bridge functions stack on those listed in the previous 2
bullets, so their behaviour is changed correspondingly
As a result, all drivers using the panel_bridge now behave the new way
without any changes. Converting them to not stop using the panel_bridge is
a goal, but can be done over time. Still this series converts a few
drivers.
== Series outline
1. move code around in preparation
drm: of: move drm_of_find_panel_or_bridge() from drm_of.c to drm_panel.c
drm: of: remove now unnecessary forward declarations
drm/panel: move to a new module
drm/bridge: panel: move all code to drm_panel.c
2. The main change
drm/panel: embed a drm_bridge into every drm_panel
3. API cleanup
drm/bridge: remove devm_drm_put_bridge()
drm/panel: deprecate panel-bridge APIs
drm/todo: add entry for removing the panel_bridge API
4. Update some drivers to not create a panel_bridge
drm/bridge: tc358767: don't create a panel_bridge
drm/bridge: waveshare-dsi: don't create a panel_bridge
drm/mcde: dsi: remove unused includes
drm/mcde: dsi: don't create a panel_bridge
drm/bridge: fsl-ldb: don't create a panel_bridge
drm/bridge: samsung-dsim: don't create a panel_bridge
drm/bridge: tc358768: don't create a panel_bridge
drm/bridge: ssd2825: don't create a panel_bridge
drm/omap: dss: don't create a panel_bridge
drm/tve200: don't create a panel_bridge
drm/bridge: analogix_dp: don't create a panel_bridge
== Dependencies
This series depends on:
* "drm/bridge: Kconfig: cleanup DRM_PANEL usage"
https://lore.kernel.org/r/20260915-drm-bridge-drm_panel-cleanup-v4-0-30401d9406f3@bootlin.com
Reason: trivial, both touch drivers/gpu/drm/bridge/Kconfig, would
conflict otherwise
== Grand plan
This is part of the work to support hotplug of DRM bridges. The grand plan
was discussed in [0].
Here's the work breakdown (➜ marks the current series):
1. ➜ add refcounting to DRM bridges struct drm_bridge,
based on devm_drm_bridge_alloc()
A. ✔ add new alloc API and refcounting (v6.16)
B. ✔ convert all bridge drivers to new API (v6.17)
C. ✔ kunit tests (v6.17)
D. ✔ add get/put to drm_bridge_add/remove() + attach/detach()
and warn on old allocation pattern (v6.17)
E. ➜ add get/put on drm_bridge accessors
1. ✔ drm_bridge_chain_get_first_bridge(), add cleanup action (v6.18)
2. ✔ drm_bridge_get_prev_bridge() (v6.18)
3. ✔ drm_bridge_get_next_bridge() (v6.19)
4. ✔ drm_for_each_bridge_in_chain() (v6.19)
5. ✔ drm_bridge_connector_init (v6.19)
6. ✔ protect encoder bridge chain with a mutex (v7.2)
7. ✔ of_drm_find_bridge
a. ✔ add of_drm_get_bridge() (v7.0),
convert basic direct users (v7.0-v7.1)
b. ✔ convert direct of_drm_get_bridge() users, part 2 (v7.0)
c. ✔ convert direct of_drm_get_bridge() users, part 3 (v7.0)
d. ✔ convert direct of_drm_get_bridge() users, part 4 (v7.1-v7.2)
e. ✔ bridge-only drm_of_find_panel_or_bridge() users (v7.2)
8. ➜ panel_bridge lifetime
a. … cleanup DRM_PANEL in bridge drivers
b. ➜ add a panel_bridge to every panel
9. ✔ enforce drm_bridge_add before drm_bridge_attach (v6.19)
F. ✔ debugfs improvements
1. ✔ add top-level 'bridges' file (v6.16)
2. ✔ show refcount and list lingering bridges (v6.19)
2. ✔ handle gracefully atomic updates during bridge removal
A. ✔ Add drm_bridge_enter/exit() to protect device resources (v7.0)
B. ✔ Add drm_bridge_clear_and_put() (v7.1)
3. … DSI host-device driver interaction
4. ✔ removing the need for the "always-disconnected" connector
5. ✔ Migrate i.MX LCDIF driver to bridge-connector (v7.2)
6. … DRM bridge hotplug
A. … Bridge hotplug management in the DRM core
1. ✔ bridge-connector: attach encoder to the connector (v7.2)
2. … drm bridge hotplug
B. Device tree description
[0] https://lore.kernel.org/lkml/20250206-hotplug-drm-bridge-v6-0-9d6f2c9c3058@bootlin.com/#t
[1] https://lore.kernel.org/all/emuj2innmp6zmzd7pyakqzjqpdzhly6qfhakya3ydwmd63pl26@5jwxaidpikjw/
[2] https://lore.kernel.org/lkml/20250206-hotplug-drm-bridge-v6-8-9d6f2c9c3058@bootlin.com/
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
Changes in v3:
- Move the panel_bridge code to drm_panel.c, don't duplicate it, and change
the panel_bridge API to just wrap the newly embedded drm_bridge
- Remove deprecated devm_drm_put_bridge() and TODO entry
- Deprecate panel_bridge APIA, add TODO entry for its removal
- Link to v2: https://patch.msgid.link/20260903-drm-bridge-every-panel-v2-0-2ab8ee24538e@bootlin.com
Changes in v2:
- Totally new approach: embed a drm_bridge, don't create it dynamically
- New approach to module dependencies management: new drm_panel module etc
- Convert more drivers, including a complex, multi-user one (analogix_dp)
- Add Albert and Anusha to Cc list
- Minor improvements
- Link to v1: https://patch.msgid.link/20260814-drm-bridge-every-panel-v1-0-19cd5277cc8d@bootlin.com
---
Luca Ceresoli (19):
drm: of: move drm_of_find_panel_or_bridge() from drm_of.c to drm_panel.c
drm: of: remove now unnecessary forward declarations
drm/panel: move to a new module
drm/bridge: panel: move all code to drm_panel.c
drm/panel: embed a drm_bridge into every drm_panel
drm/bridge: remove devm_drm_put_bridge()
drm/panel: deprecate panel-bridge APIs
drm/todo: add entry for removing the panel_bridge API
drm/bridge: tc358767: don't create a panel_bridge
drm/bridge: waveshare-dsi: don't create a panel_bridge
drm/mcde: dsi: remove unused includes
drm/mcde: dsi: don't create a panel_bridge
drm/bridge: fsl-ldb: don't create a panel_bridge
drm/bridge: samsung-dsim: don't create a panel_bridge
drm/bridge: tc358768: don't create a panel_bridge
drm/bridge: ssd2825: don't create a panel_bridge
drm/omap: dss: don't create a panel_bridge
drm/tve200: don't create a panel_bridge
drm/bridge: analogix_dp: don't create a panel_bridge
Documentation/gpu/todo.rst | 33 +-
drivers/gpu/drm/Makefile | 3 +-
drivers/gpu/drm/adp/adp-mipi.c | 1 +
drivers/gpu/drm/arm/display/komeda/komeda_crtc.c | 1 +
drivers/gpu/drm/bridge/Kconfig | 10 +-
drivers/gpu/drm/bridge/analogix/Kconfig | 1 +
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 40 +-
drivers/gpu/drm/bridge/aux-bridge.c | 1 +
drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c | 1 +
drivers/gpu/drm/bridge/fsl-ldb.c | 19 +-
drivers/gpu/drm/bridge/imx/imx93-pdfc.c | 1 +
drivers/gpu/drm/bridge/panel.c | 563 -----------------
drivers/gpu/drm/bridge/samsung-dsim.c | 24 +-
drivers/gpu/drm/bridge/ssd2825.c | 23 +-
drivers/gpu/drm/bridge/tc358767.c | 64 +-
drivers/gpu/drm/bridge/tc358768.c | 25 +-
drivers/gpu/drm/bridge/ti-tdp158.c | 1 +
drivers/gpu/drm/bridge/waveshare-dsi.c | 17 +-
drivers/gpu/drm/display/drm_bridge_connector.c | 1 +
drivers/gpu/drm/drm_bridge.c | 17 -
drivers/gpu/drm/drm_of.c | 63 --
drivers/gpu/drm/drm_panel.c | 664 +++++++++++++++++++--
drivers/gpu/drm/exynos/exynos_dp.c | 36 +-
drivers/gpu/drm/imx/dc/dc-kms.c | 1 +
drivers/gpu/drm/imx/dcss/Kconfig | 1 +
drivers/gpu/drm/ingenic/Kconfig | 1 +
drivers/gpu/drm/logicvc/Kconfig | 1 +
drivers/gpu/drm/mcde/Kconfig | 2 +-
drivers/gpu/drm/mcde/mcde_display.c | 1 +
drivers/gpu/drm/mcde/mcde_dsi.c | 45 +-
drivers/gpu/drm/msm/dp/dp_display.c | 1 +
drivers/gpu/drm/msm/dsi/dsi.c | 3 +-
drivers/gpu/drm/omapdrm/dss/omapdss.h | 1 -
drivers/gpu/drm/omapdrm/dss/output.c | 42 +-
drivers/gpu/drm/panel/Kconfig | 2 +-
drivers/gpu/drm/pl111/Kconfig | 1 +
drivers/gpu/drm/rockchip/Kconfig | 2 +
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 9 -
drivers/gpu/drm/stm/Kconfig | 1 +
drivers/gpu/drm/tegra/rgb.c | 1 +
drivers/gpu/drm/tidss/Kconfig | 1 +
drivers/gpu/drm/tve200/Kconfig | 2 +-
drivers/gpu/drm/tve200/tve200_drm.h | 1 -
drivers/gpu/drm/tve200/tve200_drv.c | 30 +-
include/drm/bridge/analogix_dp.h | 1 -
include/drm/drm_bridge.h | 54 --
include/drm/drm_of.h | 15 +-
include/drm/drm_panel.h | 99 ++-
48 files changed, 855 insertions(+), 1072 deletions(-)
---
base-commit: acb05c825e393b0584adb5472bfbb17c8033a99f
change-id: 20260812-drm-bridge-every-panel-a1596d6efea4
prerequisite-change-id: 20260812-drm-bridge-drm_panel-cleanup-09ed5cc10948:v4
prerequisite-patch-id: e15ab172f92263f58d86253708d0ad31d0a876e2
prerequisite-patch-id: 8e8841279db302d98d060c2311781c51673031cd
prerequisite-patch-id: 45c8dac16aad1187d7573c3680117954544b75ff
prerequisite-patch-id: 9afefac08440b7aab2979bb919baf78ba60af1c0
prerequisite-patch-id: 904a81179c02e6a3fe9e85d9a356cf265a4f4d11
prerequisite-patch-id: 665576b9273a19567a410888e2eaf1ac3221ae3e
prerequisite-patch-id: 9578cfffb25341935a89501736a5a59e59c50c56
prerequisite-patch-id: ec32062a627672377ee6621cf73a7a1b99680403
prerequisite-patch-id: d311eba3ac81be3b6af2264442369ff2b8fd5e48
Best regards,
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v3 01/19] drm: of: move drm_of_find_panel_or_bridge() from drm_of.c to drm_panel.c
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
@ 2026-09-16 13:45 ` Luca Ceresoli
2026-09-21 15:06 ` Maxime Ripard
2026-09-16 13:45 ` [PATCH v3 02/19] drm: of: remove now unnecessary forward declarations Luca Ceresoli
` (17 subsequent siblings)
18 siblings, 1 reply; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, 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() (drm_of.c, drm module)
-> calls of_drm_find_panel (drm_panel.c, future drm_panel module)
Avoid this issue by moving drm_of_find_panel_or_bridge() to drm_panel.c.
Update Kconfig symbols of drivers calling drm_of_find_panel_or_bridge() to
select DRM_PANEL when this is not done already.
No functional changes, just moving code around.
Suggested-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/bridge/Kconfig | 2 ++
drivers/gpu/drm/bridge/analogix/Kconfig | 2 ++
drivers/gpu/drm/drm_of.c | 63 ---------------------------------
drivers/gpu/drm/drm_panel.c | 63 +++++++++++++++++++++++++++++++++
drivers/gpu/drm/imx/dcss/Kconfig | 1 +
drivers/gpu/drm/ingenic/Kconfig | 1 +
drivers/gpu/drm/logicvc/Kconfig | 1 +
drivers/gpu/drm/mcde/Kconfig | 1 +
drivers/gpu/drm/pl111/Kconfig | 1 +
drivers/gpu/drm/rockchip/Kconfig | 2 ++
drivers/gpu/drm/stm/Kconfig | 1 +
drivers/gpu/drm/tidss/Kconfig | 1 +
drivers/gpu/drm/tve200/Kconfig | 1 +
include/drm/drm_of.h | 12 -------
include/drm/drm_panel.h | 13 +++++++
15 files changed, 90 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..da156fd15764 100644
--- a/drivers/gpu/drm/bridge/analogix/Kconfig
+++ b/drivers/gpu/drm/bridge/analogix/Kconfig
@@ -6,6 +6,7 @@ config DRM_ANALOGIX_ANX6345
select DRM_DISPLAY_DP_HELPER
select DRM_DISPLAY_HELPER
select DRM_KMS_HELPER
+ select DRM_PANEL
select REGMAP_I2C
help
ANX6345 is an ultra-low power Full-HD DisplayPort/eDP
@@ -32,6 +33,7 @@ config DRM_ANALOGIX_DP
depends on DRM
depends on OF
select DRM_DISPLAY_DP_AUX_BUS
+ select DRM_PANEL
config DRM_ANALOGIX_ANX7625
tristate "Analogix Anx7625 MIPI to DP interface support"
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/drm_panel.c b/drivers/gpu/drm/drm_panel.c
index f8f6082e637f..e1f8a4ff37d2 100644
--- a/drivers/gpu/drm/drm_panel.c
+++ b/drivers/gpu/drm/drm_panel.c
@@ -498,6 +498,69 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np)
return ERR_PTR(-EPROBE_DEFER);
}
EXPORT_SYMBOL(of_drm_find_panel);
+
+/**
+ * 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/imx/dcss/Kconfig b/drivers/gpu/drm/imx/dcss/Kconfig
index e014ed3ae66c..d278bebfc33c 100644
--- a/drivers/gpu/drm/imx/dcss/Kconfig
+++ b/drivers/gpu/drm/imx/dcss/Kconfig
@@ -6,6 +6,7 @@ config DRM_IMX_DCSS
select DRM_DISPLAY_HELPER
select DRM_BRIDGE_CONNECTOR
select DRM_GEM_DMA_HELPER
+ select DRM_PANEL
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..53bd1ae61c83 100644
--- a/drivers/gpu/drm/logicvc/Kconfig
+++ b/drivers/gpu/drm/logicvc/Kconfig
@@ -6,6 +6,7 @@ config DRM_LOGICVC
select DRM_KMS_HELPER
select DRM_KMS_DMA_HELPER
select DRM_GEM_DMA_HELPER
+ select DRM_PANEL
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/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index e7f49fe845ea..1b4a87eeaf3f 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -124,6 +124,7 @@ config ROCKCHIP_LVDS
depends on PINCTRL && OF
select DRM_DISPLAY_HELPER
select DRM_BRIDGE_CONNECTOR
+ select DRM_PANEL
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 +137,7 @@ config ROCKCHIP_RGB
depends on PINCTRL
select DRM_DISPLAY_HELPER
select DRM_BRIDGE_CONNECTOR
+ select DRM_PANEL
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/tidss/Kconfig b/drivers/gpu/drm/tidss/Kconfig
index 31ad582b7602..52a64fa1ad5d 100644
--- a/drivers/gpu/drm/tidss/Kconfig
+++ b/drivers/gpu/drm/tidss/Kconfig
@@ -7,6 +7,7 @@ config DRM_TIDSS
select DRM_DISPLAY_HELPER
select DRM_BRIDGE_CONNECTOR
select DRM_GEM_DMA_HELPER
+ select DRM_PANEL
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_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)
diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
index b87323443f49..bf15e40fd796 100644
--- a/include/drm/drm_panel.h
+++ b/include/drm/drm_panel.h
@@ -33,6 +33,7 @@
struct backlight_device;
struct dentry;
struct device_node;
+struct drm_bridge;
struct drm_connector;
struct drm_panel_follower;
struct drm_panel;
@@ -337,11 +338,23 @@ int drm_panel_get_modes(struct drm_panel *panel, struct drm_connector *connector
#if defined(CONFIG_OF) && defined(CONFIG_DRM_PANEL)
struct drm_panel *of_drm_find_panel(const struct device_node *np);
+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_panel *of_drm_find_panel(const struct device_node *np)
{
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
#if defined(CONFIG_DRM_PANEL)
--
2.55.0
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v3 02/19] drm: of: remove now unnecessary forward declarations
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 01/19] drm: of: move drm_of_find_panel_or_bridge() from drm_of.c to drm_panel.c Luca Ceresoli
@ 2026-09-16 13:45 ` Luca Ceresoli
2026-09-21 15:06 ` Maxime Ripard
2026-09-16 13:45 ` [PATCH v3 03/19] drm/panel: move to a new module Luca Ceresoli
` (16 subsequent siblings)
18 siblings, 1 reply; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, Luca Ceresoli
These forward declarations are now redundant after having moved
drm_of_find_panel_or_bridge():
* struct drm_panel is not referenced in this file
* struct drm_bridge is now referenced only inside an
#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_DRM_PANEL_BRIDGE)
block, and in this case struct drm_bridge is already declared thanks to
these lines:
#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_DRM_PANEL_BRIDGE)
...
#include <drm/drm_bridge.h>
#endif
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
include/drm/drm_of.h | 2 --
1 file changed, 2 deletions(-)
diff --git a/include/drm/drm_of.h b/include/drm/drm_of.h
index 402f5db11e47..f6dad2c6e9b9 100644
--- a/include/drm/drm_of.h
+++ b/include/drm/drm_of.h
@@ -14,8 +14,6 @@ struct component_match;
struct device;
struct drm_device;
struct drm_encoder;
-struct drm_panel;
-struct drm_bridge;
struct device_node;
struct mipi_dsi_device_info;
struct mipi_dsi_host;
--
2.55.0
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v3 03/19] drm/panel: move to a new module
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 01/19] drm: of: move drm_of_find_panel_or_bridge() from drm_of.c to drm_panel.c Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 02/19] drm: of: remove now unnecessary forward declarations Luca Ceresoli
@ 2026-09-16 13:45 ` Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 04/19] drm/bridge: panel: move all code to drm_panel.c Luca Ceresoli
` (15 subsequent siblings)
18 siblings, 0 replies; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, 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.
Reviewed-by: Maxime Ripard <mripard@kernel.org>
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 e635fcffd379..29c9c1d90c11 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 bf15e40fd796..34fcbcdda2c8 100644
--- a/include/drm/drm_panel.h
+++ b/include/drm/drm_panel.h
@@ -336,7 +336,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);
int drm_of_find_panel_or_bridge(const struct device_node *np,
int port, int endpoint,
@@ -357,7 +357,7 @@ static inline int drm_of_find_panel_or_bridge(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 [flat|nested] 29+ messages in thread
* [PATCH v3 04/19] drm/bridge: panel: move all code to drm_panel.c
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (2 preceding siblings ...)
2026-09-16 13:45 ` [PATCH v3 03/19] drm/panel: move to a new module Luca Ceresoli
@ 2026-09-16 13:45 ` Luca Ceresoli
2026-09-21 15:08 ` Maxime Ripard
2026-09-16 13:45 ` [PATCH v3 05/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (14 subsequent siblings)
18 siblings, 1 reply; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, Luca Ceresoli
Work is in progress for every drm_panel to embed a drm_bridge, replacing
the panel_bridge entirely. However most of the panel_bridge code will be
reused for the drm_bridge embedded into the drm_panel, so just move the
code there.
Adapt users of the moved functions to include drm_panel.h when necessary.
No functional changes, just moving code around.
Suggested-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/Makefile | 1 -
drivers/gpu/drm/adp/adp-mipi.c | 1 +
drivers/gpu/drm/arm/display/komeda/komeda_crtc.c | 1 +
drivers/gpu/drm/bridge/aux-bridge.c | 1 +
drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c | 1 +
drivers/gpu/drm/bridge/imx/imx93-pdfc.c | 1 +
drivers/gpu/drm/bridge/panel.c | 563 ----------------------
drivers/gpu/drm/bridge/ti-tdp158.c | 1 +
drivers/gpu/drm/display/drm_bridge_connector.c | 1 +
drivers/gpu/drm/drm_panel.c | 574 ++++++++++++++++++++++-
drivers/gpu/drm/imx/dc/dc-kms.c | 1 +
drivers/gpu/drm/mcde/mcde_display.c | 1 +
drivers/gpu/drm/msm/dp/dp_display.c | 1 +
drivers/gpu/drm/msm/dsi/dsi.c | 3 +-
drivers/gpu/drm/tegra/rgb.c | 1 +
include/drm/drm_bridge.h | 52 --
include/drm/drm_of.h | 1 +
include/drm/drm_panel.h | 53 +++
18 files changed, 622 insertions(+), 636 deletions(-)
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 29c9c1d90c11..4ac7b909bd61 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -156,7 +156,6 @@ 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
diff --git a/drivers/gpu/drm/adp/adp-mipi.c b/drivers/gpu/drm/adp/adp-mipi.c
index 232bb9539423..956533870781 100644
--- a/drivers/gpu/drm/adp/adp-mipi.c
+++ b/drivers/gpu/drm/adp/adp-mipi.c
@@ -8,6 +8,7 @@
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
#define DSI_GEN_HDR 0x6c
#define DSI_GEN_PLD_DATA 0x70
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
index 3d81b413efae..0fd069fc3386 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
@@ -15,6 +15,7 @@
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include <drm/drm_bridge.h>
+#include <drm/drm_panel.h>
#include "komeda_dev.h"
#include "komeda_kms.h"
diff --git a/drivers/gpu/drm/bridge/aux-bridge.c b/drivers/gpu/drm/bridge/aux-bridge.c
index 169939d23310..90f76bb529cc 100644
--- a/drivers/gpu/drm/bridge/aux-bridge.c
+++ b/drivers/gpu/drm/bridge/aux-bridge.c
@@ -12,6 +12,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/bridge/aux-bridge.h>
+#include <drm/drm_panel.h>
static DEFINE_IDA(drm_aux_bridge_ida);
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
index c3e466ded84a..1e28ea579b06 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
@@ -7,6 +7,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
+#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
#include <video/mipi_display.h>
#include <video/videomode.h>
diff --git a/drivers/gpu/drm/bridge/imx/imx93-pdfc.c b/drivers/gpu/drm/bridge/imx/imx93-pdfc.c
index 2d6ca95ed554..2e5019ed951a 100644
--- a/drivers/gpu/drm/bridge/imx/imx93-pdfc.c
+++ b/drivers/gpu/drm/bridge/imx/imx93-pdfc.c
@@ -16,6 +16,7 @@
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_bridge.h>
+#include <drm/drm_panel.h>
#define IMX93_DISPLAY_MUX_REG 0x60
#define PARALLEL_DISP_FORMAT GENMASK(10, 8)
diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
deleted file mode 100644
index 02388a3de626..000000000000
--- a/drivers/gpu/drm/bridge/panel.c
+++ /dev/null
@@ -1,563 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- * Copyright (C) 2017 Broadcom
- */
-
-#include <linux/debugfs.h>
-#include <linux/export.h>
-
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_bridge.h>
-#include <drm/drm_connector.h>
-#include <drm/drm_encoder.h>
-#include <drm/drm_managed.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>
-
-struct panel_bridge {
- struct drm_bridge bridge;
- struct drm_connector connector;
- struct drm_panel *panel;
- u32 connector_type;
-};
-
-static inline struct panel_bridge *
-drm_bridge_to_panel_bridge(struct drm_bridge *bridge)
-{
- return container_of(bridge, struct panel_bridge, bridge);
-}
-
-static inline struct panel_bridge *
-drm_connector_to_panel_bridge(struct drm_connector *connector)
-{
- return container_of(connector, struct panel_bridge, connector);
-}
-
-static int panel_bridge_connector_get_modes(struct drm_connector *connector)
-{
- struct panel_bridge *panel_bridge =
- drm_connector_to_panel_bridge(connector);
-
- return drm_panel_get_modes(panel_bridge->panel, connector);
-}
-
-static const struct drm_connector_helper_funcs
-panel_bridge_connector_helper_funcs = {
- .get_modes = panel_bridge_connector_get_modes,
-};
-
-static const struct drm_connector_funcs 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 panel_bridge_attach(struct drm_bridge *bridge,
- struct drm_encoder *encoder,
- enum drm_bridge_attach_flags flags)
-{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
- struct drm_connector *connector = &panel_bridge->connector;
- int ret;
-
- if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
- return 0;
-
- drm_connector_helper_add(connector,
- &panel_bridge_connector_helper_funcs);
-
- ret = drm_connector_init(bridge->dev, connector,
- &panel_bridge_connector_funcs,
- panel_bridge->connector_type);
- if (ret) {
- DRM_ERROR("Failed to initialize connector\n");
- return ret;
- }
-
- drm_panel_bridge_set_orientation(connector, bridge);
-
- drm_connector_attach_encoder(&panel_bridge->connector,
- encoder);
-
- if (bridge->dev->registered) {
- if (connector->funcs->reset)
- connector->funcs->reset(connector);
- drm_connector_register(connector);
- }
-
- return 0;
-}
-
-static void panel_bridge_detach(struct drm_bridge *bridge)
-{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
- struct drm_connector *connector = &panel_bridge->connector;
-
- /*
- * Cleanup the connector if we know it was initialized.
- *
- * FIXME: This wouldn't be needed if the panel_bridge structure was
- * allocated with drmm_kzalloc(). This might be tricky since the
- * drm_device pointer can only be retrieved when the bridge is attached.
- */
- if (connector->dev)
- drm_connector_cleanup(connector);
-}
-
-static void panel_bridge_atomic_pre_enable(struct drm_bridge *bridge,
- struct drm_atomic_commit *atomic_state)
-{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(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_state, encoder);
- if (!crtc)
- return;
-
- old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
- if (old_crtc_state && old_crtc_state->self_refresh_active)
- return;
-
- drm_panel_prepare(panel_bridge->panel);
-}
-
-static void panel_bridge_atomic_enable(struct drm_bridge *bridge,
- struct drm_atomic_commit *atomic_state)
-{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(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_state, encoder);
- if (!crtc)
- return;
-
- old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
- if (old_crtc_state && old_crtc_state->self_refresh_active)
- return;
-
- drm_panel_enable(panel_bridge->panel);
-}
-
-static void panel_bridge_atomic_disable(struct drm_bridge *bridge,
- struct drm_atomic_commit *atomic_state)
-{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(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_state, encoder);
- if (!crtc)
- return;
-
- new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
- if (new_crtc_state && new_crtc_state->self_refresh_active)
- return;
-
- drm_panel_disable(panel_bridge->panel);
-}
-
-static void panel_bridge_atomic_post_disable(struct drm_bridge *bridge,
- struct drm_atomic_commit *atomic_state)
-{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(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_state, encoder);
- if (!crtc)
- return;
-
- new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
- if (new_crtc_state && new_crtc_state->self_refresh_active)
- return;
-
- drm_panel_unprepare(panel_bridge->panel);
-}
-
-static int panel_bridge_get_modes(struct drm_bridge *bridge,
- struct drm_connector *connector)
-{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
-
- return drm_panel_get_modes(panel_bridge->panel, connector);
-}
-
-static void panel_bridge_debugfs_init(struct drm_bridge *bridge,
- struct dentry *root)
-{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
- struct drm_panel *panel = panel_bridge->panel;
-
- root = debugfs_create_dir("panel", root);
- if (panel->funcs->debugfs_init)
- panel->funcs->debugfs_init(panel, root);
-}
-
-static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
- .attach = panel_bridge_attach,
- .detach = panel_bridge_detach,
- .atomic_pre_enable = panel_bridge_atomic_pre_enable,
- .atomic_enable = panel_bridge_atomic_enable,
- .atomic_disable = panel_bridge_atomic_disable,
- .atomic_post_disable = panel_bridge_atomic_post_disable,
- .get_modes = 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 = panel_bridge_debugfs_init,
-};
-
-/**
- * drm_bridge_is_panel - 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)
-{
- return bridge->funcs == &panel_bridge_bridge_funcs;
-}
-EXPORT_SYMBOL(drm_bridge_is_panel);
-
-/**
- * drm_panel_bridge_add - Creates a &drm_bridge and &drm_connector that
- * just calls the appropriate functions from &drm_panel.
- *
- * @panel: The drm_panel being wrapped. Must be non-NULL.
- *
- * For drivers converting from directly using drm_panel: The expected
- * usage pattern is that during either encoder module probe or DSI
- * host attach, a drm_panel will be looked up through
- * drm_of_find_panel_or_bridge(). drm_panel_bridge_add() is used to
- * wrap that panel in the new bridge, and the result can then be
- * passed to drm_bridge_attach(). The drm_panel_prepare() and related
- * functions can be dropped from the encoder driver (they're now
- * called by the KMS helpers before calling into the encoder), along
- * with connector creation. When done with the bridge (after
- * drm_mode_config_cleanup() if the bridge has already been attached), then
- * drm_panel_bridge_remove() to free it.
- *
- * The connector type is set to @panel->connector_type, which must be set to a
- * known type. Calling this function with a panel whose connector type is
- * DRM_MODE_CONNECTOR_Unknown will return ERR_PTR(-EINVAL).
- *
- * See devm_drm_panel_bridge_add() for an automatically managed version of this
- * function.
- */
-struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel)
-{
- if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
- return ERR_PTR(-EINVAL);
-
- return drm_panel_bridge_add_typed(panel, panel->connector_type);
-}
-EXPORT_SYMBOL(drm_panel_bridge_add);
-
-/**
- * drm_panel_bridge_add_typed - Creates a &drm_bridge and &drm_connector with
- * an explicit connector type.
- * @panel: The drm_panel being wrapped. Must be non-NULL.
- * @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
- *
- * This is just like drm_panel_bridge_add(), but forces the connector type to
- * @connector_type instead of infering it from the panel.
- *
- * This function is deprecated and should not be used in new drivers. Use
- * drm_panel_bridge_add() instead, and fix panel drivers as necessary if they
- * don't report a connector type.
- */
-struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
- u32 connector_type)
-{
- struct panel_bridge *panel_bridge;
-
- if (!panel)
- return ERR_PTR(-EINVAL);
-
- panel_bridge = devm_drm_bridge_alloc(panel->dev, struct panel_bridge, bridge,
- &panel_bridge_bridge_funcs);
- if (IS_ERR(panel_bridge))
- return (void *)panel_bridge;
-
- panel_bridge->connector_type = connector_type;
- panel_bridge->panel = drm_panel_get(panel);
-
- panel_bridge->bridge.of_node = panel->dev->of_node;
- panel_bridge->bridge.ops = DRM_BRIDGE_OP_MODES;
- panel_bridge->bridge.type = connector_type;
- panel_bridge->bridge.pre_enable_prev_first = panel->prepare_prev_first;
-
- drm_bridge_add(&panel_bridge->bridge);
-
- return &panel_bridge->bridge;
-}
-EXPORT_SYMBOL(drm_panel_bridge_add_typed);
-
-/**
- * drm_panel_bridge_remove - Unregisters and frees a drm_bridge
- * created by drm_panel_bridge_add().
- *
- * @bridge: The drm_bridge being freed.
- */
-void drm_panel_bridge_remove(struct drm_bridge *bridge)
-{
- struct panel_bridge *panel_bridge;
- struct drm_panel *panel;
-
- if (!bridge)
- return;
-
- if (!drm_bridge_is_panel(bridge)) {
- drm_warn(bridge->dev, "%s: called on non-panel bridge!\n", __func__);
- return;
- }
-
- panel_bridge = drm_bridge_to_panel_bridge(bridge);
- panel = panel_bridge->panel;
-
- drm_bridge_remove(bridge);
- /* TODO remove this after reworking panel_bridge lifetime */
- devm_drm_put_bridge(panel->dev, bridge);
- drm_panel_put(panel);
-}
-EXPORT_SYMBOL(drm_panel_bridge_remove);
-
-/**
- * drm_panel_bridge_set_orientation - Set the connector's panel orientation
- * from the bridge that can be transformed to panel bridge.
- *
- * @connector: The connector to be set panel orientation.
- * @bridge: The drm_bridge to be transformed to panel bridge.
- *
- * Returns 0 on success, negative errno on failure.
- */
-int drm_panel_bridge_set_orientation(struct drm_connector *connector,
- struct drm_bridge *bridge)
-{
- struct panel_bridge *panel_bridge;
-
- panel_bridge = drm_bridge_to_panel_bridge(bridge);
-
- return drm_connector_set_orientation_from_panel(connector,
- panel_bridge->panel);
-}
-EXPORT_SYMBOL(drm_panel_bridge_set_orientation);
-
-static void devm_drm_panel_bridge_release(struct device *dev, void *res)
-{
- struct drm_bridge *bridge = *(struct drm_bridge **)res;
- struct panel_bridge *panel_bridge;
- struct drm_panel *panel;
-
- if (!bridge)
- return;
-
- panel_bridge = drm_bridge_to_panel_bridge(bridge);
- panel = panel_bridge->panel;
- drm_bridge_remove(bridge);
- drm_panel_put(panel);
-}
-
-/**
- * devm_drm_panel_bridge_add - Creates a managed &drm_bridge and &drm_connector
- * that just calls the appropriate functions from &drm_panel.
- * @dev: device to tie the bridge lifetime to
- * @panel: The drm_panel being wrapped. Must be non-NULL.
- *
- * This is the managed version of drm_panel_bridge_add() which automatically
- * calls drm_panel_bridge_remove() when @dev is unbound.
- */
-struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
- struct drm_panel *panel)
-{
- if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
- return ERR_PTR(-EINVAL);
-
- return devm_drm_panel_bridge_add_typed(dev, panel,
- panel->connector_type);
-}
-EXPORT_SYMBOL(devm_drm_panel_bridge_add);
-
-/**
- * devm_drm_panel_bridge_add_typed - Creates a managed &drm_bridge and
- * &drm_connector with an explicit connector type.
- * @dev: device to tie the bridge lifetime to
- * @panel: The drm_panel being wrapped. Must be non-NULL.
- * @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
- *
- * This is just like devm_drm_panel_bridge_add(), but forces the connector type
- * to @connector_type instead of infering it from the panel.
- *
- * This function is deprecated and should not be used in new drivers. Use
- * devm_drm_panel_bridge_add() instead, and fix panel drivers as necessary if
- * they don't report a connector type.
- */
-struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
- struct drm_panel *panel,
- u32 connector_type)
-{
- struct drm_bridge **ptr, *bridge;
-
- ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),
- GFP_KERNEL);
- if (!ptr)
- return ERR_PTR(-ENOMEM);
-
- bridge = drm_panel_bridge_add_typed(panel, connector_type);
- if (IS_ERR(bridge)) {
- devres_free(ptr);
- return bridge;
- }
-
- *ptr = bridge;
- devres_add(dev, ptr);
-
- return bridge;
-}
-EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed);
-
-static void drmm_drm_panel_bridge_release(struct drm_device *drm, void *ptr)
-{
- struct drm_bridge *bridge = ptr;
-
- drm_panel_bridge_remove(bridge);
-}
-
-/**
- * drmm_panel_bridge_add - Creates a DRM-managed &drm_bridge and
- * &drm_connector that just calls the
- * appropriate functions from &drm_panel.
- *
- * @drm: DRM device to tie the bridge lifetime to
- * @panel: The drm_panel being wrapped. Must be non-NULL.
- *
- * This is the DRM-managed version of drm_panel_bridge_add() which
- * automatically calls drm_panel_bridge_remove() when @dev is cleaned
- * up.
- */
-struct drm_bridge *drmm_panel_bridge_add(struct drm_device *drm,
- struct drm_panel *panel)
-{
- struct drm_bridge *bridge;
- int ret;
-
- bridge = drm_panel_bridge_add_typed(panel, panel->connector_type);
- if (IS_ERR(bridge))
- return bridge;
-
- ret = drmm_add_action_or_reset(drm, drmm_drm_panel_bridge_release,
- bridge);
- if (ret)
- return ERR_PTR(ret);
-
- return bridge;
-}
-EXPORT_SYMBOL(drmm_panel_bridge_add);
-
-/**
- * drm_panel_bridge_connector - return the connector for the panel bridge
- * @bridge: The drm_bridge.
- *
- * drm_panel_bridge creates the connector.
- * This function gives external access to the connector.
- *
- * Returns: Pointer to drm_connector
- */
-struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge)
-{
- struct panel_bridge *panel_bridge;
-
- panel_bridge = drm_bridge_to_panel_bridge(bridge);
-
- return &panel_bridge->connector;
-}
-EXPORT_SYMBOL(drm_panel_bridge_connector);
-
-#ifdef CONFIG_OF
-/**
- * devm_drm_of_get_bridge - Return next bridge in the chain
- * @dev: device to tie the bridge lifetime to
- * @np: device tree node containing encoder output ports
- * @port: port in the device tree node
- * @endpoint: endpoint in the device tree node
- *
- * Given a DT node's port and endpoint number, finds the connected node
- * and returns the associated bridge if any, or creates and returns a
- * drm panel bridge instance if a panel is connected.
- *
- * Returns a pointer to the bridge if successful, or an error pointer
- * otherwise.
- */
-struct drm_bridge *devm_drm_of_get_bridge(struct device *dev,
- struct device_node *np,
- u32 port, u32 endpoint)
-{
- struct drm_bridge *bridge;
- struct drm_panel *panel;
- int ret;
-
- ret = drm_of_find_panel_or_bridge(np, port, endpoint,
- &panel, &bridge);
- if (ret)
- return ERR_PTR(ret);
-
- if (panel) {
- bridge = devm_drm_panel_bridge_add(dev, panel);
- drm_panel_put(panel);
- }
-
- return bridge;
-}
-EXPORT_SYMBOL(devm_drm_of_get_bridge);
-
-/**
- * drmm_of_get_bridge - Return next bridge in the chain
- * @drm: device to tie the bridge lifetime to
- * @np: device tree node containing encoder output ports
- * @port: port in the device tree node
- * @endpoint: endpoint in the device tree node
- *
- * Given a DT node's port and endpoint number, finds the connected node
- * and returns the associated bridge if any, or creates and returns a
- * drm panel bridge instance if a panel is connected.
- *
- * Returns a drmm managed pointer to the bridge if successful, or an error
- * pointer otherwise.
- */
-struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm,
- struct device_node *np,
- u32 port, u32 endpoint)
-{
- struct drm_bridge *bridge;
- struct drm_panel *panel;
- int ret;
-
- ret = drm_of_find_panel_or_bridge(np, port, endpoint,
- &panel, &bridge);
- if (ret)
- return ERR_PTR(ret);
-
- if (panel) {
- bridge = drmm_panel_bridge_add(drm, panel);
- drm_panel_put(panel);
- }
-
- return bridge;
-}
-EXPORT_SYMBOL(drmm_of_get_bridge);
-
-#endif
diff --git a/drivers/gpu/drm/bridge/ti-tdp158.c b/drivers/gpu/drm/bridge/ti-tdp158.c
index 01fc643bd78f..8e3e99cbe41a 100644
--- a/drivers/gpu/drm/bridge/ti-tdp158.c
+++ b/drivers/gpu/drm/bridge/ti-tdp158.c
@@ -8,6 +8,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
+#include <drm/drm_panel.h>
struct tdp158 {
struct drm_bridge bridge;
diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 00feb73e63d7..5b92ba848fa0 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -18,6 +18,7 @@
#include <drm/drm_edid.h>
#include <drm/drm_managed.h>
#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/display/drm_hdcp_helper.h>
diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
index e1f8a4ff37d2..30e7dc81dd15 100644
--- a/drivers/gpu/drm/drm_panel.c
+++ b/drivers/gpu/drm/drm_panel.c
@@ -1,36 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2013, NVIDIA Corporation. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sub license,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
+ * Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ * Copyright (C) 2017 Broadcom
*/
#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_bridge.h>
+#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_managed.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 +38,550 @@ static LIST_HEAD(panel_list);
* take look at drm_panel_bridge_add() and devm_drm_panel_bridge_add().
*/
+struct panel_bridge {
+ struct drm_bridge bridge;
+ struct drm_connector connector;
+ struct drm_panel *panel;
+ u32 connector_type;
+};
+
+static inline struct panel_bridge *
+drm_bridge_to_panel_bridge(struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct panel_bridge, bridge);
+}
+
+static inline struct panel_bridge *
+drm_connector_to_panel_bridge(struct drm_connector *connector)
+{
+ return container_of(connector, struct panel_bridge, connector);
+}
+
+static int panel_bridge_connector_get_modes(struct drm_connector *connector)
+{
+ struct panel_bridge *panel_bridge =
+ drm_connector_to_panel_bridge(connector);
+
+ return drm_panel_get_modes(panel_bridge->panel, connector);
+}
+
+static const struct drm_connector_helper_funcs
+panel_bridge_connector_helper_funcs = {
+ .get_modes = panel_bridge_connector_get_modes,
+};
+
+static const struct drm_connector_funcs 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 panel_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
+ enum drm_bridge_attach_flags flags)
+{
+ struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+ struct drm_connector *connector = &panel_bridge->connector;
+ int ret;
+
+ if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
+ return 0;
+
+ drm_connector_helper_add(connector,
+ &panel_bridge_connector_helper_funcs);
+
+ ret = drm_connector_init(bridge->dev, connector,
+ &panel_bridge_connector_funcs,
+ panel_bridge->connector_type);
+ if (ret) {
+ DRM_ERROR("Failed to initialize connector\n");
+ return ret;
+ }
+
+ drm_panel_bridge_set_orientation(connector, bridge);
+
+ drm_connector_attach_encoder(&panel_bridge->connector,
+ encoder);
+
+ if (bridge->dev->registered) {
+ if (connector->funcs->reset)
+ connector->funcs->reset(connector);
+ drm_connector_register(connector);
+ }
+
+ return 0;
+}
+
+static void panel_bridge_detach(struct drm_bridge *bridge)
+{
+ struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+ struct drm_connector *connector = &panel_bridge->connector;
+
+ /*
+ * Cleanup the connector if we know it was initialized.
+ *
+ * FIXME: This wouldn't be needed if the panel_bridge structure was
+ * allocated with drmm_kzalloc(). This might be tricky since the
+ * drm_device pointer can only be retrieved when the bridge is attached.
+ */
+ if (connector->dev)
+ drm_connector_cleanup(connector);
+}
+
+static void panel_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+ struct drm_atomic_commit *atomic_state)
+{
+ struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(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_state, encoder);
+ if (!crtc)
+ return;
+
+ old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
+ if (old_crtc_state && old_crtc_state->self_refresh_active)
+ return;
+
+ drm_panel_prepare(panel_bridge->panel);
+}
+
+static void panel_bridge_atomic_enable(struct drm_bridge *bridge,
+ struct drm_atomic_commit *atomic_state)
+{
+ struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(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_state, encoder);
+ if (!crtc)
+ return;
+
+ old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
+ if (old_crtc_state && old_crtc_state->self_refresh_active)
+ return;
+
+ drm_panel_enable(panel_bridge->panel);
+}
+
+static void panel_bridge_atomic_disable(struct drm_bridge *bridge,
+ struct drm_atomic_commit *atomic_state)
+{
+ struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(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_state, encoder);
+ if (!crtc)
+ return;
+
+ new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
+ if (new_crtc_state && new_crtc_state->self_refresh_active)
+ return;
+
+ drm_panel_disable(panel_bridge->panel);
+}
+
+static void panel_bridge_atomic_post_disable(struct drm_bridge *bridge,
+ struct drm_atomic_commit *atomic_state)
+{
+ struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(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_state, encoder);
+ if (!crtc)
+ return;
+
+ new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
+ if (new_crtc_state && new_crtc_state->self_refresh_active)
+ return;
+
+ drm_panel_unprepare(panel_bridge->panel);
+}
+
+static int panel_bridge_get_modes(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+
+ return drm_panel_get_modes(panel_bridge->panel, connector);
+}
+
+static void panel_bridge_debugfs_init(struct drm_bridge *bridge,
+ struct dentry *root)
+{
+ struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+ struct drm_panel *panel = panel_bridge->panel;
+
+ root = debugfs_create_dir("panel", root);
+ if (panel->funcs->debugfs_init)
+ panel->funcs->debugfs_init(panel, root);
+}
+
+static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
+ .attach = panel_bridge_attach,
+ .detach = panel_bridge_detach,
+ .atomic_pre_enable = panel_bridge_atomic_pre_enable,
+ .atomic_enable = panel_bridge_atomic_enable,
+ .atomic_disable = panel_bridge_atomic_disable,
+ .atomic_post_disable = panel_bridge_atomic_post_disable,
+ .get_modes = 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 = panel_bridge_debugfs_init,
+};
+
+/**
+ * drm_bridge_is_panel - 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)
+{
+ return bridge->funcs == &panel_bridge_bridge_funcs;
+}
+EXPORT_SYMBOL(drm_bridge_is_panel);
+
+/**
+ * drm_panel_bridge_add - Creates a &drm_bridge and &drm_connector that
+ * just calls the appropriate functions from &drm_panel.
+ *
+ * @panel: The drm_panel being wrapped. Must be non-NULL.
+ *
+ * For drivers converting from directly using drm_panel: The expected
+ * usage pattern is that during either encoder module probe or DSI
+ * host attach, a drm_panel will be looked up through
+ * drm_of_find_panel_or_bridge(). drm_panel_bridge_add() is used to
+ * wrap that panel in the new bridge, and the result can then be
+ * passed to drm_bridge_attach(). The drm_panel_prepare() and related
+ * functions can be dropped from the encoder driver (they're now
+ * called by the KMS helpers before calling into the encoder), along
+ * with connector creation. When done with the bridge (after
+ * drm_mode_config_cleanup() if the bridge has already been attached), then
+ * drm_panel_bridge_remove() to free it.
+ *
+ * The connector type is set to @panel->connector_type, which must be set to a
+ * known type. Calling this function with a panel whose connector type is
+ * DRM_MODE_CONNECTOR_Unknown will return ERR_PTR(-EINVAL).
+ *
+ * See devm_drm_panel_bridge_add() for an automatically managed version of this
+ * function.
+ */
+struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel)
+{
+ if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
+ return ERR_PTR(-EINVAL);
+
+ return drm_panel_bridge_add_typed(panel, panel->connector_type);
+}
+EXPORT_SYMBOL(drm_panel_bridge_add);
+
+/**
+ * drm_panel_bridge_add_typed - Creates a &drm_bridge and &drm_connector with
+ * an explicit connector type.
+ * @panel: The drm_panel being wrapped. Must be non-NULL.
+ * @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
+ *
+ * This is just like drm_panel_bridge_add(), but forces the connector type to
+ * @connector_type instead of infering it from the panel.
+ *
+ * This function is deprecated and should not be used in new drivers. Use
+ * drm_panel_bridge_add() instead, and fix panel drivers as necessary if they
+ * don't report a connector type.
+ */
+struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
+ u32 connector_type)
+{
+ struct panel_bridge *panel_bridge;
+
+ if (!panel)
+ return ERR_PTR(-EINVAL);
+
+ panel_bridge = devm_drm_bridge_alloc(panel->dev, struct panel_bridge, bridge,
+ &panel_bridge_bridge_funcs);
+ if (IS_ERR(panel_bridge))
+ return (void *)panel_bridge;
+
+ panel_bridge->connector_type = connector_type;
+ panel_bridge->panel = drm_panel_get(panel);
+
+ panel_bridge->bridge.of_node = panel->dev->of_node;
+ panel_bridge->bridge.ops = DRM_BRIDGE_OP_MODES;
+ panel_bridge->bridge.type = connector_type;
+ panel_bridge->bridge.pre_enable_prev_first = panel->prepare_prev_first;
+
+ drm_bridge_add(&panel_bridge->bridge);
+
+ return &panel_bridge->bridge;
+}
+EXPORT_SYMBOL(drm_panel_bridge_add_typed);
+
+/**
+ * drm_panel_bridge_remove - Unregisters and frees a drm_bridge
+ * created by drm_panel_bridge_add().
+ *
+ * @bridge: The drm_bridge being freed.
+ */
+void drm_panel_bridge_remove(struct drm_bridge *bridge)
+{
+ struct panel_bridge *panel_bridge;
+ struct drm_panel *panel;
+
+ if (!bridge)
+ return;
+
+ if (!drm_bridge_is_panel(bridge)) {
+ drm_warn(bridge->dev, "%s: called on non-panel bridge!\n", __func__);
+ return;
+ }
+
+ panel_bridge = drm_bridge_to_panel_bridge(bridge);
+ panel = panel_bridge->panel;
+
+ drm_bridge_remove(bridge);
+ /* TODO remove this after reworking panel_bridge lifetime */
+ devm_drm_put_bridge(panel->dev, bridge);
+ drm_panel_put(panel);
+}
+EXPORT_SYMBOL(drm_panel_bridge_remove);
+
+/**
+ * drm_panel_bridge_set_orientation - Set the connector's panel orientation
+ * from the bridge that can be transformed to panel bridge.
+ *
+ * @connector: The connector to be set panel orientation.
+ * @bridge: The drm_bridge to be transformed to panel bridge.
+ *
+ * Returns 0 on success, negative errno on failure.
+ */
+int drm_panel_bridge_set_orientation(struct drm_connector *connector,
+ struct drm_bridge *bridge)
+{
+ struct panel_bridge *panel_bridge;
+
+ panel_bridge = drm_bridge_to_panel_bridge(bridge);
+
+ return drm_connector_set_orientation_from_panel(connector,
+ panel_bridge->panel);
+}
+EXPORT_SYMBOL(drm_panel_bridge_set_orientation);
+
+static void devm_drm_panel_bridge_release(struct device *dev, void *res)
+{
+ struct drm_bridge *bridge = *(struct drm_bridge **)res;
+ struct panel_bridge *panel_bridge;
+ struct drm_panel *panel;
+
+ if (!bridge)
+ return;
+
+ panel_bridge = drm_bridge_to_panel_bridge(bridge);
+ panel = panel_bridge->panel;
+ drm_bridge_remove(bridge);
+ drm_panel_put(panel);
+}
+
+/**
+ * devm_drm_panel_bridge_add - Creates a managed &drm_bridge and &drm_connector
+ * that just calls the appropriate functions from &drm_panel.
+ * @dev: device to tie the bridge lifetime to
+ * @panel: The drm_panel being wrapped. Must be non-NULL.
+ *
+ * This is the managed version of drm_panel_bridge_add() which automatically
+ * calls drm_panel_bridge_remove() when @dev is unbound.
+ */
+struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
+ struct drm_panel *panel)
+{
+ if (WARN_ON(panel->connector_type == DRM_MODE_CONNECTOR_Unknown))
+ return ERR_PTR(-EINVAL);
+
+ return devm_drm_panel_bridge_add_typed(dev, panel,
+ panel->connector_type);
+}
+EXPORT_SYMBOL(devm_drm_panel_bridge_add);
+
+/**
+ * devm_drm_panel_bridge_add_typed - Creates a managed &drm_bridge and
+ * &drm_connector with an explicit connector type.
+ * @dev: device to tie the bridge lifetime to
+ * @panel: The drm_panel being wrapped. Must be non-NULL.
+ * @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
+ *
+ * This is just like devm_drm_panel_bridge_add(), but forces the connector type
+ * to @connector_type instead of infering it from the panel.
+ *
+ * This function is deprecated and should not be used in new drivers. Use
+ * devm_drm_panel_bridge_add() instead, and fix panel drivers as necessary if
+ * they don't report a connector type.
+ */
+struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
+ struct drm_panel *panel,
+ u32 connector_type)
+{
+ struct drm_bridge **ptr, *bridge;
+
+ ptr = devres_alloc(devm_drm_panel_bridge_release, sizeof(*ptr),
+ GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ bridge = drm_panel_bridge_add_typed(panel, connector_type);
+ if (IS_ERR(bridge)) {
+ devres_free(ptr);
+ return bridge;
+ }
+
+ *ptr = bridge;
+ devres_add(dev, ptr);
+
+ return bridge;
+}
+EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed);
+
+static void drmm_drm_panel_bridge_release(struct drm_device *drm, void *ptr)
+{
+ struct drm_bridge *bridge = ptr;
+
+ drm_panel_bridge_remove(bridge);
+}
+
+/**
+ * drmm_panel_bridge_add - Creates a DRM-managed &drm_bridge and
+ * &drm_connector that just calls the
+ * appropriate functions from &drm_panel.
+ *
+ * @drm: DRM device to tie the bridge lifetime to
+ * @panel: The drm_panel being wrapped. Must be non-NULL.
+ *
+ * This is the DRM-managed version of drm_panel_bridge_add() which
+ * automatically calls drm_panel_bridge_remove() when @dev is cleaned
+ * up.
+ */
+struct drm_bridge *drmm_panel_bridge_add(struct drm_device *drm,
+ struct drm_panel *panel)
+{
+ struct drm_bridge *bridge;
+ int ret;
+
+ bridge = drm_panel_bridge_add_typed(panel, panel->connector_type);
+ if (IS_ERR(bridge))
+ return bridge;
+
+ ret = drmm_add_action_or_reset(drm, drmm_drm_panel_bridge_release,
+ bridge);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return bridge;
+}
+EXPORT_SYMBOL(drmm_panel_bridge_add);
+
+/**
+ * drm_panel_bridge_connector - return the connector for the panel bridge
+ * @bridge: The drm_bridge.
+ *
+ * drm_panel_bridge creates the connector.
+ * This function gives external access to the connector.
+ *
+ * Returns: Pointer to drm_connector
+ */
+struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge)
+{
+ struct panel_bridge *panel_bridge;
+
+ panel_bridge = drm_bridge_to_panel_bridge(bridge);
+
+ return &panel_bridge->connector;
+}
+EXPORT_SYMBOL(drm_panel_bridge_connector);
+
+#ifdef CONFIG_OF
+/**
+ * devm_drm_of_get_bridge - Return next bridge in the chain
+ * @dev: device to tie the bridge lifetime to
+ * @np: device tree node containing encoder output ports
+ * @port: port in the device tree node
+ * @endpoint: endpoint in the device tree node
+ *
+ * Given a DT node's port and endpoint number, finds the connected node
+ * and returns the associated bridge if any, or creates and returns a
+ * drm panel bridge instance if a panel is connected.
+ *
+ * Returns a pointer to the bridge if successful, or an error pointer
+ * otherwise.
+ */
+struct drm_bridge *devm_drm_of_get_bridge(struct device *dev,
+ struct device_node *np,
+ u32 port, u32 endpoint)
+{
+ struct drm_bridge *bridge;
+ struct drm_panel *panel;
+ int ret;
+
+ ret = drm_of_find_panel_or_bridge(np, port, endpoint,
+ &panel, &bridge);
+ if (ret)
+ return ERR_PTR(ret);
+
+ if (panel) {
+ bridge = devm_drm_panel_bridge_add(dev, panel);
+ drm_panel_put(panel);
+ }
+
+ return bridge;
+}
+EXPORT_SYMBOL(devm_drm_of_get_bridge);
+
+/**
+ * drmm_of_get_bridge - Return next bridge in the chain
+ * @drm: device to tie the bridge lifetime to
+ * @np: device tree node containing encoder output ports
+ * @port: port in the device tree node
+ * @endpoint: endpoint in the device tree node
+ *
+ * Given a DT node's port and endpoint number, finds the connected node
+ * and returns the associated bridge if any, or creates and returns a
+ * drm panel bridge instance if a panel is connected.
+ *
+ * Returns a drmm managed pointer to the bridge if successful, or an error
+ * pointer otherwise.
+ */
+struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm,
+ struct device_node *np,
+ u32 port, u32 endpoint)
+{
+ struct drm_bridge *bridge;
+ struct drm_panel *panel;
+ int ret;
+
+ ret = drm_of_find_panel_or_bridge(np, port, endpoint,
+ &panel, &bridge);
+ if (ret)
+ return ERR_PTR(ret);
+
+ if (panel) {
+ bridge = drmm_panel_bridge_add(drm, panel);
+ drm_panel_put(panel);
+ }
+
+ return bridge;
+}
+EXPORT_SYMBOL(drmm_of_get_bridge);
+
+#endif
+
/**
* drm_panel_init - initialize a panel
* @panel: DRM panel
diff --git a/drivers/gpu/drm/imx/dc/dc-kms.c b/drivers/gpu/drm/imx/dc/dc-kms.c
index a9adcfc68b84..0e2ce6a42548 100644
--- a/drivers/gpu/drm/imx/dc/dc-kms.c
+++ b/drivers/gpu/drm/imx/dc/dc-kms.c
@@ -15,6 +15,7 @@
#include <drm/drm_encoder.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_mode_config.h>
+#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
diff --git a/drivers/gpu/drm/mcde/mcde_display.c b/drivers/gpu/drm/mcde/mcde_display.c
index d1d01f3d8ab4..b2455391bdd7 100644
--- a/drivers/gpu/drm/mcde/mcde_display.c
+++ b/drivers/gpu/drm/mcde/mcde_display.c
@@ -18,6 +18,7 @@
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_bridge.h>
#include <drm/drm_vblank.h>
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index bc646d172abe..525c188ac951 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -15,6 +15,7 @@
#include <drm/display/drm_dp_aux_bus.h>
#include <drm/display/drm_hdmi_audio_helper.h>
#include <drm/drm_edid.h>
+#include <drm/drm_panel.h>
#include "msm_drv.h"
#include "msm_kms.h"
diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c
index 3c9f01ed6271..c726fc628a08 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.c
+++ b/drivers/gpu/drm/msm/dsi/dsi.c
@@ -5,6 +5,8 @@
#include "dsi.h"
+#include <drm/drm_panel.h>
+
bool msm_dsi_is_cmd_mode(struct msm_dsi *msm_dsi)
{
unsigned long host_flags = msm_dsi_host_get_mode_flags(msm_dsi->host);
@@ -267,4 +269,3 @@ void msm_dsi_snapshot(struct msm_disp_state *disp_state, struct msm_dsi *msm_dsi
msm_dsi_host_snapshot(disp_state, msm_dsi->host);
msm_dsi_phy_snapshot(disp_state, msm_dsi->phy);
}
-
diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c
index bc1c93c7554c..b6d09a8d8e5e 100644
--- a/drivers/gpu/drm/tegra/rgb.c
+++ b/drivers/gpu/drm/tegra/rgb.c
@@ -10,6 +10,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge_connector.h>
#include <drm/drm_encoder.h>
+#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include "drm.h"
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 58fff047f43b..11c203391de5 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -1473,58 +1473,6 @@ 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
-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,
- u32 connector_type);
-void drm_panel_bridge_remove(struct drm_bridge *bridge);
-int drm_panel_bridge_set_orientation(struct drm_connector *connector,
- struct drm_bridge *bridge);
-struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
- struct drm_panel *panel);
-struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
- struct drm_panel *panel,
- u32 connector_type);
-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)
-{
- return false;
-}
-
-static inline int drm_panel_bridge_set_orientation(struct drm_connector *connector,
- struct drm_bridge *bridge)
-{
- return -EINVAL;
-}
-#endif
-
-#if defined(CONFIG_OF) && defined(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,
- u32 port, u32 endpoint);
-#else
-static inline struct drm_bridge *devm_drm_of_get_bridge(struct device *dev,
- struct device_node *node,
- u32 port,
- u32 endpoint)
-{
- return ERR_PTR(-ENODEV);
-}
-
-static inline struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm,
- struct device_node *node,
- u32 port,
- u32 endpoint)
-{
- return ERR_PTR(-ENODEV);
-}
-#endif
-
void devm_drm_put_bridge(struct device *dev, struct drm_bridge *bridge);
void drm_bridge_debugfs_params(struct dentry *root);
diff --git a/include/drm/drm_of.h b/include/drm/drm_of.h
index f6dad2c6e9b9..002ba1b18eb1 100644
--- a/include/drm/drm_of.h
+++ b/include/drm/drm_of.h
@@ -7,6 +7,7 @@
#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_DRM_PANEL_BRIDGE)
#include <linux/of.h>
#include <drm/drm_bridge.h>
+#include <drm/drm_panel.h>
#endif
struct component_master_ops;
diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
index 34fcbcdda2c8..bede046fb281 100644
--- a/include/drm/drm_panel.h
+++ b/include/drm/drm_panel.h
@@ -35,6 +35,7 @@ struct dentry;
struct device_node;
struct drm_bridge;
struct drm_connector;
+struct drm_device;
struct drm_panel_follower;
struct drm_panel;
struct display_timing;
@@ -394,4 +395,56 @@ static inline int drm_panel_of_backlight(struct drm_panel *panel)
}
#endif
+#ifdef 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,
+ u32 connector_type);
+void drm_panel_bridge_remove(struct drm_bridge *bridge);
+int drm_panel_bridge_set_orientation(struct drm_connector *connector,
+ struct drm_bridge *bridge);
+struct drm_bridge *devm_drm_panel_bridge_add(struct device *dev,
+ struct drm_panel *panel);
+struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
+ struct drm_panel *panel,
+ u32 connector_type);
+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)
+{
+ return false;
+}
+
+static inline int drm_panel_bridge_set_orientation(struct drm_connector *connector,
+ struct drm_bridge *bridge)
+{
+ return -EINVAL;
+}
+#endif
+
+#if defined(CONFIG_OF) && defined(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,
+ u32 port, u32 endpoint);
+#else
+static inline struct drm_bridge *devm_drm_of_get_bridge(struct device *dev,
+ struct device_node *node,
+ u32 port,
+ u32 endpoint)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static inline struct drm_bridge *drmm_of_get_bridge(struct drm_device *drm,
+ struct device_node *node,
+ u32 port,
+ u32 endpoint)
+{
+ return ERR_PTR(-ENODEV);
+}
+#endif
+
#endif
--
2.55.0
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v3 05/19] drm/panel: embed a drm_bridge into every drm_panel
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (3 preceding siblings ...)
2026-09-16 13:45 ` [PATCH v3 04/19] drm/bridge: panel: move all code to drm_panel.c Luca Ceresoli
@ 2026-09-16 13:45 ` Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 06/19] drm/bridge: remove devm_drm_put_bridge() Luca Ceresoli
` (13 subsequent siblings)
18 siblings, 0 replies; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, 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
won't happen as needed.
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 adapting
the panel_bridge code, doing the minimal adaptations 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
Now drivers should progressively stop using the panel_bridge API. Until
that happens, that API becomes now a wrapper to the new embedded
drm_bridge:
* drm_panel_bridge_add() and derivatives don't create a bridge, they
just drm_bridge_get() and return a pointer to the existing one
* drm_panel_bridge_remove() and devm_drm_panel_bridge_release() don't
remove the bridge, they just drm-bridge_put() it
* The other panel_bridge functions stack on those listed in the previous 2
bullets, so their behaviour is changed correspondingly; they include:
- all drm_panel_bridge_add() variants
- their removal counterparts
- *_of_get_bridge().
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
Changes in v3:
- previous patches don't duplicate but rather move the panel_bridge code
to drm_bridge.c, so adapt to that: as there are no more 2 versions of
that code we need to handle right now the fact that existing users of
panel_bridge need to be transparently use the embedded bridge
- add missing panel->bridge initializations to drm_panel_add()
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 | 184 +++++++++++++++++++-------------------------
include/drm/drm_panel.h | 29 ++++---
2 files changed, 96 insertions(+), 117 deletions(-)
diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
index 30e7dc81dd15..707ad9aa907a 100644
--- a/drivers/gpu/drm/drm_panel.c
+++ b/drivers/gpu/drm/drm_panel.c
@@ -38,6 +38,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);
+}
+
struct panel_bridge {
struct drm_bridge bridge;
struct drm_connector connector;
@@ -45,24 +57,11 @@ struct panel_bridge {
u32 connector_type;
};
-static inline struct panel_bridge *
-drm_bridge_to_panel_bridge(struct drm_bridge *bridge)
-{
- return container_of(bridge, struct panel_bridge, bridge);
-}
-
-static inline struct panel_bridge *
-drm_connector_to_panel_bridge(struct drm_connector *connector)
-{
- return container_of(connector, struct panel_bridge, connector);
-}
-
static int panel_bridge_connector_get_modes(struct drm_connector *connector)
{
- struct panel_bridge *panel_bridge =
- drm_connector_to_panel_bridge(connector);
+ struct drm_panel *panel = drm_connector_to_panel(connector);
- return drm_panel_get_modes(panel_bridge->panel, connector);
+ return drm_panel_get_modes(panel, connector);
}
static const struct drm_connector_helper_funcs
@@ -82,8 +81,8 @@ static int panel_bridge_attach(struct drm_bridge *bridge,
struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
- struct drm_connector *connector = &panel_bridge->connector;
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+ struct drm_connector *connector = &panel->connector;
int ret;
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
@@ -94,7 +93,7 @@ static int panel_bridge_attach(struct drm_bridge *bridge,
ret = drm_connector_init(bridge->dev, connector,
&panel_bridge_connector_funcs,
- panel_bridge->connector_type);
+ panel->connector_type);
if (ret) {
DRM_ERROR("Failed to initialize connector\n");
return ret;
@@ -102,8 +101,7 @@ static int panel_bridge_attach(struct drm_bridge *bridge,
drm_panel_bridge_set_orientation(connector, bridge);
- drm_connector_attach_encoder(&panel_bridge->connector,
- encoder);
+ drm_connector_attach_encoder(connector, encoder);
if (bridge->dev->registered) {
if (connector->funcs->reset)
@@ -116,16 +114,10 @@ static int panel_bridge_attach(struct drm_bridge *bridge,
static void panel_bridge_detach(struct drm_bridge *bridge)
{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
- struct drm_connector *connector = &panel_bridge->connector;
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
+ struct drm_connector *connector = &panel->connector;
- /*
- * Cleanup the connector if we know it was initialized.
- *
- * FIXME: This wouldn't be needed if the panel_bridge structure was
- * allocated with drmm_kzalloc(). This might be tricky since the
- * drm_device pointer can only be retrieved when the bridge is attached.
- */
+ /* Cleanup the connector if we know it was initialized */
if (connector->dev)
drm_connector_cleanup(connector);
}
@@ -133,7 +125,7 @@ static void panel_bridge_detach(struct drm_bridge *bridge)
static void panel_bridge_atomic_pre_enable(struct drm_bridge *bridge,
struct drm_atomic_commit *atomic_state)
{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+ 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;
@@ -146,13 +138,13 @@ static void panel_bridge_atomic_pre_enable(struct drm_bridge *bridge,
if (old_crtc_state && old_crtc_state->self_refresh_active)
return;
- drm_panel_prepare(panel_bridge->panel);
+ drm_panel_prepare(panel);
}
static void panel_bridge_atomic_enable(struct drm_bridge *bridge,
struct drm_atomic_commit *atomic_state)
{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+ 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;
@@ -165,13 +157,13 @@ static void panel_bridge_atomic_enable(struct drm_bridge *bridge,
if (old_crtc_state && old_crtc_state->self_refresh_active)
return;
- drm_panel_enable(panel_bridge->panel);
+ drm_panel_enable(panel);
}
static void panel_bridge_atomic_disable(struct drm_bridge *bridge,
struct drm_atomic_commit *atomic_state)
{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+ 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;
@@ -184,13 +176,13 @@ static void panel_bridge_atomic_disable(struct drm_bridge *bridge,
if (new_crtc_state && new_crtc_state->self_refresh_active)
return;
- drm_panel_disable(panel_bridge->panel);
+ drm_panel_disable(panel);
}
static void panel_bridge_atomic_post_disable(struct drm_bridge *bridge,
struct drm_atomic_commit *atomic_state)
{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+ 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;
@@ -203,22 +195,21 @@ static void panel_bridge_atomic_post_disable(struct drm_bridge *bridge,
if (new_crtc_state && new_crtc_state->self_refresh_active)
return;
- drm_panel_unprepare(panel_bridge->panel);
+ drm_panel_unprepare(panel);
}
static int panel_bridge_get_modes(struct drm_bridge *bridge,
struct drm_connector *connector)
{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
- return drm_panel_get_modes(panel_bridge->panel, connector);
+ return drm_panel_get_modes(panel, connector);
}
static void panel_bridge_debugfs_init(struct drm_bridge *bridge,
struct dentry *root)
{
- struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
- struct drm_panel *panel = panel_bridge->panel;
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
root = debugfs_create_dir("panel", root);
if (panel->funcs->debugfs_init)
@@ -288,7 +279,7 @@ struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel)
EXPORT_SYMBOL(drm_panel_bridge_add);
/**
- * drm_panel_bridge_add_typed - Creates a &drm_bridge and &drm_connector with
+ * drm_panel_bridge_add_typed - Pretend to create a &drm_bridge and &drm_connector with
* an explicit connector type.
* @panel: The drm_panel being wrapped. Must be non-NULL.
* @connector_type: The connector type (DRM_MODE_CONNECTOR_*)
@@ -303,27 +294,10 @@ EXPORT_SYMBOL(drm_panel_bridge_add);
struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
u32 connector_type)
{
- struct panel_bridge *panel_bridge;
-
if (!panel)
return ERR_PTR(-EINVAL);
- panel_bridge = devm_drm_bridge_alloc(panel->dev, struct panel_bridge, bridge,
- &panel_bridge_bridge_funcs);
- if (IS_ERR(panel_bridge))
- return (void *)panel_bridge;
-
- panel_bridge->connector_type = connector_type;
- panel_bridge->panel = drm_panel_get(panel);
-
- panel_bridge->bridge.of_node = panel->dev->of_node;
- panel_bridge->bridge.ops = DRM_BRIDGE_OP_MODES;
- panel_bridge->bridge.type = connector_type;
- panel_bridge->bridge.pre_enable_prev_first = panel->prepare_prev_first;
-
- drm_bridge_add(&panel_bridge->bridge);
-
- return &panel_bridge->bridge;
+ return drm_bridge_get(&panel->bridge);
}
EXPORT_SYMBOL(drm_panel_bridge_add_typed);
@@ -335,9 +309,6 @@ EXPORT_SYMBOL(drm_panel_bridge_add_typed);
*/
void drm_panel_bridge_remove(struct drm_bridge *bridge)
{
- struct panel_bridge *panel_bridge;
- struct drm_panel *panel;
-
if (!bridge)
return;
@@ -346,13 +317,7 @@ void drm_panel_bridge_remove(struct drm_bridge *bridge)
return;
}
- panel_bridge = drm_bridge_to_panel_bridge(bridge);
- panel = panel_bridge->panel;
-
- drm_bridge_remove(bridge);
- /* TODO remove this after reworking panel_bridge lifetime */
- devm_drm_put_bridge(panel->dev, bridge);
- drm_panel_put(panel);
+ drm_bridge_put(bridge);
}
EXPORT_SYMBOL(drm_panel_bridge_remove);
@@ -361,35 +326,27 @@ EXPORT_SYMBOL(drm_panel_bridge_remove);
* from the bridge that can be transformed to panel bridge.
*
* @connector: The connector to be set panel orientation.
- * @bridge: The drm_bridge to be transformed to panel bridge.
+ * @bridge: The drm_bridge whose orientation should be set.
*
* Returns 0 on success, negative errno on failure.
*/
int drm_panel_bridge_set_orientation(struct drm_connector *connector,
struct drm_bridge *bridge)
{
- struct panel_bridge *panel_bridge;
+ struct drm_panel *panel = drm_bridge_to_panel(bridge);
- panel_bridge = drm_bridge_to_panel_bridge(bridge);
-
- return drm_connector_set_orientation_from_panel(connector,
- panel_bridge->panel);
+ return drm_connector_set_orientation_from_panel(connector, panel);
}
EXPORT_SYMBOL(drm_panel_bridge_set_orientation);
static void devm_drm_panel_bridge_release(struct device *dev, void *res)
{
struct drm_bridge *bridge = *(struct drm_bridge **)res;
- struct panel_bridge *panel_bridge;
- struct drm_panel *panel;
if (!bridge)
return;
- panel_bridge = drm_bridge_to_panel_bridge(bridge);
- panel = panel_bridge->panel;
- drm_bridge_remove(bridge);
- drm_panel_put(panel);
+ drm_bridge_put(bridge);
}
/**
@@ -446,7 +403,7 @@ struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
*ptr = bridge;
devres_add(dev, ptr);
- return bridge;
+ return &panel->bridge;
}
EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed);
@@ -489,21 +446,21 @@ struct drm_bridge *drmm_panel_bridge_add(struct drm_device *drm,
EXPORT_SYMBOL(drmm_panel_bridge_add);
/**
- * drm_panel_bridge_connector - return the connector for the panel bridge
+ * drm_panel_bridge_connector - return the connector for the panel (for
+ * legacy drivers not using DRM_BRIDGE_ATTACH_NO_CONNECTOR)
* @bridge: The drm_bridge.
*
- * drm_panel_bridge creates the connector.
* This function gives external access to the connector.
*
* Returns: Pointer to drm_connector
*/
struct drm_connector *drm_panel_bridge_connector(struct drm_bridge *bridge)
{
- struct panel_bridge *panel_bridge;
+ struct drm_panel *panel;
- panel_bridge = drm_bridge_to_panel_bridge(bridge);
+ panel = drm_bridge_to_panel(bridge);
- return &panel_bridge->connector;
+ return &panel->connector;
}
EXPORT_SYMBOL(drm_panel_bridge_connector);
@@ -622,6 +579,13 @@ void drm_panel_add(struct drm_panel *panel)
mutex_lock(&panel_lock);
list_add_tail(&panel->list, &panel_list);
mutex_unlock(&panel_lock);
+
+ panel->bridge.of_node = panel->dev->of_node;
+ panel->bridge.ops = DRM_BRIDGE_OP_MODES;
+ panel->bridge.type = panel->connector_type;
+ panel->bridge.pre_enable_prev_first = panel->prepare_prev_first;
+
+ drm_bridge_add(&panel->bridge);
}
EXPORT_SYMBOL(drm_panel_add);
@@ -633,6 +597,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);
@@ -906,13 +871,6 @@ int drm_panel_get_modes(struct drm_panel *panel,
}
EXPORT_SYMBOL(drm_panel_get_modes);
-static void __drm_panel_free(struct kref *kref)
-{
- struct drm_panel *panel = container_of(kref, struct drm_panel, refcount);
-
- kfree(panel->container);
-}
-
/**
* drm_panel_get - Acquire a panel reference
* @panel: DRM panel
@@ -923,10 +881,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;
}
@@ -942,7 +898,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);
@@ -965,8 +921,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) {
@@ -974,14 +944,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,
+ &panel_bridge_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)
diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
index bede046fb281..58113ea7d63a 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;
@@ -230,6 +232,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:
*
@@ -283,17 +301,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,
--
2.55.0
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v3 06/19] drm/bridge: remove devm_drm_put_bridge()
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (4 preceding siblings ...)
2026-09-16 13:45 ` [PATCH v3 05/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
@ 2026-09-16 13:45 ` Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 07/19] drm/panel: deprecate panel-bridge APIs Luca Ceresoli
` (12 subsequent siblings)
18 siblings, 0 replies; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, Luca Ceresoli
The deprecated devm_drm_put_bridge() function is not used anymore.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
Documentation/gpu/todo.rst | 16 ----------------
drivers/gpu/drm/drm_bridge.c | 17 -----------------
include/drm/drm_bridge.h | 2 --
3 files changed, 35 deletions(-)
diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst
index b7351467dc74..cb0ce432c114 100644
--- a/Documentation/gpu/todo.rst
+++ b/Documentation/gpu/todo.rst
@@ -484,22 +484,6 @@ Contact: Douglas Anderson <dianders@chromium.org>
Level: Starter
-Remove devm_drm_put_bridge()
-----------------------------
-
-Due to how the panel bridge handles the drm_bridge object lifetime, special
-care must be taken to dispose of the drm_bridge object when the
-panel_bridge is removed. This is currently managed using
-devm_drm_put_bridge(), but that is an unsafe, temporary workaround. To fix
-that, the DRM panel lifetime needs to be reworked. After the rework is
-done, remove devm_drm_put_bridge() and the TODO in
-drm_panel_bridge_remove().
-
-Contact: Maxime Ripard <mripard@kernel.org>,
- Luca Ceresoli <luca.ceresoli@bootlin.com>
-
-Level: Intermediate
-
Convert users of of_drm_find_bridge() to of_drm_find_and_get_bridge()
---------------------------------------------------------------------
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 649f6b6ab5c8..632dccd79e91 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -1737,23 +1737,6 @@ struct drm_bridge *of_drm_get_bridge_by_endpoint(const struct device_node *np,
EXPORT_SYMBOL_GPL(of_drm_get_bridge_by_endpoint);
#endif
-/**
- * devm_drm_put_bridge - Release a bridge reference obtained via devm
- * @dev: device that got the bridge via devm
- * @bridge: pointer to a struct drm_bridge obtained via devm
- *
- * Same as drm_bridge_put() for bridge pointers obtained via devm functions
- * such as devm_drm_bridge_alloc().
- *
- * This function is a temporary workaround and MUST NOT be used. Manual
- * handling of bridge lifetime is inherently unsafe.
- */
-void devm_drm_put_bridge(struct device *dev, struct drm_bridge *bridge)
-{
- devm_release_action(dev, drm_bridge_put_void, bridge);
-}
-EXPORT_SYMBOL(devm_drm_put_bridge);
-
static void drm_bridge_debugfs_show_bridge(struct drm_printer *p,
struct drm_bridge *bridge,
unsigned int idx,
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 11c203391de5..9a688b20bc1e 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -1473,8 +1473,6 @@ void drm_bridge_hpd_disable(struct drm_bridge *bridge);
void drm_bridge_hpd_notify(struct drm_bridge *bridge,
enum drm_connector_status status);
-void devm_drm_put_bridge(struct device *dev, struct drm_bridge *bridge);
-
void drm_bridge_debugfs_params(struct dentry *root);
void drm_bridge_debugfs_encoder_params(struct dentry *root, struct drm_encoder *encoder);
--
2.55.0
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v3 07/19] drm/panel: deprecate panel-bridge APIs
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (5 preceding siblings ...)
2026-09-16 13:45 ` [PATCH v3 06/19] drm/bridge: remove devm_drm_put_bridge() Luca Ceresoli
@ 2026-09-16 13:45 ` Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 08/19] drm/todo: add entry for removing the panel_bridge API Luca Ceresoli
` (11 subsequent siblings)
18 siblings, 0 replies; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, Luca Ceresoli
Now that a drm_bridge is embedded into every drm_panel, the panel_bridge is
not needed anymore. Its APIs are just accessing the embedded drm_bridge
transparently.
Deprecate them all, encouraging to use the drm_bridge API.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
drivers/gpu/drm/drm_panel.c | 31 +++++++++++++++++++++++++------
1 file changed, 25 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
index 707ad9aa907a..c00529bfb706 100644
--- a/drivers/gpu/drm/drm_panel.c
+++ b/drivers/gpu/drm/drm_panel.c
@@ -250,6 +250,9 @@ EXPORT_SYMBOL(drm_bridge_is_panel);
*
* @panel: The drm_panel being wrapped. Must be non-NULL.
*
+ * This function is deprecated. A drm_bridge is embedded into every panel.
+ * Don't use it in new drivers and update your driver to stop using it.
+ *
* For drivers converting from directly using drm_panel: The expected
* usage pattern is that during either encoder module probe or DSI
* host attach, a drm_panel will be looked up through
@@ -287,9 +290,8 @@ EXPORT_SYMBOL(drm_panel_bridge_add);
* This is just like drm_panel_bridge_add(), but forces the connector type to
* @connector_type instead of infering it from the panel.
*
- * This function is deprecated and should not be used in new drivers. Use
- * drm_panel_bridge_add() instead, and fix panel drivers as necessary if they
- * don't report a connector type.
+ * This function is deprecated. A drm_bridge is embedded into every panel.
+ * Don't use it in new drivers and update your driver to stop using it.
*/
struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
u32 connector_type)
@@ -306,6 +308,10 @@ EXPORT_SYMBOL(drm_panel_bridge_add_typed);
* created by drm_panel_bridge_add().
*
* @bridge: The drm_bridge being freed.
+ *
+ * This function is deprecated. A drm_bridge is embedded into every panel
+ * and removed when the panel is removed. Don't use it in new drivers and
+ * update your driver to stop using it.
*/
void drm_panel_bridge_remove(struct drm_bridge *bridge)
{
@@ -355,6 +361,9 @@ static void devm_drm_panel_bridge_release(struct device *dev, void *res)
* @dev: device to tie the bridge lifetime to
* @panel: The drm_panel being wrapped. Must be non-NULL.
*
+ * This function is deprecated. A drm_bridge is embedded into every panel.
+ * Don't use it in new drivers and update your driver to stop using it.
+ *
* This is the managed version of drm_panel_bridge_add() which automatically
* calls drm_panel_bridge_remove() when @dev is unbound.
*/
@@ -379,9 +388,8 @@ EXPORT_SYMBOL(devm_drm_panel_bridge_add);
* This is just like devm_drm_panel_bridge_add(), but forces the connector type
* to @connector_type instead of infering it from the panel.
*
- * This function is deprecated and should not be used in new drivers. Use
- * devm_drm_panel_bridge_add() instead, and fix panel drivers as necessary if
- * they don't report a connector type.
+ * This function is deprecated. A drm_bridge is embedded into every panel.
+ * Don't use it in new drivers and update your driver to stop using it.
*/
struct drm_bridge *devm_drm_panel_bridge_add_typed(struct device *dev,
struct drm_panel *panel,
@@ -422,6 +430,9 @@ static void drmm_drm_panel_bridge_release(struct drm_device *drm, void *ptr)
* @drm: DRM device to tie the bridge lifetime to
* @panel: The drm_panel being wrapped. Must be non-NULL.
*
+ * This function is deprecated. A drm_bridge is embedded into every panel.
+ * Don't use it in new drivers and update your driver to stop using it.
+ *
* This is the DRM-managed version of drm_panel_bridge_add() which
* automatically calls drm_panel_bridge_remove() when @dev is cleaned
* up.
@@ -472,6 +483,10 @@ EXPORT_SYMBOL(drm_panel_bridge_connector);
* @port: port in the device tree node
* @endpoint: endpoint in the device tree node
*
+ * This function is deprecated. A drm_bridge is embedded into every panel.
+ * Don't use it in new drivers and convert your driver to
+ * of_drm_get_bridge_by_endpoint().
+ *
* Given a DT node's port and endpoint number, finds the connected node
* and returns the associated bridge if any, or creates and returns a
* drm panel bridge instance if a panel is connected.
@@ -508,6 +523,10 @@ EXPORT_SYMBOL(devm_drm_of_get_bridge);
* @port: port in the device tree node
* @endpoint: endpoint in the device tree node
*
+ * This function is deprecated. A drm_bridge is embedded into every panel.
+ * Don't use it in new drivers and convert your driver to
+ * of_drm_get_bridge_by_endpoint().
+ *
* Given a DT node's port and endpoint number, finds the connected node
* and returns the associated bridge if any, or creates and returns a
* drm panel bridge instance if a panel is connected.
--
2.55.0
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v3 08/19] drm/todo: add entry for removing the panel_bridge API
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (6 preceding siblings ...)
2026-09-16 13:45 ` [PATCH v3 07/19] drm/panel: deprecate panel-bridge APIs Luca Ceresoli
@ 2026-09-16 13:45 ` Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 09/19] drm/bridge: tc358767: don't create a panel_bridge Luca Ceresoli
` (10 subsequent siblings)
18 siblings, 0 replies; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, Luca Ceresoli
Now that a drm-bridge is embedded into every drm_panel during the panel
creation, the panel_bridge does not really exist anymore. Its API has been
deprecated and kept until drivers convert to the bridge API.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
Documentation/gpu/todo.rst | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst
index cb0ce432c114..a437ae5c71f4 100644
--- a/Documentation/gpu/todo.rst
+++ b/Documentation/gpu/todo.rst
@@ -484,6 +484,31 @@ Contact: Douglas Anderson <dianders@chromium.org>
Level: Starter
+Remove panel_bridge API functions
+---------------------------------
+
+Now that a drm_bridge is embedded into every drm_panel, the panel_bridge is
+not needed anymore. Its APIs are just accessing the embedded drm_bridge
+transparently, and the are deprecated.
+
+The funcions to remove are:
+ - drm_panel_bridge_add_typed()
+ - devm_drm_of_get_bridge()
+ - drmm_of_get_bridge()
+ - drm_panel_bridge_remove()
+ - drmm_drm_panel_bridge_release()
+ - devm_drm_panel_bridge_release()
+ - their direct or indirect callers
+
+Convert users of those functions and eventually remove them when unused, or
+make them static drm_panel.c functions when used internally by the
+``drm_panel.c`` code.
+
+Contact: Luca Ceresoli <luca.ceresoli@bootlin.com>
+ Maxime Ripard <mripard@kernel.org>,
+
+Level: Easy
+
Convert users of of_drm_find_bridge() to of_drm_find_and_get_bridge()
---------------------------------------------------------------------
--
2.55.0
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v3 09/19] drm/bridge: tc358767: don't create a panel_bridge
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (7 preceding siblings ...)
2026-09-16 13:45 ` [PATCH v3 08/19] drm/todo: add entry for removing the panel_bridge API Luca Ceresoli
@ 2026-09-16 13:45 ` Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 10/19] drm/bridge: waveshare-dsi: " Luca Ceresoli
` (9 subsequent siblings)
18 siblings, 0 replies; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, Luca Ceresoli
Now a panel_bridge is automatically created for every drm_panel and the
panel-bridge API is just a deprecated wrapper to access it.
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 89e87460aefc..4766ae85da17 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 [flat|nested] 29+ messages in thread
* [PATCH v3 10/19] drm/bridge: waveshare-dsi: don't create a panel_bridge
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (8 preceding siblings ...)
2026-09-16 13:45 ` [PATCH v3 09/19] drm/bridge: tc358767: don't create a panel_bridge Luca Ceresoli
@ 2026-09-16 13:45 ` Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 11/19] drm/mcde: dsi: remove unused includes Luca Ceresoli
` (8 subsequent siblings)
18 siblings, 0 replies; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, Luca Ceresoli
Now a panel_bridge is automatically created for every drm_panel and the
panel-bridge API is just a deprecated wrapper to access it.
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 [flat|nested] 29+ messages in thread
* [PATCH v3 11/19] drm/mcde: dsi: remove unused includes
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (9 preceding siblings ...)
2026-09-16 13:45 ` [PATCH v3 10/19] drm/bridge: waveshare-dsi: " Luca Ceresoli
@ 2026-09-16 13:45 ` Luca Ceresoli
2026-09-20 22:26 ` Linus Walleij
2026-09-16 13:45 ` [PATCH v3 12/19] drm/mcde: dsi: don't create a panel_bridge Luca Ceresoli
` (7 subsequent siblings)
18 siblings, 1 reply; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, Luca Ceresoli
The helpers are included but unused.
However symbols from drm_atomic_helper.h are used, and were previously
available as a side effect of drm_atomic_helper.h including
drm_atomic_state_helper.h. Add drm_atomic_state_helper.h.
Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
New patch in v2
---
drivers/gpu/drm/mcde/mcde_dsi.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c
index ce078aa3910f..77cf253a2152 100644
--- a/drivers/gpu/drm/mcde/mcde_dsi.c
+++ b/drivers/gpu/drm/mcde/mcde_dsi.c
@@ -11,17 +11,15 @@
#include <linux/regulator/consumer.h>
#include <video/mipi_display.h>
-#include <drm/drm_atomic_helper.h>
+#include <drm/drm_atomic_state_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 [flat|nested] 29+ messages in thread
* [PATCH v3 12/19] drm/mcde: dsi: don't create a panel_bridge
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (10 preceding siblings ...)
2026-09-16 13:45 ` [PATCH v3 11/19] drm/mcde: dsi: remove unused includes Luca Ceresoli
@ 2026-09-16 13:45 ` Luca Ceresoli
2026-09-20 22:26 ` Linus Walleij
2026-09-16 13:45 ` [PATCH v3 13/19] drm/bridge: fsl-ldb: " Luca Ceresoli
` (6 subsequent siblings)
18 siblings, 1 reply; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, Luca Ceresoli
Now a panel_bridge is automatically created for every drm_panel and the
panel-bridge API is just a deprecated wrapper to access it.
Update and simplify the code by just getting a reference to the
already-existing bridge using of_drm_find_and_get_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 77cf253a2152..daac8d67913d 100644
--- a/drivers/gpu/drm/mcde/mcde_dsi.c
+++ b/drivers/gpu/drm/mcde/mcde_dsi.c
@@ -37,7 +37,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;
@@ -1074,7 +1073,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)) {
@@ -1102,40 +1100,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);
@@ -1157,8 +1136,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 [flat|nested] 29+ messages in thread
* [PATCH v3 13/19] drm/bridge: fsl-ldb: don't create a panel_bridge
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (11 preceding siblings ...)
2026-09-16 13:45 ` [PATCH v3 12/19] drm/mcde: dsi: don't create a panel_bridge Luca Ceresoli
@ 2026-09-16 13:45 ` Luca Ceresoli
2026-09-21 14:22 ` Laurentiu Palcu
2026-09-16 13:45 ` [PATCH v3 14/19] drm/bridge: samsung-dsim: " Luca Ceresoli
` (5 subsequent siblings)
18 siblings, 1 reply; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, Luca Ceresoli
Now a panel_bridge is automatically created for every drm_panel and the
panel-bridge API is just a deprecated wrapper to access it.
Update and simplify the code by just getting a reference to the
already-existing bridge using 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 4766ae85da17..0ab3cab92363 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 [flat|nested] 29+ messages in thread
* [PATCH v3 14/19] drm/bridge: samsung-dsim: don't create a panel_bridge
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (12 preceding siblings ...)
2026-09-16 13:45 ` [PATCH v3 13/19] drm/bridge: fsl-ldb: " Luca Ceresoli
@ 2026-09-16 13:45 ` Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 15/19] drm/bridge: tc358768: " Luca Ceresoli
` (4 subsequent siblings)
18 siblings, 0 replies; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, Luca Ceresoli
Now a panel_bridge is automatically created for every drm_panel and the
panel-bridge API is just a deprecated wrapper to access it.
Update and simplify the code by just getting a reference to the
already-existing bridge using of_drm_find_and_get_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 0ab3cab92363..4be220f7335c 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 [flat|nested] 29+ messages in thread
* [PATCH v3 15/19] drm/bridge: tc358768: don't create a panel_bridge
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (13 preceding siblings ...)
2026-09-16 13:45 ` [PATCH v3 14/19] drm/bridge: samsung-dsim: " Luca Ceresoli
@ 2026-09-16 13:45 ` Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 16/19] drm/bridge: ssd2825: " Luca Ceresoli
` (3 subsequent siblings)
18 siblings, 0 replies; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, Luca Ceresoli
Now a panel_bridge is automatically created for every drm_panel and the
panel-bridge API is just a deprecated wrapper to access it.
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 when not used anymore.
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 4be220f7335c..847a6397eb10 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 [flat|nested] 29+ messages in thread
* [PATCH v3 16/19] drm/bridge: ssd2825: don't create a panel_bridge
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (14 preceding siblings ...)
2026-09-16 13:45 ` [PATCH v3 15/19] drm/bridge: tc358768: " Luca Ceresoli
@ 2026-09-16 13:45 ` Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 17/19] drm/omap: dss: " Luca Ceresoli
` (2 subsequent siblings)
18 siblings, 0 replies; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, Luca Ceresoli
Now a panel_bridge is automatically created for every drm_panel and the
panel-bridge API is just a deprecated wrapper to access it.
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 when not used anymore.
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 847a6397eb10..c7da6b02d7b6 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 [flat|nested] 29+ messages in thread
* [PATCH v3 17/19] drm/omap: dss: don't create a panel_bridge
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (15 preceding siblings ...)
2026-09-16 13:45 ` [PATCH v3 16/19] drm/bridge: ssd2825: " Luca Ceresoli
@ 2026-09-16 13:45 ` Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 18/19] drm/tve200: " Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 19/19] drm/bridge: analogix_dp: " Luca Ceresoli
18 siblings, 0 replies; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, Luca Ceresoli
Now a panel_bridge is automatically created for every drm_panel and the
panel-bridge API is just a deprecated wrapper to access it.
Update and simplify the code by just getting a reference to the
already-existing bridge using of_drm_get_bridge_by_endpoint().
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 [flat|nested] 29+ messages in thread
* [PATCH v3 18/19] drm/tve200: don't create a panel_bridge
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (16 preceding siblings ...)
2026-09-16 13:45 ` [PATCH v3 17/19] drm/omap: dss: " Luca Ceresoli
@ 2026-09-16 13:45 ` Luca Ceresoli
2026-09-17 15:14 ` Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 19/19] drm/bridge: analogix_dp: " Luca Ceresoli
18 siblings, 1 reply; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, Luca Ceresoli
Now a panel_bridge is automatically created for every drm_panel and the
panel-bridge API is just a deprecated wrapper to access it.
Update and simplify the code by just getting a reference to the
already-existing bridge using of_drm_get_bridge_by_endpoint().
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 | 30 +++++++-----------------------
3 files changed, 7 insertions(+), 25 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 631a9f5d9aa6..708f8020667a 100644
--- a/drivers/gpu/drm/tve200/tve200_drm.h
+++ b/drivers/gpu/drm/tve200/tve200_drm.h
@@ -103,7 +103,6 @@ struct tve200_drm_dev_private {
struct drm_device *drm;
struct drm_connector *connector;
- struct drm_panel *panel;
struct drm_bridge *bridge;
struct drm_plane plane;
struct drm_crtc crtc;
diff --git a/drivers/gpu/drm/tve200/tve200_drv.c b/drivers/gpu/drm/tve200/tve200_drv.c
index 63ca4a53fc4c..9874554e5065 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");
@@ -121,9 +113,6 @@ static int tve200_modeset_init(struct drm_device *dev)
goto out_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");
@@ -136,8 +125,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;
@@ -233,8 +220,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);
@@ -248,10 +233,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 [flat|nested] 29+ messages in thread
* [PATCH v3 19/19] drm/bridge: analogix_dp: don't create a panel_bridge
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
` (17 preceding siblings ...)
2026-09-16 13:45 ` [PATCH v3 18/19] drm/tve200: " Luca Ceresoli
@ 2026-09-16 13:45 ` Luca Ceresoli
2026-09-21 3:07 ` Damon Ding
18 siblings, 1 reply; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-16 13:45 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Linus Walleij, Inki Dae, Jagan Teki,
Marek Szyprowski, Sean Paul, Jonathan Corbet, Shuah Khan,
Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, Luca Ceresoli
Now a panel_bridge is automatically created for every drm_panel and the
panel-bridge API is just a deprecated wrapper to access it.
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. 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 | 1 -
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(+), 62 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig
index da156fd15764..5672d83cb4a1 100644
--- a/drivers/gpu/drm/bridge/analogix/Kconfig
+++ b/drivers/gpu/drm/bridge/analogix/Kconfig
@@ -33,7 +33,6 @@ config DRM_ANALOGIX_DP
depends on DRM
depends on OF
select DRM_DISPLAY_DP_AUX_BUS
- select DRM_PANEL
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 18e76d1e78e1..6df6963740d2 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>
@@ -1567,15 +1566,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);
@@ -1647,6 +1637,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);
@@ -1655,14 +1650,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 [flat|nested] 29+ messages in thread
* Re: [PATCH v3 18/19] drm/tve200: don't create a panel_bridge
2026-09-16 13:45 ` [PATCH v3 18/19] drm/tve200: " Luca Ceresoli
@ 2026-09-17 15:14 ` Luca Ceresoli
0 siblings, 0 replies; 29+ messages in thread
From: Luca Ceresoli @ 2026-09-17 15:14 UTC (permalink / raw)
To: Luca Ceresoli, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jessica Zhang, Laurentiu Palcu,
Lucas Stach, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Paul Cercueil, Paul Kocialkowski, Linus Walleij,
Inki Dae, Jagan Teki, Marek Szyprowski, Sean Paul,
Jonathan Corbet, Shuah Khan, Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc
Hello,
On Wed Sep 16, 2026 at 3:45 PM CEST, Luca Ceresoli wrote:
> Now a panel_bridge is automatically created for every drm_panel and the
> panel-bridge API is just a deprecated wrapper to access it.
>
> Update and simplify the code by just getting a reference to the
> already-existing bridge using of_drm_get_bridge_by_endpoint().
>
> 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>
I just found this patch fails building on current drm-misc-next due to
another patch landed earlier this week. Will be fixed in v4.
Luca
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3 11/19] drm/mcde: dsi: remove unused includes
2026-09-16 13:45 ` [PATCH v3 11/19] drm/mcde: dsi: remove unused includes Luca Ceresoli
@ 2026-09-20 22:26 ` Linus Walleij
0 siblings, 0 replies; 29+ messages in thread
From: Linus Walleij @ 2026-09-20 22:26 UTC (permalink / raw)
To: Luca Ceresoli
Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Inki Dae, Jagan Teki, Marek Szyprowski,
Sean Paul, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc
On Wed, Sep 16, 2026 at 3:47 PM Luca Ceresoli <luca.ceresoli@bootlin.com> wrote:
> The helpers are included but unused.
>
> However symbols from drm_atomic_helper.h are used, and were previously
> available as a side effect of drm_atomic_helper.h including
> drm_atomic_state_helper.h. Add drm_atomic_state_helper.h.
>
> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3 12/19] drm/mcde: dsi: don't create a panel_bridge
2026-09-16 13:45 ` [PATCH v3 12/19] drm/mcde: dsi: don't create a panel_bridge Luca Ceresoli
@ 2026-09-20 22:26 ` Linus Walleij
0 siblings, 0 replies; 29+ messages in thread
From: Linus Walleij @ 2026-09-20 22:26 UTC (permalink / raw)
To: Luca Ceresoli
Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Laurentiu Palcu, Lucas Stach, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Paul Cercueil,
Paul Kocialkowski, Inki Dae, Jagan Teki, Marek Szyprowski,
Sean Paul, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc
On Wed, Sep 16, 2026 at 3:47 PM Luca Ceresoli <luca.ceresoli@bootlin.com> wrote:
> Now a panel_bridge is automatically created for every drm_panel and the
> panel-bridge API is just a deprecated wrapper to access it.
>
> Update and simplify the code by just getting a reference to the
> already-existing bridge using of_drm_find_and_get_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>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3 19/19] drm/bridge: analogix_dp: don't create a panel_bridge
2026-09-16 13:45 ` [PATCH v3 19/19] drm/bridge: analogix_dp: " Luca Ceresoli
@ 2026-09-21 3:07 ` Damon Ding
2026-09-21 6:34 ` Damon Ding
0 siblings, 1 reply; 29+ messages in thread
From: Damon Ding @ 2026-09-21 3:07 UTC (permalink / raw)
To: Luca Ceresoli, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jessica Zhang, Laurentiu Palcu,
Lucas Stach, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Paul Cercueil, Paul Kocialkowski, Linus Walleij,
Inki Dae, Jagan Teki, Marek Szyprowski, Sean Paul,
Jonathan Corbet, Shuah Khan, Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, Heiko Stuebner
Hi Luca,
On 9/16/2026 9:45 PM, Luca Ceresoli wrote:
> Now a panel_bridge is automatically created for every drm_panel and the
> panel-bridge API is just a deprecated wrapper to access it.
>
> 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. 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 | 1 -
> 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(+), 62 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/analogix/Kconfig b/drivers/gpu/drm/bridge/analogix/Kconfig
> index da156fd15764..5672d83cb4a1 100644
> --- a/drivers/gpu/drm/bridge/analogix/Kconfig
> +++ b/drivers/gpu/drm/bridge/analogix/Kconfig
> @@ -33,7 +33,6 @@ config DRM_ANALOGIX_DP
> depends on DRM
> depends on OF
> select DRM_DISPLAY_DP_AUX_BUS
> - select DRM_PANEL
>
> 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 18e76d1e78e1..6df6963740d2 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>
>
> @@ -1567,15 +1566,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);
> @@ -1647,6 +1637,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);
> @@ -1655,14 +1650,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;
> - }
> -
TIP: In my WIP v3 patch series, I use of_drm_find_panel() together with
devm_drm_panel_bridge_add() to maintain this backward compatibility. But
I also think this old approach should be deprecated now. Shall we add
some notes in the commit message to mention the deprecation of this method?
> 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;
>
I apply this patch series with the related one[0], and the eDP work well
on my RK3576 board.
Tested-by: Damon Ding <damon.ding@rock-chips.com>
In my patch series for Analogix DP HPD support, Heiko also pointed out
that devm_drm_of_get_bridge()(deprecated now) can be used to get the
panel bridge directly, and the redundant &analogix_dp_plat_data.panel
can be removed[1]. Since your patch series already contains these
optimizations, I will rebase my patch series on top of yours for
subsequent updates.
Reviewed-by: Damon Ding <damon.ding@rock-chips.com>
[0]
https://lore.kernel.org/all/20260915-drm-bridge-drm_panel-cleanup-v4-0-30401d9406f3@bootlin.com/
[1] https://lore.kernel.org/all/5609825.iZASKD2KPV@diego/
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3 19/19] drm/bridge: analogix_dp: don't create a panel_bridge
2026-09-21 3:07 ` Damon Ding
@ 2026-09-21 6:34 ` Damon Ding
0 siblings, 0 replies; 29+ messages in thread
From: Damon Ding @ 2026-09-21 6:34 UTC (permalink / raw)
To: Luca Ceresoli, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jessica Zhang, Laurentiu Palcu,
Lucas Stach, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Paul Cercueil, Paul Kocialkowski, Linus Walleij,
Inki Dae, Jagan Teki, Marek Szyprowski, Sean Paul,
Jonathan Corbet, Shuah Khan, Randy Dunlap
Cc: Albert Esteve, Anusha Srivatsa, Dmitry Baryshkov, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel, linux-mips, linux-rockchip, linux-stm32, asahi,
linux-arm-msm, freedreno, linux-tegra, linux-doc,
linux-samsung-soc, Heiko Stuebner
On 9/21/2026 11:07 AM, Damon Ding wrote:
> Hi Luca,
>
> On 9/16/2026 9:45 PM, Luca Ceresoli wrote:
>> Now a panel_bridge is automatically created for every drm_panel and the
>> panel-bridge API is just a deprecated wrapper to access it.
>>
>> 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. 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 | 1 -
>> 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(+), 62 deletions(-)
>>
[snip]
>> @@ -488,14 +487,6 @@ static void rockchip_dp_remove(struct
>> platform_device *pdev)
>> {
>> struct rockchip_dp_device *dp = platform_get_drvdata(pdev);
The above unused &rockchip_dp_device could be also remved.
>> - /*
>> - * 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;
>>
>
> I apply this patch series with the related one[0], and the eDP work well
> on my RK3576 board.
>
> Tested-by: Damon Ding <damon.ding@rock-chips.com>
>
> In my patch series for Analogix DP HPD support, Heiko also pointed out
> that devm_drm_of_get_bridge()(deprecated now) can be used to get the
> panel bridge directly, and the redundant &analogix_dp_plat_data.panel
> can be removed[1]. Since your patch series already contains these
> optimizations, I will rebase my patch series on top of yours for
> subsequent updates.
>
> Reviewed-by: Damon Ding <damon.ding@rock-chips.com>
>
> [0] https://lore.kernel.org/all/20260915-drm-bridge-drm_panel-cleanup-
> v4-0-30401d9406f3@bootlin.com/
> [1] https://lore.kernel.org/all/5609825.iZASKD2KPV@diego/
>
Best regards,
Damon
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3 13/19] drm/bridge: fsl-ldb: don't create a panel_bridge
2026-09-16 13:45 ` [PATCH v3 13/19] drm/bridge: fsl-ldb: " Luca Ceresoli
@ 2026-09-21 14:22 ` Laurentiu Palcu
0 siblings, 0 replies; 29+ messages in thread
From: Laurentiu Palcu @ 2026-09-21 14:22 UTC (permalink / raw)
To: Luca Ceresoli
Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jessica Zhang,
Lucas Stach, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Paul Cercueil, Paul Kocialkowski, Linus Walleij,
Inki Dae, Jagan Teki, Marek Szyprowski, Sean Paul,
Jonathan Corbet, Shuah Khan, Randy Dunlap, Albert Esteve,
Anusha Srivatsa, Dmitry Baryshkov, Hui Pu, Ian Ray,
Thomas Petazzoni, dri-devel, linux-kernel, imx, linux-arm-kernel,
linux-mips, linux-rockchip, linux-stm32, asahi, linux-arm-msm,
freedreno, linux-tegra, linux-doc, linux-samsung-soc
Hi Luca,
On Wed, Sep 16, 2026 at 03:45:37PM +0200, Luca Ceresoli wrote:
> Now a panel_bridge is automatically created for every drm_panel and the
> panel-bridge API is just a deprecated wrapper to access it.
>
> Update and simplify the code by just getting a reference to the
> already-existing bridge using 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>
Reviewed-by: Laurentiu Palcu <laurentiu.palcu@oss.nxp.com>
--
Thanks,
Laurentiu
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3 01/19] drm: of: move drm_of_find_panel_or_bridge() from drm_of.c to drm_panel.c
2026-09-16 13:45 ` [PATCH v3 01/19] drm: of: move drm_of_find_panel_or_bridge() from drm_of.c to drm_panel.c Luca Ceresoli
@ 2026-09-21 15:06 ` Maxime Ripard
0 siblings, 0 replies; 29+ messages in thread
From: Maxime Ripard @ 2026-09-21 15:06 UTC (permalink / raw)
To: Luca Ceresoli
Cc: asahi, dri-devel, freedreno, imx, linux-arm-kernel,
linux-arm-msm, linux-doc, linux-kernel, linux-mips,
linux-rockchip, linux-samsung-soc, linux-stm32, linux-tegra,
Albert Esteve, Andrzej Hajda, Anusha Srivatsa, David Airlie,
Dmitry Baryshkov, Fabio Estevam, Frank Li, Hui Pu, Ian Ray,
Inki Dae, Jagan Teki, Jernej Skrabec, Jessica Zhang,
Jonas Karlman, Jonathan Corbet, Laurent Pinchart,
Laurentiu Palcu, Linus Walleij, Lucas Stach, Maarten Lankhorst,
Marek Szyprowski, Maxime Ripard, Neil Armstrong, Paul Cercueil,
Paul Kocialkowski, Pengutronix Kernel Team, Randy Dunlap,
Robert Foss, Sascha Hauer, Sean Paul, Shuah Khan, Simona Vetter,
Thomas Petazzoni, Thomas Zimmermann
On Wed, 16 Sep 2026 15:45:25 +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() (drm_of.c, drm module)
>
> [ ... ]
Acked-by: Maxime Ripard <mripard@kernel.org>
Thanks!
Maxime
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3 02/19] drm: of: remove now unnecessary forward declarations
2026-09-16 13:45 ` [PATCH v3 02/19] drm: of: remove now unnecessary forward declarations Luca Ceresoli
@ 2026-09-21 15:06 ` Maxime Ripard
0 siblings, 0 replies; 29+ messages in thread
From: Maxime Ripard @ 2026-09-21 15:06 UTC (permalink / raw)
To: Luca Ceresoli
Cc: asahi, dri-devel, freedreno, imx, linux-arm-kernel,
linux-arm-msm, linux-doc, linux-kernel, linux-mips,
linux-rockchip, linux-samsung-soc, linux-stm32, linux-tegra,
Albert Esteve, Andrzej Hajda, Anusha Srivatsa, David Airlie,
Dmitry Baryshkov, Fabio Estevam, Frank Li, Hui Pu, Ian Ray,
Inki Dae, Jagan Teki, Jernej Skrabec, Jessica Zhang,
Jonas Karlman, Jonathan Corbet, Laurent Pinchart,
Laurentiu Palcu, Linus Walleij, Lucas Stach, Maarten Lankhorst,
Marek Szyprowski, Maxime Ripard, Neil Armstrong, Paul Cercueil,
Paul Kocialkowski, Pengutronix Kernel Team, Randy Dunlap,
Robert Foss, Sascha Hauer, Sean Paul, Shuah Khan, Simona Vetter,
Thomas Petazzoni, Thomas Zimmermann
On Wed, 16 Sep 2026 15:45:26 +0200, Luca Ceresoli wrote:
> These forward declarations are now redundant after having moved
> drm_of_find_panel_or_bridge():
>
> * struct drm_panel is not referenced in this file
>
>
> [ ... ]
Acked-by: Maxime Ripard <mripard@kernel.org>
Thanks!
Maxime
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v3 04/19] drm/bridge: panel: move all code to drm_panel.c
2026-09-16 13:45 ` [PATCH v3 04/19] drm/bridge: panel: move all code to drm_panel.c Luca Ceresoli
@ 2026-09-21 15:08 ` Maxime Ripard
0 siblings, 0 replies; 29+ messages in thread
From: Maxime Ripard @ 2026-09-21 15:08 UTC (permalink / raw)
To: Luca Ceresoli
Cc: asahi, dri-devel, freedreno, imx, linux-arm-kernel,
linux-arm-msm, linux-doc, linux-kernel, linux-mips,
linux-rockchip, linux-samsung-soc, linux-stm32, linux-tegra,
Albert Esteve, Andrzej Hajda, Anusha Srivatsa, David Airlie,
Dmitry Baryshkov, Fabio Estevam, Frank Li, Hui Pu, Ian Ray,
Inki Dae, Jagan Teki, Jernej Skrabec, Jessica Zhang,
Jonas Karlman, Jonathan Corbet, Laurent Pinchart,
Laurentiu Palcu, Linus Walleij, Lucas Stach, Maarten Lankhorst,
Marek Szyprowski, Maxime Ripard, Neil Armstrong, Paul Cercueil,
Paul Kocialkowski, Pengutronix Kernel Team, Randy Dunlap,
Robert Foss, Sascha Hauer, Sean Paul, Shuah Khan, Simona Vetter,
Thomas Petazzoni, Thomas Zimmermann
On Wed, 16 Sep 2026 15:45:28 +0200, Luca Ceresoli wrote:
> Work is in progress for every drm_panel to embed a drm_bridge, replacing
> the panel_bridge entirely. However most of the panel_bridge code will be
> reused for the drm_bridge embedded into the drm_panel, so just move the
> code there.
>
>
> [ ... ]
Acked-by: Maxime Ripard <mripard@kernel.org>
Thanks!
Maxime
^ permalink raw reply [flat|nested] 29+ messages in thread
end of thread, other threads:[~2026-09-21 15:08 UTC | newest]
Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-16 13:45 [PATCH v3 00/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 01/19] drm: of: move drm_of_find_panel_or_bridge() from drm_of.c to drm_panel.c Luca Ceresoli
2026-09-21 15:06 ` Maxime Ripard
2026-09-16 13:45 ` [PATCH v3 02/19] drm: of: remove now unnecessary forward declarations Luca Ceresoli
2026-09-21 15:06 ` Maxime Ripard
2026-09-16 13:45 ` [PATCH v3 03/19] drm/panel: move to a new module Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 04/19] drm/bridge: panel: move all code to drm_panel.c Luca Ceresoli
2026-09-21 15:08 ` Maxime Ripard
2026-09-16 13:45 ` [PATCH v3 05/19] drm/panel: embed a drm_bridge into every drm_panel Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 06/19] drm/bridge: remove devm_drm_put_bridge() Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 07/19] drm/panel: deprecate panel-bridge APIs Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 08/19] drm/todo: add entry for removing the panel_bridge API Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 09/19] drm/bridge: tc358767: don't create a panel_bridge Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 10/19] drm/bridge: waveshare-dsi: " Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 11/19] drm/mcde: dsi: remove unused includes Luca Ceresoli
2026-09-20 22:26 ` Linus Walleij
2026-09-16 13:45 ` [PATCH v3 12/19] drm/mcde: dsi: don't create a panel_bridge Luca Ceresoli
2026-09-20 22:26 ` Linus Walleij
2026-09-16 13:45 ` [PATCH v3 13/19] drm/bridge: fsl-ldb: " Luca Ceresoli
2026-09-21 14:22 ` Laurentiu Palcu
2026-09-16 13:45 ` [PATCH v3 14/19] drm/bridge: samsung-dsim: " Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 15/19] drm/bridge: tc358768: " Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 16/19] drm/bridge: ssd2825: " Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 17/19] drm/omap: dss: " Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 18/19] drm/tve200: " Luca Ceresoli
2026-09-17 15:14 ` Luca Ceresoli
2026-09-16 13:45 ` [PATCH v3 19/19] drm/bridge: analogix_dp: " Luca Ceresoli
2026-09-21 3:07 ` Damon Ding
2026-09-21 6:34 ` Damon Ding
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®