Skip to contentSkip to conversation

drm/panel: embed a drm_bridge into every drm_panel

PATCH In review Luca Ceresoli 7 participants 59 messages Sep 16 – Nov 11

Subsystems (32)
lore
Share & tools
lore

Luca Ceresoli

author reviewer
#0 lore raw

v3 cover drm/panel: embed a drm_bridge into every drm_panel

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/[email protected]/#t

[1] https://lore.kernel.org/all/emuj2innmp6zmzd7pyakqzjqpdzhly6qfhakya3ydwmd63pl26@5jwxaidpikjw/
[2] https://lore.kernel.org/lkml/[email protected]/

---
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/[email protected]

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/[email protected]

---
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,

Signature · 3 lines
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
author reviewer
#1 lore raw

PATCH v3 1/19 drm: of: move drm_of_find_panel_or_bridge() from drm_of.c to drm_panel.c

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.

---
 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(-)
drivers/gpu/drm/bridge/Kconfig +2 -0
index f2db7f60d40f..89e87460aefc 100644
@@ -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
drivers/gpu/drm/bridge/analogix/Kconfig +2 -0
index 57bb2daa5aaf..da156fd15764 100644
@@ -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"
drivers/gpu/drm/drm_of.c +0 -63

69 lines not on this page · raw message

drivers/gpu/drm/drm_panel.c +63 -0

69 lines not on this page · raw message

drivers/gpu/drm/imx/dcss/Kconfig +1 -0
index e014ed3ae66c..d278bebfc33c 100644
@@ -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
drivers/gpu/drm/ingenic/Kconfig +1 -0
index 04ecfb0c5dd6..987ed42f6f7a 100644
@@ -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
drivers/gpu/drm/logicvc/Kconfig +1 -0
index 579a358ed5cf..53bd1ae61c83 100644
@@ -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
drivers/gpu/drm/mcde/Kconfig +1 -0
index 3516c8d2a5d9..6ebfb930cbfa 100644
@@ -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
drivers/gpu/drm/pl111/Kconfig +1 -0
index 82e918820950..20201ec20aa7 100644
@@ -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.
drivers/gpu/drm/rockchip/Kconfig +2 -0
index e7f49fe845ea..1b4a87eeaf3f 100644
@@ -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
drivers/gpu/drm/stm/Kconfig +1 -0
index 635be0ac00af..1e3205aa2c7e 100644
@@ -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
drivers/gpu/drm/tidss/Kconfig +1 -0
index 31ad582b7602..52a64fa1ad5d 100644
@@ -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
drivers/gpu/drm/tve200/Kconfig +1 -0
index a9d6fe535d88..c0746ae8f703 100644
@@ -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
include/drm/drm_of.h +0 -12
index ebebed14c611..402f5db11e47 100644
@@ -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)
include/drm/drm_panel.h +13 -0
index b87323443f49..bf15e40fd796 100644
@@ -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)
Signature · 1 line
2.55.0
maintainer Acked-by on v3 1/19
#2 lore raw

Re: [PATCH v3 01/19] drm: of: move drm_of_find_panel_or_bridge() from drm_of.c to drm_panel.c

Quoted 7 lines · 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)

[ ... ]

Thanks!
Maxime

author reviewer
#3 lore raw

PATCH v3 2/19 drm: of: remove now unnecessary forward declarations

In reply to 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
---
 include/drm/drm_of.h | 2 --
 1 file changed, 2 deletions(-)
include/drm/drm_of.h +0 -2
index 402f5db11e47..f6dad2c6e9b9 100644
@@ -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;
Signature · 1 line
2.55.0
maintainer Acked-by on v3 2/19
#4 lore raw

Re: [PATCH v3 02/19] drm: of: remove now unnecessary forward declarations

Quoted 7 lines · 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

[ ... ]

Thanks!
Maxime

author reviewer
#5 lore raw

PATCH v3 3/19 drm/panel: move to a new module

In reply to 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.

---
 drivers/gpu/drm/Makefile      | 2 +-
 drivers/gpu/drm/panel/Kconfig | 2 +-
 include/drm/drm_panel.h       | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)
drivers/gpu/drm/Makefile +1 -1
index e635fcffd379..29c9c1d90c11 100644
@@ -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
 
drivers/gpu/drm/panel/Kconfig +1 -1
index 747f47347521..0a79a0558101 100644
@@ -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.
include/drm/drm_panel.h +2 -2
index bf15e40fd796..34fcbcdda2c8 100644
@@ -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);
Signature · 1 line
2.55.0
author reviewer
#6 lore raw

PATCH v3 4/19 drm/bridge: panel: move all code to drm_panel.c

In reply to 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.

---
 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(-)
drivers/gpu/drm/Makefile +0 -1
index 29c9c1d90c11..4ac7b909bd61 100644
@@ -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
 
