[PATCH] drm/bridge: dw-mipi-dsi: fix cmd mode transition when disabling

From: Icenowy Zheng

Date: Fri Oct 30 2026 - 01:58:33 EST


With pre_enable_prev_first flag set, the atomic_post_disable hook of the
next bridge (which should be the DSI panel bridge and calls panel
unprepare hook) is called before the hook of the DSI controller bridge,
which leads to the switch to command mode happening after the panel
unprepare. In this case some panels' unprepare hooks sliently fails
because they expect the DSI controller to be in command mode.

As the DSI controller atomic_disable hook happens after panel bridge
atomic_disable but before panel bridge atomic_post_disable, it seems to
be a good position for the transition to the command mode.

Move the mode transition from the atomic_post_disable hook to a newly
created atomic_disable hook.

Fixes: 05aa61334592 ("drm: bridge: dw-mipi-dsi: Fix enable/disable of DSI controller")
Signed-off-by: Icenowy Zheng <zhengxingda@xxxxxxxxxxx>
---
Tested on Lichee Console 4A with a pending glue driver for T-Head TH1520
DW MIPI DSI. This device has a always-powered panel (no switchable
supply and no reset pin), so correct execution of unprepare commands is
critical.

drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 23 ++++++++++++-------
1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
index 5dd475fcaacf8..49b6228ca69e5 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
@@ -944,14 +944,6 @@ static void dw_mipi_dsi_bridge_post_atomic_disable(struct drm_bridge *bridge,
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;

- /*
- * Switch to command mode before panel-bridge post_disable &
- * panel unprepare.
- * Note: panel-bridge disable & panel disable has been called
- * before by the drm framework.
- */
- dw_mipi_dsi_set_mode(dsi, 0);
-
if (phy_ops->power_off)
phy_ops->power_off(dsi->plat_data->priv_data);

@@ -1058,6 +1050,20 @@ static void dw_mipi_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
dw_mipi_dsi_set_mode(dsi->slave, MIPI_DSI_MODE_VIDEO);
}

+static void dw_mipi_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
+ struct drm_atomic_commit *state)
+{
+ struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
+
+ /*
+ * Switch to command mode before panel-bridge post_disable &
+ * panel unprepare.
+ * Note: panel-bridge disable & panel disable has been called
+ * before by the drm framework.
+ */
+ dw_mipi_dsi_set_mode(dsi, 0);
+}
+
static enum drm_mode_status
dw_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_info *info,
@@ -1098,6 +1104,7 @@ static const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = {
.atomic_create_state = drm_atomic_helper_bridge_create_state,
.atomic_pre_enable = dw_mipi_dsi_bridge_atomic_pre_enable,
.atomic_enable = dw_mipi_dsi_bridge_atomic_enable,
+ .atomic_disable = dw_mipi_dsi_bridge_atomic_disable,
.atomic_post_disable = dw_mipi_dsi_bridge_post_atomic_disable,
.mode_set = dw_mipi_dsi_bridge_mode_set,
.mode_valid = dw_mipi_dsi_bridge_mode_valid,
--
2.56.0