Blob Blame History Raw
From: Russell King <rmk+kernel@armlinux.org.uk>
Date: Mon, 30 Jul 2018 11:52:34 +0100
Subject: drm/armada: use old_state for update tracking in atomic_update()
Git-commit: 3acea7b9b62c282ea3d4d0cd156ca8e35dfa8a8c
Patch-mainline: v4.19-rc1
References: FATE#326289 FATE#326079 FATE#326049 FATE#322398 FATE#326166

Rather than tracking the register state, we can now check the previous
state and decide which registers need updating from that since the old
plane state indicates the previous state which was programmed into the
hardware.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 drivers/gpu/drm/armada/armada_crtc.c    |  116 ++++++++++---------
 drivers/gpu/drm/armada/armada_crtc.h    |   12 --
 drivers/gpu/drm/armada/armada_overlay.c |  189 ++++++++++++++------------------
 3 files changed, 144 insertions(+), 173 deletions(-)

--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -1114,64 +1114,14 @@ int armada_drm_plane_atomic_check(struct
 	return 0;
 }
 
-static unsigned int armada_drm_primary_update_state(
-	struct drm_plane_state *state, struct armada_regs *regs)
-{
-	struct armada_plane *dplane = drm_to_armada_plane(state->plane);
-	struct armada_crtc *dcrtc = drm_to_armada_crtc(state->crtc);
-	struct armada_framebuffer *dfb = drm_fb_to_armada_fb(state->fb);
-	bool was_disabled;
-	unsigned int idx = 0;
-	u32 val;
-
-	val = CFG_GRA_FMT(dfb->fmt) | CFG_GRA_MOD(dfb->mod);
-	if (dfb->fmt > CFG_420)
-		val |= CFG_PALETTE_ENA;
-	if (state->visible)
-		val |= CFG_GRA_ENA;
-	if (drm_rect_width(&state->src) >> 16 != drm_rect_width(&state->dst))
-		val |= CFG_GRA_HSMOOTH;
-	if (dcrtc->interlaced)
-		val |= CFG_GRA_FTOGGLE;
-
-	was_disabled = !(dplane->state.ctrl0 & CFG_GRA_ENA);
-	if (was_disabled)
-		armada_reg_queue_mod(regs, idx,
-				     0, CFG_PDWN64x66, LCD_SPU_SRAM_PARA1);
-
-	dplane->state.ctrl0 = val;
-	dplane->state.src_hw = armada_rect_hw_fp(&state->src);
-	dplane->state.dst_hw = armada_rect_hw(&state->dst);
-	dplane->state.dst_yx = armada_rect_yx(&state->dst);
-
-	idx += armada_drm_crtc_calc_fb(&dfb->fb, state->src.x1 >> 16,
-				       state->src.y1 >> 16, regs + idx,
-				       dcrtc->interlaced);
-	armada_reg_queue_set(regs, idx, dplane->state.dst_yx,
-			     LCD_SPU_GRA_OVSA_HPXL_VLN);
-	armada_reg_queue_set(regs, idx, dplane->state.src_hw,
-			     LCD_SPU_GRA_HPXL_VLN);
-	armada_reg_queue_set(regs, idx, dplane->state.dst_hw,
-			     LCD_SPU_GZM_HPXL_VLN);
-	armada_reg_queue_mod(regs, idx, dplane->state.ctrl0, CFG_GRAFORMAT |
-			     CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |
-					 CFG_SWAPYU | CFG_YUV2RGB) |
-			     CFG_PALETTE_ENA | CFG_GRA_FTOGGLE |
-			     CFG_GRA_HSMOOTH | CFG_GRA_ENA,
-			     LCD_SPU_DMA_CTRL0);
-
-	dplane->state.vsync_update = !was_disabled;
-	dplane->state.changed = true;
-
-	return idx;
-}
-
 static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
 	struct drm_plane_state *old_state)
 {
 	struct drm_plane_state *state = plane->state;
 	struct armada_crtc *dcrtc;
 	struct armada_regs *regs;
+	u32 cfg, cfg_mask, val;
+	unsigned int idx;
 
 	DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
 
@@ -1187,13 +1137,69 @@ static void armada_drm_primary_plane_ato
 	dcrtc = drm_to_armada_crtc(state->crtc);
 	regs = dcrtc->regs + dcrtc->regs_idx;
 
-	dcrtc->regs_idx += armada_drm_primary_update_state(state, regs);
+	idx = 0;
+	if (!old_state->visible && state->visible) {
+		val = CFG_PDWN64x66;
+		if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420)
+			val |= CFG_PDWN256x24;
+		armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1);
+	}
+	val = armada_rect_hw_fp(&state->src);
+	if (armada_rect_hw_fp(&old_state->src) != val)
+		armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN);
+	val = armada_rect_yx(&state->dst);
+	if (armada_rect_yx(&old_state->dst) != val)
+		armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN);
+	val = armada_rect_hw(&state->dst);
+	if (armada_rect_hw(&old_state->dst) != val)
+		armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN);
+	if (old_state->src.x1 != state->src.x1 ||
+	    old_state->src.y1 != state->src.y1 ||
+	    old_state->fb != state->fb) {
+		idx += armada_drm_crtc_calc_fb(state->fb,
+					       state->src.x1 >> 16,
+					       state->src.y1 >> 16,
+					       regs + idx,
+					       dcrtc->interlaced);
+	}
+	if (old_state->fb != state->fb) {
+		cfg = CFG_GRA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) |
+		      CFG_GRA_MOD(drm_fb_to_armada_fb(state->fb)->mod);
+		if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420)
+			cfg |= CFG_PALETTE_ENA;
+		if (state->visible)
+			cfg |= CFG_GRA_ENA;
+		if (dcrtc->interlaced)
+			cfg |= CFG_GRA_FTOGGLE;
+		cfg_mask = CFG_GRAFORMAT |
+			   CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |
+				       CFG_SWAPYU | CFG_YUV2RGB) |
+			   CFG_PALETTE_ENA | CFG_GRA_FTOGGLE |
+			   CFG_GRA_ENA;
+	} else if (old_state->visible != state->visible) {
+		cfg = state->visible ? CFG_GRA_ENA : 0;
+		cfg_mask = CFG_GRA_ENA;
+	} else {
+		cfg = cfg_mask = 0;
+	}
+	if (drm_rect_width(&old_state->src) != drm_rect_width(&state->src) ||
+	    drm_rect_width(&old_state->dst) != drm_rect_width(&state->dst)) {
+		cfg_mask |= CFG_GRA_HSMOOTH;
+		if (drm_rect_width(&state->src) >> 16 !=
+		    drm_rect_width(&state->dst))
+			cfg |= CFG_GRA_HSMOOTH;
+	}
+
+	if (cfg_mask)
+		armada_reg_queue_mod(regs, idx, cfg, cfg_mask,
+				     LCD_SPU_DMA_CTRL0);
+
+	dcrtc->regs_idx += idx;
 }
 
 static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane,
 	struct drm_plane_state *old_state)
 {
-	struct armada_plane *dplane = drm_to_armada_plane(plane);
 	struct armada_crtc *dcrtc;
 	struct armada_regs *regs;
 	unsigned int idx = 0;
@@ -1208,8 +1214,6 @@ static void armada_drm_primary_plane_ato
 		old_state->crtc->base.id, old_state->crtc->name,
 		old_state->fb->base.id);
 
