[PATCH 1/7] drm/bridge: lt9211: drop delayed work
From: Philipp Zabel
Date: Thu Aug 06 2026 - 09:17:50 EST
Replace the delayed work with a delay and synchronous initialization
in atomic_enable. This should fix all 5 issues sashiko flagged as
high priority [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.
[1] https://sashiko.dev/#/patchset/20260719-add-lt9211c-bridge-v6-0-e56d22152586%40oss.qualcomm.com
Signed-off-by: Philipp Zabel <p.zabel@xxxxxxxxxxxxxx>
---
drivers/gpu/drm/bridge/lontium-lt9211.c | 93 ++++++++-----------------
1 file changed, 30 insertions(+), 63 deletions(-)
diff --git a/drivers/gpu/drm/bridge/lontium-lt9211.c b/drivers/gpu/drm/bridge/lontium-lt9211.c
index ffd0f9f08e2d..1b5cb601adde 100644
--- a/drivers/gpu/drm/bridge/lontium-lt9211.c
+++ b/drivers/gpu/drm/bridge/lontium-lt9211.c
@@ -62,14 +62,7 @@ struct lt9211 {
struct regulator *vccio;
bool lvds_dual_link;
bool lvds_dual_link_even_odd_swap;
- /* LT9211C specific fields */
enum lt9211_chip_type chip_type;
- struct workqueue_struct *wq;
- struct delayed_work lt9211_dw;
- struct drm_display_mode mode;
- bool bpp24;
- bool jeida;
- bool de;
};
static const struct regmap_range lt9211_rw_ranges[] = {
@@ -154,8 +147,6 @@ static const struct regmap_config lt9211c_regmap_config = {
.max_register = 0xda00,
};
-static void lt9211_delayed_work_func(struct work_struct *work);
-
static struct lt9211 *bridge_to_lt9211(struct drm_bridge *bridge)
{
return container_of(bridge, struct lt9211, bridge);
@@ -896,8 +887,8 @@ static int lt9211c_configure_plls(struct lt9211 *ctx,
return ret;
}
-static int lt9211c_configure_tx(struct lt9211 *ctx,
- const struct drm_display_mode *mode)
+static int lt9211c_configure_tx(struct lt9211 *ctx, bool jeida, bool bpp24,
+ bool de, const struct drm_display_mode *mode)
{
const struct reg_sequence lt9211c_tx_phy_off_seq[] = {
{ 0x8236, 0x00 },
@@ -949,10 +940,10 @@ static int lt9211c_configure_tx(struct lt9211 *ctx,
{ 0x8556, 0x20 },
{ 0x8568, 0x00 },
- { 0x856e, 0x10 | (ctx->de ? BIT(6) : 0) },
- { 0x856f, 0x81 | (ctx->jeida ? BIT(6) : 0) |
+ { 0x856e, 0x10 | (de ? BIT(6) : 0) },
+ { 0x856f, 0x81 | (jeida ? BIT(6) : 0) |
(ctx->lvds_dual_link ? BIT(4) : 0) |
- (ctx->bpp24 ? BIT(2) : 0) },
+ (bpp24 ? BIT(2) : 0) },
};
const struct reg_sequence lt9211c_tx_ssc_seq[] = {
@@ -995,7 +986,7 @@ static int lt9211c_configure_tx(struct lt9211 *ctx,
dev_info(ctx->dev,
"dual_link=%d,even_odd_swap=%d,bpp24=%d,jeida=%d,de=%d\n",
ctx->lvds_dual_link, ctx->lvds_dual_link_even_odd_swap,
- ctx->bpp24, ctx->jeida, ctx->de);
+ bpp24, jeida, de);
ret = regmap_multi_reg_write(ctx->regmap, lt9211c_tx_phy_off_seq,
ARRAY_SIZE(lt9211c_tx_phy_off_seq));
@@ -1138,39 +1129,6 @@ static int lt9211c_configure_tx(struct lt9211 *ctx,
return 0;
}
-static void lt9211_delayed_work_func(struct work_struct *work)
-{
- struct delayed_work *dw = to_delayed_work(work);
- struct lt9211 *ctx = container_of(dw, struct lt9211, lt9211_dw);
- const struct drm_display_mode *mode = &ctx->mode;
- int ret;
-
- if (ctx->chip_type != LT9211C) {
- dev_err(ctx->dev, "LT9211: Delayed work called for non-LT9211C chip\n");
- return;
- }
-
- ret = lt9211c_configure_rx(ctx);
- if (ret)
- return;
-
- ret = lt9211c_autodetect_rx(ctx, mode);
- if (ret)
- return;
-
- ret = lt9211c_configure_timing(ctx, mode);
- if (ret)
- return;
-
- ret = lt9211c_configure_plls(ctx, mode);
- if (ret)
- return;
-
- ret = lt9211c_configure_tx(ctx, mode);
- if (ret)
- return;
-}
-
static void lt9211_atomic_enable(struct drm_bridge *bridge,
struct drm_atomic_commit *state)
{
@@ -1240,11 +1198,30 @@ static void lt9211_atomic_enable(struct drm_bridge *bridge,
if (ret)
return;
- if (ctx->chip_type == LT9211C && ctx->wq) {
- drm_mode_copy(&ctx->mode, mode);
- /* LT9211C must enable after mipi clock enable */
- queue_delayed_work(ctx->wq, &ctx->lt9211_dw,
- msecs_to_jiffies(100));
+ if (ctx->chip_type == LT9211C) {
+ msleep(100);
+
+ ret = lt9211c_configure_rx(ctx);
+ if (ret)
+ return;
+
+ ret = lt9211c_autodetect_rx(ctx, mode);
+ if (ret)
+ return;
+
+ ret = lt9211c_configure_timing(ctx, mode);
+ if (ret)
+ return;
+
+ ret = lt9211c_configure_plls(ctx, mode);
+ if (ret)
+ return;
+
+ ret = lt9211c_configure_tx(ctx, lvds_format_jeida, lvds_format_24bpp,
+ bus_flags & DRM_BUS_FLAG_DE_HIGH, mode);
+ if (ret)
+ return;
+
dev_dbg(ctx->dev, "LT9211C enabled.\n");
return;
}
@@ -1501,13 +1478,6 @@ static int lt9211_probe(struct i2c_client *client)
if (IS_ERR(ctx->regmap))
return PTR_ERR(ctx->regmap);
- if (ctx->chip_type == LT9211C) {
- ctx->wq = create_workqueue("lt9211_work");
- if (!ctx->wq)
- return -ENOMEM;
- INIT_DELAYED_WORK(&ctx->lt9211_dw, lt9211_delayed_work_func);
- }
-
dev_set_drvdata(dev, ctx);
i2c_set_clientdata(client, ctx);
@@ -1525,9 +1495,6 @@ static void lt9211_remove(struct i2c_client *client)
{
struct lt9211 *ctx = i2c_get_clientdata(client);
- if (ctx->wq)
- destroy_workqueue(ctx->wq);
-
drm_bridge_remove(&ctx->bridge);
}
--
2.47.3