[Intel-gfx] [RFC 2/2] drm/i915: Render decompression support for Gen9

Vandana Kannan vandana.kannan at intel.com
Tue Dec 8 21:15:44 PST 2015


This patch includes enabling render decompression after checking all the
requirements (format, tiling, rotation etc.). Along with this, the WAs
mentioned in BSpec Workaround page have been implemented.
In case, any of the conditions fail, the flip will fail.

TODO:
1. Disable stereo 3D when render decomp is enabled (bit 7:6)
2. Render decompression must not be used in VTd pass-through mode
3. Program hashing select CHICKEN_MISC1 bit 15

Note: This patch is based on top of Chandra's and Ville's NV12/fb->offset
related patches series.

Signed-off-by: Vandana Kannan <vandana.kannan at intel.com>
Cc: Konduru, Chandra <chandra.konduru at intel.com>
Cc: Ville Syrjälä <ville.syrjala at linux.intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h           |   1 +
 drivers/gpu/drm/i915/intel_atomic_plane.c |  18 ++-
 drivers/gpu/drm/i915/intel_display.c      | 233 ++++++++++++++++++++++++++++--
 drivers/gpu/drm/i915/intel_drv.h          |   9 ++
 drivers/gpu/drm/i915/intel_sprite.c       |  53 +++++--
 5 files changed, 281 insertions(+), 33 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index f1a8a53..340bb0f 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1866,6 +1866,7 @@ struct drm_i915_private {
 
 	struct drm_property *broadcast_rgb_property;
 	struct drm_property *force_audio_property;
+	struct drm_property *render_comp_property;
 
 	/* hda/i915 audio component */
 	struct i915_audio_component *audio_component;
diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
index c6bb0fc..7324204 100644
--- a/drivers/gpu/drm/i915/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
@@ -222,8 +222,13 @@ intel_plane_atomic_get_property(struct drm_plane *plane,
 				struct drm_property *property,
 				uint64_t *val)
 {
-	DRM_DEBUG_KMS("Unknown plane property '%s'\n", property->name);
-	return -EINVAL;
+	if (property == dev_priv->render_comp_property) {
+		*val = intel_state->render_comp_enable;
+	} else {
+		DRM_DEBUG_KMS("Unknown plane property '%s'\n", property->name);
+		return -EINVAL;
+	}
+	return 0;
 }
 
 /**
@@ -244,6 +249,11 @@ intel_plane_atomic_set_property(struct drm_plane *plane,
 				struct drm_property *property,
 				uint64_t val)
 {
-	DRM_DEBUG_KMS("Unknown plane property '%s'\n", property->name);
-	return -EINVAL;
+	if (property == dev_priv->render_comp_property) {
+		intel_state->render_comp_enable = val;
+	} else {
+		DRM_DEBUG_KMS("Unknown plane property '%s'\n", property->name);
+		return -EINVAL;
+	}
+	return 0;
 }
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index b421d3c..255c5f9 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -118,6 +118,9 @@ static void skylake_pfit_enable(struct intel_crtc *crtc);
 static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force);
 static void ironlake_pfit_enable(struct intel_crtc *crtc);
 static void intel_modeset_setup_hw_state(struct drm_device *dev);
+static int skl_check_compression(struct drm_device *dev,
+				struct intel_plane_state *plane_state,
+				enum pipe pipe, int x, int y);
 
 typedef struct {
 	int	min, max;
@@ -3075,7 +3078,7 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
 	bool visible = to_intel_plane_state(plane->state)->visible;
 	int pipe = intel_crtc->pipe;
 	u32 plane_ctl, stride;
-	unsigned int rotation;
+	unsigned int rotation, render_comp;
 	u32 surf_addr;
 	struct intel_crtc_state *crtc_state = intel_crtc->config;
 	struct intel_plane_state *plane_state;
@@ -3084,7 +3087,7 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
 	int dst_x, dst_y, dst_w, dst_h;
 	unsigned long aux_dist = 0;
 	u32 aux_x_offset = 0, aux_y_offset = 0, aux_stride = 0;
-	u32 tile_row_adjustment = 0;
+	u32 tile_row_adjustment = 0, height_in_mem = 0;
 	u32 hphase = 0, vphase = 0;
 	int pixel_size;
 
@@ -3155,15 +3158,15 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
 				fb->pixel_format);
 		tile_height = PAGE_SIZE / intel_fb_stride_alignment(dev_priv, fb->modifier[0],
 				fb->pixel_format);
+		height_in_mem = (fb->offsets[1]/fb->pitches[0]);
+		/*
+		 * If UV starts from middle of a page, then UV start should
+		 * be programmed to beginning of that page. And offset into that
+		 * page to be programmed into y-offset
+		 */
+		tile_row_adjustment = height_in_mem % tile_height;
 
 		if (fb->pixel_format == DRM_FORMAT_NV12) {
-			int height_in_mem = (fb->offsets[1]/fb->pitches[0]);
-			/*
-			 * If UV starts from middle of a page, then UV start should
-			 * be programmed to beginning of that page. And offset into that
-			 * page to be programmed into y-offset
-			 */
-			tile_row_adjustment = height_in_mem % tile_height;
 			aux_dist = fb->pitches[0] * (height_in_mem - tile_row_adjustment);
 			aux_x_offset = DIV_ROUND_UP(x, 2);
 			aux_y_offset = DIV_ROUND_UP(y, 2) + tile_row_adjustment;
@@ -3176,6 +3179,22 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
 		}
 	}
 
+	render_comp = to_intel_plane_state(plane->state)->render_comp_enable;
+	if (render_comp) {
+		/*
+		 * FIXME: This calculation may change based on HW team's
+		 * confirmation.
+		 */
+		aux_dist = (fb->pitches[0] *
+				(height_in_mem - tile_row_adjustment));
+		aux_stride = fb->pitches[1] / intel_fb_stride_alignment(dev_priv, fb->modifier[0],
+				fb->pixel_format);
+
+		plane_ctl |= PLANE_CTL_DECOMPRESSION_ENABLE;
+	} else {
+		plane_ctl &= ~PLANE_CTL_DECOMPRESSION_ENABLE;
+	}
+
 	intel_add_fb_offsets(&x, &y, fb, 0, rotation);
 	surf_addr = intel_compute_page_offset(&x, &y, fb, 0, stride, rotation);
 
@@ -3197,13 +3216,22 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
 
 	/*
 	 * Per bspec, for SKL C and BXT A steppings, when the plane source pixel
-	 * format is NV12, the CHICKEN_PIPESL register bit 22 must be set to 1
+	 * format is NV12, the CHICKEN_PIPESL register bit 22 must be set to 1.
+	 * When render compression is enabled, bit 22 must be set to 0.
 	 */
 	if (((IS_SKYLAKE(dev) && intel_get_stepping(dev) == 'C') ||
-				(IS_BROXTON(dev) && intel_get_stepping(dev) == 'A')) &&
-			fb->pixel_format == DRM_FORMAT_NV12) {
-		I915_WRITE(CHICKEN_PIPESL(pipe),
-				I915_READ(CHICKEN_PIPESL(pipe)) | DISABLE_STREAMER_FIX);
+				(IS_BROXTON(dev) && intel_get_stepping(dev) == 'A'))) {
+		u32 temp = I915_READ(CHICKEN_PIPESL(pipe));
+		if (fb->pixel_format == DRM_FORMAT_NV12) {
+			if (!(temp & DISABLE_STREAMER_FIX))
+				I915_WRITE(CHICKEN_PIPESL(pipe),
+						temp | DISABLE_STREAMER_FIX);
+		}
+		if (render_comp) {
+			if ((temp & DISABLE_STREAMER_FIX) == DISABLE_STREAMER_FIX)
+				I915_WRITE(CHICKEN_PIPESL(pipe),
+						temp & ~DISABLE_STREAMER_FIX);
+		}
 	}
 
 	if (scaler_id >= 0) {
@@ -11841,6 +11869,17 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
 				intel_plane_state);
 		if (ret)
 			return ret;
+
+		if (fb && to_intel_plane_state(plane_state)->
+				render_comp_enable) {
+			ret = skl_check_compression(dev,
+					to_intel_plane_state(plane_state),
+					intel_crtc->pipe, crtc->x, crtc->y);
+			if (ret) {
+				DRM_DEBUG_KMS("Render compr checks failed\n");
+				return ret;
+			}
+		}
 	}
 
 	was_visible = old_plane_state->visible;
@@ -11927,6 +11966,19 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
 			intel_crtc->atomic.disable_fbc = true;
 
 		/*
+		 * Disable FBC if render decompression has to be enabled.
+		 * FIXME: If FBC is disabled here because render decomp
+		 * has to be enabled, then in update_primary_plane(), if
+		 * render decomp is disabled for some reason, we need to
+		 * enable FBC ?
+		 */
+		if ((IS_SKYLAKE(dev) && intel_get_stepping(dev) < 'C') &&
+			dev_priv->fbc.crtc == intel_crtc &&
+			to_intel_plane_state(plane_state)->render_comp_enable) {
+			intel_crtc->atomic.disable_fbc = true;
+		}
+
+		/*
 		 * BDW signals flip done immediately if the plane
 		 * is disabled, even if the plane enable is already
 		 * armed to occur at the next vblank :(
@@ -12046,6 +12098,41 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
 			return ret;
 	}
 
+	/*
+	 * On SKL:*:C and BXT:*:A, there is a possible hang with NV12 format.
+	 * WA: render decompression must not be enabled on any of the planes in
+	 * that pipe.
+	 */
+	if ((IS_BROXTON(dev) && intel_get_stepping(dev) == 'A') ||
+		(IS_SKYLAKE(dev) && intel_get_stepping(dev) == 'C')) {
+		struct drm_plane *p;
+		bool rc_enabled = false, nv12_enabled = false;
+
+		drm_for_each_plane_mask(p, dev, crtc_state->plane_mask) {
+			struct drm_plane_state *plane_state =
+				drm_atomic_get_plane_state(state, p);
+
+			if (plane_state) {
+				if (to_intel_plane_state(plane_state)->
+						render_comp_enable)
+					rc_enabled = true;
+
+				if (plane_state->fb &&
+					plane_state->fb->pixel_format ==
+					DRM_FORMAT_NV12)
+					nv12_enabled = true;
+			}
+
+		}
+		if (rc_enabled && nv12_enabled) {
+			DRM_DEBUG_KMS("RC should not be enabled "
+					"on any plane of the "
+					"pipe on which NV12 is "
+					"enabled\n");
+			return -EINVAL;
+		}
+	}
+
 	if (INTEL_INFO(dev)->gen >= 9) {
 		if (mode_changed)
 			ret = skl_update_scaler_crtc(pipe_config);
@@ -13889,6 +13976,91 @@ skl_max_scale(struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state
 	return max_scale;
 }
 
+static int skl_check_compression(struct drm_device *dev,
+		struct intel_plane_state *plane_state,
+		enum pipe pipe, int x, int y)
+{
+	struct drm_framebuffer *fb = plane_state->base.fb;
+	struct drm_plane *plane = plane_state->base.plane;
+	int x_offset;
+	int src_w = drm_rect_width(&plane_state->src) >> 16;
+
+	if (!IS_SKYLAKE(dev) && !IS_BROXTON(dev)) {
+		DRM_DEBUG_KMS("RC support on CNL+ needs to be revisited\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * TODO:
+	 * 1. Disable stereo 3D when render decomp is enabled (bit 7:6)
+	 * 2. Render decompression must not be used in VTd pass-through mode
+	 * 3. Program hashing select CHICKEN_MISC1 bit 15
+	 */
+
+	/* Render compression is supported only on planes 1 & 2 */
+	if (to_intel_plane(plane)->plane != PLANE_A) {
+		DRM_DEBUG_KMS("RC supported only on planes 1 & 2\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * On SKL A and SKL B,
+	 * Do not enable render decompression when the plane
+	 * width is smaller than 32 pixels or greater than
+	 * 2048 pixels
+	 */
+	if ((IS_SKYLAKE(dev) && intel_get_stepping(dev) < 'C')
+			&& ((src_w < 32) || (src_w > 2048))) {
+		DRM_DEBUG_KMS("SKL-A, SKL-B RC: width > 2048 or < 32\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Conditions to satisfy before enabling render decomp.
+	 * SKL+
+	 * Pipe A & B, Planes 1 & 2
+	 * RGB8888 Tile-Y format
+	 * 0/180 rotation
+	 */
+	if (pipe == PIPE_C) {
+		DRM_DEBUG_KMS("RC supported only on pipe A & B\n");
+		return -EINVAL;
+	}
+
+	if (intel_rotation_90_or_270(plane_state->base.rotation)) {
+		DRM_DEBUG_KMS("RC support only with 0/180 degree rotation\n");
+		return -EINVAL;
+	}
+
+	if ((fb->modifier[0] == DRM_FORMAT_MOD_NONE) ||
+			(fb->modifier[0] == I915_FORMAT_MOD_X_TILED)) {
+		DRM_DEBUG_KMS("RC supported only with Y-tile\n");
+		return -EINVAL;
+	}
+
+	if ((fb->pixel_format != DRM_FORMAT_XBGR8888) &&
+			(fb->pixel_format != DRM_FORMAT_ABGR8888)) {
+		DRM_DEBUG_KMS("RC supported only with RGB8888 formats\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * For SKL & BXT,
+	 * When the render compression is enabled with plane
+	 * width greater than 3840 and horizontal panning,
+	 * the stride programmed in the PLANE_STRIDE register
+	 * must be multiple of 4.
+	 */
+	x_offset = x;
+
+	if (src_w > 3840 && x_offset != 0) {
+		DRM_DEBUG_KMS("RC: width > 3840, horizontal panning\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int
 intel_check_primary_plane(struct drm_plane *plane,
 			  struct intel_crtc_state *crtc_state,
@@ -14052,11 +14224,44 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
 	if (INTEL_INFO(dev)->gen >= 4)
 		intel_create_rotation_property(dev, primary);
 
+	if (INTEL_INFO(dev)->gen >= 9)
+		intel_create_render_comp_property(dev, primary);
+
 	drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs);
 
 	return &primary->base;
 }
 
+void intel_create_render_comp_property(struct drm_device *dev,
+		struct intel_plane *plane)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	static const struct drm_prop_enum_list rc_status[] = {
+		{ COMP_UNCOMPRESSED,   "Uncompressed/not capable" },
+		{ COMP_RENDER,  "Only render decompression" },
+	};
+
+	if (!dev_priv->render_comp_property) {
+		dev_priv->render_comp_property =
+			drm_property_create_bitmask(dev, 0,
+					"render compression",
+					rc_status, ARRAY_SIZE(rc_status),
+					BIT(COMP_UNCOMPRESSED) |
+					BIT(COMP_RENDER));
+		if (!dev_priv->render_comp_property) {
+			DRM_ERROR("RC: Failed to create property\n");
+			return;
+		}
+	}
+
+	if (dev_priv->render_comp_property) {
+		drm_object_attach_property(&plane->base.base,
+				dev_priv->render_comp_property, 0);
+	}
+	dev->mode_config.allow_aux_plane = true;
+}
+
 void intel_create_rotation_property(struct drm_device *dev, struct intel_plane *plane)
 {
 	if (!dev->mode_config.rotation_property) {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 50f83d2..bc4a5b5 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -251,6 +251,10 @@ struct intel_atomic_state {
 	struct intel_wm_config wm_config;
 };
 
+/* render compression property bits */
+#define COMP_UNCOMPRESSED          0
+#define COMP_RENDER                1
+
 struct intel_plane_state {
 	struct drm_plane_state base;
 	struct drm_rect src;
@@ -282,6 +286,9 @@ struct intel_plane_state {
 
 	/* async flip related structures */
 	struct drm_i915_gem_request *wait_req;
+
+	/* Render compression */
+	unsigned int render_comp_enable;
 };
 
 struct intel_initial_plane_config {
@@ -1135,6 +1142,8 @@ intel_rotation_90_or_270(unsigned int rotation)
 
 void intel_create_rotation_property(struct drm_device *dev,
 					struct intel_plane *plane);
+void intel_create_render_comp_property(struct drm_device *dev,
+					struct intel_plane *plane);
 
 /* shared dpll functions */
 struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc);
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 2aff300..0ddbd49 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -195,12 +195,12 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc,
 	const struct drm_intel_sprite_colorkey *key =
 		&to_intel_plane_state(drm_plane->state)->ckey;
 	unsigned int surf_addr;
-	unsigned int rotation;
+	unsigned int rotation, render_comp;
 	struct intel_crtc_state *crtc_state = to_intel_crtc(crtc)->config;
 	int scaler_id;
 	unsigned long aux_dist = 0;
 	u32 aux_x_offset = 0, aux_y_offset = 0, aux_stride = 0;
-	u32 tile_row_adjustment = 0;
+	u32 tile_row_adjustment = 0, height_in_mem = 0;
 	u32 hphase = 0, vphase = 0;
 
 	plane_ctl = PLANE_CTL_ENABLE |
@@ -259,15 +259,15 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc,
 				fb->pixel_format);
 		tile_height = PAGE_SIZE / intel_fb_stride_alignment(dev_priv, fb->modifier[0],
 				fb->pixel_format);
+		height_in_mem = (fb->offsets[1]/fb->pitches[0]);
+		/*
+		 * If UV starts from middle of a page, then UV start should
+		 * be programmed to beginning of that page. And offset into that
+		 * page to be programmed into y-offset
+		 */
+		tile_row_adjustment = height_in_mem % tile_height;
 
 		if (fb->pixel_format == DRM_FORMAT_NV12) {
-			int height_in_mem = (fb->offsets[1]/fb->pitches[0]);
-			/*
-			 * If UV starts from middle of a page, then UV start should
-			 * be programmed to beginning of that page. And offset into that
-			 * page to be programmed into y-offset
-			 */
-			tile_row_adjustment = height_in_mem % tile_height;
 			aux_dist = fb->pitches[0] * (height_in_mem - tile_row_adjustment);
 			aux_x_offset = DIV_ROUND_UP(x, 2);
 			aux_y_offset = DIV_ROUND_UP(y, 2) + tile_row_adjustment;
@@ -280,6 +280,18 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc,
 		}
 	}
 
+	render_comp = to_intel_plane_state(drm_plane->state)->render_comp_enable;
+	if (render_comp) {
+		aux_dist = (fb->pitches[0] *
+				(height_in_mem - tile_row_adjustment));
+		aux_stride = fb->pitches[1] / intel_fb_stride_alignment(dev_priv, fb->modifier[0],
+				fb->pixel_format);
+
+		plane_ctl |= PLANE_CTL_DECOMPRESSION_ENABLE;
+	} else {
+		plane_ctl &= ~PLANE_CTL_DECOMPRESSION_ENABLE;
+	}
+
 	intel_add_fb_offsets(&x, &y, fb, 0, rotation);
 	surf_addr = intel_compute_page_offset(&x, &y, fb, 0, stride, rotation);
 
@@ -297,16 +309,24 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc,
 
 	/*
 	 * Per bspec, for SKL C and BXT A steppings, when the plane source pixel
-	 * format is NV12, the CHICKEN_PIPESL register bit 22 must be set to 1
+	 * format is NV12, the CHICKEN_PIPESL register bit 22 must be set to 1.
+	 * When render compression is enabled, bit 22 must be set to 0.
 	 */
 	if (((IS_SKYLAKE(dev) && intel_get_stepping(dev) == 'C') ||
-				(IS_BROXTON(dev) && intel_get_stepping(dev) == 'A')) &&
-			fb->pixel_format == DRM_FORMAT_NV12) {
-		I915_WRITE(CHICKEN_PIPESL(pipe),
-				I915_READ(CHICKEN_PIPESL(pipe)) | DISABLE_STREAMER_FIX);
+				(IS_BROXTON(dev) && intel_get_stepping(dev) == 'A'))) {
+		u32 temp = I915_READ(CHICKEN_PIPESL(pipe));
+		if (fb->pixel_format == DRM_FORMAT_NV12) {
+			if (!(temp & DISABLE_STREAMER_FIX))
+				I915_WRITE(CHICKEN_PIPESL(pipe),
+						temp | DISABLE_STREAMER_FIX);
+		}
+		if (render_comp) {
+			if ((temp & DISABLE_STREAMER_FIX) == DISABLE_STREAMER_FIX)
+				I915_WRITE(CHICKEN_PIPESL(pipe),
+						temp & ~DISABLE_STREAMER_FIX);
+		}
 	}
 
-
 	/* program plane scaler */
 	if (scaler_id >= 0) {
 		uint32_t ps_ctrl = 0;
@@ -1200,6 +1220,9 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
 
 	intel_create_rotation_property(dev, intel_plane);
 
+	if (INTEL_INFO(dev)->gen >= 9)
+		intel_create_render_comp_property(dev, intel_plane);
+
 	drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs);
 
 out:
-- 
1.9.1



More information about the Intel-gfx mailing list