-	dplane->state.ctrl0 &= ~CFG_GRA_ENA;
-
 	dcrtc = drm_to_armada_crtc(old_state->crtc);
 	regs = dcrtc->regs + dcrtc->regs_idx;
 
--- a/drivers/gpu/drm/armada/armada_crtc.h
+++ b/drivers/gpu/drm/armada/armada_crtc.h
@@ -45,24 +45,12 @@ struct armada_plane_work {
 	struct armada_regs regs[14];
 };
 
-struct armada_plane_state {
-	u16 src_x;
-	u16 src_y;
-	u32 src_hw;
-	u32 dst_hw;
-	u32 dst_yx;
-	u32 ctrl0;
-	bool changed;
-	bool vsync_update;
-};
-
 struct armada_plane {
 	struct drm_plane	base;
 	wait_queue_head_t	frame_wait;
 	bool			next_work;
 	struct armada_plane_work works[2];
 	struct armada_plane_work *work;
-	struct armada_plane_state state;
 };
 #define drm_to_armada_plane(p) container_of(p, struct armada_plane, base)
 
--- a/drivers/gpu/drm/armada/armada_overlay.c
+++ b/drivers/gpu/drm/armada/armada_overlay.c
@@ -35,6 +35,7 @@ struct armada_ovl_plane_properties {
 
 struct armada_ovl_plane {
 	struct armada_plane base;
+	bool wait_vblank;
 	struct armada_ovl_plane_properties prop;
 };
 #define drm_to_armada_ovl_plane(p) \
@@ -80,52 +81,55 @@ static void armada_ovl_plane_work(struct
 	spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
 }
 
-static unsigned int armada_ovl_plane_update_state(struct drm_plane_state *state,
-	struct armada_regs *regs)
+static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane,
+	struct drm_plane_state *old_state)
 {
-	struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(state->plane);
-	struct armada_framebuffer *dfb = drm_fb_to_armada_fb(state->fb);
-	const struct drm_format_info *format;
-	unsigned int idx = 0;
-	bool fb_changed;
-	u32 val, ctrl0;
-	u16 src_x, src_y;
-
-	ctrl0 = CFG_DMA_FMT(dfb->fmt) | CFG_DMA_MOD(dfb->mod) | CFG_CBSH_ENA;
-	if (state->visible)
-		ctrl0 |= CFG_DMA_ENA;
-	if (drm_rect_width(&state->src) >> 16 != drm_rect_width(&state->dst))
-		ctrl0 |= CFG_DMA_HSMOOTH;
-
-	/*
-	 * Shifting a YUV packed format image by one pixel causes the U/V
-	 * planes to swap.  Compensate for it by also toggling the UV swap.
-	 */
-	format = dfb->fb.format;
-	if (format->num_planes == 1 && state->src.x1 >> 16 & (format->hsub - 1))
-		ctrl0 ^= CFG_DMA_MOD(CFG_SWAPUV);
+	struct drm_plane_state *state = plane->state;
+	struct armada_crtc *dcrtc;
+	struct armada_regs *regs;
+	unsigned int idx;
+	u32 cfg, cfg_mask, val;
 
-	if (~dplane->base.state.ctrl0 & ctrl0 & CFG_DMA_ENA) {
-		/* Power up the Y/U/V FIFOs on ENA 0->1 transitions */
-		armada_reg_queue_mod(regs, idx,
-				     0, CFG_PDWN16x66 | CFG_PDWN32x66,
-				     LCD_SPU_SRAM_PARA1);
-	}
+	DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
 
-	fb_changed = dplane->base.base.fb != &dfb->fb ||
-		     dplane->base.state.src_x != state->src.x1 >> 16 ||
-	             dplane->base.state.src_y != state->src.y1 >> 16;
+	if (!state->fb || WARN_ON(!state->crtc))
+		return;
 
-	dplane->base.state.vsync_update = fb_changed;
+	DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n",
+		plane->base.id, plane->name,
+		state->crtc->base.id, state->crtc->name,
+		state->fb->base.id,
+		old_state->visible, state->visible);
+
+	dcrtc = drm_to_armada_crtc(state->crtc);
+	regs = dcrtc->regs + dcrtc->regs_idx;
 