drivers/gpu/drm/adp/adp-mipi.c +1 -0
index 232bb9539423..956533870781 100644
@@ -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
drivers/gpu/drm/arm/display/komeda/komeda_crtc.c +1 -0
index 3d81b413efae..0fd069fc3386 100644
@@ -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"
drivers/gpu/drm/bridge/aux-bridge.c +1 -0
index 169939d23310..90f76bb529cc 100644
@@ -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);
 
drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c +1 -0
index c3e466ded84a..1e28ea579b06 100644
@@ -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>
drivers/gpu/drm/bridge/imx/imx93-pdfc.c +1 -0
index 2d6ca95ed554..2e5019ed951a 100644
@@ -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)
drivers/gpu/drm/bridge/panel.c deleted +0 -563

563 lines not on this page · raw message

drivers/gpu/drm/bridge/ti-tdp158.c +1 -0
index 01fc643bd78f..8e3e99cbe41a 100644
@@ -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;
drivers/gpu/drm/display/drm_bridge_connector.c +1 -0
index 00feb73e63d7..5b92ba848fa0 100644
@@ -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>
drivers/gpu/drm/drm_panel.c +555 -19

597 lines not on this page · raw message

drivers/gpu/drm/imx/dc/dc-kms.c +1 -0
index a9adcfc68b84..0e2ce6a42548 100644
@@ -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>
drivers/gpu/drm/mcde/mcde_display.c +1 -0
index d1d01f3d8ab4..b2455391bdd7 100644
@@ -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>
drivers/gpu/drm/msm/dp/dp_display.c +1 -0
index bc646d172abe..525c188ac951 100644
@@ -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"
drivers/gpu/drm/msm/dsi/dsi.c +2 -1
index 3c9f01ed6271..c726fc628a08 100644
@@ -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);
 }
-
drivers/gpu/drm/tegra/rgb.c +1 -0
index bc1c93c7554c..b6d09a8d8e5e 100644
@@ -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"
include/drm/drm_bridge.h +0 -52

58 lines not on this page · raw message

include/drm/drm_of.h +1 -0
index f6dad2c6e9b9..002ba1b18eb1 100644
@@ -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;
include/drm/drm_panel.h +53 -0

63 lines not on this page · raw message

Signature · 1 line
2.55.0
maintainer Acked-by on v3 4/19
#7 lore raw

Re: [PATCH v3 04/19] drm/bridge: panel: move all code to drm_panel.c

Quoted 7 lines · 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.

[ ... ]

Thanks!
Maxime

author reviewer
#8 lore raw

PATCH v3 5/19 drm/panel: embed a drm_bridge into every drm_panel

In reply to 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().

---

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(-)
drivers/gpu/drm/drm_panel.c +78 -106
index 30e7dc81dd15..707ad9aa907a 100644
@@ -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)
include/drm/drm_panel.h +18 -11
index bede046fb281..58113ea7d63a 100644
@@ -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,
Signature · 1 line
2.55.0
maintainer Acked-by on v3 5/19
#9 lore raw
Quoted 7 lines · 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.

[ ... ]

Thanks!
Maxime

author reviewer
#10 lore raw

PATCH v3 6/19 drm/bridge: remove devm_drm_put_bridge()

In reply to Luca Ceresoli

The deprecated devm_drm_put_bridge() function is not used anymore.

---
 Documentation/gpu/todo.rst   | 16 ----------------
 drivers/gpu/drm/drm_bridge.c | 17 -----------------
 include/drm/drm_bridge.h     |  2 --
 3 files changed, 35 deletions(-)
Documentation/gpu/todo.rst +0 -16
index b7351467dc74..cb0ce432c114 100644
@@ -484,22 +484,6 @@ Contact: Douglas Anderson <[email protected]>
 
 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 <[email protected]>,
-         Luca Ceresoli <[email protected]>
-
-Level: Intermediate
-
 Convert users of of_drm_find_bridge() to of_drm_find_and_get_bridge()
 ---------------------------------------------------------------------
 
drivers/gpu/drm/drm_bridge.c +0 -17
index 649f6b6ab5c8..632dccd79e91 100644
@@ -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,
include/drm/drm_bridge.h +0 -2
index 11c203391de5..9a688b20bc1e 100644
@@ -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);
 
Signature · 1 line
2.55.0
author reviewer
#12 lore raw

PATCH v3 7/19 drm/panel: deprecate panel-bridge APIs

In reply to 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.

---
 drivers/gpu/drm/drm_panel.c | 31 +++++++++++++++++++++++++------
 1 file changed, 25 insertions(+), 6 deletions(-)
drivers/gpu/drm/drm_panel.c +25 -6
index 707ad9aa907a..c00529bfb706 100644
@@ -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.
Signature · 1 line
2.55.0
maintainer Acked-by on v3 7/19
#13 lore raw

Re: [PATCH v3 07/19] drm/panel: deprecate panel-bridge APIs

Quoted 7 lines · 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.

[ ... ]

Thanks!
Maxime

maintainer Reviewed-by on v3 7/19
#14 lore raw

