[PATCH 2/2] drm/bridge: ti-sn65dsi83: Fix problem with premature PLL locking

From: Esben Haabendal

Date: Sat Jul 11 2026 - 07:51:54 EST


Locking PLL requires the DSI HS clock to be running, which it might not be
in probe(), but should be in atomic_enable().

This resolves issues like this:

sn65dsi83 1-002c: failed to lock PLL, ret=-110
sn65dsi83 1-002c: Unexpected link status 0x01
sn65dsi83 1-002c: Unexpected link status 0x01
sn65dsi83 1-002c: reset the pipe

as seen with nwl-dsi bridge and others.

This is the same issue as addressed in the patch by Gary Bisson [1],
but changing the ti-sn65dsi83 driver instead, so we don't have to change
all other drivers that could potentially be used with this chip.

[1] https://lore.kernel.org/all/20260120-mtkdsi-v1-1-b0f4094f3ac3@xxxxxxxxx/

Signed-off-by: Esben Haabendal <esben@xxxxxxxxxx>
---
drivers/gpu/drm/bridge/ti-sn65dsi83.c | 30 ++++++++++++++----------------
1 file changed, 14 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
index 32e9eadd7452..e87bed3a6640 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
@@ -532,7 +532,6 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge,
bool test_pattern = sn65dsi83_test_pattern;
bool lvds_format_24bpp;
bool lvds_format_jeida;
- unsigned int pval;
__le16 le16val;
u16 val;
int ret;
@@ -682,26 +681,12 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge,
regmap_write(ctx->regmap, REG_VID_CHA_TEST_PATTERN,
test_pattern ? REG_VID_CHA_TEST_PATTERN_EN : 0);

- /* Enable PLL */
- regmap_write(ctx->regmap, REG_RC_PLL_EN, REG_RC_PLL_EN_PLL_EN);
- usleep_range(3000, 4000);
- ret = regmap_read_poll_timeout(ctx->regmap, REG_RC_LVDS_PLL, pval,
- pval & REG_RC_LVDS_PLL_PLL_EN_STAT,
- 1000, 100000);
- if (ret) {
- dev_err(ctx->dev, "failed to lock PLL, ret=%i\n", ret);
- /* On failure, disable PLL again and exit. */
- regmap_write(ctx->regmap, REG_RC_PLL_EN, 0x00);
- goto err_add_action;
- }
-
/* Trigger reset after CSR register update. */
regmap_write(ctx->regmap, REG_RC_RESET, REG_RC_RESET_SOFT_RESET);

/* Wait for 10ms after soft reset as specified in datasheet */
usleep_range(10000, 12000);

-err_add_action:
devm_add_action(ctx->dev, sn65dsi83_release_resources, ctx);
err_exit:
drm_bridge_exit(idx);
@@ -712,11 +697,24 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge,
{
struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge);
unsigned int pval;
- int idx;
+ int idx, ret;

if (!drm_bridge_enter(bridge, &idx))
return;

+ /* Enable PLL */
+ regmap_write(ctx->regmap, REG_RC_PLL_EN, REG_RC_PLL_EN_PLL_EN);
+ usleep_range(3000, 4000);
+ ret = regmap_read_poll_timeout(ctx->regmap, REG_RC_LVDS_PLL, pval,
+ pval & REG_RC_LVDS_PLL_PLL_EN_STAT,
+ 1000, 100000);
+ if (ret) {
+ dev_err(ctx->dev, "failed to lock PLL, ret=%i\n", ret);
+ /* On failure, disable PLL again and exit. */
+ regmap_write(ctx->regmap, REG_RC_PLL_EN, 0x00);
+ return;
+ }
+
/* Clear all errors that got asserted during initialization. */
regmap_read(ctx->regmap, REG_IRQ_STAT, &pval);
regmap_write(ctx->regmap, REG_IRQ_STAT, pval);

--
2.55.0