[PATCH 3/3] drm: lcdif: Wait for vblank before disabling DMA
From: Paul Kocialkowski
Date: Mon Mar 30 2026 - 18:51:55 EST
It is necessary to wait for the full frame to finish streaming
through the DMA engine before we can safely disable it by removing
the DISP_PARA_DISP_ON bit. Disabling it in-flight can leave the
hardware confused and unable to resume streaming for the next frame.
This causes the FIFO underrun and empty status bits to be set and
a single solid color to be shown on the display, coming from one of
the pixels of the previous frame. The issue occurs sporadically when
a new mode is set, which triggers the crtc disable and enable paths.
Setting the shadow load bit and waiting for it to be cleared by the
DMA engine allows waiting for completion.
The NXP BSP driver addresses this issue with a hardcoded 25 ms sleep.
Fixes: 9db35bb349a0 ("drm: lcdif: Add support for i.MX8MP LCDIF variant")
Signed-off-by: Paul Kocialkowski <paulk@xxxxxxxxxxx>
Co-developed-by: Lucas Stach <l.stach@xxxxxxxxxxxxxx>
---
drivers/gpu/drm/mxsfb/lcdif_kms.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/gpu/drm/mxsfb/lcdif_kms.c b/drivers/gpu/drm/mxsfb/lcdif_kms.c
index 1aac354041c7..7dce7f48d938 100644
--- a/drivers/gpu/drm/mxsfb/lcdif_kms.c
+++ b/drivers/gpu/drm/mxsfb/lcdif_kms.c
@@ -393,6 +393,22 @@ static void lcdif_disable_controller(struct lcdif_drm_private *lcdif)
if (ret)
drm_err(lcdif->drm, "Failed to disable controller!\n");
+ /*
+ * It is necessary to wait for the full frame to finish streaming
+ * through the DMA engine before we can safely disable it by removing
+ * the DISP_PARA_DISP_ON bit. Disabling it in-flight can leave the
+ * hardware confused and unable to resume streaming for the next frame.
+ */
+ reg = readl(lcdif->base + LCDC_V8_CTRLDESCL0_5);
+ reg |= CTRLDESCL0_5_SHADOW_LOAD_EN;
+ writel(reg, lcdif->base + LCDC_V8_CTRLDESCL0_5);
+
+ ret = readl_poll_timeout(lcdif->base + LCDC_V8_CTRLDESCL0_5,
+ reg, !(reg & CTRLDESCL0_5_SHADOW_LOAD_EN),
+ 0, 36000); /* Wait ~2 frame times max */
+ if (ret)
+ drm_err(lcdif->drm, "Failed to disable controller!\n");
+
reg = readl(lcdif->base + LCDC_V8_DISP_PARA);
reg &= ~DISP_PARA_DISP_ON;
writel(reg, lcdif->base + LCDC_V8_DISP_PARA);
--
2.53.0