Re: [PATCH v3 07/19] drm/panel: deprecate panel-bridge APIs

In reply to Luca Ceresoli
Quoted 7 lines · 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.

Yours,
Linus Walleij

author reviewer
#15 lore raw

PATCH v3 8/19 drm/todo: add entry for removing the panel_bridge API

In reply to 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.

---
 Documentation/gpu/todo.rst | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)
Documentation/gpu/todo.rst +25 -0
index cb0ce432c114..a437ae5c71f4 100644
@@ -484,6 +484,31 @@ Contact: Douglas Anderson <[email protected]>
 
 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 <[email protected]>
+         Maxime Ripard <[email protected]>,
+
+Level: Easy
+
 Convert users of of_drm_find_bridge() to of_drm_find_and_get_bridge()
 ---------------------------------------------------------------------
 
Signature · 1 line
2.55.0
maintainer Acked-by on v3 8/19
#16 lore raw

Re: [PATCH v3 08/19] drm/todo: add entry for removing the panel_bridge API

Quoted 7 lines · 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.

[ ... ]

Thanks!
Maxime

maintainer Reviewed-by on v3 8/19
#17 lore raw

Re: [PATCH v3 08/19] drm/todo: add entry for removing the panel_bridge API

In reply to Luca Ceresoli
Quoted 5 lines · 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.

Yours,
Linus Walleij

author reviewer
#18 lore raw

PATCH v3 9/19 drm/bridge: tc358767: don't create a panel_bridge

In reply to 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.

---
 drivers/gpu/drm/bridge/Kconfig    |  2 --
 drivers/gpu/drm/bridge/tc358767.c | 64 ++++++++++++---------------------------
 2 files changed, 20 insertions(+), 46 deletions(-)
drivers/gpu/drm/bridge/Kconfig +0 -2
index 89e87460aefc..4766ae85da17 100644
@@ -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.
 
drivers/gpu/drm/bridge/tc358767.c +20 -44

121 lines not on this page · raw message

Signature · 1 line
2.55.0
maintainer Acked-by on v3 9/19
#19 lore raw

Re: [PATCH v3 09/19] drm/bridge: tc358767: don't create a panel_bridge

Quoted 7 lines · 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().

[ ... ]

Thanks!
Maxime

author reviewer
#20 lore raw

PATCH v3 10/19 drm/bridge: waveshare-dsi: don't create a panel_bridge

In reply to 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.

---
 drivers/gpu/drm/bridge/waveshare-dsi.c | 17 +++++------------
 1 file changed, 5 insertions(+), 12 deletions(-)
drivers/gpu/drm/bridge/waveshare-dsi.c +5 -12
index 420f3b870a74..2c40bfef2b45 100644
@@ -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)) {
Signature · 1 line
2.55.0
maintainer Acked-by on v3 10/19
#21 lore raw

Re: [PATCH v3 10/19] drm/bridge: waveshare-dsi: don't create a panel_bridge

Quoted 7 lines · 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().

[ ... ]

Thanks!
Maxime

author reviewer
#22 lore raw

PATCH v3 11/19 drm/mcde: dsi: remove unused includes

In reply to 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.

---

New patch in v2

---
 drivers/gpu/drm/mcde/mcde_dsi.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/gpu/drm/mcde/mcde_dsi.c +1 -3
index ce078aa3910f..77cf253a2152 100644
@@ -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"
Signature · 1 line
2.55.0
maintainer Reviewed-by on v3 11/19
#23 lore raw

Re: [PATCH v3 11/19] drm/mcde: dsi: remove unused includes

Quoted 7 lines · 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.

Yours,
Linus Walleij

maintainer Acked-by on v3 11/19
#24 lore raw

Re: [PATCH v3 11/19] drm/mcde: dsi: remove unused includes

In reply to Luca Ceresoli
Quoted 7 lines · 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.

[ ... ]

Thanks!
Maxime

author reviewer
#25 lore raw

PATCH v3 12/19 drm/mcde: dsi: don't create a panel_bridge

In reply to 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.

---
 drivers/gpu/drm/mcde/Kconfig    |  1 -
 drivers/gpu/drm/mcde/mcde_dsi.c | 41 +++++++++--------------------------------
 2 files changed, 9 insertions(+), 33 deletions(-)
drivers/gpu/drm/mcde/Kconfig +0 -1
index 6ebfb930cbfa..81e7d3796c06 100644
@@ -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
drivers/gpu/drm/mcde/mcde_dsi.c +9 -32

71 lines not on this page · raw message

Signature · 1 line
2.55.0
maintainer Reviewed-by on v3 12/19
#26 lore raw

Re: [PATCH v3 12/19] drm/mcde: dsi: don't create a panel_bridge

Quoted 10 lines · 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.

Yours,
Linus Walleij

maintainer
#27 lore raw

Re: [PATCH v3 12/19] drm/mcde: dsi: don't create a panel_bridge

In reply to Luca Ceresoli
Quoted 81 lines · 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.

---
 drivers/gpu/drm/mcde/Kconfig    |  1 -
 drivers/gpu/drm/mcde/mcde_dsi.c | 41 +++++++++--------------------------------
 2 files changed, 9 insertions(+), 33 deletions(-)
drivers/gpu/drm/mcde/Kconfig +0 -1
index 6ebfb930cbfa..81e7d3796c06 100644
@@ -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
drivers/gpu/drm/mcde/mcde_dsi.c +5 -24
index 77cf253a2152..daac8d67913d 100644
@@ -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);

drivers/gpu/drm/mcde/mcde_dsi.c static int mcde_dsi_bind(struct device *dev, struct device *master, · line 1117

Quoted 10 lines
drivers/gpu/drm/mcde/mcde_dsi.c +4 -3
-		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;

I wonder if we still need that branch. Every panel is a bridge now, and it looks like we don't have any specific panel handling in this driver, so I guess it supports bridges already?

Linus, do you know why this condition was here in the first place?

Maxime

author reviewer
#28 lore raw

Re: [PATCH v3 12/19] drm/mcde: dsi: don't create a panel_bridge

Hi Linus, Maxime,

Quoted 11 lines · Maxime Ripard
Quoted 10 lines · 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.

[...]

Quoted 49 lines
Quoted 34 lines
drivers/gpu/drm/mcde/mcde_dsi.c +5 -22
@@ -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);

drivers/gpu/drm/mcde/mcde_dsi.c static int mcde_dsi_bind(struct device *dev, struct device *master, · line 1117

Quoted 10 lines
drivers/gpu/drm/mcde/mcde_dsi.c +4 -3
-		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;

I wonder if we still need that branch. Every panel is a bridge now, and it looks like we don't have any specific panel handling in this driver, so I guess it supports bridges already?

Quoted 1 line

Linus, do you know why this condition was here in the first place?

I had the same thought while writing the patch, but I chose to be conservative.

Linus, unless you have more info I'm going to apply the patch as is. Removing this special case would be welcome as a later patch.

Luca

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

maintainer
#29 lore raw

Re: [PATCH v3 12/19] drm/mcde: dsi: don't create a panel_bridge

Hi Luca,

sorry for my slowness!

Quoted 15 lines · Luca Ceresoli
Quoted 13 lines · Maxime Ripard

drivers/gpu/drm/mcde/mcde_dsi.c static int mcde_dsi_bind(struct device *dev, struct device *master, · line 1117

Quoted 8 lines
drivers/gpu/drm/mcde/mcde_dsi.c +4 -1
-    } 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;

I wonder if we still need that branch. Every panel is a bridge now, and it looks like we don't have any specific panel handling in this driver, so I guess it supports bridges already?

Quoted 7 lines
Quoted 1 line

Linus, do you know why this condition was here in the first place?

I had the same thought while writing the patch, but I chose to be conservative.

Linus, unless you have more info I'm going to apply the patch as is. Removing this special case would be welcome as a later patch.

I'd say go ahead as-is.

I do have the idea to code up and submit the AV8100 encoder and I have the hardware to test it, but every other user should be using panels directly, and I would be the only non-panel user so I can deal with it when it comes up.

Yours,
Linus Walleij

maintainer
#30 lore raw

Re: [PATCH v3 12/19] drm/mcde: dsi: don't create a panel_bridge

Quoted 22 lines · Linus Walleij

Hi Luca,

sorry for my slowness!

Quoted 17 lines · Luca Ceresoli
Quoted 14 lines · Maxime Ripard

drivers/gpu/drm/mcde/mcde_dsi.c static int mcde_dsi_bind(struct device *dev, struct device *master, · line 1117

Quoted 8 lines
drivers/gpu/drm/mcde/mcde_dsi.c +4 -1
-    } 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;

I wonder if we still need that branch. Every panel is a bridge now, and it looks like we don't have any specific panel handling in this driver, so I guess it supports bridges already?

Linus, do you know why this condition was here in the first place?

Quoted 7 lines
Quoted 5 lines

I had the same thought while writing the patch, but I chose to be conservative.

Linus, unless you have more info I'm going to apply the patch as is. Removing this special case would be welcome as a later patch.

I'd say go ahead as-is.

I'm fine with that, but I really want this removed at some point.

Quoted 4 lines

I do have the idea to code up and submit the AV8100 encoder and I have the hardware to test it, but every other user should be using panels directly, and I would be the only non-panel user so I can deal with it when it comes up.

It won't change a thing. All existing "panel" users will be bridge users after this patch is merged. So whether you want to enable a bridge or not shouldn't matter, the only thing that does is whether the existing users would still work.

Maxime

maintainer
#31 lore raw

Re: [PATCH v3 12/19] drm/mcde: dsi: don't create a panel_bridge

Quoted 8 lines · Maxime Ripard
Quoted 4 lines · Linus Walleij
Quoted 2 lines

Linus, unless you have more info I'm going to apply the patch as is. Removing this special case would be welcome as a later patch.

I'd say go ahead as-is.

I'm fine with that, but I really want this removed at some point.

If Luca wanna fix this up (drop this path) that's fine by me, else send a patch immediately after this is applied and I'll ACK it.

Quoted 9 lines
Quoted 4 lines

I do have the idea to code up and submit the AV8100 encoder and I have the hardware to test it, but every other user should be using panels directly, and I would be the only non-panel user so I can deal with it when it comes up.

It won't change a thing. All existing "panel" users will be bridge users after this patch is merged. So whether you want to enable a bridge or not shouldn't matter, the only thing that does is whether the existing users would still work.

I know, all it does is create a snag that I would run into myself.

But it's not gonna be a problem for anyone else, that's all I meant.

Yours,
Linus Walleij

author reviewer
#32 lore raw

Re: [PATCH v3 12/19] drm/mcde: dsi: don't create a panel_bridge

Hello Linus,

Quoted 6 lines · Linus Walleij
Quoted 5 lines · Maxime Ripard
Quoted 3 lines · Linus Walleij
Quoted 2 lines

Linus, unless you have more info I'm going to apply the patch as is. Removing this special case would be welcome as a later patch.

Quoted 7 lines
Quoted 3 lines
Quoted 1 line

I'd say go ahead as-is.

I'm fine with that, but I really want this removed at some point.

If Luca wanna fix this up (drop this path) that's fine by me, else send a patch immediately after this is applied and I'll ACK it.

To avoid postponing this series I plan to apply as is on Monday. I can send another patch later to remove the !panel case.

Thanks for the feedback!

Luca

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

maintainer
#33 lore raw

Re: [PATCH v3 12/19] drm/mcde: dsi: don't create a panel_bridge

Quoted 11 lines · Luca Ceresoli

Hello Linus,

Quoted 8 lines · Linus Walleij
Quoted 7 lines · Maxime Ripard
Quoted 4 lines · Linus Walleij
Quoted 2 lines

Linus, unless you have more info I'm going to apply the patch as is. Removing this special case would be welcome as a later patch.

I'd say go ahead as-is.

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

I'm fine with that, but I really want this removed at some point.

If Luca wanna fix this up (drop this path) that's fine by me, else send a patch immediately after this is applied and I'll ACK it.

To avoid postponing this series I plan to apply as is on Monday. I can send another patch later to remove the !panel case.

Works for me :)

