When using continuous clock, the cdns dsi doesn't keep the clock lanes in
LP-11 long enough to signal a stop state, although the data lanes are
kept high long enough. The data lanes most likely stay in LP-11 until
there is data to send, so the LP-11 duration is not defined.

While some DSI peripherals seem to work fine without correct stop-state
on the clock lane, at least Xilinx D-PHY RX fails to initialize if it
does not observe correct stop-state.

Add explicit stop-state handling to the driver. This is not described in
the documentation, but observing the clk and data lanes with an
oscilloscope, the solution in this patch seems to work:

Set the FORCE_STOP flags for clock and data lanes before starting the
D-PHY power up and init sequence, and drop the FORCE_STOP flags after
the init has been done, and 100 us has passed.

Fixes: e19233955d9e ("drm/bridge: Add Cadence DSI driver")
Signed-off-by: Tomi Valkeinen <[email protected]>
---
 drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c 
b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
index 4b7a3bf58255..b9c87f13177a 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
@@ -635,9 +635,16 @@ static void cdns_dsi_hs_init(struct cdns_dsi *dsi)
 {
        struct cdns_dsi_output *output = &dsi->output;
        u32 status;
+       u32 val;
 
        if (dsi->phy_initialized)
                return;
+
+       /* Set force stop state on all lanes */
+       val = readl(dsi->regs + MCTL_MAIN_EN);
+       val |= DATA_FORCE_STOP | CLK_FORCE_STOP;
+       writel(val, dsi->regs + MCTL_MAIN_EN);
+
        /*
         * Power all internal DPHY blocks down and maintain their reset line
         * asserted before changing the DPHY config.
@@ -661,6 +668,13 @@ static void cdns_dsi_hs_init(struct cdns_dsi *dsi)
        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);
+
+       /* Keep stop state for at least 100 us */
+       usleep_range(100, 200);
+
+       val &= ~(DATA_FORCE_STOP | CLK_FORCE_STOP);
+       writel(val, dsi->regs + MCTL_MAIN_EN);
+
        dsi->phy_initialized = true;
 }
 

-- 
2.43.0

Reply via email to