From: Sean Paul Date: Thu, 13 Sep 2012 23:18:47 +0000 (-0700) Subject: drm/exynos: mixer: Move layer update out of vsync X-Git-Url: http://git.cascardo.eti.br/?a=commitdiff_plain;h=546a8af5adf17d04e1a19583e8d24440e1ddb225;p=cascardo%2Flinux.git drm/exynos: mixer: Move layer update out of vsync Move the mixer's layer update command out of the vsync interrupt and do it only once per layer per vsync. We also don't want to finish a pageflip if a layer update is in progress since it will still be scanning out and X/userspace will start drawing to the front buffer. BUG=chrome-os-partner:13692 TEST=Tested on snow, no corruption detected Change-Id: I811da726daaf52117f9a42a299dbc98b43d7c3bd Signed-off-by: Sean Paul Reviewed-on: https://gerrit.chromium.org/gerrit/33252 Reviewed-by: Stéphane Marchesin --- diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 0879538e0b64..62beac879c78 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -67,6 +67,7 @@ struct hdmi_win_data { unsigned int mode_width; unsigned int mode_height; unsigned int scan_flags; + bool updated; }; struct mixer_resources { @@ -379,6 +380,30 @@ static int mixer_wait_for_vsync(struct mixer_context *ctx) return -ETIME; } +static int mixer_get_layer_update_count(struct mixer_context *ctx) +{ + struct mixer_resources *res = &ctx->mixer_res; + u32 val; + + if (!res->is_soc_exynos5) + return 0; + + val = mixer_reg_read(res, MXR_CFG); + + 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; + + if (!res->is_soc_exynos5) + return; + + mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE); +} + static void vp_video_buffer(struct mixer_context *ctx, int win) { struct mixer_resources *res = &ctx->mixer_res; @@ -603,6 +628,13 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win) mixer_cfg_rgb_fmt(ctx, mode_height); mixer_cfg_layer(ctx, win, true); mixer_cfg_layer(ctx, MIXER_DEFAULT_WIN, true); + + /* Only allow one update per vsync */ + if (!win_data->updated) + mixer_layer_update(ctx); + + win_data->updated = true; + mixer_run(ctx); mixer_vsync_set_update(ctx, true); @@ -783,6 +815,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); @@ -805,10 +838,6 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) wake_up(&ctx->mixer_res.event_queue); goto out; } - /* layer update mandatory for exynos5 soc,and not present - * in exynos4 */ - if (res->is_soc_exynos5) - mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE); /* interlace scan need to check shadow register */ if (ctx->interlace) { @@ -824,9 +853,16 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) } drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe); + + /* 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; + exynos_drm_crtc_finish_pageflip(drm_hdmi_ctx->drm_dev, ctx->pipe); - } out: diff --git a/drivers/gpu/drm/exynos/regs-mixer.h b/drivers/gpu/drm/exynos/regs-mixer.h index d7250e6c379b..23534a786cf2 100644 --- a/drivers/gpu/drm/exynos/regs-mixer.h +++ b/drivers/gpu/drm/exynos/regs-mixer.h @@ -139,6 +139,8 @@ /* Adding reset and Layer update registers Exynos5 */ #define MXR_CFG_LAYER_UPDATE (1 << 31) +#define MXR_CFG_LAYER_UPDATE_COUNT0 29 +#define MXR_CFG_LAYER_UPDATE_COUNT_MASK ((1 << 29) | (1 << 30)) #define MXR_STATUS_SOFT_RESET (1 << 8) #endif /* SAMSUNG_REGS_MIXER_H */