]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drm/exynos: exynos7_drm_decon: properly clear channels during bind
authorKaustabh Chakraborty <kauschluss@disroot.org>
Sat, 18 Oct 2025 02:26:41 +0000 (22:26 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 29 Oct 2025 13:04:31 +0000 (14:04 +0100)
[ Upstream commit 5f1a453974204175f20b3788824a0fe23cc36f79 ]

The DECON channels are not cleared properly as the windows aren't
shadow protected. When accompanied with an IOMMU, it pagefaults, and
the kernel panics.

Implement shadow protect/unprotect, along with a standalone update,
for channel clearing to properly take effect.

Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Stable-dep-of: e1361a4f1be9 ("drm/exynos: exynos7_drm_decon: remove ctx->suspended")
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/gpu/drm/exynos/exynos7_drm_decon.c

index 6d18a20e1104dee2edbe08436ab723a6266f7414..6223c89a66548abc5ba703a9e7c8909c13d88554 100644 (file)
@@ -82,6 +82,28 @@ static const enum drm_plane_type decon_win_types[WINDOWS_NR] = {
        DRM_PLANE_TYPE_CURSOR,
 };
 
+/**
+ * decon_shadow_protect_win() - disable updating values from shadow registers at vsync
+ *
+ * @ctx: display and enhancement controller context
+ * @win: window to protect registers for
+ * @protect: 1 to protect (disable updates)
+ */
+static void decon_shadow_protect_win(struct decon_context *ctx,
+                                    unsigned int win, bool protect)
+{
+       u32 bits, val;
+
+       bits = SHADOWCON_WINx_PROTECT(win);
+
+       val = readl(ctx->regs + SHADOWCON);
+       if (protect)
+               val |= bits;
+       else
+               val &= ~bits;
+       writel(val, ctx->regs + SHADOWCON);
+}
+
 static void decon_wait_for_vblank(struct decon_context *ctx)
 {
        if (ctx->suspended)
@@ -102,18 +124,27 @@ static void decon_wait_for_vblank(struct decon_context *ctx)
 static void decon_clear_channels(struct decon_context *ctx)
 {
        unsigned int win, ch_enabled = 0;
+       u32 val;
 
        /* Check if any channel is enabled. */
        for (win = 0; win < WINDOWS_NR; win++) {
-               u32 val = readl(ctx->regs + WINCON(win));
+               val = readl(ctx->regs + WINCON(win));
 
                if (val & WINCONx_ENWIN) {
+                       decon_shadow_protect_win(ctx, win, true);
+
                        val &= ~WINCONx_ENWIN;
                        writel(val, ctx->regs + WINCON(win));
                        ch_enabled = 1;
+
+                       decon_shadow_protect_win(ctx, win, false);
                }
        }
 
+       val = readl(ctx->regs + DECON_UPDATE);
+       val |= DECON_UPDATE_STANDALONE_F;
+       writel(val, ctx->regs + DECON_UPDATE);
+
        /* Wait for vsync, as disable channel takes effect at next vsync */
        if (ch_enabled)
                decon_wait_for_vblank(ctx);
@@ -341,28 +372,6 @@ static void decon_win_set_colkey(struct decon_context *ctx, unsigned int win)
        writel(keycon1, ctx->regs + WKEYCON1_BASE(win));
 }
 
-/**
- * decon_shadow_protect_win() - disable updating values from shadow registers at vsync
- *
- * @ctx: display and enhancement controller context
- * @win: window to protect registers for
- * @protect: 1 to protect (disable updates)
- */
-static void decon_shadow_protect_win(struct decon_context *ctx,
-                                    unsigned int win, bool protect)
-{
-       u32 bits, val;
-
-       bits = SHADOWCON_WINx_PROTECT(win);
-
-       val = readl(ctx->regs + SHADOWCON);
-       if (protect)
-               val |= bits;
-       else
-               val &= ~bits;
-       writel(val, ctx->regs + SHADOWCON);
-}
-
 static void decon_atomic_begin(struct exynos_drm_crtc *crtc)
 {
        struct decon_context *ctx = crtc->ctx;