+	drm_to_armada_ovl_plane(plane)->wait_vblank = false;
+
+	idx = 0;
+	if (!old_state->visible && state->visible)
+		armada_reg_queue_mod(regs, idx,
+				     0, CFG_PDWN16x66 | CFG_PDWN32x66,
+				     LCD_SPU_SRAM_PARA1);
+	val = armada_rect_hw_fp(&state->src);
+	if (armada_rect_hw_fp(&old_state->src) != val)
+		armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_HPXL_VLN);
+	val = armada_rect_yx(&state->dst);
+	if (armada_rect_yx(&old_state->dst) != val)
+		armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_OVSA_HPXL_VLN);
+	val = armada_rect_hw(&state->dst);
+	if (armada_rect_hw(&old_state->dst) != val)
+		armada_reg_queue_set(regs, idx, val, LCD_SPU_DZM_HPXL_VLN);
 	/* FIXME: overlay on an interlaced display */
-	if (fb_changed) {
+	if (old_state->src.x1 != state->src.x1 ||
+	    old_state->src.y1 != state->src.y1 ||
+	    old_state->fb != state->fb) {
+		const struct drm_format_info *format;
+		u16 src_x = state->src.x1 >> 16;
+		u16 src_y = state->src.y1 >> 16;
 		u32 addrs[3];
 
-		dplane->base.state.src_y = src_y = state->src.y1 >> 16;
-		dplane->base.state.src_x = src_x = state->src.x1 >> 16;
-
-		armada_drm_plane_calc_addrs(addrs, &dfb->fb, src_x, src_y);
+		armada_drm_plane_calc_addrs(addrs, state->fb, src_x, src_y);
 
 		armada_reg_queue_set(regs, idx, addrs[0],
 				     LCD_SPU_DMA_START_ADDR_Y0);
@@ -140,79 +144,56 @@ static unsigned int armada_ovl_plane_upd
 		armada_reg_queue_set(regs, idx, addrs[2],
 				     LCD_SPU_DMA_START_ADDR_V1);
 
-		val = dfb->fb.pitches[0] << 16 | dfb->fb.pitches[0];
-		armada_reg_queue_set(regs, idx, val,
-				     LCD_SPU_DMA_PITCH_YC);
-		val = dfb->fb.pitches[1] << 16 | dfb->fb.pitches[2];
-		armada_reg_queue_set(regs, idx, val,
-				     LCD_SPU_DMA_PITCH_UV);
-	}
-
-	val = armada_rect_hw_fp(&state->src);
-	if (dplane->base.state.src_hw != val) {
-		dplane->base.state.src_hw = val;
-		armada_reg_queue_set(regs, idx, val,
-				     LCD_SPU_DMA_HPXL_VLN);
-	}
-
-	val = armada_rect_hw(&state->dst);
-	if (dplane->base.state.dst_hw != val) {
-		dplane->base.state.dst_hw = val;
-		armada_reg_queue_set(regs, idx, val,
-				     LCD_SPU_DZM_HPXL_VLN);
-	}
+		val = state->fb->pitches[0] << 16 | state->fb->pitches[0];
+		armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_YC);
+		val = state->fb->pitches[1] << 16 | state->fb->pitches[2];
+		armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_UV);
+
+		cfg = CFG_DMA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) |
+		      CFG_DMA_MOD(drm_fb_to_armada_fb(state->fb)->mod) |
+		      CFG_CBSH_ENA;
+		if (state->visible)
+			cfg |= CFG_DMA_ENA;
 
-	val = armada_rect_yx(&state->dst);
-	if (dplane->base.state.dst_yx != val) {
-		dplane->base.state.dst_yx = val;
-		armada_reg_queue_set(regs, idx, val,
-				     LCD_SPU_DMA_OVSA_HPXL_VLN);
+		/*
+		 * Shifting a YUV packed format image by one pixel causes the
+		 * U/V planes to swap.  Compensate for it by also toggling
+		 * the UV swap.
+		 */
+		format = state->fb->format;
+		if (format->num_planes == 1 && src_x & (format->hsub - 1))
+			cfg ^= CFG_DMA_MOD(CFG_SWAPUV);
+		cfg_mask = CFG_CBSH_ENA | CFG_DMAFORMAT |
+			   CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV |
+				       CFG_SWAPYU | CFG_YUV2RGB) |
+			   CFG_DMA_FTOGGLE | CFG_DMA_TSTMODE |
+			   CFG_DMA_ENA;
+
+		drm_to_armada_ovl_plane(plane)->wait_vblank = true;
+	} else if (old_state->visible != state->visible) {
+		cfg = state->visible ? CFG_DMA_ENA : 0;
+		cfg_mask = CFG_DMA_ENA;
+	} else {
+		cfg = cfg_mask = 0;
 	}