Maxime

author reviewer
#34 lore raw

PATCH v3 13/19 drm/bridge: fsl-ldb: don't create a panel_bridge

In reply to 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.

---
 drivers/gpu/drm/bridge/Kconfig   |  1 -
 drivers/gpu/drm/bridge/fsl-ldb.c | 19 +++++--------------
 2 files changed, 5 insertions(+), 15 deletions(-)
drivers/gpu/drm/bridge/Kconfig +0 -1
index 4766ae85da17..0ab3cab92363 100644
@@ -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.
 
drivers/gpu/drm/bridge/fsl-ldb.c +5 -14
index 26cc72948f31..7ec84c81cd78 100644
@@ -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;
Signature · 1 line
2.55.0
maintainer Reviewed-by on v3 13/19
#35 lore raw

Re: [PATCH v3 13/19] drm/bridge: fsl-ldb: don't create a panel_bridge

Hi Luca,

Quoted 10 lines · 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.

Signature · 2 lines
Thanks,
Laurentiu
maintainer Acked-by on v3 13/19
#36 lore raw

Re: [PATCH v3 13/19] drm/bridge: fsl-ldb: don't create a panel_bridge

In reply to Luca Ceresoli
Quoted 7 lines · 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().

[ ... ]

Thanks!
Maxime

author reviewer
#37 lore raw

PATCH v3 14/19 drm/bridge: samsung-dsim: don't create a panel_bridge

In reply to 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().

---
 drivers/gpu/drm/bridge/Kconfig        |  1 -
 drivers/gpu/drm/bridge/samsung-dsim.c | 24 +++++-------------------
 2 files changed, 5 insertions(+), 20 deletions(-)
drivers/gpu/drm/bridge/Kconfig +0 -1
index 0ab3cab92363..4be220f7335c 100644
@@ -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
drivers/gpu/drm/bridge/samsung-dsim.c +5 -19
index 5457a7b02a33..ea2837384774 100644
@@ -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);
 
Signature · 1 line
2.55.0
maintainer Acked-by on v3 14/19
#38 lore raw

Re: [PATCH v3 14/19] drm/bridge: samsung-dsim: don't create a panel_bridge

Quoted 7 lines · 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().

[ ... ]

Thanks!
Maxime

author reviewer
#39 lore raw

PATCH v3 15/19 drm/bridge: tc358768: don't create a panel_bridge

In reply to 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.

---
 drivers/gpu/drm/bridge/Kconfig    |  2 --
 drivers/gpu/drm/bridge/tc358768.c | 25 ++++++-------------------
 2 files changed, 6 insertions(+), 21 deletions(-)
