Skip to content

Commit a02e841

Browse files
Kaustabh Chakrabortygregkh
authored andcommitted
drm/exynos: exynos7_drm_decon: properly clear channels during bind
[ Upstream commit 5f1a453 ] 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 <[email protected]> Signed-off-by: Inki Dae <[email protected]> Stable-dep-of: e1361a4 ("drm/exynos: exynos7_drm_decon: remove ctx->suspended") Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 2812c6b commit a02e841

File tree

1 file changed

+32
-23
lines changed

1 file changed

+32
-23
lines changed

drivers/gpu/drm/exynos/exynos7_drm_decon.c

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,28 @@ static const enum drm_plane_type decon_win_types[WINDOWS_NR] = {
8181
DRM_PLANE_TYPE_CURSOR,
8282
};
8383

84+
/**
85+
* decon_shadow_protect_win() - disable updating values from shadow registers at vsync
86+
*
87+
* @ctx: display and enhancement controller context
88+
* @win: window to protect registers for
89+
* @protect: 1 to protect (disable updates)
90+
*/
91+
static void decon_shadow_protect_win(struct decon_context *ctx,
92+
unsigned int win, bool protect)
93+
{
94+
u32 bits, val;
95+
96+
bits = SHADOWCON_WINx_PROTECT(win);
97+
98+
val = readl(ctx->regs + SHADOWCON);
99+
if (protect)
100+
val |= bits;
101+
else
102+
val &= ~bits;
103+
writel(val, ctx->regs + SHADOWCON);
104+
}
105+
84106
static void decon_wait_for_vblank(struct decon_context *ctx)
85107
{
86108
if (ctx->suspended)
@@ -101,18 +123,27 @@ static void decon_wait_for_vblank(struct decon_context *ctx)
101123
static void decon_clear_channels(struct decon_context *ctx)
102124
{
103125
unsigned int win, ch_enabled = 0;
126+
u32 val;
104127

105128
/* Check if any channel is enabled. */
106129
for (win = 0; win < WINDOWS_NR; win++) {
107-
u32 val = readl(ctx->regs + WINCON(win));
130+
val = readl(ctx->regs + WINCON(win));
108131

109132
if (val & WINCONx_ENWIN) {
133+
decon_shadow_protect_win(ctx, win, true);
134+
110135
val &= ~WINCONx_ENWIN;
111136
writel(val, ctx->regs + WINCON(win));
112137
ch_enabled = 1;
138+
139+
decon_shadow_protect_win(ctx, win, false);
113140
}
114141
}
115142

143+
val = readl(ctx->regs + DECON_UPDATE);
144+
val |= DECON_UPDATE_STANDALONE_F;
145+
writel(val, ctx->regs + DECON_UPDATE);
146+
116147
/* Wait for vsync, as disable channel takes effect at next vsync */
117148
if (ch_enabled)
118149
decon_wait_for_vblank(ctx);
@@ -340,28 +371,6 @@ static void decon_win_set_colkey(struct decon_context *ctx, unsigned int win)
340371
writel(keycon1, ctx->regs + WKEYCON1_BASE(win));
341372
}
342373

343-
/**
344-
* decon_shadow_protect_win() - disable updating values from shadow registers at vsync
345-
*
346-
* @ctx: display and enhancement controller context
347-
* @win: window to protect registers for
348-
* @protect: 1 to protect (disable updates)
349-
*/
350-
static void decon_shadow_protect_win(struct decon_context *ctx,
351-
unsigned int win, bool protect)
352-
{
353-
u32 bits, val;
354-
355-
bits = SHADOWCON_WINx_PROTECT(win);
356-
357-
val = readl(ctx->regs + SHADOWCON);
358-
if (protect)
359-
val |= bits;
360-
else
361-
val &= ~bits;
362-
writel(val, ctx->regs + SHADOWCON);
363-
}
364-
365374
static void decon_atomic_begin(struct exynos_drm_crtc *crtc)
366375
{
367376
struct decon_context *ctx = crtc->ctx;

0 commit comments

Comments
 (0)