[Intel-gfx] [PATCH v6 01/12] drm/i915: Rewrite fb rotation GTT handling

Daniel Vetter daniel at ffwll.ch
Wed Aug 10 09:49:33 UTC 2016


On Wed, Aug 10, 2016 at 12:23:10PM +0300, ville.syrjala at linux.intel.com wrote:
> From: Ville Syrjälä <ville.syrjala at linux.intel.com>
> 
> Redo the fb rotation handling in order to:
> - eliminate the NV12 special casing
> - handle fb->offsets[] properly
> - make the rotation handling easier for the plane code
> 
> To achieve these goals we reduce intel_rotation_info to only contain
> (for each plane) the rotated view width,height,stride in tile units,
> and the page offset into the object where the plane starts. Each plane
> is handled exactly the same way, no special casing for NV12 or other
> formats. We then store the computed rotation_info under
> intel_framebuffer so that we don't have to recompute it again.
> 
> To handle fb->offsets[] we treat them as a linear offsets and convert
> them to x/y offsets from the start of the relevant GTT mapping (either
> normal or rotated). We store the x/y offsets under intel_framebuffer,
> and for some extra convenience we also store the rotated pitch (ie.
> tile aligned plane height). So for each plane we have the normal
> x/y offsets, rotated x/y offsets, and the rotated pitch. The normal
> pitch is available already in fb->pitches[].
> 
> While we're gathering up all that extra information, we can also easily
> compute the storage requirements for the framebuffer, so that we can
> check that the object is big enough to hold it.
> 
> When it comes time to deal with the plane source coordinates, we first
> rotate the clipped src coordinates to match the relevant GTT view
> orientation, then add to them the fb x/y offsets. Next we compute
> the aligned surface page offset, and as a result we're left with some
> residual x/y offsets. Finally, if required by the hardware, we convert
> the remaining x/y offsets into a linear offset.
> 
> For gen2/3 we simply skip computing the final page offset, and just
> convert the src+fb x/y offsets directly into a linear offset since
> that's what the hardware wants.
> 
> After this all platforms, incluing SKL+, compute these things in exactly
> the same way (excluding alignemnt differences).
> 
> v2: Use BIT(DRM_ROTATE_270) instead of ROTATE_270 when rotating
>     plane src coordinates
>     Drop some spurious changes that got left behind during
>     development
> v3: Split out more changes to prep patches (Daniel)
>     s/intel_fb->plane[].foo.bar/intel_fb->foo[].bar/ for brevity
>     Rename intel_surf_gtt_offset to intel_fb_gtt_offset
>     Kill the pointless 'plane' parameter from intel_fb_gtt_offset()
> v4: Fix alignment vs. alignment-1 when calling
>     _intel_compute_tile_offset() from intel_fill_fb_info()
>     Pass the pitch in tiles in
>     stad of pixels to intel_adjust_tile_offset() from intel_fill_fb_info()
>     Pass the full width/height of the rotated area to
>     drm_rect_rotate() for clarity
>     Use u32 for more offsets
> v5: Preserve the upper_32_bits()/lower_32_bits() handling for the
>     fb ggtt offset (Sivakumar)
> v6: Rebase due to drm_plane_state src/dst rects
> 
> Cc: Sivakumar Thulasimani <sivakumar.thulasimani at intel.com>
> Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
> Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani at intel.com>

Not feeling like checking the entire math again in full detail, but makes
sense, and I did check the math on an earlier version.

