mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
drm/exynos: exynos7_drm_decon: properly clear channels during bind
[ 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>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
98c15dc950
commit
cbbe08268a
@@ -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)
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user