From: Andrzej Hajda Date: Mon, 27 Jun 2016 08:52:16 +0000 (+0200) Subject: drm/exynos/decon5433: Fix standalone update code X-Git-Tag: accepted/tizen/common/20160810.161706~128 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0cdf521f9f16503abe5f953f82d348dbc33f8ffd;p=platform%2Fkernel%2Flinux-exynos.git drm/exynos/decon5433: Fix standalone update code Documentation is not clear about the subject, but it seems that shadowed registers should be updated only if STANDALONE_UPDATE_F bit is clear. After completing update of shadowed registers driver should enable this bit. Without this logic one can observe flickering, black screens or white noise. Change-Id: Ia1e54423cd321bf7c8ac9e8cf90d1dc8c8d64daf Signed-off-by: Andrzej Hajda --- diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index de234d21..6448471 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -150,6 +150,23 @@ static void decon_setup_trigger(struct decon_context *ctx) writel(val, ctx->addr + DECON_TRIGCON); } +static void decon_update(struct decon_context *ctx) +{ + decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); +} + +static void decon_wait_for_update(struct decon_context *ctx) +{ + /* wait up to duration of 2 frames */ + unsigned long timeout = jiffies + msecs_to_jiffies(2 * 1000 / 60); + + while (readl(ctx->addr + DECON_UPDATE) & STANDALONE_UPDATE_F) { + if (time_is_after_jiffies(timeout)) + break; + usleep_range(500, 1000); + } +} + static void decon_commit(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; @@ -157,6 +174,8 @@ static void decon_commit(struct exynos_drm_crtc *crtc) bool interlaced = false; u32 val; + decon_wait_for_update(ctx); + decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID, 0); /* enable clock gate */ @@ -229,6 +248,7 @@ static void decon_commit(struct exynos_drm_crtc *crtc) /* enable output and display signal */ decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID | VIDCON0_ENVID_F, ~0); + decon_update(ctx); } #define BIT_VAL(x, e, s) (((x) & ((1 << ((e) - (s) + 1)) - 1)) << (s)) @@ -322,6 +342,8 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) return; } + decon_wait_for_update(ctx); + decon_shadow_protect_win(ctx, win, true); /* FIXME: padding? padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width */ @@ -376,10 +398,7 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) decon_shadow_protect_win(ctx, win, false); - /* standalone update */ - val = readl(ctx->addr + DECON_UPDATE); - val |= STANDALONE_UPDATE_F; - writel(val, ctx->addr + DECON_UPDATE); + decon_update(ctx); if (ctx->i80_if && ctx->trg_type == EXYNOS_DISPLAY_SW_TRIGGER) atomic_set(&ctx->win_updated, 1); @@ -404,6 +423,8 @@ static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) return; } + decon_wait_for_update(ctx); + decon_shadow_protect_win(ctx, win, true); /* window disable */ @@ -413,10 +434,7 @@ static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) decon_shadow_protect_win(ctx, win, false); - /* standalone update */ - val = readl(ctx->addr + DECON_UPDATE); - val |= STANDALONE_UPDATE_F; - writel(val, ctx->addr + DECON_UPDATE); + decon_update(ctx); plane->enabled = false; } @@ -645,6 +663,8 @@ static void decon_clear_channel(struct decon_context *ctx) goto err; } + decon_wait_for_update(ctx); + for (win = 0; win < WINDOWS_NR; win++) { /* shadow update disable */ val = readl(ctx->addr + DECON_SHADOWCON); @@ -660,13 +680,10 @@ static void decon_clear_channel(struct decon_context *ctx) val = readl(ctx->addr + DECON_SHADOWCON); val &= ~SHADOWCON_Wx_PROTECT(win); writel(val, ctx->addr + DECON_SHADOWCON); - - /* standalone update */ - val = readl(ctx->addr + DECON_UPDATE); - val |= STANDALONE_UPDATE_F; - writel(val, ctx->addr + DECON_UPDATE); } + decon_update(ctx); + atomic_set(&ctx->wait_vsync_event, 1); /*