diff mbox

[RFC,2/2] drm/i915: Render decompression support for Gen9

Message ID 1449638144-21945-2-git-send-email-vandana.kannan@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

vandana.kannan@intel.com Dec. 9, 2015, 5:15 a.m. UTC
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@intel.com>
Cc: Konduru, Chandra <chandra.konduru@intel.com>
Cc: Ville Syrjälä <ville.syrjala@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(-)

Comments

Daniel Stone Dec. 9, 2015, 6:05 p.m. UTC | #1
Hi,

On 9 December 2015 at 05:15, Vandana Kannan <vandana.kannan@intel.com> wrote:
> 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.
>
> [...]
>
> --- 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;

Using this as a property is a concern to me. Under the following
scenario, you can easily trigger a failure:
  - compression-aware client runs and sets compression to true on the
primary plane
  - VT switch
  - non-compression-aware client takes over, changes the FB to a
non-compressed buffer, leaves compression property alone as it is
unaware of it
  - ???

It seems like the best thing to do in this case is to make compression
a property of the FB, through modifiers. This also enables seamless
use of render compression from clients using EGL/GBM, where GBM just
hands a buffer over to the client and lets the client deal with
presenting it through KMS. In this case, the client is not aware if
compression should be enabled or not.

Cheers,
Daniel
vandana.kannan@intel.com Dec. 23, 2015, 3:20 a.m. UTC | #2
Hi Daniel,

How does VT switch work in case of rotation, setting different pixel 
format, etc?

- Vandana

On 12/9/2015 11:35 PM, Daniel Stone wrote:
> Hi,
>
> On 9 December 2015 at 05:15, Vandana Kannan <vandana.kannan@intel.com> wrote:
>> 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.
>>
>> [...]
>>
>> --- 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;
>
> Using this as a property is a concern to me. Under the following
> scenario, you can easily trigger a failure:
>    - compression-aware client runs and sets compression to true on the
> primary plane
>    - VT switch
>    - non-compression-aware client takes over, changes the FB to a
> non-compressed buffer, leaves compression property alone as it is
> unaware of it
>    - ???
>
> It seems like the best thing to do in this case is to make compression
> a property of the FB, through modifiers. This also enables seamless
> use of render compression from clients using EGL/GBM, where GBM just
> hands a buffer over to the client and lets the client deal with
> presenting it through KMS. In this case, the client is not aware if
> compression should be enabled or not.
>
> Cheers,
> Daniel
>
Daniel Stone Dec. 23, 2015, 9:37 a.m. UTC | #3
Hi Vandana,

On 23 December 2015 at 03:20, Kannan, Vandana <vandana.kannan@intel.com> wrote:
> How does VT switch work in case of rotation, setting different pixel format,
> etc?

Pixel format is a property of the framebuffer, not a per-plane
property, so is unaffected. Rotation is generic, so there is specific
code to handle it for fbdev etc.

But the real problem is that this is an Intel-specific property, and
in order to get correct results, userspace must know about these
specific properties in order to unset them. This means that you can't
run generic userspace, and you can't run old userspace which predates
these properties either. This seems like a total non-starter to me.

It would be much cleaner if there was a way to attach the render
compression property to the framebuffer, e.g. by using the format
modifiers which were specifically introduced to deal with compression
and tiling.

Cheers,
Daniel
Chandra Konduru Jan. 12, 2016, 12:39 a.m. UTC | #4
> -----Original Message-----

> From: Daniel Stone [mailto:daniel@fooishbar.org]

> Sent: Wednesday, December 23, 2015 1:37 AM

> To: Kannan, Vandana

> Cc: intel-gfx; Konduru, Chandra; Murthy, Arun R

> Subject: Re: [Intel-gfx] [RFC 2/2] drm/i915: Render decompression support for

> Gen9

> 

> Hi Vandana,

> 

> On 23 December 2015 at 03:20, Kannan, Vandana

> <vandana.kannan@intel.com> wrote:

> > How does VT switch work in case of rotation, setting different pixel format,

> > etc?

> 

> Pixel format is a property of the framebuffer, not a per-plane

> property, so is unaffected. Rotation is generic, so there is specific

> code to handle it for fbdev etc.

> 

> But the real problem is that this is an Intel-specific property, and

> in order to get correct results, userspace must know about these

> specific properties in order to unset them. This means that you can't

> run generic userspace, and you can't run old userspace which predates

> these properties either. This seems like a total non-starter to me.

> 

> It would be much cleaner if there was a way to attach the render

> compression property to the framebuffer, e.g. by using the format

> modifiers which were specifically introduced to deal with compression

> and tiling.

> 

> Cheers,

> Daniel


Hi Daniel,
Plan is to handle compression property similar to rotation property. 
Don't see why that will be an issue. 

To address VT-switch concern, there will be a small code change 
resetting compression property in the VT-switch case - which may as well 
apply to other properties.

Please let us know if this is resolving your feedback.

By the way, for rotation in VT switch path (or any other property), 
there isn't code to reset to 0. The only place where reset is at  
"i915_driver_lastclose - clean up after all DRM clients have exited".

Thanks,
Chandra
diff mbox

Patch

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: