cdns_dsi_bridge_atomic_pre_enable() uses pm_runtime_get_sync() to resume
the DSI controller. The helper increments the runtime PM usage count
even if the resume fails.
The corresponding post-disable callback unconditionally accesses the
controller registers, releases the PHY, and drops the runtime PM
reference. However, the DRM bridge pre-enable callback returns void, so
a failed resume does not prevent the later post-disable callback from
running.
Use pm_runtime_resume_and_get() to avoid retaining a usage count on
failure. Track successful runtime PM acquisition and skip post-disable
cleanup if pre-enable failed.
Also move the bridge state validation before runtime PM acquisition.
This change was prepared with assistance from DeepSeek-V4.1-Flash and
GPT-6.1-Sol.
Fixes: e19233955d9e ("drm/bridge: Add Cadence DSI driver")
Signed-off-by: Wentao Liang <[email protected]>
---
Changes in v2:
- Sorry for the very late reply, and thanks for the review.
- Use pm_runtime_resume_and_get() as suggested by Laurent.
- Track successful runtime PM acquisition.
- Skip post-disable cleanup after a failed pre-enable.
- Validate the bridge state before acquiring the PM reference.
---
drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c | 12 +++++++++---
drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h | 1 +
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
index 1e28ea579b06..da27f5611bb7 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
@@ -613,6 +613,9 @@ static void cdns_dsi_bridge_atomic_post_disable(struct
drm_bridge *bridge,
* disable their streams.
*/
+ if (!dsi->bridge_pm_active)
+ return;
+
val = readl(dsi->regs + MCTL_MAIN_DATA_CTL);
val &= ~(IF_VID_SELECT_MASK | IF_VID_MODE | VID_EN | HOST_EOT_GEN |
DISP_EOT_GEN);
@@ -630,6 +633,7 @@ static void cdns_dsi_bridge_atomic_post_disable(struct
drm_bridge *bridge,
phy_exit(dsi->dphy);
pm_runtime_put(dsi->base.dev);
+ dsi->bridge_pm_active = false;
}
static void cdns_dsi_hs_init(struct cdns_dsi *dsi)
@@ -734,13 +738,15 @@ static void cdns_dsi_bridge_atomic_pre_enable(struct
drm_bridge *bridge,
* enable their streams.
*/
- if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0))
- return;
-
new_bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
if (WARN_ON(!new_bridge_state))
return;
+ if (WARN_ON(pm_runtime_resume_and_get(dsi->base.dev) < 0))
+ return;
+
+ dsi->bridge_pm_active = true;
+
dsi_state = to_cdns_dsi_bridge_state(new_bridge_state);
dsi_cfg = dsi_state->dsi_cfg;
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h
b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h
index 5db5dbbbcaad..6ed6e1bb8573 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.h
@@ -76,6 +76,7 @@ struct cdns_dsi {
struct clk *dsi_sys_clk;
bool link_initialized;
bool phy_initialized;
+ bool bridge_pm_active;
struct phy *dphy;
};