<div dir="ltr"><div>Reviewed-by: Thomas Hebb <<a href="mailto:tommyhebb@gmail.com">tommyhebb@gmail.com</a>></div><div><br></div><div>Thank you for catching this, and sorry that my original fix broke things.</div><div>There had actually been a report of this breakage from my patch, but I</div><div>missed that email until it had already been merged and then didn't have</div><div>time to follow up on it. Totally my bad.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Sep 27, 2021 at 11:00 AM Brian Norris <<a href="mailto:briannorris@chromium.org">briannorris@chromium.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">In commit 43c2de1002d2, we moved most HW configuration to bind(), but we<br>
didn't move the runtime PM management. Therefore, depending on initial<br>
boot state, runtime-PM workqueue delays, and other timing factors, we<br>
may disable our power domain in between the hardware configuration<br>
(bind()) and when we enable the display. This can cause us to lose<br>
hardware state and fail to configure our display. For example:<br>
<br>
  dw-mipi-dsi-rockchip ff968000.mipi: failed to write command FIFO<br>
  panel-innolux-p079zca ff960000.mipi.0: failed to write command 0<br>
<br>
or:<br>
<br>
  dw-mipi-dsi-rockchip ff968000.mipi: failed to write command FIFO<br>
  panel-kingdisplay-kd097d04 ff960000.mipi.0: failed write init cmds: -110<br>
<br>
We should match the runtime PM to the lifetime of the bind()/unbind()<br>
cycle.<br>
<br>
Tested on Acer Chrometab 10 (RK3399 Gru-Scarlet), with panel drivers<br>
built either as modules or built-in.<br>
<br>
Side notes: it seems one is more likely to see this problem when the<br>
panel driver is built into the kernel. I've also seen this problem<br>
bisect down to commits that simply changed Kconfig dependencies, because<br>
it changed the order in which driver init functions were compiled into<br>
the kernel, and therefore the ordering and timing of built-in device<br>
probe.<br>
<br>
Fixes: 43c2de1002d2 ("drm/rockchip: dsi: move all lane config except LCDC mux to bind()")<br>
Link: <a href="https://lore.kernel.org/linux-rockchip/9aedfb528600ecf871885f7293ca4207c84d16c1.camel@gmail.com/Reported-by" rel="noreferrer" target="_blank">https://lore.kernel.org/linux-rockchip/9aedfb528600ecf871885f7293ca4207c84d16c1.camel@gmail.com/<br>
Reported-by</a>: <<a href="mailto:aleksandr.o.makarov@gmail.com" target="_blank">aleksandr.o.makarov@gmail.com</a>><br>
Cc: <<a href="mailto:stable@vger.kernel.org" target="_blank">stable@vger.kernel.org</a>><br>
Signed-off-by: Brian Norris <<a href="mailto:briannorris@chromium.org" target="_blank">briannorris@chromium.org</a>><br>
Tested-by: Nícolas F. R. A. Prado <<a href="mailto:nfraprado@collabora.com" target="_blank">nfraprado@collabora.com</a>><br>
---<br>
<br>
Changes in v2:<br>
- Clean up pm-runtime state in error cases.<br>
- Correct git hash for Fixes.<br>
<br>
 .../gpu/drm/rockchip/dw-mipi-dsi-rockchip.c   | 37 ++++++++++---------<br>
 1 file changed, 19 insertions(+), 18 deletions(-)<br>
<br>
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c<br>
index a2262bee5aa4..45676b23c019 100644<br>
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c<br>
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c<br>
@@ -773,10 +773,6 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)<br>
        if (mux < 0)<br>
                return;<br>
