From: Sean Paul <seanpaul@xxxxxxxxxxxx> We should not finish a pageflip or set wait_for_vblank to zero if a layer update is pending. This might result in a page fault or corruption on screen. This patch adds a check in the irq handler to exit if a layer update is pending. Also, calls layer_update only once per layer per vsync. Signed-off-by: Sean Paul <seanpaul@xxxxxxxxxxxx> Signed-off-by: Prathyush K <prathyush.k@xxxxxxxxxxx> --- drivers/gpu/drm/exynos/exynos_mixer.c | 35 ++++++++++++++++++++++++++++++----- drivers/gpu/drm/exynos/regs-mixer.h | 1 + 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 2506567..3369d57 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -58,6 +58,7 @@ struct hdmi_win_data { unsigned int mode_width; unsigned int mode_height; unsigned int scan_flags; + bool updated; bool enabled; bool resume; }; @@ -486,16 +487,21 @@ static void vp_video_buffer(struct mixer_context *ctx, int win) vp_regs_dump(ctx); } -static void mixer_layer_update(struct mixer_context *ctx) +static int mixer_get_layer_update_count(struct mixer_context *ctx) { struct mixer_resources *res = &ctx->mixer_res; u32 val; val = mixer_reg_read(res, MXR_CFG); - /* allow one update per vsync only */ - if (!(val & MXR_CFG_LAYER_UPDATE_COUNT_MASK)) - mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE); + return (val & MXR_CFG_LAYER_UPDATE_COUNT_MASK) >> + MXR_CFG_LAYER_UPDATE_COUNT0; +} + +static void mixer_layer_update(struct mixer_context *ctx) +{ + struct mixer_resources *res = &ctx->mixer_res; + mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE); } static void mixer_graph_buffer(struct mixer_context *ctx, int win) @@ -547,6 +553,11 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win) ctx->interlace = false; spin_lock_irqsave(&res->reg_slock, flags); + + /* Only allow one update per vsync */ + if (ctx->mxr_ver == MXR_VER_16_0_33_0 && win_data->updated) + goto end; + mixer_vsync_set_update(ctx, false); /* setup format */ @@ -580,12 +591,15 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win) mixer_cfg_layer(ctx, win, true); /* layer update mandatory for mixer 16.0.33.0 */ - if (ctx->mxr_ver == MXR_VER_16_0_33_0) + if (ctx->mxr_ver == MXR_VER_16_0_33_0) { mixer_layer_update(ctx); + win_data->updated = true; + } mixer_run(ctx); mixer_vsync_set_update(ctx, true); +end: spin_unlock_irqrestore(&res->reg_slock, flags); } @@ -1000,6 +1014,7 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) struct mixer_context *ctx = drm_hdmi_ctx->ctx; struct mixer_resources *res = &ctx->mixer_res; u32 val, base, shadow; + int i; spin_lock(&res->reg_slock); @@ -1022,6 +1037,16 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) } drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe); + + if (ctx->mxr_ver == MXR_VER_16_0_33_0) { + /* Bail out if a layer update is pending */ + if (mixer_get_layer_update_count(ctx)) + goto out; + + for (i = 0; i < MIXER_WIN_NR; i++) + ctx->win_data[i].updated = false; + } + mixer_finish_pageflip(drm_hdmi_ctx->drm_dev, ctx->pipe); /* set wait vsync event to zero and wake up queue. */ diff --git a/drivers/gpu/drm/exynos/regs-mixer.h b/drivers/gpu/drm/exynos/regs-mixer.h index 5d8dbc0..bad2b99 100644 --- a/drivers/gpu/drm/exynos/regs-mixer.h +++ b/drivers/gpu/drm/exynos/regs-mixer.h @@ -79,6 +79,7 @@ /* bits for MXR_CFG */ #define MXR_CFG_LAYER_UPDATE (1 << 31) +#define MXR_CFG_LAYER_UPDATE_COUNT0 29 #define MXR_CFG_LAYER_UPDATE_COUNT_MASK (3 << 29) #define MXR_CFG_RGB601_0_255 (0 << 9) #define MXR_CFG_RGB601_16_235 (1 << 9) -- 1.8.0 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel