summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Kocialkowski <paulk@sys-base.io>2026-04-02 20:33:51 +0200
committerLucas Stach <l.stach@pengutronix.de>2026-05-29 17:18:10 +0200
commit351af554edd994898db12217c3be39979e168d35 (patch)
tree88426e268efd4d079e8ede40547d3019c299a877
parent108b5876d6aa2c719001ba64c9c30dfb5ff15807 (diff)
downloadlinux-351af554edd994898db12217c3be39979e168d35.tar.gz
linux-351af554edd994898db12217c3be39979e168d35.zip
drm: lcdif: Wait for vblank before disabling DMA
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@sys-base.io> Co-developed-by: Lucas Stach <l.stach@pengutronix.de> Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de> Tested-by: Frieder Schrempf <frieder.schrempf@kontron.de> Acked-by: Liu Ying <victor.liu@nxp.com> Link: https://patch.msgid.link/20260402183351.3281123-3-paulk@sys-base.io Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
-rw-r--r--drivers/gpu/drm/mxsfb/lcdif_kms.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/drivers/gpu/drm/mxsfb/lcdif_kms.c b/drivers/gpu/drm/mxsfb/lcdif_kms.c
index 0b5f86c6d206..79e0f483ca20 100644
--- a/drivers/gpu/drm/mxsfb/lcdif_kms.c
+++ b/drivers/gpu/drm/mxsfb/lcdif_kms.c
@@ -375,14 +375,23 @@ static void lcdif_disable_controller(struct lcdif_drm_private *lcdif)
int ret;
reg = readl(lcdif->base + LCDC_V8_CTRLDESCL0_5);
+ /* Disable the layer for DMA. */
reg &= ~CTRLDESCL0_5_EN;
+ /*
+ * 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 |= CTRLDESCL0_5_SHADOW_LOAD_EN;
writel(reg, lcdif->base + LCDC_V8_CTRLDESCL0_5);
+ /* Wait for the frame to finish or timeout after 50 ms. */
ret = readl_poll_timeout(lcdif->base + LCDC_V8_CTRLDESCL0_5,
- reg, !(reg & CTRLDESCL0_5_EN),
- 0, 36000); /* Wait ~2 frame times max */
+ reg, !(reg & CTRLDESCL0_5_SHADOW_LOAD_EN),
+ 200, 50000);
if (ret)
- drm_err(lcdif->drm, "Failed to disable controller!\n");
+ drm_err(lcdif->drm, "Timed out waiting for final vblank!\n");
reg = readl(lcdif->base + LCDC_V8_DISP_PARA);
reg &= ~DISP_PARA_DISP_ON;