[PATCH] drm/bridge: dw-mipi-dsi: use the lane rate for lbcc when lanes run faster

From: Romain TISSERAND

Date: Sun Oct 25 2026 - 10:27:00 EST


Commit ac87d23694f4 ("drm/bridge: synopsys: dw-mipi-dsi: Use pixel clock
rate to calculate lbcc") counts HSA, HBP and HLINE from the pixel clock,
which is only right when the lanes run at the pixel bandwidth (pixel
clock * bpp / lanes). Commit 93e82bb4de01 ("drm/bridge: synopsys:
dw-mipi-dsi: Fix hcomponent lbcc for burst mode") went back to the lane
rate for burst mode, where the lanes are faster on purpose.

The Rockchip glue runs the lanes faster in every mode: it adds 25% to
the pixel bandwidth, or uses the rate the panel asks for. In non-burst
video mode the line programmed in lane byte clocks is then shorter than
the DPI line. On the GPD XD (RK3288, ILI9881C panel, 4 lanes at
752 Mbps, 59.5 MHz pixel clock, htotal 747) HLINE was 561 lane byte
clocks (6.0 us) for a 12.55 us line: the DPI payload FIFO overflows
(dpi_pld_wr_err in DSI_INT_ST1) and the panel shows garbage as soon as
a client page-flips.

Use the lane rate when it is clearly above the pixel bandwidth (more
than 1/8), and keep the pixel clock formula when both match, as on
i.MX93, Meson and STM in non-burst mode, where lane_mbps is the pixel
bandwidth rounded up to the next MHz. On the GPD XD this gives HLINE
1181, HSA 21 and HBP 7, and the picture is stable.

Fixes: ac87d23694f4 ("drm/bridge: synopsys: dw-mipi-dsi: Use pixel clock rate to calculate lbcc")
Signed-off-by: Romain TISSERAND <romain.tisserand@xxxxxxxxx>
---
Notes for reviewers (not for the changelog):
- The 1/8 threshold separates glues that report the pixel bandwidth
rounded up to the next MHz (i.MX93, Meson; STM in non-burst mode) from
Rockchip, which adds 25% in every mode. If a per-glue flag is
preferred instead of a threshold, I can rework it that way.
- Testing: built with W=1 for arm (multi_v7) and arm64 (defconfig),
DRM_DW_MIPI_DSI=y and =m, no warnings. Tested live on the GPD XD
(RK3288, ILI9881C, non-burst with sync pulses), 6.18.54 with this
exact change applied: HLINE 1181, HSA 21, HBP 7 read back from the
DSI host, no dpi_pld_wr_err in DSI_INT_ST1 while the UI page-flips,
and a clean picture in the UI and in games (before the change: garbage
as soon as a client page-flips).
Not tested on i.MX93, Meson or STM hardware; for them the computation
is unchanged unless the lane rate is more than 1/8 above the pixel
bandwidth.
- Tool disclosure: this patch was prepared with Claude Opus 5.5
(Anthropic) as a coding assistant, in an interactive session where I
asked it to bring up the GPD XD display and then to prepare the fix
for upstream. It located the cause from the DSI host registers, went
through the history of the lbcc computation (ac87d23694f4,
93e82bb4de01) and the lane rates of the other dw-mipi-dsi glues, and
drafted the code change and the changelog. I reviewed and understand
both, and tested the patch on the GPD XD as described above.

drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 23 +++++++++++++------
1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
index 22d1b8cbe1..b026b602ab 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
@@ -781,19 +781,28 @@ static u32 dw_mipi_dsi_get_hcomponent_lbcc(struct dw_mipi_dsi *dsi,
u32 hcomponent)
{
u32 frac, lbcc, minimum_lbcc;
+ u64 pixel_kbps;
int bpp;

- if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) {
+ bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
+ if (bpp < 0) {
+ dev_err(dsi->dev, "failed to get bpp\n");
+ return 0;
+ }
+
+ /*
+ * Use the lane rate when it is above the pixel bandwidth (burst, or
+ * glues adding margin in all modes); the 1/8 slack ignores lane_mbps
+ * being rounded up to the next MHz. Otherwise the pixel clock is more
+ * precise.
+ */
+ pixel_kbps = div_u64((u64)mode->clock * bpp, dsi->lanes);
+ if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST ||
+ (u64)dsi->lane_mbps * MSEC_PER_SEC > pixel_kbps + pixel_kbps / 8) {
/* lbcc based on lane_mbps */
lbcc = hcomponent * dsi->lane_mbps * MSEC_PER_SEC / 8;
} else {
/* lbcc based on pixel clock rate */
- bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
- if (bpp < 0) {
- dev_err(dsi->dev, "failed to get bpp\n");
- return 0;
- }
-
lbcc = div_u64((u64)hcomponent * mode->clock * bpp, dsi->lanes * 8);
}


base-commit: cf61bef3801c3c9d0d8c39026b7b2fb242898a3a
--
2.43.0