Skip to content

Commit

Permalink
drm/exynos: exynos7_drm_decon: properly clear channels during bind
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Kaustabh Chakraborty authored and Inki Dae committed Nov 4, 2024
1 parent f3cb045 commit 5f1a453
Showing 1 changed file with 32 additions and 23 deletions.
55 changes: 32 additions & 23 deletions drivers/gpu/drm/exynos/exynos7_drm_decon.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,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)
Expand All @@ -101,18 +123,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);
Expand Down Expand Up @@ -340,28 +371,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;
Expand Down

0 comments on commit 5f1a453

Please sign in to comment.