cdns_dsi_hs_init() ignored PHY API failures and converted the PLL-lock
wait into a WARN_ON_ONCE(). The bridge pre-enable path also only logged
a lane-ready timeout and then continued programming video registers and
enabling the interface.

Return errors from the PHY initialization helper, unwind the PHY when
initialization fails, and stop bridge pre-enable when either the PLL or
lane-ready wait fails. The bridge hook is still void, so this is
intended as an RFC patch for maintainer review of the failure policy.

Signed-off-by: Pengpeng Hou <[email protected]>
---
 .../gpu/drm/bridge/cadence/cdns-dsi-core.c    | 67 +++++++++++++++++--
 1 file changed, 55 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c 
b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
index cf90d4468..86f31eb46 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
@@ -631,13 +631,14 @@ static void cdns_dsi_bridge_atomic_post_disable(struct 
drm_bridge *bridge,
        pm_runtime_put(dsi->base.dev);
 }
 
-static void cdns_dsi_hs_init(struct cdns_dsi *dsi)
+static int cdns_dsi_hs_init(struct cdns_dsi *dsi)
 {
        struct cdns_dsi_output *output = &dsi->output;
        u32 status;
+       int ret;
 
        if (dsi->phy_initialized)
-               return;
+               return 0;
        /*
         * Power all internal DPHY blocks down and maintain their reset line
         * asserted before changing the DPHY config.
@@ -646,22 +647,45 @@ static void cdns_dsi_hs_init(struct cdns_dsi *dsi)
               DPHY_CMN_PDN | DPHY_PLL_PDN,
               dsi->regs + MCTL_DPHY_CFG0);
 
-       phy_init(dsi->dphy);
-       phy_set_mode(dsi->dphy, PHY_MODE_MIPI_DPHY);
-       phy_configure(dsi->dphy, &output->phy_opts);
-       phy_power_on(dsi->dphy);
+       ret = phy_init(dsi->dphy);
+       if (ret)
+               return ret;
+
+       ret = phy_set_mode(dsi->dphy, PHY_MODE_MIPI_DPHY);
+       if (ret)
+               goto err_phy_exit;
+
+       ret = phy_configure(dsi->dphy, &output->phy_opts);
+       if (ret)
+               goto err_phy_exit;
+
+       ret = phy_power_on(dsi->dphy);
+       if (ret)
+               goto err_phy_exit;
 
        /* Activate the PLL and wait until it's locked. */
        writel(PLL_LOCKED, dsi->regs + MCTL_MAIN_STS_CLR);
        writel(DPHY_CMN_PSO | DPHY_ALL_D_PDN | DPHY_C_PDN | DPHY_CMN_PDN,
               dsi->regs + MCTL_DPHY_CFG0);
-       WARN_ON_ONCE(readl_poll_timeout(dsi->regs + MCTL_MAIN_STS, status,
-                                       status & PLL_LOCKED, 100, 100));
+       ret = readl_poll_timeout(dsi->regs + MCTL_MAIN_STS, status,
+                                status & PLL_LOCKED, 100, 100);
+       if (ret)
+               goto err_phy_power_off;
+
        /* De-assert data and clock reset lines. */
        writel(DPHY_CMN_PSO | DPHY_ALL_D_PDN | DPHY_C_PDN | DPHY_CMN_PDN |
               DPHY_D_RSTB(output->dev->lanes) | DPHY_C_RSTB,
               dsi->regs + MCTL_DPHY_CFG0);
        dsi->phy_initialized = true;
+
+       return 0;
+
+err_phy_power_off:
+       phy_power_off(dsi->dphy);
+err_phy_exit:
+       phy_exit(dsi->dphy);
+
+       return ret;
 }
 
 static void cdns_dsi_init_link(struct cdns_dsi *dsi)
@@ -716,7 +740,7 @@ static void cdns_dsi_bridge_atomic_pre_enable(struct 
drm_bridge *bridge,
        unsigned long tx_byte_period;
        struct cdns_dsi_cfg dsi_cfg;
        u32 tmp, reg_wakeup, div, status;
-       int nlanes;
+       int nlanes, ret;
 
        /*
         * The cdns-dsi controller needs to be enabled before it's DPI source
@@ -753,7 +777,12 @@ static void cdns_dsi_bridge_atomic_pre_enable(struct 
drm_bridge *bridge,
        nlanes = output->dev->lanes;
 
        cdns_dsi_init_link(dsi);
-       cdns_dsi_hs_init(dsi);
+       ret = cdns_dsi_hs_init(dsi);
+       if (ret) {
+               dev_err(dsi->base.dev, "failed to initialize DSI PHY: %d\n",
+                       ret);
+               goto err_disable;
+       }
 
        /*
         * Now that the DSI Link and DSI Phy are initialized,
@@ -763,10 +792,13 @@ static void cdns_dsi_bridge_atomic_pre_enable(struct 
drm_bridge *bridge,
        for (int i = 0; i < nlanes; i++)
                tmp |= DATA_LANE_RDY(i);
 
-       if (readl_poll_timeout(dsi->regs + MCTL_MAIN_STS, status,
-                              (tmp == (status & tmp)), 100, 500000))
+       ret = readl_poll_timeout(dsi->regs + MCTL_MAIN_STS, status,
+                                (tmp == (status & tmp)), 100, 500000);
+       if (ret) {
                dev_err(dsi->base.dev,
                        "Timed Out: DSI-DPhy Clock and Data Lanes not 
ready.\n");
+               goto err_disable;
+       }
 
        writel(HBP_LEN(dsi_cfg.hbp) | HSA_LEN(dsi_cfg.hsa),
               dsi->regs + VID_HSIZE1);
@@ -886,6 +918,19 @@ static void cdns_dsi_bridge_atomic_pre_enable(struct 
drm_bridge *bridge,
 
        tmp = readl(dsi->regs + MCTL_MAIN_EN) | IF_EN(input->id);
        writel(tmp, dsi->regs + MCTL_MAIN_EN);
+
+       return;
+
+err_disable:
+       if (dsi->phy_initialized) {
+               dsi->phy_initialized = false;
+               phy_power_off(dsi->dphy);
+               phy_exit(dsi->dphy);
+       }
+       dsi->link_initialized = false;
+       if (dsi->platform_ops && dsi->platform_ops->disable)
+               dsi->platform_ops->disable(dsi);
+       pm_runtime_put(dsi->base.dev);
 }
 
 static u32 *cdns_dsi_bridge_get_input_bus_fmts(struct drm_bridge *bridge,
-- 
2.50.1 (Apple Git-155)

Reply via email to