Replace the asynchronous work item with synchronous initialization in
lt9211_atomic_enable. This should fix 3 issues flagged by sashiko [1].

The next bridge or panel in the chain may depend on the LVDS signal
being active after atomic_enable, so arbitrarily deferring bridge
initialization is not an option.

If deferring initialization into an asynchronous work item fixes DSI
stream detection, there might be a bug in the upstream display
controller or MIPI DSI host controller bridge drivers, as the DSI
signal should already be streaming when lt9211_atomic_enable is called.

[1] https://lore.kernel.org/all/[email protected]/

Signed-off-by: Philipp Zabel <[email protected]>
---
 drivers/gpu/drm/bridge/lontium-lt9211.c | 121 ++++++++----------------
 1 file changed, 38 insertions(+), 83 deletions(-)

diff --git a/drivers/gpu/drm/bridge/lontium-lt9211.c 
b/drivers/gpu/drm/bridge/lontium-lt9211.c
index 9226d967b271..244979fb9ae6 100644
--- a/drivers/gpu/drm/bridge/lontium-lt9211.c
+++ b/drivers/gpu/drm/bridge/lontium-lt9211.c
@@ -20,7 +20,6 @@
 #include <linux/of_graph.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
-#include <linux/workqueue.h>
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_bridge.h>
@@ -72,14 +71,6 @@ struct lt9211 {
        bool                            lvds_dual_link;
        bool                            lvds_dual_link_even_odd_swap;
        const struct lt9211_chip_data   *chip_data;
-       /* LT9211C specific fields */
-       struct workqueue_struct         *wq;
-       struct work_struct              lt9211_work;
-       struct drm_crtc                 *lt9211c_crtc;
-       struct drm_display_mode lt9211c_mode;
-       bool                            lt9211c_bpp24;
-       bool                            lt9211c_jeida;
-       bool                            lt9211c_de_high;
 };
 
 static const struct regmap_range lt9211_rw_ranges[] = {
@@ -1157,51 +1148,6 @@ static int lt9211c_configure_tx(struct lt9211 *ctx, bool 
jeida, bool bpp24,
        return 0;
 }
 
-static void lt9211_work_func(struct work_struct *work)
-{
-       struct lt9211 *ctx = container_of(work, struct lt9211, lt9211_work);
-       const struct drm_display_mode *mode = &ctx->lt9211c_mode;
-       int ret;
-
-       /* wait for vblank irq to correctly configure bridge and autodetect 
stream */
-       ret = drm_crtc_wait_one_vblank(ctx->lt9211c_crtc);
-       if (ret) {
-               dev_err(ctx->dev, "LT9211C: wait for vblank failed: %d\n", ret);
-               return;
-       }
-
-       ret = lt9211c_configure_rx(ctx);
-       if (ret) {
-               dev_err(ctx->dev, "LT9211C: configure_rx failed: %d\n", ret);
-               return;
-       }
-
-       ret = lt9211c_autodetect_rx(ctx, mode);
-       if (ret) {
-               dev_err(ctx->dev, "LT9211C: autodetect_rx failed: %d\n", ret);
-               return;
-       }
-
-       ret = lt9211c_configure_timing(ctx, mode);
-       if (ret) {
-               dev_err(ctx->dev, "LT9211C: configure_timing failed: %d\n", 
ret);
-               return;
-       }
-
-       ret = lt9211c_configure_plls(ctx, mode);
-       if (ret) {
-               dev_err(ctx->dev, "LT9211C: configure_plls failed: %d\n", ret);
-               return;
-       }
-
-       ret = lt9211c_configure_tx(ctx, ctx->lt9211c_jeida, ctx->lt9211c_bpp24,
-                                  ctx->lt9211c_de_high, mode);
-       if (ret) {
-               dev_err(ctx->dev, "LT9211C: configure_tx failed: %d\n", ret);
-               return;
-       }
-}
-
 static void lt9211_atomic_enable(struct drm_bridge *bridge,
                                 struct drm_atomic_state *state)
 {
@@ -1272,17 +1218,45 @@ static void lt9211_atomic_enable(struct drm_bridge 
*bridge,
                return;
 
        if (ctx->chip_data->chip_type == LT9211C) {
-               drm_mode_copy(&ctx->lt9211c_mode, mode);
-               ctx->lt9211c_bpp24 = lvds_format_24bpp;
-               ctx->lt9211c_jeida = lvds_format_jeida;
-               ctx->lt9211c_de_high = !!(bus_flags & DRM_BUS_FLAG_DE_HIGH);
-               ctx->lt9211c_crtc = crtc;
+               /* wait for vblank irq to correctly configure bridge and 
autodetect stream */
+               ret = drm_crtc_wait_one_vblank(crtc);
+               if (ret) {
+                       dev_err(ctx->dev, "LT9211C: wait for vblank failed: 
%d\n", ret);
+                       return;
+               }
 
-               /*
-                * Needs a live DSI stream to auto-detect RX resolution/format;
-                * defer bridge configuration until vblank inside the work item.
-                */
-               queue_work(ctx->wq, &ctx->lt9211_work);
+               ret = lt9211c_configure_rx(ctx);
+               if (ret) {
+                       dev_err(ctx->dev, "LT9211C: configure_rx failed: %d\n", 
ret);
+                       return;
+               }
+
+               ret = lt9211c_autodetect_rx(ctx, mode);
+               if (ret) {
+                       dev_err(ctx->dev, "LT9211C: autodetect_rx failed: 
%d\n", ret);
+                       return;
+               }
+
+               ret = lt9211c_configure_timing(ctx, mode);
+               if (ret) {
+                       dev_err(ctx->dev, "LT9211C: configure_timing failed: 
%d\n", ret);
+                       return;
+               }
+
+               ret = lt9211c_configure_plls(ctx, mode);
+               if (ret) {
+                       dev_err(ctx->dev, "LT9211C: configure_plls failed: 
%d\n", ret);
+                       return;
+               }
+
+               ret = lt9211c_configure_tx(ctx, lvds_format_jeida, 
lvds_format_24bpp,
+                                          bus_flags & DRM_BUS_FLAG_DE_HIGH, 
mode);
+               if (ret) {
+                       dev_err(ctx->dev, "LT9211C: configure_tx failed: %d\n", 
ret);
+                       return;
+               }
+
+               dev_dbg(ctx->dev, "LT9211C enabled.\n");
                return;
        }
 
@@ -1320,9 +1294,6 @@ static void lt9211_atomic_disable(struct drm_bridge 
*bridge,
        struct lt9211 *ctx = bridge_to_lt9211(bridge);
        int ret;
 
-       if (ctx->chip_data->chip_type == LT9211C)
-               cancel_work_sync(&ctx->lt9211_work);
-
        /*
         * Put the chip in reset, pull nRST line low,
         * and assure lengthy 10ms reset low timing.
@@ -1483,11 +1454,6 @@ static int lt9211_host_attach(struct lt9211 *ctx)
        return 0;
 }
 
-static void lt9211_destroy_wq(void *data)
-{
-       destroy_workqueue(data);
-}
-
 static int lt9211_probe(struct i2c_client *client)
 {
        struct device *dev = &client->dev;
@@ -1532,17 +1498,6 @@ static int lt9211_probe(struct i2c_client *client)
        if (ret)
                return ret;
 
-       if (ctx->chip_data->chip_type == LT9211C) {
-               ctx->wq = create_workqueue("lt9211_work");
-               if (!ctx->wq)
-                       return -ENOMEM;
-               /* Register after DSI attach so devres flushes work before 
freeing ctx->dsi. */
-               ret = devm_add_action_or_reset(dev, lt9211_destroy_wq, ctx->wq);
-               if (ret)
-                       return ret;
-               INIT_WORK(&ctx->lt9211_work, lt9211_work_func);
-       }
-
        return 0;
 }
 
-- 
2.47.3

Reply via email to