[PATCH 5/8] drm/exynos: mixer: do not finish a pageflip if layer update in progress
Prathyush K
prathyush.k at samsung.com
Wed Dec 26 03:27:42 PST 2012
From: Sean Paul <seanpaul at chromium.org>
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 at chromium.org>
Signed-off-by: Prathyush K <prathyush.k at samsung.com>
---
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
More information about the dri-devel
mailing list