Subject: Re: [PATCH 00/37] drm bridge hotplug

From: "Luca Ceresoli" <[email-masked]>
Date: Mon, 01 Jun 2026 17:44:31 +0200

Hello,

I presented this series last Friday during the Display Next Hackfest
2026. Here's a summary of the discussion.

The discussion was mostly with Dmitry Baryshkov (major contributor to the
drm_bridge_connector code) and a bit with Paul Kocialkowski and
others. Thanks all!

The proposal to extend the drm_bridge_connector to implement hotplug, and
the general architecture proposed, raised no objection. So I'm going to
continue with this approach.

There were various implementation aspects discussed, which will be my
focus in the coming weeks:

 * The requirement that bridge drivers (the last bridge before the
   hotplug connector, at least) must return -EPROBE_DEFER when the next
   bridge is not present is risky: some drivers might just defer during
   their probe, potentially generating defer loops.

   * Alternative discussed: bridge drivers can expose info about how to
     find the next bridge (the fwnode perhaps) using a new API, keeping the
     existing untouched. Maybe they could also expose the previous driver
     fwnode, even though it currently seems unnecessary.

   * There are various options about how such new API should look like:
     during registration (drm_bridge_add()? too early for some complex
     drivers?), at attach time (maybe too late?) or as a new callback
     (called when?). In all cases this new API would be a superset of the
     .is_tail callback proposed in patch 30, which would then become
     unnecessary.

 * Dmitry asked whether all the attach chain could be entirely moved to the
   drm_bridge_connector for drivers using it. Worth investigating.

   * I did a quick investigation after the event and it would work nicely
     for many drivers but some are tricky. Needs more understanding.

 * The added drm_atomic_shutdown() is wrong, it would stop streaming on
   all outputs on the card. But it is probably unnecessary, just removing
   the connector should be enough.

That's all according to my notes. Feel free to reply in case I forgot
anything or something is wrong. Expect a v2 in the coming weeks with the
above changes, or discussion in case of unexpected issues.

Kind regards,
Luca

On Tue May 19, 2026 at 12:37 PM CEST, Luca Ceresoli wrote:
> Hello,
>
> this series adds support for Linux-based devices with a DRM pipeline whose
> final components, including one or more bridges, can be hot-plugged and
> hot-unplugged.
>
> TL;DR:
>
>  * This new approach is totally different from the one proposed in the
>    past [0], and the code is an almost completely rewrite
>  * If you already know the use case, feel free to skip to the "Design"
>    section below
>
> Use case
> ========
>
> This series targets as its first use case a professional product (GE SUNH)
> that is composed of a "main" part, with the main SoC and able to work
> autonomously with limited features, and an optional "add-on" that enables
> more features by adding more hardware peripherals.
>
> The hotplug connector has a MIPI DSI bus. The addon has a DSI-to-LVDS
> bridge and an LVDS panel attached to it. Different addon models can have
> different components. As a consequence, a DRM bridge must be added and
> removed at runtime without tearing down the whole card. This is currently
> not possible, and this series enables it.
>
> DRM already supports pipelines whose display can be removed, but all the
> components preceding it (all the display controller and any bridges) are
> assumed to be fixed and cannot be plugged, removed or modified at
> runtime. Additionally, dynamic drm_connectors are supported for DP MST.
>
> This picture summarizes the DRM structure implemented by this series:
>
>  .------------------------.
>  |   DISPLAY CONTROLLER   |
>  | .---------.   .------. |
>  | | ENCODER |<--| CRTC | |
>  | '---------'   '------' |
>  '------|-----------------'
>         |              MACHANICAL
>         |DSI            HOTPLUG
>         V              CONNECTOR
>    .---------.        .--.    .-.        .---------.         .-------.
>    | 0 to N  |        | _|   _| |        | 1 to N  |         |       |
>    | BRIDGES |--DSI-->||_   |_  |--DSI-->| BRIDGES |--LVDS-->| PANEL |
>    |         |        |  |    | |        |         |         |       |
>    '---------'        '--'    '-'        '---------'         '-------'
>
>  [--- fixed components --]  [----------- removable add-on -----------]
>
> The video bus is MIPI DSI in the example and in the implementation provided
> by this series, but the implementation is meant to allow generalization to
> other video busses without native hotplug support, such as parallel video
> and LVDS. Addons which terminate with a HDMI/DP connector are possible too.
>
> == Design
>
> The old approach [0] was based on a hotplug-bridge driver, connected
> between the last fixed bridge and the first removable bridge.
>
> That approach has been rejected, and this new approach is based on a
> central place to handle DRM hotplug, not a specific driver.
>
> The drm_bridge_connector is nowadays the recommended way to implement DRM
> connectors when a chain of bridges is used. It takes care of adding the
> drm_connector when the pipeline is composed by an arbitrarily long chain of
> bridges, which it scans to properly implement the drm_connector
> operations.
>
> As such the drm_bridge_connector looked like the ideal component to
> implement DRM bridge hotplug.
>
> This series augments the drm_bridge_connector code to be able to create and
> destroy the drm_connector reacting on hot(un)plug events.
>
> == Series description
>
> This series has many preparatory patches: to make the drm_bridge_connector
> code allocate the drm_connector dynamically and to prepare various other
> parts of the involved DRM code.
>
> In current code the last bridge in the encoder chain is always assumed to
> complete the pipeline. There is no way for a bridge to tell "I'm currently
> the last bridge in the encoder chain, but I need an next bridge to
> work". This series has some patches to allow such a behaviour:
>
>  * bridges can now report whether they conclude the pipeline or not (I
>    propose the "tail bridge" naming to tell this)
>  * returning -EPROBE_DEFER on bridge attach is not considered a hard error
>    anymore, it's normal when the next bridge is needed but not yet present
>
> Compared to the hotplug-bridge approach, now bridge drivers need a bit of
> adaptation in order to support that the following bridge is
> hotpluggable. So there are a few changes to the samsung-dsim bridge driver,
> which in the hardware I'm working on is the last fixed bridge.
>
> Finally, as the current drm_bridge_connector API is unable to support
> hotplug, a new API is added to enable the new features. This makes existing
> drivers not affected by the changes. The last patch shows to changes needed
> to an encoder driver to switch to the new API enabling hotplug support.
>
> == Series layout
>
>  1. Add a dynamic variant of drm_connector_hdmi_init()
>     (needed for the bridge-connector to allocate the connector dynamically)
>
>      * drm/connector: split drmm_connector_hdmi_init() in 3 parts
>      * drm/connector: add drm_connector_hdmi_dynamic_init()
>
>  2. bridge-connector: split the long drm_bridge_connector_init() in various
>     parts in preparation to be called in different ways
>
>      * drm/display: bridge-connector: rename variable for consistency
>      * drm/display: bridge-connector: store the drm_device pointer
>      * drm/display: bridge-connector: split code creating the connector to a subfunction
>      * drm/display: bridge-connector: use a drm_bridge_connector internally, not a drm_connector
>      * drm/display: bridge-connector: extract drm_bridge_connector_get_bridges()
>      * drm/display: bridge-connector: return int from drm_bridge_connector_get_bridges()
>      * drm/display: bridge-connector: extract drm_bridge_connector_init_hdmi_audio_cec()
>      * drm/display: bridge-connector: return int from drm_bridge_connector_init_hdmi_audio_cec()
>      * drm/display: bridge-connector: return int from drm_bridge_connector_add_connector()
>
>  3. bridge-connector: create the drm_connector dynamically
>
>      * drm/display: bridge-connector: hoist error management to common code
>      * drm/display: bridge-connector: move drm_bridge_connector_put_bridges() definition eariler
>      * drm/display: bridge-connector: add non-drmm variant of drm_bridge_connector_put_bridges()
>      * drm/display: bridge-connector: allocate the connector dynamically
>      * drm/display: bridge-connector: move per-connector fields to the dynamic connector
>      * drm/display: bridge-connector: protect dynconn creation and destruction with a mutex
>
>  4. samsung-dsim: prepare driver to work when the following bridge is hotpluggable
>
>      * drm/bridge: samsung-dsim: remove the panel_bridge on host_detach
>      * drm/bridge: samsung-dsim: move drm_bridge_add() call to probe
>      * drm/bridge: samsung-dsim: attach: return -EPROBE_DEFER is next bridge not yet available
>
>  5. Misc preparation work
>
>      * drm/bridge: initialize chain_node list head on allocation
>      * drm/bridge: initialize chain_node list head on detach and attach errors
>
>  6. drm_bridge: stop pipeline when a bridge is removed
>
>      * drm/encoder: add drm_encoder_cleanup_from()
>      * drm/atomic: move drm_atomic_helper_disable_all() and drm_atomic_helper_shutdown() from drm_atomic_helper to drm_atomic
>      * drm/bridge: shutdown and cleanup on bridge unplug
>
>  7. Add notifier mechanism to let common code (the bridge-connector)
>     take actions on hotplug events
>
>      * drm: event-notifier: add mechanism to notify about hotplug events
>      * drm/bridge: notify about detached bridges
>      * drm/mipi-dsi: turn DRM_MIPI_DSI into a tristate
>      * drm/mipi-dsi: notify about DSI attach
>
>  8. Allow common code to know when the pipeline is complete
>
>      * drm/bridge: add drm_bridge_is_tail() to know whether a bridge completes the pipeline
>      * drm/bridge: panel: implement .is_tail
>      * drm/bridge: display-connector: implement .is_tail
>      * drm/bridge: samsung-dsim: implement .is_tail
>      * drm/bridge: ti-sn65dsi83: implement .is_tail
>
>  9. Allow probing incomplete pipelines
>
>      * drm/bridge: drm_bridge_attach(): don't fail on -EPROBE_DEFER
>
>  10. Implement bridge hotplug in bridge-connector, enable it in a driver
>
>      * drm/display: bridge-connector: handle bridge hotplug
>      * drm/mxsfb/lcdif: enable bridge hotplug
>
> == 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.   drm_of_find_panel_or_bridge, *_of_get_bridge
>        9. ✔ enforce drm_bridge_add before drm_bridge_attach (v6.19)
>     F. ✔ debugfs improvements
>        1. ✔ add top-level 'bridges' file (v6.16)
>        2. ✔ show refcount and list lingering bridges (v6.19)
>  2. … handle gracefully atomic updates during bridge removal
>     A. ✔ Add drm_bridge_enter/exit() to protect device resources (v7.0)
>     B. … protect private_obj removal from list
>     C. ✔ Add drm_bridge_clear_and_put() (v7.1)
>  3. … DSI host-device driver interaction
>  4. ✔ removing the need for the "always-disconnected" connector
>  5. ✔ Migrate i.MX LCDIF driver to bridge-connector (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-masked]/#t
>
> == Dependencies
>
> This series depends on:
>
>  * "drm/atomic: drm_atomic_private_obj_fini: protect private_obj removal
>     from list"
>    - https://lore.kernel.org/lkml/20[email-masked]/
>    - Reason: avoid sporadic deadlock
>
> Signed-off-by: Luca Ceresoli <[email-masked]>
> ---
> Luca Ceresoli (37):
>       drm/connector: split drmm_connector_hdmi_init() in 3 parts
>       drm/connector: add drm_connector_hdmi_dynamic_init()
>       drm/display: bridge-connector: rename variable for consistency
>       drm/display: bridge-connector: store the drm_device pointer
>       drm/display: bridge-connector: split code creating the connector to a subfunction
>       drm/display: bridge-connector: use a drm_bridge_connector internally, not a drm_connector
>       drm/display: bridge-connector: extract drm_bridge_connector_get_bridges()
>       drm/display: bridge-connector: return int from drm_bridge_connector_get_bridges()
>       drm/display: bridge-connector: extract drm_bridge_connector_init_hdmi_audio_cec()
>       drm/display: bridge-connector: return int from drm_bridge_connector_init_hdmi_audio_cec()
>       drm/display: bridge-connector: return int from drm_bridge_connector_add_connector()
>       drm/display: bridge-connector: hoist error management to common code
>       drm/display: bridge-connector: move drm_bridge_connector_put_bridges() definition eariler
>       drm/display: bridge-connector: add non-drmm variant of drm_bridge_connector_put_bridges()
>       drm/display: bridge-connector: allocate the connector dynamically
>       drm/display: bridge-connector: move per-connector fields to the dynamic connector
>       drm/display: bridge-connector: protect dynconn creation and destruction with a mutex
>       drm/bridge: samsung-dsim: remove the panel_bridge on host_detach
>       drm/bridge: samsung-dsim: move drm_bridge_add() call to probe
>       drm/bridge: samsung-dsim: attach: return -EPROBE_DEFER is next bridge not yet available
>       drm/bridge: initialize chain_node list head on allocation
>       drm/bridge: initialize chain_node list head on detach and attach errors
>       drm/encoder: add drm_encoder_cleanup_from()
>       drm/atomic: move drm_atomic_helper_disable_all() and drm_atomic_helper_shutdown() from drm_atomic_helper to drm_atomic
>       drm/bridge: shutdown and cleanup on bridge unplug
>       drm: event-notifier: add mechanism to notify about hotplug events
>       drm/bridge: notify about detached bridges
>       drm/mipi-dsi: turn DRM_MIPI_DSI into a tristate
>       drm/mipi-dsi: notify about DSI attach
>       drm/bridge: add drm_bridge_is_tail() to know whether a bridge completes the pipeline
>       drm/bridge: panel: implement .is_tail
>       drm/bridge: display-connector: implement .is_tail
>       drm/bridge: samsung-dsim: implement .is_tail
>       drm/bridge: ti-sn65dsi83: implement .is_tail
>       drm/bridge: drm_bridge_attach(): don't fail on -EPROBE_DEFER
>       drm/display: bridge-connector: handle bridge hotplug
>       drm/mxsfb/lcdif: enable bridge hotplug
>
>  drivers/gpu/drm/Kconfig                        |   7 +-
>  drivers/gpu/drm/Makefile                       |   2 +
>  drivers/gpu/drm/bridge/display-connector.c     |   7 +
>  drivers/gpu/drm/bridge/panel.c                 |   8 +-
>  drivers/gpu/drm/bridge/samsung-dsim.c          |  36 +-
>  drivers/gpu/drm/bridge/ti-sn65dsi83.c          |   7 +
>  drivers/gpu/drm/display/drm_bridge_connector.c | 835 +++++++++++++++++--------
>  drivers/gpu/drm/drm_atomic.c                   | 115 ++++
>  drivers/gpu/drm/drm_atomic_helper.c            |  76 +--
>  drivers/gpu/drm/drm_bridge.c                   |  47 +-
>  drivers/gpu/drm/drm_connector.c                | 155 +++--
>  drivers/gpu/drm/drm_encoder.c                  |  38 ++
>  drivers/gpu/drm/drm_event_notifier.c           |  58 ++
>  drivers/gpu/drm/drm_mipi_dsi.c                 |   3 +
>  drivers/gpu/drm/mxsfb/lcdif_drv.c              |   8 +-
>  include/drm/bridge/samsung-dsim.h              |   2 +
>  include/drm/drm_atomic.h                       |   3 +
>  include/drm/drm_bridge.h                       |  19 +
>  include/drm/drm_bridge_connector.h             |   2 +
>  include/drm/drm_connector.h                    |   9 +
>  include/drm/drm_encoder.h                      |   1 +
>  include/drm/drm_event_notifier.h               |  36 ++
>  22 files changed, 1078 insertions(+), 396 deletions(-)
> ---
> base-commit: 289b9a790d52a6865db3006f07922a9191faa54e
> change-id: 20260515-drm-bridge-hotplug-46265d3a2f85
>
> Best regards,
> --
> Luca Ceresoli, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com

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