Skip to content

Commit 5f1a453

Browse files
Kaustabh Chakrabortydaeinki
authored andcommitted
drm/exynos: exynos7_drm_decon: properly clear channels during bind
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]>
1 parent f3cb045 commit 5f1a453

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)