[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