drivers/gpu/drm/bridge/Kconfig +0 -2
index 4be220f7335c..847a6397eb10 100644
@@ -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
drivers/gpu/drm/bridge/tc358768.c +6 -19
index d1fc6af37cc5..cc989ab5cf25 100644
@@ -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;
 }
Signature · 1 line
2.55.0
maintainer Acked-by on v3 15/19
#40 lore raw

Re: [PATCH v3 15/19] drm/bridge: tc358768: don't create a panel_bridge

Quoted 7 lines · 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().

[ ... ]

Thanks!
Maxime

author reviewer
#41 lore raw

PATCH v3 16/19 drm/bridge: ssd2825: don't create a panel_bridge

In reply to 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.

---
 drivers/gpu/drm/bridge/Kconfig   |  2 --
 drivers/gpu/drm/bridge/ssd2825.c | 23 +++++------------------
 2 files changed, 5 insertions(+), 20 deletions(-)
drivers/gpu/drm/bridge/Kconfig +0 -2
index 847a6397eb10..c7da6b02d7b6 100644
@@ -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.
drivers/gpu/drm/bridge/ssd2825.c +5 -18
index b0142d6d40dc..71877699dfab 100644
@@ -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,
Signature · 1 line
2.55.0
maintainer Acked-by on v3 16/19
#42 lore raw

Re: [PATCH v3 16/19] drm/bridge: ssd2825: don't create a panel_bridge

Quoted 7 lines · 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().

[ ... ]

Thanks!
Maxime

author reviewer
#43 lore raw

PATCH v3 17/19 drm/omap: dss: don't create a panel_bridge

In reply to 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().

---
 drivers/gpu/drm/omapdrm/dss/omapdss.h |  1 -
 drivers/gpu/drm/omapdrm/dss/output.c  | 42 ++++-------------------------------
 2 files changed, 4 insertions(+), 39 deletions(-)
drivers/gpu/drm/omapdrm/dss/omapdss.h +0 -1
index 4c22c09c93d5..e3e685c931f1 100644
@@ -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;
 
drivers/gpu/drm/omapdrm/dss/output.c +4 -38

72 lines not on this page · raw message

Signature · 1 line
2.55.0
maintainer Acked-by on v3 17/19
#44 lore raw

Re: [PATCH v3 17/19] drm/omap: dss: don't create a panel_bridge

Quoted 7 lines · 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().

[ ... ]

Thanks!
Maxime

#45 lore raw

Re: [PATCH v3 17/19] drm/omap: dss: don't create a panel_bridge

In reply to Luca Ceresoli
Quoted 7 lines · On Wed, 16 Sep 2026 15:45:41 +0200 Luca Ceresoli <[email protected]>…

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().

This breaks the display on GTA04/OMAPDRM.

Panel is panel-tpo-td028ttec1 attached via DPI, controlled via spi_gpio.

I get

[   12.050201] omapdrm omapdrm.0: [drm] No compatible format found
[   12.050231] omapdrm omapdrm.0: [drm] Cannot find any crtc or sizes

Workaround:
rmmod omapdrm
modprobe omapdrm

Regards,
Andreas

Quoted 98 lines
---
 drivers/gpu/drm/omapdrm/dss/omapdss.h |  1 -
 drivers/gpu/drm/omapdrm/dss/output.c  | 42 ++++-------------------------------
 2 files changed, 4 insertions(+), 39 deletions(-)
drivers/gpu/drm/omapdrm/dss/omapdss.h +0 -1
index 4c22c09c93d5..e3e685c931f1 100644
@@ -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;
 
drivers/gpu/drm/omapdrm/dss/output.c +4 -38
index 6e9bc605ee22..36d37deac802 100644
@@ -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);
 }
author reviewer
#46 lore raw

PATCH v3 18/19 drm/tve200: don't create a panel_bridge

In reply to 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.

---
 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(-)
drivers/gpu/drm/tve200/Kconfig +0 -1
index c0746ae8f703..afe243df4ebb 100644
@@ -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
drivers/gpu/drm/tve200/tve200_drm.h +0 -1
index 631a9f5d9aa6..708f8020667a 100644
@@ -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;
drivers/gpu/drm/tve200/tve200_drv.c +7 -23
index 63ca4a53fc4c..9874554e5065 100644
@@ -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);
Signature · 1 line
2.55.0
author reviewer
#47 lore raw

Re: [PATCH v3 18/19] drm/tve200: don't create a panel_bridge

Hello,

Quoted 10 lines · 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.

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

maintainer Acked-by on v3 18/19
#48 lore raw

Re: [PATCH v3 18/19] drm/tve200: don't create a panel_bridge

In reply to Luca Ceresoli
Quoted 7 lines · 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().

[ ... ]

Thanks!
Maxime

maintainer Reviewed-by on v3 18/19
#49 lore raw

