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:
