Re: [PATCH 00/35] drm/panel: let the panels use the atomic state

From: Dmitry Baryshkov

Date: Tue Oct 27 2026 - 08:10:53 EST


On Mon, Oct 26, 2026 at 01:09:49PM +0200, Dmitry Baryshkov wrote:
> The panel is the only element of the display pipeline which never sees
> the atomic commit. Its prepare() and enable() callbacks get nothing but
> the panel, so a panel which has to be programmed differently depending
> on the mode can only guess it. The NT35950 driver, for example, saves
> the connector in get_modes() and reads connector->state->crtc->state
> while being prepared: without the locks, from the current state rather
> than from the one being committed, and with no way to reject a mode it
> doesn't know.
>
> Every panel has a struct drm_bridge embedded into it, and the bridge
> already has all the missing parts: atomic_check(), a state object which
> can be subclassed and the commit passed to the callbacks. Rather than
> growing struct drm_panel_funcs into a copy of that, let the panel driver
> provide struct drm_bridge_funcs for the embedded bridge. This is opt-in:
> the panels which have no use for the atomic state keep using struct
> drm_panel_funcs and are not touched by it.
>
> To get there the bridge callbacks become the entry point to the panel,
> with drm_panel_prepare() and friends calling them rather than the other
> way around. The panel core still has to track the panel state, notify
> the panel followers and handle the backlight, so the driver doesn't fill
> in the power callbacks directly, it wraps its functions with the macros
> doing that part. NT35950 is converted as the first user.
>
> The bulk of the series is the cleanup of what the panel core and the
> bridge need from the panel driver, so that a panel providing the bridge
> callbacks doesn't need struct drm_panel_funcs for anything:
>
> - get_timings() had no callers.
>
> - The connector type was stored both in the panel and in its bridge, and
> the display drivers could override it while creating the panel bridge.
>
> - The orientation was read from the DT, stored and returned by nearly
> identical code in more than twenty panel drivers, and some of them
> also had to set it on the connector from get_modes(), with a TODO
> asking for a better place. The core reads it now. It is applied to the
> connector from the new connector_init() bridge callback, which is not
> specific to the panels: other bridges have properties to set up on the
> connector being created too (HDCP, DP link properties), and currently
> have nowhere to do it.
>
> - disable() and unprepare() returned an error which nobody could act on.
> Worse, a failed unprepare() left the panel marked as prepared, so it
> was never initialised again.
>
> Behaviour changes worth knowing about:
>
> - Panels with the rotation property whose driver ignored it now get the
> orientation property. In the tree this is the Motorola Mapphone panel
> (panel-dsi-cm).
>
> - sun6i_mipi_dsi, sti_dvo and the Tegra DSI get their panel after the
> DRM device has been registered, which is too late to create the
> property, so they lose the orientation which the panel drivers used to
> set from get_modes(). None of the rotated panels in the tree are used
> with them.
>
> - A panel implementing atomic_check() can only be driven through the
> bridge chain. The display drivers calling drm_panel_prepare() directly
> have no commit to pass.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@xxxxxxxxxxxxxxxx>
> ---
> Dmitry Baryshkov (35):
> drm/panel: remove the get_timings() callback
> drm/panel: remove the unused struct panel_bridge
> drm/tidss: get the panel type from the embedded bridge
> drm/bridge: lvds-codec: use devm_drm_panel_bridge_add()
> drm/ingenic: use devm_drm_panel_bridge_add()
> drm: mxsfb: use devm_drm_panel_bridge_add()
> drm: rcar-du: use devm_drm_panel_bridge_add()
> drm: rz-du: use devm_drm_panel_bridge_add()
> drm/mcde: use drm_panel_bridge_add()
> drm/pl111: use drm_panel_bridge_add()
> drm/rockchip: lvds: use drm_panel_bridge_add()
> drm/rockchip: rgb: use drm_panel_bridge_add()
> drm/panel: remove the _typed() panel bridge functions

Gmail barked at me for sending too many emails for too many recipients
in the middle of the series. I guess, I'll have to split the series into
smaller parts. Please consider reviewing the posted patches, letting me
split / land the series in parts.

> drm/panel: remove drm_panel.connector_type
> drm/bridge: anx6345: set the panel orientation on the connector
> drm/exynos: dpi: set the panel orientation on the connector
> drm/fsl-dcu: set the panel orientation on the connector
> drm/logicvc: set the panel orientation on the connector
> drm/stm: lvds: set the panel orientation on the connector
> drm/sun4i: set the panel orientation on the connector
> drm/tegra: sor: set the panel orientation on the connector
> drm/panel: drop the orientation workaround from get_modes()
> drm/panel: read the panel orientation in the core
> drm/panel: use the orientation from the panel core
> drm/panel: remove the get_orientation() callback
> drm/bridge: add the connector_init callback
> drm/bridge-connector: let the bridges set up the connector
> drm/panel: let the bridges set up the panel connector
> drm/panel: set the orientation from the connector_init callback
> drm/panel: make the disable and unprepare callbacks return void
> drm/panel: don't hold the follower lock over the panel callbacks
> drm/panel: route the panel calls through the bridge callbacks
> drm/panel: let the panel drivers provide struct drm_bridge_funcs
> drm/panel: novatek-nt35950: provide struct drm_bridge_funcs
> drm/panel: novatek-nt35950: use the atomic state to select the mode
>

--
With best wishes
Dmitry