Re: [PATCH v3 18/19] drm/tve200: don't create a panel_bridge

In reply to Luca Ceresoli
Quoted 10 lines · 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.

Yours,
Linus Walleij

author reviewer
#50 lore raw

PATCH v3 19/19 drm/bridge: analogix_dp: don't create a panel_bridge

In reply to 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
---
 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(-)
drivers/gpu/drm/bridge/analogix/Kconfig +0 -1
index da156fd15764..5672d83cb4a1 100644
@@ -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"
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +23 -17
index 18e76d1e78e1..6df6963740d2 100644
@@ -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);
 }
drivers/gpu/drm/exynos/exynos_dp.c +2 -34
index e1c9e2946b8a..82c238829921 100644
@@ -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);
 }
 
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +0 -9
index 587e60232ec7..071d31aa5288 100644
@@ -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);
 }
 
include/drm/bridge/analogix_dp.h +0 -1
index 0e0b87abee59..6033137b651e 100644
@@ -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;
Signature · 1 line
2.55.0
Tested-by Reviewed-by on v3 19/19
#51 lore raw

Re: [PATCH v3 19/19] drm/bridge: analogix_dp: don't create a panel_bridge

Hi Luca,

Quoted 132 lines · 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
---
  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(-)
drivers/gpu/drm/bridge/analogix/Kconfig +0 -1
index da156fd15764..5672d83cb4a1 100644
@@ -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"
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +23 -17
index 18e76d1e78e1..6df6963740d2 100644
@@ -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);
  }
drivers/gpu/drm/exynos/exynos_dp.c +0 -4
index e1c9e2946b8a..82c238829921 100644
@@ -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);

drivers/gpu/drm/exynos/exynos_dp.c static int exynos_dp_probe(struct platform_device *pdev) · line 177

Quoted 10 lines
drivers/gpu/drm/exynos/exynos_dp.c +0 -10
-	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?

Quoted 75 lines
drivers/gpu/drm/exynos/exynos_dp.c +2 -20
  	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);
  }
 
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +0 -9
index 587e60232ec7..071d31aa5288 100644
@@ -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);
  }
 
include/drm/bridge/analogix_dp.h +0 -0
index 0e0b87abee59..6033137b651e 100644

include/drm/bridge/analogix_dp.h static inline bool analogix_dp_is_rockchip(enum analogix_dp_devtype type) · line 40

Quoted 7 lines
include/drm/bridge/analogix_dp.h +0 -1
@@ -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.

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.

[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/

#52 lore raw

Re: [PATCH v3 19/19] drm/bridge: analogix_dp: don't create a panel_bridge

Quoted 26 lines · Damon Ding

Hi Luca,

Quoted 23 lines · 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

---
  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]

Quoted 4 lines