<br>
-       pm_runtime_get_sync(dsi->dev);<br>
-       if (dsi->slave)<br>
-               pm_runtime_get_sync(dsi->slave->dev);<br>
-<br>
        /*<br>
         * For the RK3399, the clk of grf must be enabled before writing grf<br>
         * register. And for RK3288 or other soc, this grf_clk must be NULL,<br>
@@ -795,20 +791,10 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)<br>
        clk_disable_unprepare(dsi->grf_clk);<br>
 }<br>
<br>
-static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)<br>
-{<br>
-       struct dw_mipi_dsi_rockchip *dsi = to_dsi(encoder);<br>
-<br>
-       if (dsi->slave)<br>
-               pm_runtime_put(dsi->slave->dev);<br>
-       pm_runtime_put(dsi->dev);<br>
-}<br>
-<br>
 static const struct drm_encoder_helper_funcs<br>
 dw_mipi_dsi_encoder_helper_funcs = {<br>
        .atomic_check = dw_mipi_dsi_encoder_atomic_check,<br>
        .enable = dw_mipi_dsi_encoder_enable,<br>
-       .disable = dw_mipi_dsi_encoder_disable,<br>
 };<br>
<br>
 static int rockchip_dsi_drm_create_encoder(struct dw_mipi_dsi_rockchip *dsi,<br>
@@ -938,10 +924,14 @@ static int dw_mipi_dsi_rockchip_bind(struct device *dev,<br>
                put_device(second);<br>
        }<br>
<br>
+       pm_runtime_get_sync(dsi->dev);<br>
+       if (dsi->slave)<br>
+               pm_runtime_get_sync(dsi->slave->dev);<br>
+<br>
        ret = clk_prepare_enable(dsi->pllref_clk);<br>
        if (ret) {<br>
                DRM_DEV_ERROR(dev, "Failed to enable pllref_clk: %d\n", ret);<br>
-               return ret;<br>
+               goto out_pm_runtime;<br>
        }<br>
<br>
        /*<br>
@@ -953,7 +943,7 @@ static int dw_mipi_dsi_rockchip_bind(struct device *dev,<br>
        ret = clk_prepare_enable(dsi->grf_clk);<br>
        if (ret) {<br>
                DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret);<br>
-               return ret;<br>
+               goto out_pm_runtime;<br>
        }<br>
<br>
        dw_mipi_dsi_rockchip_config(dsi);<br>
@@ -965,16 +955,23 @@ static int dw_mipi_dsi_rockchip_bind(struct device *dev,<br>
        ret = rockchip_dsi_drm_create_encoder(dsi, drm_dev);<br>
        if (ret) {<br>
                DRM_DEV_ERROR(dev, "Failed to create drm encoder\n");<br>
-               return ret;<br>
+               goto out_pm_runtime;<br>
        }<br>
<br>
        ret = dw_mipi_dsi_bind(dsi->dmd, &dsi->encoder);<br>
        if (ret) {<br>
                DRM_DEV_ERROR(dev, "Failed to bind: %d\n", ret);<br>
-               return ret;<br>
+               goto out_pm_runtime;<br>
        }<br>
<br>
        return 0;<br>
+<br>
+out_pm_runtime:<br>
+       pm_runtime_put(dsi->dev);<br>
+       if (dsi->slave)<br>
+               pm_runtime_put(dsi->slave->dev);<br>
+<br>
+       return ret;<br>
 }<br>
<br>
 static void dw_mipi_dsi_rockchip_unbind(struct device *dev,<br>
@@ -989,6 +986,10 @@ static void dw_mipi_dsi_rockchip_unbind(struct device *dev,<br>
        dw_mipi_dsi_unbind(dsi->dmd);<br>
<br>
        clk_disable_unprepare(dsi->pllref_clk);<br>
+<br>
+       pm_runtime_put(dsi->dev);<br>
+       if (dsi->slave)<br>
+               pm_runtime_put(dsi->slave->dev);<br>
 }<br>
<br>
 static const struct component_ops dw_mipi_dsi_rockchip_ops = {<br>
-- <br>
2.33.0.685.g46640cef36-goog<br>
<br>
</blockquote></div></div>