Acked-by: Daniel Vetter <daniel.vetter at ffwll.ch>
> ---
>  drivers/gpu/drm/i915/i915_gem_gtt.c  |  51 ++---
>  drivers/gpu/drm/i915/i915_gem_gtt.h  |   5 +-
>  drivers/gpu/drm/i915/intel_display.c | 368 ++++++++++++++++++++++++-----------
>  drivers/gpu/drm/i915/intel_drv.h     |  19 +-
>  drivers/gpu/drm/i915/intel_sprite.c  |  97 ++++-----
>  5 files changed, 331 insertions(+), 209 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
> index 18c7c9644761..d876501694c6 100644
> --- a/drivers/gpu/drm/i915/i915_gem_gtt.c
> +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
> @@ -3449,18 +3449,16 @@ rotate_pages(const dma_addr_t *in, unsigned int offset,
>  }
>  
>  static struct sg_table *
> -intel_rotate_fb_obj_pages(struct intel_rotation_info *rot_info,
> +intel_rotate_fb_obj_pages(const struct intel_rotation_info *rot_info,
>  			  struct drm_i915_gem_object *obj)
>  {
>  	const size_t n_pages = obj->base.size / PAGE_SIZE;
> -	unsigned int size_pages = rot_info->plane[0].width * rot_info->plane[0].height;
> -	unsigned int size_pages_uv;
> +	unsigned int size = intel_rotation_info_size(rot_info);
>  	struct sgt_iter sgt_iter;
>  	dma_addr_t dma_addr;
>  	unsigned long i;
>  	dma_addr_t *page_addr_list;
>  	struct sg_table *st;
> -	unsigned int uv_start_page;
>  	struct scatterlist *sg;
>  	int ret = -ENOMEM;
>  
> @@ -3471,18 +3469,12 @@ intel_rotate_fb_obj_pages(struct intel_rotation_info *rot_info,
>  	if (!page_addr_list)
>  		return ERR_PTR(ret);
>  
> -	/* Account for UV plane with NV12. */
> -	if (rot_info->pixel_format == DRM_FORMAT_NV12)
> -		size_pages_uv = rot_info->plane[1].width * rot_info->plane[1].height;
> -	else
> -		size_pages_uv = 0;
> -
>  	/* Allocate target SG list. */
>  	st = kmalloc(sizeof(*st), GFP_KERNEL);
>  	if (!st)
>  		goto err_st_alloc;
>  
> -	ret = sg_alloc_table(st, size_pages + size_pages_uv, GFP_KERNEL);
> +	ret = sg_alloc_table(st, size, GFP_KERNEL);
>  	if (ret)
>  		goto err_sg_alloc;
>  
> @@ -3495,32 +3487,14 @@ intel_rotate_fb_obj_pages(struct intel_rotation_info *rot_info,
>  	st->nents = 0;
>  	sg = st->sgl;
>  
> -	/* Rotate the pages. */
> -	sg = rotate_pages(page_addr_list, 0,
> -			  rot_info->plane[0].width, rot_info->plane[0].height,
> -			  rot_info->plane[0].width,
> -			  st, sg);
> -
> -	/* Append the UV plane if NV12. */
> -	if (rot_info->pixel_format == DRM_FORMAT_NV12) {
> -		uv_start_page = size_pages;
> -
> -		/* Check for tile-row un-alignment. */
> -		if (offset_in_page(rot_info->uv_offset))
> -			uv_start_page--;
> -
> -		rot_info->uv_start_page = uv_start_page;
> -
> -		sg = rotate_pages(page_addr_list, rot_info->uv_start_page,
> -				  rot_info->plane[1].width, rot_info->plane[1].height,
> -				  rot_info->plane[1].width,
> -				  st, sg);
> +	for (i = 0 ; i < ARRAY_SIZE(rot_info->plane); i++) {
> +		sg = rotate_pages(page_addr_list, rot_info->plane[i].offset,
> +				  rot_info->plane[i].width, rot_info->plane[i].height,
> +				  rot_info->plane[i].stride, st, sg);
>  	}
>  
> -	DRM_DEBUG_KMS("Created rotated page mapping for object size %zu (%ux%u tiles, %u pages (%u plane 0)).\n",
> -		      obj->base.size, rot_info->plane[0].width,
> -		      rot_info->plane[0].height, size_pages + size_pages_uv,
> -		      size_pages);
> +	DRM_DEBUG_KMS("Created rotated page mapping for object size %zu (%ux%u tiles, %u pages)\n",
> +		      obj->base.size, rot_info->plane[0].width, rot_info->plane[0].height, size);
>  
>  	drm_free_large(page_addr_list);
>  
> @@ -3531,10 +3505,9 @@ err_sg_alloc:
>  err_st_alloc:
>  	drm_free_large(page_addr_list);
>  
> -	DRM_DEBUG_KMS("Failed to create rotated mapping for object size %zu! (%d) (%ux%u tiles, %u pages (%u plane 0))\n",
> -		      obj->base.size, ret, rot_info->plane[0].width,
> -		      rot_info->plane[0].height, size_pages + size_pages_uv,
> -		      size_pages);
> +	DRM_DEBUG_KMS("Failed to create rotated mapping for object size %zu! (%ux%u tiles, %u pages)\n",
> +		      obj->base.size, rot_info->plane[0].width, rot_info->plane[0].height, size);
> +
>  	return ERR_PTR(ret);
>  }
>  
> diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
> index cc56206a1600..56e64a5355e8 100644
> --- a/drivers/gpu/drm/i915/i915_gem_gtt.h
> +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
> @@ -139,12 +139,9 @@ enum i915_ggtt_view_type {
>  };
>  
>  struct intel_rotation_info {
> -	unsigned int uv_offset;
> -	uint32_t pixel_format;
> -	unsigned int uv_start_page;
>  	struct {
>  		/* tiles */
> -		unsigned int width, height;
> +		unsigned int width, height, stride, offset;
>  	} plane[2];
>  };
>  
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 8e71dc200880..f16a59ea7c18 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -2147,33 +2147,6 @@ intel_fill_fb_ggtt_view(struct i915_ggtt_view *view,
>  	}
>  }
>  
> -static void
> -intel_fill_fb_info(struct drm_i915_private *dev_priv,
> -		   struct drm_framebuffer *fb)
> -{
> -	struct intel_rotation_info *info = &to_intel_framebuffer(fb)->rot_info;
> -	unsigned int tile_size, tile_width, tile_height, cpp;
> -
> -	tile_size = intel_tile_size(dev_priv);
> -
> -	cpp = drm_format_plane_cpp(fb->pixel_format, 0);
> -	intel_tile_dims(dev_priv, &tile_width, &tile_height,
> -			fb->modifier[0], cpp);
> -
> -	info->plane[0].width = DIV_ROUND_UP(fb->pitches[0], tile_width * cpp);
> -	info->plane[0].height = DIV_ROUND_UP(fb->height, tile_height);
> -
> -	if (info->pixel_format == DRM_FORMAT_NV12) {
> -		cpp = drm_format_plane_cpp(fb->pixel_format, 1);
> -		intel_tile_dims(dev_priv, &tile_width, &tile_height,
> -				fb->modifier[1], cpp);
> -
> -		info->uv_offset = fb->offsets[1];
> -		info->plane[1].width = DIV_ROUND_UP(fb->pitches[1], tile_width * cpp);
> -		info->plane[1].height = DIV_ROUND_UP(fb->height / 2, tile_height);
> -	}
> -}
> -
>  static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_priv)
>  {
>  	if (INTEL_INFO(dev_priv)->gen >= 9)
> @@ -2295,6 +2268,42 @@ void intel_unpin_fb_obj(struct drm_framebuffer *fb, unsigned int rotation)
>  }
>  
>  /*
> + * Convert the x/y offsets into a linear offset.
> + * Only valid with 0/180 degree rotation, which is fine since linear
> + * offset is only used with linear buffers on pre-hsw and tiled buffers
> + * with gen2/3, and 90/270 degree rotations isn't supported on any of them.
> + */
> +u32 intel_fb_xy_to_linear(int x, int y,
> +			  const struct drm_framebuffer *fb, int plane)
> +{
> +	unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
> +	unsigned int pitch = fb->pitches[plane];
> +
> +	return y * pitch + x * cpp;
> +}
> +
> +/*
> + * Add the x/y offsets derived from fb->offsets[] to the user
> + * specified plane src x/y offsets. The resulting x/y offsets
> + * specify the start of scanout from the beginning of the gtt mapping.
> + */
> +void intel_add_fb_offsets(int *x, int *y,
> +			  const struct drm_framebuffer *fb, int plane,
> +			  unsigned int rotation)
> +
> +{
> +	const struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
> +
> +	if (intel_rotation_90_or_270(rotation)) {
> +		*x += intel_fb->rotated[plane].x;
> +		*y += intel_fb->rotated[plane].y;
> +	} else {
> +		*x += intel_fb->normal[plane].x;
> +		*y += intel_fb->normal[plane].y;
> +	}
> +}
> +
> +/*
>   * Adjust the tile offset by moving the difference into
>   * the x/y offsets.
>   *
> @@ -2330,18 +2339,24 @@ static u32 intel_adjust_tile_offset(int *x, int *y,
>   * In the 90/270 rotated case, x and y are assumed
>   * to be already rotated to match the rotated GTT view, and
>   * pitch is the tile_height aligned framebuffer height.
> + *
> + * This function is used when computing the derived information
> + * under intel_framebuffer, so using any of that information
> + * here is not allowed. Anything under drm_framebuffer can be
> + * used. This is why the user has to pass in the pitch since it
> + * is specified in the rotated orientation.
>   */
> -u32 intel_compute_tile_offset(int *x, int *y,
> -			      const struct drm_framebuffer *fb, int plane,
> -			      unsigned int pitch,
> -			      unsigned int rotation)
> +static u32 _intel_compute_tile_offset(const struct drm_i915_private *dev_priv,
> +				      int *x, int *y,
> +				      const struct drm_framebuffer *fb, int plane,
> +				      unsigned int pitch,
> +				      unsigned int rotation,
> +				      u32 alignment)
>  {
> -	const struct drm_i915_private *dev_priv = to_i915(fb->dev);
>  	uint64_t fb_modifier = fb->modifier[plane];
>  	unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
> -	u32 offset, offset_aligned, alignment;
> +	u32 offset, offset_aligned;
>  
> -	alignment = intel_surf_alignment(dev_priv, fb_modifier);
>  	if (alignment)
>  		alignment--;
>  
> @@ -2383,6 +2398,141 @@ u32 intel_compute_tile_offset(int *x, int *y,
>  	return offset_aligned;
>  }
>  
> +u32 intel_compute_tile_offset(int *x, int *y,
> +			      const struct drm_framebuffer *fb, int plane,
> +			      unsigned int pitch,
> +			      unsigned int rotation)
> +{
> +	const struct drm_i915_private *dev_priv = to_i915(fb->dev);
> +	u32 alignment = intel_surf_alignment(dev_priv, fb->modifier[plane]);
> +
> +	return _intel_compute_tile_offset(dev_priv, x, y, fb, plane, pitch,
> +					  rotation, alignment);
> +}
> +
> +/* Convert the fb->offset[] linear offset into x/y offsets */
> +static void intel_fb_offset_to_xy(int *x, int *y,
> +				  const struct drm_framebuffer *fb, int plane)
> +{
> +	unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
> +	unsigned int pitch = fb->pitches[plane];
> +	u32 linear_offset = fb->offsets[plane];
> +
> +	*y = linear_offset / pitch;
> +	*x = linear_offset % pitch / cpp;
> +}
> +
> +static int
> +intel_fill_fb_info(struct drm_i915_private *dev_priv,
> +		   struct drm_framebuffer *fb)
> +{
> +	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
> +	struct intel_rotation_info *rot_info = &intel_fb->rot_info;
> +	u32 gtt_offset_rotated = 0;
> +	unsigned int max_size = 0;
> +	uint32_t format = fb->pixel_format;
> +	int i, num_planes = drm_format_num_planes(format);
> +	unsigned int tile_size = intel_tile_size(dev_priv);
> +
> +	for (i = 0; i < num_planes; i++) {
> +		unsigned int width, height;
> +		unsigned int cpp, size;
> +		u32 offset;
> +		int x, y;
> +
> +		cpp = drm_format_plane_cpp(format, i);
> +		width = drm_format_plane_width(fb->width, format, i);
> +		height = drm_format_plane_height(fb->height, format, i);
> +
> +		intel_fb_offset_to_xy(&x, &y, fb, i);
> +
> +		/*
> +		 * First pixel of the framebuffer from
> +		 * the start of the normal gtt mapping.
> +		 */
> +		intel_fb->normal[i].x = x;
> +		intel_fb->normal[i].y = y;
> +
> +		offset = _intel_compute_tile_offset(dev_priv, &x, &y,
> +						    fb, 0, fb->pitches[i],
> +						    BIT(DRM_ROTATE_0), tile_size);
> +		offset /= tile_size;
> +
> +		if (fb->modifier[i] != DRM_FORMAT_MOD_NONE) {
> +			unsigned int tile_width, tile_height;
> +			unsigned int pitch_tiles;
> +			struct drm_rect r;
> +
> +			intel_tile_dims(dev_priv, &tile_width, &tile_height,
> +					fb->modifier[i], cpp);
> +
> +			rot_info->plane[i].offset = offset;
> +			rot_info->plane[i].stride = DIV_ROUND_UP(fb->pitches[i], tile_width * cpp);
> +			rot_info->plane[i].width = DIV_ROUND_UP(x + width, tile_width);
> +			rot_info->plane[i].height = DIV_ROUND_UP(y + height, tile_height);
> +
> +			intel_fb->rotated[i].pitch =
> +				rot_info->plane[i].height * tile_height;
> +
> +			/* how many tiles does this plane need */
> +			size = rot_info->plane[i].stride * rot_info->plane[i].height;
> +			/*
> +			 * If the plane isn't horizontally tile aligned,
> +			 * we need one more tile.
> +			 */
> +			if (x != 0)
> +				size++;
> +
> +			/* rotate the x/y offsets to match the GTT view */
> +			r.x1 = x;
> +			r.y1 = y;
> +			r.x2 = x + width;
> +			r.y2 = y + height;
> +			drm_rect_rotate(&r,
> +					rot_info->plane[i].width * tile_width,
> +					rot_info->plane[i].height * tile_height,
> +					BIT(DRM_ROTATE_270));
> +			x = r.x1;
> +			y = r.y1;
> +
> +			/* rotate the tile dimensions to match the GTT view */
> +			pitch_tiles = intel_fb->rotated[i].pitch / tile_height;
> +			swap(tile_width, tile_height);
> +
> +			/*
> +			 * We only keep the x/y offsets, so push all of the
> +			 * gtt offset into the x/y offsets.
> +			 */
> +			intel_adjust_tile_offset(&x, &y, tile_size,
> +						 tile_width, tile_height, pitch_tiles,
> +						 gtt_offset_rotated * tile_size, 0);
> +
> +			gtt_offset_rotated += rot_info->plane[i].width * rot_info->plane[i].height;
> +
> +			/*
> +			 * First pixel of the framebuffer from
> +			 * the start of the rotated gtt mapping.
> +			 */
> +			intel_fb->rotated[i].x = x;
> +			intel_fb->rotated[i].y = y;
> +		} else {
> +			size = DIV_ROUND_UP((y + height) * fb->pitches[i] +
> +					    x * cpp, tile_size);
> +		}
> +
> +		/* how many tiles in total needed in the bo */
> +		max_size = max(max_size, offset + size);
> +	}
> +
> +	if (max_size * tile_size > to_intel_framebuffer(fb)->obj->base.size) {
> +		DRM_DEBUG("fb too big for bo (need %u bytes, have %zu bytes)\n",
> +			  max_size * tile_size, to_intel_framebuffer(fb)->obj->base.size);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
>  static int i9xx_format_to_fourcc(int format)
>  {
>  	switch (format) {
> @@ -2618,7 +2768,6 @@ static void i9xx_update_primary_plane(struct drm_plane *primary,
>  	u32 dspcntr;
>  	i915_reg_t reg = DSPCNTR(plane);
>  	unsigned int rotation = plane_state->base.rotation;
> -	int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
>  	int x = plane_state->base.src.x1 >> 16;
>  	int y = plane_state->base.src.y1 >> 16;
>  
> @@ -2677,30 +2826,25 @@ static void i9xx_update_primary_plane(struct drm_plane *primary,
>  	if (IS_G4X(dev))
>  		dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
>  
> -	linear_offset = y * fb->pitches[0] + x * cpp;
> +	intel_add_fb_offsets(&x, &y, fb, 0, rotation);
>  
> -	if (INTEL_INFO(dev)->gen >= 4) {
> +	if (INTEL_INFO(dev)->gen >= 4)
>  		intel_crtc->dspaddr_offset =
>  			intel_compute_tile_offset(&x, &y, fb, 0,
>  						  fb->pitches[0], rotation);
> -		linear_offset -= intel_crtc->dspaddr_offset;
> -	} else {
> -		intel_crtc->dspaddr_offset = linear_offset;
> -	}
>  
>  	if (rotation == DRM_ROTATE_180) {
>  		dspcntr |= DISPPLANE_ROTATE_180;
>  
>  		x += (crtc_state->pipe_src_w - 1);
>  		y += (crtc_state->pipe_src_h - 1);
> -
> -		/* Finding the last pixel of the last line of the display
> -		data and adding to linear_offset*/
> -		linear_offset +=
> -			(crtc_state->pipe_src_h - 1) * fb->pitches[0] +
> -			(crtc_state->pipe_src_w - 1) * cpp;
>  	}
>  
> +	linear_offset = intel_fb_xy_to_linear(x, y, fb, 0);
> +
> +	if (INTEL_INFO(dev)->gen < 4)
> +		intel_crtc->dspaddr_offset = linear_offset;
> +
>  	intel_crtc->adjusted_x = x;
>  	intel_crtc->adjusted_y = y;
>  
> @@ -2709,7 +2853,8 @@ static void i9xx_update_primary_plane(struct drm_plane *primary,
>  	I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
>  	if (INTEL_INFO(dev)->gen >= 4) {
>  		I915_WRITE(DSPSURF(plane),
> -			   i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
> +			   intel_fb_gtt_offset(fb, rotation) +
> +			   intel_crtc->dspaddr_offset);
>  		I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
>  		I915_WRITE(DSPLINOFF(plane), linear_offset);
>  	} else
> @@ -2747,7 +2892,6 @@ static void ironlake_update_primary_plane(struct drm_plane *primary,
>  	u32 dspcntr;
>  	i915_reg_t reg = DSPCNTR(plane);
>  	unsigned int rotation = plane_state->base.rotation;
> -	int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
>  	int x = plane_state->base.src.x1 >> 16;
>  	int y = plane_state->base.src.y1 >> 16;
>  
> @@ -2786,26 +2930,23 @@ static void ironlake_update_primary_plane(struct drm_plane *primary,
>  	if (!IS_HASWELL(dev) && !IS_BROADWELL(dev))
>  		dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
>  
> -	linear_offset = y * fb->pitches[0] + x * cpp;
> +	intel_add_fb_offsets(&x, &y, fb, 0, rotation);
> +
>  	intel_crtc->dspaddr_offset =
>  		intel_compute_tile_offset(&x, &y, fb, 0,
>  					  fb->pitches[0], rotation);
> -	linear_offset -= intel_crtc->dspaddr_offset;
> +
>  	if (rotation == DRM_ROTATE_180) {
>  		dspcntr |= DISPPLANE_ROTATE_180;
>  
>  		if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) {
>  			x += (crtc_state->pipe_src_w - 1);
>  			y += (crtc_state->pipe_src_h - 1);
> -
> -			/* Finding the last pixel of the last line of the display
> -			data and adding to linear_offset*/
> -			linear_offset +=
> -				(crtc_state->pipe_src_h - 1) * fb->pitches[0] +
> -				(crtc_state->pipe_src_w - 1) * cpp;
>  		}
>  	}
>  
> +	linear_offset = intel_fb_xy_to_linear(x, y, fb, 0);
> +
>  	intel_crtc->adjusted_x = x;
>  	intel_crtc->adjusted_y = y;
>  
> @@ -2813,7 +2954,8 @@ static void ironlake_update_primary_plane(struct drm_plane *primary,
>  
>  	I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
>  	I915_WRITE(DSPSURF(plane),
> -		   i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
> +		   intel_fb_gtt_offset(fb, rotation) +
> +		   intel_crtc->dspaddr_offset);
>  	if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
>  		I915_WRITE(DSPOFFSET(plane), (y << 16) | x);
>  	} else {
> @@ -2835,28 +2977,16 @@ u32 intel_fb_stride_alignment(const struct drm_i915_private *dev_priv,
>  	}
>  }
>  
> -u32 intel_plane_obj_offset(struct intel_plane *intel_plane,
> -			   struct drm_i915_gem_object *obj,
> -			   unsigned int plane)
> +u32 intel_fb_gtt_offset(struct drm_framebuffer *fb,
> +			unsigned int rotation)
>  {
> +	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
>  	struct i915_ggtt_view view;
> -	struct i915_vma *vma;
>  	u64 offset;
>  
> -	intel_fill_fb_ggtt_view(&view, intel_plane->base.state->fb,
> -				intel_plane->base.state->rotation);
> -
> -	vma = i915_gem_obj_to_ggtt_view(obj, &view);
> -	if (WARN(!vma, "ggtt vma for display object not found! (view=%u)\n",
> -		view.type))
> -		return -1;
> -
> -	offset = vma->node.start;
> +	intel_fill_fb_ggtt_view(&view, fb, rotation);
>  
> -	if (plane == 1) {
> -		offset += vma->ggtt_view.params.rotated.uv_start_page *
> -			  PAGE_SIZE;
> -	}
> +	offset = i915_gem_obj_ggtt_offset_view(obj, &view);
>  
>  	WARN_ON(upper_32_bits(offset));
>  
> @@ -2979,12 +3109,9 @@ static void skylake_update_primary_plane(struct drm_plane *plane,
>  	struct drm_i915_private *dev_priv = to_i915(dev);
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
>  	struct drm_framebuffer *fb = plane_state->base.fb;
> -	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
>  	int pipe = intel_crtc->pipe;
>  	u32 plane_ctl, stride_div, stride;
> -	u32 tile_height, plane_offset, plane_size;
>  	unsigned int rotation = plane_state->base.rotation;
> -	int x_offset, y_offset;
>  	u32 surf_addr;
>  	int scaler_id = plane_state->scaler_id;
>  	int src_x = plane_state->base.src.x1 >> 16;
> @@ -3005,36 +3132,49 @@ static void skylake_update_primary_plane(struct drm_plane *plane,
>  	plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE;
>  	plane_ctl |= skl_plane_ctl_rotation(rotation);
>  
> -	stride_div = intel_fb_stride_alignment(dev_priv, fb->modifier[0],
> -					       fb->pixel_format);
> -	surf_addr = intel_plane_obj_offset(to_intel_plane(plane), obj, 0);
> -
> -	WARN_ON(drm_rect_width(&plane_state->base.src) == 0);
> -
>  	if (intel_rotation_90_or_270(rotation)) {
> +		struct drm_rect r = {
> +			.x1 = src_x,
> +			.x2 = src_x + src_w,
> +			.y1 = src_y,
> +			.y2 = src_y + src_h,
> +		};
>  		int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
> +		struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
> +
> +		/* Rotate src coordinates to match rotated GTT view */
> +		drm_rect_rotate(&r, fb->width, fb->height, BIT(DRM_ROTATE_270));
>  
> -		/* stride = Surface height in tiles */
> -		tile_height = intel_tile_height(dev_priv, fb->modifier[0], cpp);
> -		stride = DIV_ROUND_UP(fb->height, tile_height);
> -		x_offset = stride * tile_height - src_y - src_h;
> -		y_offset = src_x;
> -		plane_size = (src_w - 1) << 16 | (src_h - 1);
> +		src_x = r.x1;
> +		src_y = r.y1;
> +		src_w = drm_rect_width(&r);
> +		src_h = drm_rect_height(&r);
> +
> +		stride_div = intel_tile_height(dev_priv, fb->modifier[0], cpp);
> +		stride = intel_fb->rotated[0].pitch;
>  	} else {
> -		stride = fb->pitches[0] / stride_div;
> -		x_offset = src_x;
> -		y_offset = src_y;
> -		plane_size = (src_h - 1) << 16 | (src_w - 1);
> +		stride_div = intel_fb_stride_alignment(dev_priv, fb->modifier[0],
> +						       fb->pixel_format);
> +		stride = fb->pitches[0];
>  	}
> -	plane_offset = y_offset << 16 | x_offset;
>  
> -	intel_crtc->adjusted_x = x_offset;
> -	intel_crtc->adjusted_y = y_offset;
> +	intel_add_fb_offsets(&src_x, &src_y, fb, 0, rotation);
> +	surf_addr = intel_compute_tile_offset(&src_x, &src_y, fb, 0,
> +					      stride, rotation);
> +
> +	/* Sizes are 0 based */
> +	src_w--;
> +	src_h--;
> +	dst_w--;
> +	dst_h--;
> +
> +	intel_crtc->adjusted_x = src_x;
> +	intel_crtc->adjusted_y = src_y;
>  
>  	I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl);
> -	I915_WRITE(PLANE_OFFSET(pipe, 0), plane_offset);
> -	I915_WRITE(PLANE_SIZE(pipe, 0), plane_size);
> -	I915_WRITE(PLANE_STRIDE(pipe, 0), stride);
> +	I915_WRITE(PLANE_OFFSET(pipe, 0), (src_y << 16) | src_x);
> +	I915_WRITE(PLANE_STRIDE(pipe, 0), stride / stride_div);
> +	I915_WRITE(PLANE_SIZE(pipe, 0), (src_h << 16) | src_w);
>  
>  	if (scaler_id >= 0) {
>  		uint32_t ps_ctrl = 0;
> @@ -3051,7 +3191,8 @@ static void skylake_update_primary_plane(struct drm_plane *plane,
>  		I915_WRITE(PLANE_POS(pipe, 0), (dst_y << 16) | dst_x);
>  	}
>  
> -	I915_WRITE(PLANE_SURF(pipe, 0), surf_addr);
> +	I915_WRITE(PLANE_SURF(pipe, 0),
> +		   intel_fb_gtt_offset(fb, rotation) + surf_addr);
>  
>  	POSTING_READ(PLANE_SURF(pipe, 0));
>  }
> @@ -11462,7 +11603,7 @@ static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
>  	struct drm_i915_private *dev_priv = to_i915(dev);
>  	struct drm_framebuffer *fb = intel_crtc->base.primary->fb;
>  	const enum pipe pipe = intel_crtc->pipe;
> -	u32 ctl, stride, tile_height;
> +	u32 ctl, stride;
>  
>  	ctl = I915_READ(PLANE_CTL(pipe, 0));
>  	ctl &= ~PLANE_CTL_TILED_MASK;
> @@ -11487,9 +11628,11 @@ static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
>  	 * linear buffers or in number of tiles for tiled buffers.
>  	 */
>  	if (intel_rotation_90_or_270(rotation)) {
> -		/* stride = Surface height in tiles */
> -		tile_height = intel_tile_height(dev_priv, fb->modifier[0], 0);
> -		stride = DIV_ROUND_UP(fb->height, tile_height);
> +		int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
> +		struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
> +
> +		stride = intel_fb->rotated[0].pitch /
> +			intel_tile_height(dev_priv, fb->modifier[0], cpp);
>  	} else {
>  		stride = fb->pitches[0] /
>  			intel_fb_stride_alignment(dev_priv, fb->modifier[0],
> @@ -11769,8 +11912,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>  	if (ret)
>  		goto cleanup_pending;
>  
> -	work->gtt_offset = intel_plane_obj_offset(to_intel_plane(primary),
> -						  obj, 0);
> +	work->gtt_offset = intel_fb_gtt_offset(fb, primary->state->rotation);
>  	work->gtt_offset += intel_crtc->dspaddr_offset;
>  	work->rotation = crtc->primary->state->rotation;
>  
> @@ -14988,7 +15130,6 @@ static int intel_framebuffer_init(struct drm_device *dev,
>  				  struct drm_i915_gem_object *obj)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(dev);
> -	unsigned int aligned_height;
>  	int ret;
>  	u32 pitch_limit, stride_alignment;
>  
> @@ -15114,17 +15255,12 @@ static int intel_framebuffer_init(struct drm_device *dev,
>  	if (mode_cmd->offsets[0] != 0)
>  		return -EINVAL;
>  
> -	aligned_height = intel_fb_align_height(dev, mode_cmd->height,
> -					       mode_cmd->pixel_format,
> -					       mode_cmd->modifier[0]);
> -	/* FIXME drm helper for size checks (especially planar formats)? */
> -	if (obj->base.size < aligned_height * mode_cmd->pitches[0])
> -		return -EINVAL;
> -
>  	drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd);
>  	intel_fb->obj = obj;
>  
> -	intel_fill_fb_info(dev_priv, &intel_fb->base);
> +	ret = intel_fill_fb_info(dev_priv, &intel_fb->base);
> +	if (ret)
> +		return ret;
>  
>  	ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
>  	if (ret) {
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index c29a429cbc45..a81d2b8bd740 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -178,6 +178,16 @@ struct intel_framebuffer {
>  	struct drm_framebuffer base;
>  	struct drm_i915_gem_object *obj;
>  	struct intel_rotation_info rot_info;
> +
> +	/* for each plane in the normal GTT view */
> +	struct {
> +		unsigned int x, y;
> +	} normal[2];
> +	/* for each plane in the rotated GTT view */
> +	struct {
> +		unsigned int x, y;
> +		unsigned int pitch; /* pixels */
> +	} rotated[2];
>  };
>  
>  struct intel_fbdev {
> @@ -1153,6 +1163,11 @@ int vlv_get_cck_clock(struct drm_i915_private *dev_priv,
>  		      const char *name, u32 reg, int ref_freq);
>  extern const struct drm_plane_funcs intel_plane_funcs;
>  void intel_init_display_hooks(struct drm_i915_private *dev_priv);
> +unsigned int intel_fb_xy_to_linear(int x, int y,
> +				   const struct drm_framebuffer *fb, int plane);
> +void intel_add_fb_offsets(int *x, int *y,
> +			  const struct drm_framebuffer *fb, int plane,
> +			  unsigned int rotation);
>  unsigned int intel_rotation_info_size(const struct intel_rotation_info *rot_info);
>  bool intel_has_pending_fb_unpin(struct drm_device *dev);
>  void intel_mark_busy(struct drm_i915_private *dev_priv);
> @@ -1322,9 +1337,7 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode,
>  int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state);
>  int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state);
>  
> -u32 intel_plane_obj_offset(struct intel_plane *intel_plane,
> -			   struct drm_i915_gem_object *obj,
> -			   unsigned int plane);
> +u32 intel_fb_gtt_offset(struct drm_framebuffer *fb, unsigned int rotation);
>  
>  u32 skl_plane_ctl_format(uint32_t pixel_format);
>  u32 skl_plane_ctl_tiling(uint64_t fb_modifier);
> diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> index cbdca7e4d307..ef4d0a6e23af 100644
> --- a/drivers/gpu/drm/i915/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/intel_sprite.c
> @@ -203,15 +203,13 @@ skl_update_plane(struct drm_plane *drm_plane,
>  	struct drm_i915_private *dev_priv = to_i915(dev);
>  	struct intel_plane *intel_plane = to_intel_plane(drm_plane);
>  	struct drm_framebuffer *fb = plane_state->base.fb;
> -	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
> +	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
>  	const int pipe = intel_plane->pipe;
>  	const int plane = intel_plane->plane + 1;
>  	u32 plane_ctl, stride_div, stride;
>  	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
>  	u32 surf_addr;
> -	u32 tile_height, plane_offset, plane_size;
>  	unsigned int rotation = plane_state->base.rotation;
> -	int x_offset, y_offset;
>  	int crtc_x = plane_state->base.dst.x1;
>  	int crtc_y = plane_state->base.dst.y1;
>  	uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
> @@ -230,15 +228,6 @@ skl_update_plane(struct drm_plane *drm_plane,
>  
>  	plane_ctl |= skl_plane_ctl_rotation(rotation);
>  
> -	stride_div = intel_fb_stride_alignment(dev_priv, fb->modifier[0],
> -					       fb->pixel_format);
> -
> -	/* Sizes are 0 based */
> -	src_w--;
> -	src_h--;
> -	crtc_w--;
> -	crtc_h--;
> -
>  	if (key->flags) {
>  		I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value);
>  		I915_WRITE(PLANE_KEYMAX(pipe, plane), key->max_value);
> @@ -250,28 +239,44 @@ skl_update_plane(struct drm_plane *drm_plane,
>  	else if (key->flags & I915_SET_COLORKEY_SOURCE)
>  		plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE;
>  
> -	surf_addr = intel_plane_obj_offset(intel_plane, obj, 0);
> -
>  	if (intel_rotation_90_or_270(rotation)) {
> -		int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
> -
> -		/* stride: Surface height in tiles */
> -		tile_height = intel_tile_height(dev_priv, fb->modifier[0], cpp);
> -		stride = DIV_ROUND_UP(fb->height, tile_height);
> -		plane_size = (src_w << 16) | src_h;
> -		x_offset = stride * tile_height - y - (src_h + 1);
> -		y_offset = x;
> +		struct drm_rect r = {
> +			.x1 = x,
> +			.x2 = x + src_w,
> +			.y1 = y,
> +			.y2 = y + src_h,
> +		};
> +		unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
> +
> +		/* Rotate src coordinates to match rotated GTT view */
> +		drm_rect_rotate(&r, fb->width, fb->height, BIT(DRM_ROTATE_270));
> +
> +		x = r.x1;
> +		y = r.y1;
> +		src_w = drm_rect_width(&r);
> +		src_h = drm_rect_height(&r);
> +
> +		stride_div = intel_tile_height(dev_priv, fb->modifier[0], cpp);
> +		stride = intel_fb->rotated[0].pitch;
>  	} else {
> -		stride = fb->pitches[0] / stride_div;
> -		plane_size = (src_h << 16) | src_w;
> -		x_offset = x;
> -		y_offset = y;
> +		stride_div = intel_fb_stride_alignment(dev_priv, fb->modifier[0],
> +						       fb->pixel_format);
> +		stride = fb->pitches[0];
>  	}
> -	plane_offset = y_offset << 16 | x_offset;
>  
> -	I915_WRITE(PLANE_OFFSET(pipe, plane), plane_offset);
> -	I915_WRITE(PLANE_STRIDE(pipe, plane), stride);
> -	I915_WRITE(PLANE_SIZE(pipe, plane), plane_size);
> +	intel_add_fb_offsets(&x, &y, fb, 0, rotation);
> +	surf_addr = intel_compute_tile_offset(&x, &y, fb, 0,
> +					      stride, rotation);
> +
> +	/* Sizes are 0 based */
> +	src_w--;
> +	src_h--;
> +	crtc_w--;
> +	crtc_h--;
> +
> +	I915_WRITE(PLANE_OFFSET(pipe, plane), (y << 16) | x);
> +	I915_WRITE(PLANE_STRIDE(pipe, plane), stride / stride_div);
> +	I915_WRITE(PLANE_SIZE(pipe, plane), (src_h << 16) | src_w);
>  
>  	/* program plane scaler */
>  	if (plane_state->scaler_id >= 0) {
> @@ -296,7 +301,8 @@ skl_update_plane(struct drm_plane *drm_plane,
>  	}
>  
>  	I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl);
> -	I915_WRITE(PLANE_SURF(pipe, plane), surf_addr);
> +	I915_WRITE(PLANE_SURF(pipe, plane),
> +		   intel_fb_gtt_offset(fb, rotation) + surf_addr);
>  	POSTING_READ(PLANE_SURF(pipe, plane));
>  }
>  
> @@ -369,7 +375,6 @@ vlv_update_plane(struct drm_plane *dplane,
>  	u32 sprctl;
>  	u32 sprsurf_offset, linear_offset;
>  	unsigned int rotation = dplane->state->rotation;
> -	int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
>  	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
>  	int crtc_x = plane_state->base.dst.x1;
>  	int crtc_y = plane_state->base.dst.y1;
> @@ -440,19 +445,19 @@ vlv_update_plane(struct drm_plane *dplane,
>  	crtc_w--;
>  	crtc_h--;
>  
> -	linear_offset = y * fb->pitches[0] + x * cpp;
> +	intel_add_fb_offsets(&x, &y, fb, 0, rotation);
>  	sprsurf_offset = intel_compute_tile_offset(&x, &y, fb, 0,
>  						   fb->pitches[0], rotation);
> -	linear_offset -= sprsurf_offset;
>  
>  	if (rotation == DRM_ROTATE_180) {
>  		sprctl |= SP_ROTATE_180;
>  
>  		x += src_w;
>  		y += src_h;
> -		linear_offset += src_h * fb->pitches[0] + src_w * cpp;
>  	}
>  
> +	linear_offset = intel_fb_xy_to_linear(x, y, fb, 0);
> +
>  	if (key->flags) {
>  		I915_WRITE(SPKEYMINVAL(pipe, plane), key->min_value);
>  		I915_WRITE(SPKEYMAXVAL(pipe, plane), key->max_value);
> @@ -477,8 +482,8 @@ vlv_update_plane(struct drm_plane *dplane,
>  
>  	I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w);
>  	I915_WRITE(SPCNTR(pipe, plane), sprctl);
> -	I915_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) +
> -		   sprsurf_offset);
> +	I915_WRITE(SPSURF(pipe, plane),
> +		   intel_fb_gtt_offset(fb, rotation) + sprsurf_offset);
>  	POSTING_READ(SPSURF(pipe, plane));
>  }
>  
> @@ -511,7 +516,6 @@ ivb_update_plane(struct drm_plane *plane,
>  	u32 sprctl, sprscale = 0;
>  	u32 sprsurf_offset, linear_offset;
>  	unsigned int rotation = plane_state->base.rotation;
> -	int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
>  	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
>  	int crtc_x = plane_state->base.dst.x1;
>  	int crtc_y = plane_state->base.dst.y1;
> @@ -573,10 +577,9 @@ ivb_update_plane(struct drm_plane *plane,
>  	if (crtc_w != src_w || crtc_h != src_h)
>  		sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
>  
> -	linear_offset = y * fb->pitches[0] + x * cpp;
> +	intel_add_fb_offsets(&x, &y, fb, 0, rotation);
>  	sprsurf_offset = intel_compute_tile_offset(&x, &y, fb, 0,
>  						   fb->pitches[0], rotation);
> -	linear_offset -= sprsurf_offset;
>  
>  	if (rotation == DRM_ROTATE_180) {
>  		sprctl |= SPRITE_ROTATE_180;
> @@ -585,10 +588,11 @@ ivb_update_plane(struct drm_plane *plane,
>  		if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) {
>  			x += src_w;
>  			y += src_h;
> -			linear_offset += src_h * fb->pitches[0] + src_w * cpp;
>  		}
>  	}
>  
> +	linear_offset = intel_fb_xy_to_linear(x, y, fb, 0);
> +
>  	if (key->flags) {
>  		I915_WRITE(SPRKEYVAL(pipe), key->min_value);
>  		I915_WRITE(SPRKEYMAX(pipe), key->max_value);
> @@ -617,7 +621,7 @@ ivb_update_plane(struct drm_plane *plane,
>  		I915_WRITE(SPRSCALE(pipe), sprscale);
>  	I915_WRITE(SPRCTL(pipe), sprctl);
>  	I915_WRITE(SPRSURF(pipe),
> -		   i915_gem_obj_ggtt_offset(obj) + sprsurf_offset);
> +		   intel_fb_gtt_offset(fb, rotation) + sprsurf_offset);
>  	POSTING_READ(SPRSURF(pipe));
>  }
>  
> @@ -652,7 +656,6 @@ ilk_update_plane(struct drm_plane *plane,
>  	u32 dvscntr, dvsscale;
>  	u32 dvssurf_offset, linear_offset;
>  	unsigned int rotation = plane_state->base.rotation;
> -	int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
>  	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
>  	int crtc_x = plane_state->base.dst.x1;
>  	int crtc_y = plane_state->base.dst.y1;
> @@ -710,19 +713,19 @@ ilk_update_plane(struct drm_plane *plane,
>  	if (crtc_w != src_w || crtc_h != src_h)
>  		dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
>  
> -	linear_offset = y * fb->pitches[0] + x * cpp;
> +	intel_add_fb_offsets(&x, &y, fb, 0, rotation);
>  	dvssurf_offset = intel_compute_tile_offset(&x, &y, fb, 0,
>  						   fb->pitches[0], rotation);
> -	linear_offset -= dvssurf_offset;
>  
>  	if (rotation == DRM_ROTATE_180) {
>  		dvscntr |= DVS_ROTATE_180;
>  
>  		x += src_w;
>  		y += src_h;
> -		linear_offset += src_h * fb->pitches[0] + src_w * cpp;
>  	}
>  
> +	linear_offset = intel_fb_xy_to_linear(x, y, fb, 0);
> +
>  	if (key->flags) {
>  		I915_WRITE(DVSKEYVAL(pipe), key->min_value);
>  		I915_WRITE(DVSKEYMAX(pipe), key->max_value);
> @@ -746,7 +749,7 @@ ilk_update_plane(struct drm_plane *plane,
>  	I915_WRITE(DVSSCALE(pipe), dvsscale);
>  	I915_WRITE(DVSCNTR(pipe), dvscntr);
>  	I915_WRITE(DVSSURF(pipe),
> -		   i915_gem_obj_ggtt_offset(obj) + dvssurf_offset);
> +		   intel_fb_gtt_offset(fb, rotation) + dvssurf_offset);
>  	POSTING_READ(DVSSURF(pipe));
>  }
>  
> -- 
> 2.7.4
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch


More information about the Intel-gfx mailing list