drivers/gpu/drm/rockchip/analogix_dp-rockchip.c static void rockchip_dp_remove(struct · line 489

Quoted 4 lines
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +0 -0
@@ -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.

Quoted 27 lines
Quoted 17 lines
(quoted diff) +0 -2
-    /*
-     * 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); }

include/drm/bridge/analogix_dp.h +0 -0
index 0e0b87abee59..6033137b651e 100644

include/drm/bridge/analogix_dp.h static inline bool analogix_dp_is_rockchip(enum · line 40

Quoted 7 lines
include/drm/bridge/analogix_dp.h +0 -1
@@ -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.

Quoted 9 lines

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.

[0] https://lore.kernel.org/all/20260915-drm-bridge-drm_panel-cleanup- [email protected]/
[1] https://lore.kernel.org/all/5609825.iZASKD2KPV@diego/

Best regards,
Damon

_______________________________________________
Linux-rockchip mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-rockchip

author reviewer
#53 lore raw

Re: [PATCH v3 19/19] drm/bridge: analogix_dp: don't create a panel_bridge

Hello Damon,

Quoted 30 lines · Damon Ding
Quoted 28 lines · Damon Ding

Hi Luca,

Quoted 25 lines · 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

---
  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(-)
Quoted 8 lines

[snip]

Quoted 4 lines

drivers/gpu/drm/rockchip/analogix_dp-rockchip.c static void rockchip_dp_remove(struct · line 489

Quoted 4 lines
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +0 -0
@@ -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.

Ah, indeed!

I guess I can keep your review tags if applying this patch with only this line removed. Correct?

Luca

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

#54 lore raw

Re: [PATCH v3 19/19] drm/bridge: analogix_dp: don't create a panel_bridge

Quoted 42 lines · Luca Ceresoli

Hello Damon,

Quoted 30 lines · Damon Ding
Quoted 28 lines · Damon Ding

Hi Luca,

Quoted 25 lines · 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
---
   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(-)
Quoted 8 lines

[snip]

Quoted 4 lines

drivers/gpu/drm/rockchip/analogix_dp-rockchip.c static void rockchip_dp_remove(struct · line 489

Quoted 4 lines
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +0 -0
@@ -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.

Quoted 5 lines

Ah, indeed!

I guess I can keep your review tags if applying this patch with only this line removed. Correct?

Yeah, sure!

Best regards,
Damon

author reviewer
#55 lore raw

Re: [PATCH v3 19/19] drm/bridge: analogix_dp: don't create a panel_bridge

In reply to Damon Ding

Hello Damon,

Quoted 142 lines · Damon Ding

Hi Luca,

Quoted 139 lines · 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
---
  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(-)
drivers/gpu/drm/bridge/analogix/Kconfig +0 -1
index da156fd15764..5672d83cb4a1 100644
@@ -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"
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +23 -17
index 18e76d1e78e1..6df6963740d2 100644
@@ -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);
  }
drivers/gpu/drm/exynos/exynos_dp.c +0 -11
index e1c9e2946b8a..82c238829921 100644
@@ -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);
-
Quoted 8 lines

drivers/gpu/drm/exynos/exynos_dp.c static int exynos_dp_probe(struct platform_device *pdev) · line 177

Quoted 3 lines
drivers/gpu/drm/exynos/exynos_dp.c +0 -3
-		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?

What is the "WIP v3" series exactly? Do you have a link (to v2 in case v3 is not yet public)?

Quoted 86 lines
Quoted 75 lines
drivers/gpu/drm/exynos/exynos_dp.c +2 -20
  	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);
  }
 
drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +0 -9
index 587e60232ec7..071d31aa5288 100644
@@ -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);
  }
 
include/drm/bridge/analogix_dp.h +0 -0
index 0e0b87abee59..6033137b651e 100644

include/drm/bridge/analogix_dp.h static inline bool analogix_dp_is_rockchip(enum analogix_dp_devtype type) · line 40

Quoted 7 lines
include/drm/bridge/analogix_dp.h +0 -1
@@ -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.

Quoted 8 lines

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.

Yes, I confirm with this series devm_drm_of_get_bridge() becomes a complicated equivalent of of_drm_get_bridge_by_endpoint(). So what Heiko suggested is correct for current upstream code, but this patch goes a step further, using just the bridge API as the new recommended practice will be as soon as this series is applied.

FYI this series is now fully acked, so I plan to apply it by the end of this week or early next week.

Quoted 5 lines

[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/

Thanks for reviewing and testing!

Luca

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

maintainer
#56 lore raw

Re: [PATCH v3 19/19] drm/bridge: analogix_dp: don't create a panel_bridge

Hi Luca,

Am Dienstag, 22. September 2026, 10:12:41 Mitteleuropäische Sommerzeit schrieb Luca Ceresoli:

Quoted 2 lines · Damon Ding
Quoted 1 line · Luca Ceresoli

[...]

Quoted 22 lines
Quoted 13 lines
Quoted 13 lines
drivers/gpu/drm/exynos/exynos_dp.c +0 -9
@@ -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);
-
Quoted 8 lines

drivers/gpu/drm/exynos/exynos_dp.c static int exynos_dp_probe(struct platform_device *pdev) · line 177

Quoted 3 lines
drivers/gpu/drm/exynos/exynos_dp.c +0 -3
-		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?

Quoted 2 lines

What is the "WIP v3" series exactly? Do you have a link (to v2 in case v3 is not yet public)?

https://lore.kernel.org/linux-rockchip/[email protected]/
is the series in question.

Heiko

#57 lore raw

Re: [PATCH v3 19/19] drm/bridge: analogix_dp: don't create a panel_bridge

Hi Heiko,

Quoted 30 lines · Heiko Stuebner

Hi Luca,

Am Dienstag, 22. September 2026, 10:12:41 Mitteleuropäische Sommerzeit schrieb Luca Ceresoli:

Quoted 2 lines · Damon Ding
Quoted 1 line · Luca Ceresoli

[...]

Quoted 22 lines
Quoted 21 lines
Quoted 6 lines
drivers/gpu/drm/exynos/exynos_dp.c +0 -2
@@ -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);

drivers/gpu/drm/exynos/exynos_dp.c static int exynos_dp_probe(struct platform_device *pdev) · line 177

Quoted 10 lines
drivers/gpu/drm/exynos/exynos_dp.c +0 -10
-	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?

Quoted 7 lines
Quoted 2 lines

What is the "WIP v3" series exactly? Do you have a link (to v2 in case v3 is not yet public)?

https://lore.kernel.org/linux-rockchip/[email protected]/
is the series in question.

Sorry for the confusion. I was discussing another separate series in this thread, which caused misunderstanding. I mentioned earlier that I will try to post its v3 update within this week.[0]

Best regards,
Damon

[0] https://lore.kernel.org/all/[email protected]/

author reviewer
#58 lore raw
In reply to Luca Ceresoli
Quoted 2 lines · Luca Ceresoli

This series embeds a drm_bridge into every drm_panel, as previously discussed [1][2] and in previous iterations.

Series applied to drm-misc-next.

Luca

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com