[PATCH] drm/i915: Set src size restrictions for NV12

Vidya Srinivas vidya.srinivas at intel.com
Mon Apr 2 08:02:48 UTC 2018


As per display WA 1106, to avoid corruption issues
NV12 plane height needs to be multiplier of 4
We expect the src dimensions to be multiplier of 4
We fail the case where src width or height is not
multiple of 4 for NV12.
We also set the scaler destination height
and width to be multiple of 4. Without this, pipe
fifo underruns were seen on APL and KBL.

Credits-to: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
Signed-off-by: Vidya Srinivas <vidya.srinivas at intel.com>
---
 drivers/gpu/drm/i915/intel_display.c | 11 +++++++----
 drivers/gpu/drm/i915/intel_drv.h     |  2 ++
 drivers/gpu/drm/i915/intel_sprite.c  | 19 ++++++++++++++++---
 3 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index a622704..b5dfd73 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4809,8 +4809,9 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
 	}
 
 	if (plane_scaler_check && pixel_format == DRM_FORMAT_NV12 &&
-	    src_h < SKL_MIN_YUV_420_SRC_H) {
-		DRM_DEBUG_KMS("NV12: scaler out of range src_h=%d\n", src_h);
+	    (src_h < SKL_MIN_YUV_420_SRC_H || (src_h % 4) != 0 ||
+	     (src_w % 4) != 0)) {
+		DRM_DEBUG_KMS("NV12: src dimensions not valid\n");
 		return -EINVAL;
 	}
 
@@ -14271,8 +14272,10 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
 
 	if (fb->format->format == DRM_FORMAT_NV12 &&
 	    (fb->width < SKL_MIN_YUV_420_SRC_W ||
-	     fb->height < SKL_MIN_YUV_420_SRC_H)) {
-		DRM_DEBUG_KMS("Min fb dimensions not met for planar format\n");
+	     fb->height < SKL_MIN_YUV_420_SRC_H ||
+	     (fb->width % 4) != 0 ||
+	     (fb->height % 4) != 0)) {
+		DRM_DEBUG_KMS("src fb dimensions not met for planar format\n");
 		return -EINVAL;
 	}
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 9c58da0..a1f718d 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -159,6 +159,8 @@
 #define INTEL_I2C_BUS_DVO 1
 #define INTEL_I2C_BUS_SDVO 2
 
+#define MULT4(x) ((x + 3) & ~0x03)
+
 /* these are outputs from the chip - integrated only
    external chips are via DVO or SDVO output */
 enum intel_output_type {
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 538d938..adceadc 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -255,6 +255,12 @@ skl_update_plane(struct intel_plane *plane,
 	uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
 	unsigned long irqflags;
 
+	if (fb->format->format == DRM_FORMAT_NV12 &&
+		((src_h % 4) != 0 || (src_w % 4) != 0)) {
+		DRM_DEBUG_KMS("NV12: src dimensions not valid\n");
+		return;
+	}
+
 	/* Sizes are 0 based */
 	src_w--;
 	src_h--;
@@ -292,9 +298,12 @@ skl_update_plane(struct intel_plane *plane,
 			      PS_SCALER_EN | PS_PLANE_SEL(plane_id) | scaler->mode);
 		I915_WRITE_FW(SKL_PS_PWR_GATE(pipe, scaler_id), 0);
 		I915_WRITE_FW(SKL_PS_WIN_POS(pipe, scaler_id), (crtc_x << 16) | crtc_y);
-		I915_WRITE_FW(SKL_PS_WIN_SZ(pipe, scaler_id),
-			      ((crtc_w + 1) << 16)|(crtc_h + 1));
-
+		if (fb->format->format == DRM_FORMAT_NV12)
+			I915_WRITE_FW(SKL_PS_WIN_SZ(pipe, scaler_id),
+				      (MULT4(crtc_w) << 16) | MULT4(crtc_h));
+		else
+			I915_WRITE_FW(SKL_PS_WIN_SZ(pipe, scaler_id),
+				      ((crtc_w + 1) << 16)|(crtc_h + 1));
 		I915_WRITE_FW(PLANE_POS(pipe, plane_id), 0);
 	} else {
 		I915_WRITE_FW(PLANE_POS(pipe, plane_id), (crtc_y << 16) | crtc_x);
@@ -969,6 +978,9 @@ intel_check_sprite_plane(struct intel_plane *plane,
 		return -EINVAL;
 	}
 
+	if (fb->format->format == DRM_FORMAT_NV12)
+		goto check_plane_surface;
+
 	/* setup can_scale, min_scale, max_scale */
 	if (INTEL_GEN(dev_priv) >= 9) {
 		if (state->base.fb)
@@ -1111,6 +1123,7 @@ intel_check_sprite_plane(struct intel_plane *plane,
 	dst->y1 = crtc_y;
 	dst->y2 = crtc_y + crtc_h;
 
+check_plane_surface:
 	if (INTEL_GEN(dev_priv) >= 9) {
 		ret = skl_check_plane_surface(crtc_state, state);
 		if (ret)
-- 
2.7.4



More information about the Intel-gfx-trybot mailing list