-
-	if (dplane->base.state.ctrl0 != ctrl0) {
-		dplane->base.state.ctrl0 = ctrl0;
-		armada_reg_queue_mod(regs, idx, ctrl0,
-			CFG_CBSH_ENA | CFG_DMAFORMAT | CFG_DMA_FTOGGLE |
-			CFG_DMA_HSMOOTH | CFG_DMA_TSTMODE |
-			CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV | CFG_SWAPYU |
-			CFG_YUV2RGB) | CFG_DMA_ENA,
-			LCD_SPU_DMA_CTRL0);
-		dplane->base.state.vsync_update = true;
+	if (drm_rect_width(&old_state->src) != drm_rect_width(&state->src) ||
+	    drm_rect_width(&old_state->dst) != drm_rect_width(&state->dst)) {
+		cfg_mask |= CFG_DMA_HSMOOTH;
+		if (drm_rect_width(&state->src) >> 16 !=
+		    drm_rect_width(&state->dst))
+			cfg |= CFG_DMA_HSMOOTH;
 	}
 
-	dplane->base.state.changed = idx != 0;
-
-	return idx;
-}
-
-static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane,
-	struct drm_plane_state *old_state)
-{
-	struct drm_plane_state *state = plane->state;
-	struct armada_crtc *dcrtc;
-	struct armada_regs *regs;
+	if (cfg_mask)
+		armada_reg_queue_mod(regs, idx, cfg, cfg_mask,
+				     LCD_SPU_DMA_CTRL0);
 
-	DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
-
-	if (!state->fb || WARN_ON(!state->crtc))
-		return;
-
-	DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n",
-		plane->base.id, plane->name,
-		state->crtc->base.id, state->crtc->name,
-		state->fb->base.id,
-		old_state->visible, state->visible);
-
-	dcrtc = drm_to_armada_crtc(state->crtc);
-	regs = dcrtc->regs + dcrtc->regs_idx;
-
-	dcrtc->regs_idx += armada_ovl_plane_update_state(state, regs);
+	dcrtc->regs_idx += idx;
 }
 
 static void armada_drm_overlay_plane_atomic_disable(struct drm_plane *plane,
 	struct drm_plane_state *old_state)
 {
-	struct armada_plane *dplane = drm_to_armada_plane(plane);
 	struct armada_crtc *dcrtc;
 	struct armada_regs *regs;
 	unsigned int idx = 0;
@@ -227,8 +208,6 @@ static void armada_drm_overlay_plane_ato
 		old_state->crtc->base.id, old_state->crtc->name,
 		old_state->fb->base.id);
 
-	dplane->state.ctrl0 &= ~CFG_DMA_ENA;
-
 	dcrtc = drm_to_armada_crtc(old_state->crtc);
 	regs = dcrtc->regs + dcrtc->regs_idx;
 
@@ -288,7 +267,7 @@ static int armada_overlay_commit(struct
 	plane_funcs->atomic_update(plane, state);
 
 	/* If nothing was updated, short-circuit */
-	if (!dplane->base.state.changed)
+	if (dcrtc->regs_idx == 0)
 		goto put_state;
 
 	armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx);
@@ -298,7 +277,7 @@ static int armada_overlay_commit(struct
 		armada_drm_plane_work_cancel(dcrtc, &dplane->base);
 
 	/* Just updating the position/size? */
-	if (!dplane->base.state.vsync_update) {
+	if (!dplane->wait_vblank) {
 		armada_ovl_plane_work(dcrtc, work);
 		goto put_state;
 	}