Message ID | 1444931985-26045-1-git-send-email-ville.syrjala@linux.intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Thu, Oct 15, 2015 at 08:59:45PM +0300, ville.syrjala@linux.intel.com wrote: > From: Ville Syrjälä <ville.syrjala@linux.intel.com> > > Redo the fb rotation handling in order to: > - eliminate the NV12 special casing > - handle fb->offsets[] properly > - make the rotation handling reasier for the plane code I think this is too big and should be split a bit. There's also a pile of renames mixed int on top. > 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. That sounds like a good prep patch to split out. > We then store the computed rotation_info under > intel_framebuffer so that we don't have to recompute it again. And another one, plus then following up with the fallout. This patch also fixes the intel_plane_obj_offset issue for earlier in the series. Looks good otherwise from reading through it. > 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 > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Two comments below inline. -Daniel > --- > drivers/gpu/drm/i915/i915_gem_gtt.c | 66 ++---- > drivers/gpu/drm/i915/i915_gem_gtt.h | 14 +- > drivers/gpu/drm/i915/intel_display.c | 448 ++++++++++++++++++++++++----------- > drivers/gpu/drm/i915/intel_drv.h | 32 ++- > drivers/gpu/drm/i915/intel_sprite.c | 102 ++++---- > 5 files changed, 402 insertions(+), 260 deletions(-) > > diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c > index bb95b86..98aee6c 100644 > --- a/drivers/gpu/drm/i915/i915_gem_gtt.c > +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c > @@ -3255,11 +3255,6 @@ rotate_pages(const dma_addr_t *in, unsigned int offset, > unsigned int column, row; > unsigned int src_idx; > > - if (!sg) { > - st->nents = 0; > - sg = st->sgl; > - } > - > for (column = 0; column < width; column++) { > src_idx = stride * (height - 1) + column; > for (row = 0; row < height; row++) { > @@ -3280,16 +3275,14 @@ 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 *info, > struct drm_i915_gem_object *obj) > { > - unsigned int size_pages = rot_info->size >> PAGE_SHIFT; > - unsigned int size_pages_uv; > + unsigned int size = intel_rotation_info_size(info); > struct sg_page_iter sg_iter; > unsigned long i; > dma_addr_t *page_addr_list; > struct sg_table *st; > - unsigned int uv_start_page; > struct scatterlist *sg; > int ret = -ENOMEM; > > @@ -3299,57 +3292,32 @@ 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->size_uv >> PAGE_SHIFT; > - 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; > > /* Populate source page list from the object. */ > i = 0; > for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { > - page_addr_list[i] = sg_page_iter_dma_address(&sg_iter); > - i++; > + page_addr_list[i++] = sg_page_iter_dma_address(&sg_iter); > } > > - /* Rotate the pages. */ > - sg = rotate_pages(page_addr_list, 0, > - rot_info->width_pages, rot_info->height_pages, > - rot_info->width_pages, > - st, NULL); > + st->nents = 0; > + sg = st->sgl; > > - /* 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; > - > - rotate_pages(page_addr_list, uv_start_page, > - rot_info->width_pages_uv, > - rot_info->height_pages_uv, > - rot_info->width_pages_uv, > - st, sg); > + for (i = 0 ; i < ARRAY_SIZE(info->plane); i++) { > + sg = rotate_pages(page_addr_list, info->plane[i].offset, > + info->plane[i].width, info->plane[i].height, > + info->plane[i].stride, st, sg); > } > > - DRM_DEBUG_KMS( > - "Created rotated page mapping for object size %zu (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %u pages (%u plane 0)).\n", > - obj->base.size, rot_info->pitch, rot_info->height, > - rot_info->pixel_format, rot_info->width_pages, > - rot_info->height_pages, 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, info->plane[0].width, info->plane[0].height, size); > > drm_free_large(page_addr_list); > > @@ -3360,12 +3328,8 @@ 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) (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %u pages (%u plane 0))\n", > - obj->base.size, ret, rot_info->pitch, rot_info->height, > - rot_info->pixel_format, rot_info->width_pages, > - rot_info->height_pages, 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, info->plane[0].width, info->plane[0].height, size); > return ERR_PTR(ret); > } > > @@ -3516,7 +3480,7 @@ i915_ggtt_view_size(struct drm_i915_gem_object *obj, > if (view->type == I915_GGTT_VIEW_NORMAL) { > return obj->base.size; > } else if (view->type == I915_GGTT_VIEW_ROTATED) { > - return view->rotated.size; > + return intel_rotation_info_size(&view->rotated) << PAGE_SHIFT; > } else if (view->type == I915_GGTT_VIEW_PARTIAL) { > return view->partial.size << PAGE_SHIFT; > } else { > diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h > index 68de734..ea28f7d 100644 > --- a/drivers/gpu/drm/i915/i915_gem_gtt.h > +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h > @@ -136,16 +136,10 @@ enum i915_ggtt_view_type { > }; > > struct intel_rotation_info { > - unsigned int height; > - unsigned int pitch; > - unsigned int uv_offset; > - uint32_t pixel_format; > - uint64_t fb_modifier; > - unsigned int width_pages, height_pages; > - uint64_t size; > - unsigned int width_pages_uv, height_pages_uv; > - uint64_t size_uv; > - unsigned int uv_start_page; > + struct { > + /* tiles */ > + unsigned int width, height, stride, offset; > + } plane[2]; > }; > > struct i915_ggtt_view { > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c > index 028dc4a..0dcb710 100644 > --- a/drivers/gpu/drm/i915/intel_display.c > +++ b/drivers/gpu/drm/i915/intel_display.c > @@ -2274,49 +2274,28 @@ intel_fb_align_height(struct drm_device *dev, unsigned int height, > return ALIGN(height, tile_height); > } > > -static int > +unsigned int intel_rotation_info_size(const struct intel_rotation_info *info) > +{ > + unsigned int size = 0; > + int i; > + > + for (i = 0 ; i < ARRAY_SIZE(info->plane); i++) > + size += info->plane[i].width * info->plane[i].height; > + > + return size; > +} > + > +static void > intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, > const struct drm_framebuffer *fb, > unsigned int rotation) > { > - struct drm_i915_private *dev_priv = to_i915(fb->dev); > - struct intel_rotation_info *info = &view->rotated; > - unsigned int tile_size, tile_width, tile_height, cpp; > - > - *view = i915_ggtt_view_normal; > - > - if (!intel_rotation_90_or_270(rotation)) > - return 0; > - > - *view = i915_ggtt_view_rotated; > - > - info->height = fb->height; > - info->pixel_format = fb->pixel_format; > - info->pitch = fb->pitches[0]; > - info->uv_offset = fb->offsets[1]; > - info->fb_modifier = fb->modifier[0]; > - > - tile_size = intel_tile_size(dev_priv); > - > - cpp = drm_format_plane_cpp(fb->pixel_format, 0); > - tile_width = intel_tile_width(dev_priv, cpp, fb->modifier[0]); > - tile_height = tile_size / tile_width; > - > - info->width_pages = DIV_ROUND_UP(fb->pitches[0], tile_width); > - info->height_pages = DIV_ROUND_UP(fb->height, tile_height); > - info->size = info->width_pages * info->height_pages * tile_size; > - > - if (info->pixel_format == DRM_FORMAT_NV12) { > - cpp = drm_format_plane_cpp(fb->pixel_format, 1); > - tile_width = intel_tile_width(dev_priv, fb->modifier[1], cpp); > - tile_height = tile_size / tile_width; > - > - info->width_pages_uv = DIV_ROUND_UP(fb->pitches[1], tile_width); > - info->height_pages_uv = DIV_ROUND_UP(fb->height / 2, tile_height); > - info->size_uv = info->width_pages_uv * info->height_pages_uv * tile_size; > + if (intel_rotation_90_or_270(rotation)) { > + *view = i915_ggtt_view_rotated; > + view->rotated = to_intel_framebuffer(fb)->info; > + } else { > + *view = i915_ggtt_view_normal; > } > - > - return 0; > } > > static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_priv) > @@ -2368,9 +2347,7 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, > > alignment = intel_surf_alignment(dev_priv, fb->modifier[0]); > > - ret = intel_fill_fb_ggtt_view(&view, fb, rotation); > - if (ret) > - return ret; > + intel_fill_fb_ggtt_view(&view, fb, rotation); > > /* Note that the w/a also requires 64 PTE of padding following the > * bo. We currently fill all unused PTE with the shadow page and so > @@ -2433,18 +2410,31 @@ static void intel_unpin_fb_obj(struct drm_framebuffer *fb, unsigned int rotation > { > struct drm_i915_gem_object *obj = intel_fb_obj(fb); > struct i915_ggtt_view view; > - int ret; > > WARN_ON(!mutex_is_locked(&obj->base.dev->struct_mutex)); > > - ret = intel_fill_fb_ggtt_view(&view, fb, rotation); > - WARN_ONCE(ret, "Couldn't get view from plane state!"); > + intel_fill_fb_ggtt_view(&view, fb, rotation); > > i915_gem_object_unpin_fence(obj); > i915_gem_object_unpin_from_display_plane(obj, &view); > } > > /* > + * 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. > + */ > +unsigned int 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; > +} > + > +/* > * Return the tile dimensions in pixel units matching > * the specified rotation angle. > */ > @@ -2475,6 +2465,55 @@ static void intel_rotate_tile_dims(unsigned int *tile_width, > } > > /* > + * 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 drm_i915_private *dev_priv = to_i915(fb->dev); > + const struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); > + unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, plane); > + unsigned int pitch; > + > + if (intel_rotation_90_or_270(rotation)) { > + pitch = intel_fb->plane[plane].rotated.pitch; > + > + *x += intel_fb->plane[plane].rotated.x; > + *y += intel_fb->plane[plane].rotated.y; > + } else { > + pitch = fb->pitches[plane]; > + > + *x += intel_fb->plane[plane].normal.x; > + *y += intel_fb->plane[plane].normal.y; > + } > + > + /* minimize x */ > + if (fb->modifier[plane] != DRM_FORMAT_MOD_NONE) { > + unsigned int tile_size, tile_width, tile_height; > + > + tile_size = intel_tile_size(dev_priv); > + tile_width = intel_tile_width(dev_priv, fb->modifier[plane], cpp); > + tile_height = tile_size / tile_width; > + > + intel_rotate_tile_dims(&tile_width, &tile_height, > + &pitch, cpp, rotation); > + > + *y += *x / pitch * tile_height; > + *x = *x % pitch; > + } else { > + /* in pixels */ > + pitch /= cpp; > + > + *y += *x / pitch; > + *x = *x % pitch; > + } This is called before we do the entire page_offset dance, so I don't think we need a special case for tiled vs. untiled. -Daniel > +} > + > +/* > * Adjust the page offset by moving the difference into > * the x/y offsets. > * > @@ -2514,20 +2553,23 @@ static void intel_adjust_page_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. > */ > -unsigned long intel_compute_page_offset(int *x, int *y, > - const struct drm_framebuffer *fb, int plane, > - unsigned int pitch, > - unsigned int rotation) > +static unsigned int _intel_compute_page_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, > + unsigned int 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); > - unsigned int offset, alignment; > - > - alignment = intel_surf_alignment(dev_priv, fb_modifier); > - if (alignment) > - alignment--; > + unsigned int offset; > > if (fb_modifier != DRM_FORMAT_MOD_NONE) { > unsigned int tile_size, tile_width, tile_height; > @@ -2560,6 +2602,145 @@ unsigned long intel_compute_page_offset(int *x, int *y, > return offset & ~alignment; > } > > +unsigned int intel_compute_page_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); > + unsigned int alignment = intel_surf_alignment(dev_priv, fb->modifier[plane]); > + > + return _intel_compute_page_offset(dev_priv, x, y, fb, plane, pitch, > + rotation, alignment ? (alignment - 1) : 0); > +} > + > +/* 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]; > + unsigned int 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 *info = &intel_fb->info; > + unsigned int tile_size; > + unsigned int gtt_offset_rotated = 0; > + unsigned int max_size = 0; > + uint32_t format = fb->pixel_format; > + int i, num_planes = drm_format_num_planes(format); > + > + tile_size = intel_tile_size(dev_priv); > + > + for (i = 0; i < num_planes; i++) { > + unsigned int width, height; > + unsigned int cpp, offset, size; > + 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->plane[i].normal.x = x; > + intel_fb->plane[i].normal.y = y; > + > + offset = _intel_compute_page_offset(dev_priv, &x, &y, > + fb, 0, fb->pitches[i], > + BIT(DRM_ROTATE_0), > + tile_size); > + offset /= tile_size; > + DRM_DEBUG("page offset %u pages\n", offset); > + > + if (fb->modifier[i] != DRM_FORMAT_MOD_NONE) { > + unsigned int tile_width, tile_height; > + unsigned int pitch; > + struct drm_rect r; > + > + tile_width = intel_tile_width(dev_priv, fb->modifier[i], cpp); > + tile_height = tile_size / tile_width; > + > + info->plane[i].offset = offset; > + info->plane[i].stride = DIV_ROUND_UP(fb->pitches[i], tile_width); > + info->plane[i].width = DIV_ROUND_UP((x + width) * cpp, tile_width); > + info->plane[i].height = DIV_ROUND_UP(y + height, tile_height); > + > + > + intel_fb->plane[i].rotated.pitch = > + info->plane[i].height * tile_height; > + > + /* how many tiles does this plane need */ > + size = info->plane[i].stride * info->plane[i].height; > + /* > + * If the plane isn't horizontally tile aligned, > + * we need one more tile. > + */ > + if (x != 0) > + size++; > + > + pitch = intel_fb->plane[i].rotated.pitch; > + > + /* 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, width, pitch, BIT(DRM_ROTATE_270)); > + x = r.x1; > + y = r.y1; > + > + intel_rotate_tile_dims(&tile_width, &tile_height, &pitch, > + cpp, BIT(DRM_ROTATE_270)); > + > + /* > + * We only keep the x/y offsets, so push all of the > + * gtt offset into the x/y offsets. > + */ > + intel_adjust_page_offset(&x, &y, tile_width, tile_height, > + tile_size, pitch, > + gtt_offset_rotated * tile_size, 0); > + > + gtt_offset_rotated += info->plane[i].width * info->plane[i].height; > + > + /* > + * First pixel of the framebuffer from > + * the start of the rotated gtt mapping. > + */ > + intel_fb->plane[i].rotated.x = x; > + intel_fb->plane[i].rotated.y = y; > + } else { > + size = DIV_ROUND_UP((y + height) * fb->pitches[i] + > + x * cpp, tile_size); > + } > + DRM_DEBUG("%d offset %u, size %u, stride %u, height %u\n", > + i, offset, size, info->plane[i].stride, info->plane[i].height); > + > + /* 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) { > @@ -2761,7 +2942,7 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, > struct drm_i915_gem_object *obj; > int plane = intel_crtc->plane; > unsigned int rotation; > - unsigned long linear_offset; > + unsigned int linear_offset; > u32 dspcntr; > u32 reg = DSPCNTR(plane); > int pixel_size; > @@ -2839,30 +3020,25 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, > if (IS_G4X(dev)) > dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; > > - linear_offset = y * fb->pitches[0] + x * pixel_size; > + 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_page_offset(&x, &y, fb, 0, > fb->pitches[0], rotation); > - linear_offset -= intel_crtc->dspaddr_offset; > - } else { > - intel_crtc->dspaddr_offset = linear_offset; > - } > > if (crtc->primary->state->rotation == BIT(DRM_ROTATE_180)) { > dspcntr |= DISPPLANE_ROTATE_180; > > x += (intel_crtc->config->pipe_src_w - 1); > y += (intel_crtc->config->pipe_src_h - 1); > - > - /* Finding the last pixel of the last line of the display > - data and adding to linear_offset*/ > - linear_offset += > - (intel_crtc->config->pipe_src_h - 1) * fb->pitches[0] + > - (intel_crtc->config->pipe_src_w - 1) * pixel_size; > } > > + 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; > > @@ -2871,7 +3047,8 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, > 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_surf_gtt_offset(fb, 0, rotation) + > + intel_crtc->dspaddr_offset); > I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); > I915_WRITE(DSPLINOFF(plane), linear_offset); > } else > @@ -2891,7 +3068,7 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, > struct drm_i915_gem_object *obj; > int plane = intel_crtc->plane; > unsigned int rotation; > - unsigned long linear_offset; > + unsigned int linear_offset; > u32 dspcntr; > u32 reg = DSPCNTR(plane); > int pixel_size; > @@ -2946,26 +3123,22 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, > if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) > dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; > > - linear_offset = y * fb->pitches[0] + x * pixel_size; > + intel_add_fb_offsets(&x, &y, fb, 0, rotation); > intel_crtc->dspaddr_offset = > intel_compute_page_offset(&x, &y, fb, 0, > fb->pitches[0], rotation); > - linear_offset -= intel_crtc->dspaddr_offset; > + > if (rotation == BIT(DRM_ROTATE_180)) { > dspcntr |= DISPPLANE_ROTATE_180; > > if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) { > x += (intel_crtc->config->pipe_src_w - 1); > y += (intel_crtc->config->pipe_src_h - 1); > - > - /* Finding the last pixel of the last line of the display > - data and adding to linear_offset*/ > - linear_offset += > - (intel_crtc->config->pipe_src_h - 1) * fb->pitches[0] + > - (intel_crtc->config->pipe_src_w - 1) * pixel_size; > } > } > > + linear_offset = intel_fb_xy_to_linear(x, y, fb, 0); > + > intel_crtc->adjusted_x = x; > intel_crtc->adjusted_y = y; > > @@ -2973,7 +3146,8 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, > > I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); > I915_WRITE(DSPSURF(plane), > - i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset); > + intel_surf_gtt_offset(fb, 0, rotation) + > + intel_crtc->dspaddr_offset); > if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { > I915_WRITE(DSPOFFSET(plane), (y << 16) | x); > } else { > @@ -3000,30 +3174,15 @@ u32 intel_fb_stride_alignment(const struct drm_i915_private *dev_priv, > } > } > > -unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, > - struct drm_i915_gem_object *obj, > - unsigned int plane) > +unsigned int intel_surf_gtt_offset(struct drm_framebuffer *fb, int plane, > + unsigned int rotation) If you want to frob the interface, then I'd replace the fb and rotation with the plane state. > { > - const struct i915_ggtt_view *view = &i915_ggtt_view_normal; > - struct i915_vma *vma; > - unsigned char *offset; > + struct drm_i915_gem_object *obj = intel_fb_obj(fb); > + struct i915_ggtt_view view; > > - if (intel_rotation_90_or_270(intel_plane->base.state->rotation)) > - view = &i915_ggtt_view_rotated; > + intel_fill_fb_ggtt_view(&view, fb, 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 = (unsigned char *)vma->node.start; > - > - if (plane == 1) { > - offset += vma->ggtt_view.rotated.uv_start_page * > - PAGE_SIZE; > - } > - > - return (unsigned long)offset; > + return i915_gem_obj_ggtt_offset_view(obj, &view); > } > > static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id) > @@ -3142,18 +3301,16 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, > struct drm_i915_private *dev_priv = dev->dev_private; > struct intel_crtc *intel_crtc = to_intel_crtc(crtc); > struct drm_plane *plane = crtc->primary; > + struct intel_framebuffer *intel_fb; > bool visible = to_intel_plane_state(plane->state)->visible; > - struct drm_i915_gem_object *obj; > int pipe = intel_crtc->pipe; > u32 plane_ctl, stride_div, stride; > - u32 tile_height, plane_offset, plane_size; > unsigned int rotation; > - int x_offset, y_offset; > unsigned long surf_addr; > struct intel_crtc_state *crtc_state = intel_crtc->config; > struct intel_plane_state *plane_state; > - int src_x = 0, src_y = 0, src_w = 0, src_h = 0; > - int dst_x = 0, dst_y = 0, dst_w = 0, dst_h = 0; > + int src_w, src_h; > + int dst_x, dst_y, dst_w, dst_h; > int scaler_id = -1; > int pixel_size; > > @@ -3166,6 +3323,7 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, > return; > } > > + intel_fb = to_intel_framebuffer(fb); > pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); > > plane_ctl = PLANE_CTL_ENABLE | > @@ -3179,16 +3337,7 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, > rotation = plane->state->rotation; > plane_ctl |= skl_plane_ctl_rotation(rotation); > > - obj = intel_fb_obj(fb); > - 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->src) == 0); > - > scaler_id = plane_state->scaler_id; > - src_x = plane_state->src.x1 >> 16; > - src_y = plane_state->src.y1 >> 16; > src_w = drm_rect_width(&plane_state->src) >> 16; > src_h = drm_rect_height(&plane_state->src) >> 16; > dst_x = plane_state->dst.x1; > @@ -3196,31 +3345,48 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, > dst_w = drm_rect_width(&plane_state->dst); > dst_h = drm_rect_height(&plane_state->dst); > > - WARN_ON(x != src_x || y != src_y); > - > if (intel_rotation_90_or_270(rotation)) { > - /* stride = Surface height in tiles */ > - tile_height = intel_tile_height(dev_priv, fb->modifier[0], > - pixel_size); > - stride = DIV_ROUND_UP(fb->height, tile_height); > - x_offset = stride * tile_height - y - src_h; > - y_offset = x; > - plane_size = (src_w - 1) << 16 | (src_h - 1); > + struct drm_rect r = { > + .x1 = x, > + .x2 = x + src_w, > + .y1 = y, > + .y2 = y + src_h, > + }; > + > + /* 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], > + pixel_size); > + stride = intel_fb->plane[0].rotated.pitch; > } else { > - stride = fb->pitches[0] / stride_div; > - x_offset = x; > - y_offset = 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(&x, &y, fb, 0, rotation); > + surf_addr = intel_compute_page_offset(&x, &y, fb, 0, > + stride, rotation); > + > + /* Sizes are 0 based */ > + src_w--; > + src_h--; > + dst_w--; > + dst_h--; > + > + intel_crtc->adjusted_x = x; > + intel_crtc->adjusted_y = 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), (y << 16) | 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; > @@ -3237,7 +3403,8 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, > 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_surf_gtt_offset(fb, 0, rotation) + surf_addr); > > POSTING_READ(PLANE_SURF(pipe, 0)); > } > @@ -11521,8 +11688,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_surf_gtt_offset(fb, 0, primary->state->rotation); > work->gtt_offset += intel_crtc->dspaddr_offset; > > if (mmio_flip) { > @@ -14319,7 +14485,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; > > @@ -14443,16 +14608,13 @@ static int intel_framebuffer_init(struct drm_device *dev, > if (ret) > return ret; > > - 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; > > + 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) { > DRM_ERROR("framebuffer init failed %d\n", ret); > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h > index 36d049d..395afd3 100644 > --- a/drivers/gpu/drm/i915/intel_drv.h > +++ b/drivers/gpu/drm/i915/intel_drv.h > @@ -118,6 +118,19 @@ enum intel_output_type { > struct intel_framebuffer { > struct drm_framebuffer base; > struct drm_i915_gem_object *obj; > + struct intel_rotation_info info; > + > + struct { > + struct { > + /* pixels */ > + unsigned int x, y; > + } normal; > + struct { > + /* pixels */ > + unsigned int x, y; > + unsigned int pitch; > + } rotated; > + } plane[2]; > }; > > struct intel_fbdev { > @@ -1028,6 +1041,12 @@ void i915_audio_component_init(struct drm_i915_private *dev_priv); > void i915_audio_component_cleanup(struct drm_i915_private *dev_priv); > > /* intel_display.c */ > +unsigned int intel_rotation_info_size(const struct intel_rotation_info *info); > +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); > extern const struct drm_plane_funcs intel_plane_funcs; > bool intel_has_pending_fb_unpin(struct drm_device *dev); > int intel_pch_rawclk(struct drm_device *dev); > @@ -1134,10 +1153,10 @@ void assert_fdi_rx_pll(struct drm_i915_private *dev_priv, > void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, bool state); > #define assert_pipe_enabled(d, p) assert_pipe(d, p, true) > #define assert_pipe_disabled(d, p) assert_pipe(d, p, false) > -unsigned long intel_compute_page_offset(int *x, int *y, > - const struct drm_framebuffer *fb, int plane, > - unsigned int pitch, > - unsigned int rotation); > +unsigned int intel_compute_page_offset(int *x, int *y, > + const struct drm_framebuffer *fb, int plane, > + unsigned int pitch, > + unsigned int rotation); > void intel_prepare_reset(struct drm_device *dev); > void intel_finish_reset(struct drm_device *dev); > void hsw_enable_pc8(struct drm_i915_private *dev_priv); > @@ -1174,9 +1193,8 @@ void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file); > 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); > > -unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, > - struct drm_i915_gem_object *obj, > - unsigned int plane); > +unsigned int intel_surf_gtt_offset(struct drm_framebuffer *fb, int plane, > + 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 828c3eb..d9d37b0 100644 > --- a/drivers/gpu/drm/i915/intel_sprite.c > +++ b/drivers/gpu/drm/i915/intel_sprite.c > @@ -188,17 +188,15 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, > struct drm_device *dev = drm_plane->dev; > struct drm_i915_private *dev_priv = dev->dev_private; > struct intel_plane *intel_plane = to_intel_plane(drm_plane); > - 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; > int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); > const struct drm_intel_sprite_colorkey *key = > &to_intel_plane_state(drm_plane->state)->ckey; > - unsigned long surf_addr; > - u32 tile_height, plane_offset, plane_size; > + unsigned int surf_addr; > unsigned int rotation; > - int x_offset, y_offset; > struct intel_crtc_state *crtc_state = to_intel_crtc(crtc)->config; > int scaler_id; > > @@ -215,17 +213,8 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, > pixel_size, true, > src_w != crtc_w || src_h != crtc_h); > > - stride_div = intel_fb_stride_alignment(dev_priv, fb->modifier[0], > - fb->pixel_format); > - > scaler_id = to_intel_plane_state(drm_plane->state)->scaler_id; > > - /* 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); > @@ -237,27 +226,43 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, > 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)) { > - /* stride: Surface height in tiles */ > - tile_height = intel_tile_height(dev_priv, fb->modifier[0], > - pixel_size); > - 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, > + }; > + > + /* 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], pixel_size); > + stride = intel_fb->plane[0].rotated.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_page_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 (scaler_id >= 0) { > @@ -279,7 +284,8 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, > } > > I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl); > - I915_WRITE(PLANE_SURF(pipe, plane), surf_addr); > + I915_WRITE(PLANE_SURF(pipe, plane), > + intel_surf_gtt_offset(fb, 0, rotation) + surf_addr); > POSTING_READ(PLANE_SURF(pipe, plane)); > } > > @@ -355,8 +361,7 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, > int plane = intel_plane->plane; > u32 sprctl; > unsigned int rotation = dplane->state->rotation; > - unsigned long sprsurf_offset, linear_offset; > - int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); > + unsigned int sprsurf_offset, linear_offset; > const struct drm_intel_sprite_colorkey *key = > &to_intel_plane_state(dplane->state)->ckey; > > @@ -420,19 +425,19 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, > crtc_w--; > crtc_h--; > > - linear_offset = y * fb->pitches[0] + x * pixel_size; > + intel_add_fb_offsets(&x, &y, fb, 0, rotation); > sprsurf_offset = intel_compute_page_offset(&x, &y, fb, 0, > fb->pitches[0], rotation); > - linear_offset -= sprsurf_offset; > > if (rotation == BIT(DRM_ROTATE_180)) { > sprctl |= SP_ROTATE_180; > > x += src_w; > y += src_h; > - linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; > } > > + 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); > @@ -457,8 +462,8 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, > > 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_surf_gtt_offset(fb, 0, rotation) + sprsurf_offset); > POSTING_READ(SPSURF(pipe, plane)); > } > > @@ -492,7 +497,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, > enum pipe pipe = intel_plane->pipe; > u32 sprctl, sprscale = 0; > unsigned int rotation = plane->state->rotation; > - unsigned long sprsurf_offset, linear_offset; > + unsigned int sprsurf_offset, linear_offset; > int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); > const struct drm_intel_sprite_colorkey *key = > &to_intel_plane_state(plane->state)->ckey; > @@ -552,10 +557,9 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, > 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 * pixel_size; > + intel_add_fb_offsets(&x, &y, fb, 0, rotation); > sprsurf_offset = intel_compute_page_offset(&x, &y, fb, 0, > fb->pitches[0], rotation); > - linear_offset -= sprsurf_offset; > > if (rotation == BIT(DRM_ROTATE_180)) { > sprctl |= SPRITE_ROTATE_180; > @@ -564,11 +568,11 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, > if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) { > x += src_w; > y += src_h; > - linear_offset += src_h * fb->pitches[0] + > - src_w * pixel_size; > } > } > > + 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); > @@ -597,7 +601,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, > I915_WRITE(SPRSCALE(pipe), sprscale); > I915_WRITE(SPRCTL(pipe), sprctl); > I915_WRITE(SPRSURF(pipe), > - i915_gem_obj_ggtt_offset(obj) + sprsurf_offset); > + intel_surf_gtt_offset(fb, 0, rotation) + sprsurf_offset); > POSTING_READ(SPRSURF(pipe)); > } > > @@ -632,7 +636,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, > struct drm_i915_gem_object *obj = intel_fb_obj(fb); > int pipe = intel_plane->pipe; > unsigned int rotation = plane->state->rotation; > - unsigned long dvssurf_offset, linear_offset; > + unsigned int dvssurf_offset, linear_offset; > u32 dvscntr, dvsscale; > int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); > const struct drm_intel_sprite_colorkey *key = > @@ -689,19 +693,19 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, > 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 * pixel_size; > + intel_add_fb_offsets(&x, &y, fb, 0, rotation); > dvssurf_offset = intel_compute_page_offset(&x, &y, fb, 0, > fb->pitches[0], rotation); > - linear_offset -= dvssurf_offset; > > if (rotation == BIT(DRM_ROTATE_180)) { > dvscntr |= DVS_ROTATE_180; > > x += src_w; > y += src_h; > - linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; > } > > + 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); > @@ -725,7 +729,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, > I915_WRITE(DVSSCALE(pipe), dvsscale); > I915_WRITE(DVSCNTR(pipe), dvscntr); > I915_WRITE(DVSSURF(pipe), > - i915_gem_obj_ggtt_offset(obj) + dvssurf_offset); > + intel_surf_gtt_offset(fb, 0, rotation) + dvssurf_offset); > POSTING_READ(DVSSURF(pipe)); > } > > -- > 2.4.9 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
On Wed, Oct 21, 2015 at 02:01:01PM +0200, Daniel Vetter wrote: > On Thu, Oct 15, 2015 at 08:59:45PM +0300, ville.syrjala@linux.intel.com wrote: > > From: Ville Syrjälä <ville.syrjala@linux.intel.com> > > > > Redo the fb rotation handling in order to: > > - eliminate the NV12 special casing > > - handle fb->offsets[] properly > > - make the rotation handling reasier for the plane code > > I think this is too big and should be split a bit. There's also a pile of > renames mixed int on top. It grew from a bunch of sepearate changes, but they got gobbled together due to changing the entire approach a few times. In the end I was too scared to split it up anymore. But I guess I should really try. > > > 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. > > That sounds like a good prep patch to split out. > > > We then store the computed rotation_info under > > intel_framebuffer so that we don't have to recompute it again. > > And another one, plus then following up with the fallout. > > This patch also fixes the intel_plane_obj_offset issue for earlier in the > series. Looks good otherwise from reading through it. > > > 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 > > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> > > Two comments below inline. > -Daniel > > > --- > > drivers/gpu/drm/i915/i915_gem_gtt.c | 66 ++---- > > drivers/gpu/drm/i915/i915_gem_gtt.h | 14 +- > > drivers/gpu/drm/i915/intel_display.c | 448 ++++++++++++++++++++++++----------- > > drivers/gpu/drm/i915/intel_drv.h | 32 ++- > > drivers/gpu/drm/i915/intel_sprite.c | 102 ++++---- > > 5 files changed, 402 insertions(+), 260 deletions(-) > > > > diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c > > index bb95b86..98aee6c 100644 > > --- a/drivers/gpu/drm/i915/i915_gem_gtt.c > > +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c > > @@ -3255,11 +3255,6 @@ rotate_pages(const dma_addr_t *in, unsigned int offset, > > unsigned int column, row; > > unsigned int src_idx; > > > > - if (!sg) { > > - st->nents = 0; > > - sg = st->sgl; > > - } > > - > > for (column = 0; column < width; column++) { > > src_idx = stride * (height - 1) + column; > > for (row = 0; row < height; row++) { > > @@ -3280,16 +3275,14 @@ 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 *info, > > struct drm_i915_gem_object *obj) > > { > > - unsigned int size_pages = rot_info->size >> PAGE_SHIFT; > > - unsigned int size_pages_uv; > > + unsigned int size = intel_rotation_info_size(info); > > struct sg_page_iter sg_iter; > > unsigned long i; > > dma_addr_t *page_addr_list; > > struct sg_table *st; > > - unsigned int uv_start_page; > > struct scatterlist *sg; > > int ret = -ENOMEM; > > > > @@ -3299,57 +3292,32 @@ 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->size_uv >> PAGE_SHIFT; > > - 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; > > > > /* Populate source page list from the object. */ > > i = 0; > > for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { > > - page_addr_list[i] = sg_page_iter_dma_address(&sg_iter); > > - i++; > > + page_addr_list[i++] = sg_page_iter_dma_address(&sg_iter); > > } > > > > - /* Rotate the pages. */ > > - sg = rotate_pages(page_addr_list, 0, > > - rot_info->width_pages, rot_info->height_pages, > > - rot_info->width_pages, > > - st, NULL); > > + st->nents = 0; > > + sg = st->sgl; > > > > - /* 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; > > - > > - rotate_pages(page_addr_list, uv_start_page, > > - rot_info->width_pages_uv, > > - rot_info->height_pages_uv, > > - rot_info->width_pages_uv, > > - st, sg); > > + for (i = 0 ; i < ARRAY_SIZE(info->plane); i++) { > > + sg = rotate_pages(page_addr_list, info->plane[i].offset, > > + info->plane[i].width, info->plane[i].height, > > + info->plane[i].stride, st, sg); > > } > > > > - DRM_DEBUG_KMS( > > - "Created rotated page mapping for object size %zu (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %u pages (%u plane 0)).\n", > > - obj->base.size, rot_info->pitch, rot_info->height, > > - rot_info->pixel_format, rot_info->width_pages, > > - rot_info->height_pages, 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, info->plane[0].width, info->plane[0].height, size); > > > > drm_free_large(page_addr_list); > > > > @@ -3360,12 +3328,8 @@ 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) (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %u pages (%u plane 0))\n", > > - obj->base.size, ret, rot_info->pitch, rot_info->height, > > - rot_info->pixel_format, rot_info->width_pages, > > - rot_info->height_pages, 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, info->plane[0].width, info->plane[0].height, size); > > return ERR_PTR(ret); > > } > > > > @@ -3516,7 +3480,7 @@ i915_ggtt_view_size(struct drm_i915_gem_object *obj, > > if (view->type == I915_GGTT_VIEW_NORMAL) { > > return obj->base.size; > > } else if (view->type == I915_GGTT_VIEW_ROTATED) { > > - return view->rotated.size; > > + return intel_rotation_info_size(&view->rotated) << PAGE_SHIFT; > > } else if (view->type == I915_GGTT_VIEW_PARTIAL) { > > return view->partial.size << PAGE_SHIFT; > > } else { > > diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h > > index 68de734..ea28f7d 100644 > > --- a/drivers/gpu/drm/i915/i915_gem_gtt.h > > +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h > > @@ -136,16 +136,10 @@ enum i915_ggtt_view_type { > > }; > > > > struct intel_rotation_info { > > - unsigned int height; > > - unsigned int pitch; > > - unsigned int uv_offset; > > - uint32_t pixel_format; > > - uint64_t fb_modifier; > > - unsigned int width_pages, height_pages; > > - uint64_t size; > > - unsigned int width_pages_uv, height_pages_uv; > > - uint64_t size_uv; > > - unsigned int uv_start_page; > > + struct { > > + /* tiles */ > > + unsigned int width, height, stride, offset; > > + } plane[2]; > > }; > > > > struct i915_ggtt_view { > > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c > > index 028dc4a..0dcb710 100644 > > --- a/drivers/gpu/drm/i915/intel_display.c > > +++ b/drivers/gpu/drm/i915/intel_display.c > > @@ -2274,49 +2274,28 @@ intel_fb_align_height(struct drm_device *dev, unsigned int height, > > return ALIGN(height, tile_height); > > } > > > > -static int > > +unsigned int intel_rotation_info_size(const struct intel_rotation_info *info) > > +{ > > + unsigned int size = 0; > > + int i; > > + > > + for (i = 0 ; i < ARRAY_SIZE(info->plane); i++) > > + size += info->plane[i].width * info->plane[i].height; > > + > > + return size; > > +} > > + > > +static void > > intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, > > const struct drm_framebuffer *fb, > > unsigned int rotation) > > { > > - struct drm_i915_private *dev_priv = to_i915(fb->dev); > > - struct intel_rotation_info *info = &view->rotated; > > - unsigned int tile_size, tile_width, tile_height, cpp; > > - > > - *view = i915_ggtt_view_normal; > > - > > - if (!intel_rotation_90_or_270(rotation)) > > - return 0; > > - > > - *view = i915_ggtt_view_rotated; > > - > > - info->height = fb->height; > > - info->pixel_format = fb->pixel_format; > > - info->pitch = fb->pitches[0]; > > - info->uv_offset = fb->offsets[1]; > > - info->fb_modifier = fb->modifier[0]; > > - > > - tile_size = intel_tile_size(dev_priv); > > - > > - cpp = drm_format_plane_cpp(fb->pixel_format, 0); > > - tile_width = intel_tile_width(dev_priv, cpp, fb->modifier[0]); > > - tile_height = tile_size / tile_width; > > - > > - info->width_pages = DIV_ROUND_UP(fb->pitches[0], tile_width); > > - info->height_pages = DIV_ROUND_UP(fb->height, tile_height); > > - info->size = info->width_pages * info->height_pages * tile_size; > > - > > - if (info->pixel_format == DRM_FORMAT_NV12) { > > - cpp = drm_format_plane_cpp(fb->pixel_format, 1); > > - tile_width = intel_tile_width(dev_priv, fb->modifier[1], cpp); > > - tile_height = tile_size / tile_width; > > - > > - info->width_pages_uv = DIV_ROUND_UP(fb->pitches[1], tile_width); > > - info->height_pages_uv = DIV_ROUND_UP(fb->height / 2, tile_height); > > - info->size_uv = info->width_pages_uv * info->height_pages_uv * tile_size; > > + if (intel_rotation_90_or_270(rotation)) { > > + *view = i915_ggtt_view_rotated; > > + view->rotated = to_intel_framebuffer(fb)->info; > > + } else { > > + *view = i915_ggtt_view_normal; > > } > > - > > - return 0; > > } > > > > static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_priv) > > @@ -2368,9 +2347,7 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, > > > > alignment = intel_surf_alignment(dev_priv, fb->modifier[0]); > > > > - ret = intel_fill_fb_ggtt_view(&view, fb, rotation); > > - if (ret) > > - return ret; > > + intel_fill_fb_ggtt_view(&view, fb, rotation); > > > > /* Note that the w/a also requires 64 PTE of padding following the > > * bo. We currently fill all unused PTE with the shadow page and so > > @@ -2433,18 +2410,31 @@ static void intel_unpin_fb_obj(struct drm_framebuffer *fb, unsigned int rotation > > { > > struct drm_i915_gem_object *obj = intel_fb_obj(fb); > > struct i915_ggtt_view view; > > - int ret; > > > > WARN_ON(!mutex_is_locked(&obj->base.dev->struct_mutex)); > > > > - ret = intel_fill_fb_ggtt_view(&view, fb, rotation); > > - WARN_ONCE(ret, "Couldn't get view from plane state!"); > > + intel_fill_fb_ggtt_view(&view, fb, rotation); > > > > i915_gem_object_unpin_fence(obj); > > i915_gem_object_unpin_from_display_plane(obj, &view); > > } > > > > /* > > + * 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. > > + */ > > +unsigned int 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; > > +} > > + > > +/* > > * Return the tile dimensions in pixel units matching > > * the specified rotation angle. > > */ > > @@ -2475,6 +2465,55 @@ static void intel_rotate_tile_dims(unsigned int *tile_width, > > } > > > > /* > > + * 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 drm_i915_private *dev_priv = to_i915(fb->dev); > > + const struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); > > + unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, plane); > > + unsigned int pitch; > > + > > + if (intel_rotation_90_or_270(rotation)) { > > + pitch = intel_fb->plane[plane].rotated.pitch; > > + > > + *x += intel_fb->plane[plane].rotated.x; > > + *y += intel_fb->plane[plane].rotated.y; > > + } else { > > + pitch = fb->pitches[plane]; > > + > > + *x += intel_fb->plane[plane].normal.x; > > + *y += intel_fb->plane[plane].normal.y; > > + } > > + > > + /* minimize x */ > > + if (fb->modifier[plane] != DRM_FORMAT_MOD_NONE) { > > + unsigned int tile_size, tile_width, tile_height; > > + > > + tile_size = intel_tile_size(dev_priv); > > + tile_width = intel_tile_width(dev_priv, fb->modifier[plane], cpp); > > + tile_height = tile_size / tile_width; > > + > > + intel_rotate_tile_dims(&tile_width, &tile_height, > > + &pitch, cpp, rotation); > > + > > + *y += *x / pitch * tile_height; > > + *x = *x % pitch; > > + } else { > > + /* in pixels */ > > + pitch /= cpp; > > + > > + *y += *x / pitch; > > + *x = *x % pitch; > > + } > > This is called before we do the entire page_offset dance, so I don't think > we need a special case for tiled vs. untiled. Hmm. I think this is leftover from some earlier version where I did stuff in a different order. Yeah, the page_offset stuff should deal with this just fine, and for gen2/3 we just convert it to a linear offset anyway so it's the same thing in the end. I'll just throw the entire "minimize x" crap in the bin. > -Daniel > > > +} > > + > > +/* > > * Adjust the page offset by moving the difference into > > * the x/y offsets. > > * > > @@ -2514,20 +2553,23 @@ static void intel_adjust_page_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. > > */ > > -unsigned long intel_compute_page_offset(int *x, int *y, > > - const struct drm_framebuffer *fb, int plane, > > - unsigned int pitch, > > - unsigned int rotation) > > +static unsigned int _intel_compute_page_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, > > + unsigned int 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); > > - unsigned int offset, alignment; > > - > > - alignment = intel_surf_alignment(dev_priv, fb_modifier); > > - if (alignment) > > - alignment--; > > + unsigned int offset; > > > > if (fb_modifier != DRM_FORMAT_MOD_NONE) { > > unsigned int tile_size, tile_width, tile_height; > > @@ -2560,6 +2602,145 @@ unsigned long intel_compute_page_offset(int *x, int *y, > > return offset & ~alignment; > > } > > > > +unsigned int intel_compute_page_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); > > + unsigned int alignment = intel_surf_alignment(dev_priv, fb->modifier[plane]); > > + > > + return _intel_compute_page_offset(dev_priv, x, y, fb, plane, pitch, > > + rotation, alignment ? (alignment - 1) : 0); > > +} > > + > > +/* 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]; > > + unsigned int 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 *info = &intel_fb->info; > > + unsigned int tile_size; > > + unsigned int gtt_offset_rotated = 0; > > + unsigned int max_size = 0; > > + uint32_t format = fb->pixel_format; > > + int i, num_planes = drm_format_num_planes(format); > > + > > + tile_size = intel_tile_size(dev_priv); > > + > > + for (i = 0; i < num_planes; i++) { > > + unsigned int width, height; > > + unsigned int cpp, offset, size; > > + 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->plane[i].normal.x = x; > > + intel_fb->plane[i].normal.y = y; > > + > > + offset = _intel_compute_page_offset(dev_priv, &x, &y, > > + fb, 0, fb->pitches[i], > > + BIT(DRM_ROTATE_0), > > + tile_size); > > + offset /= tile_size; > > + DRM_DEBUG("page offset %u pages\n", offset); > > + > > + if (fb->modifier[i] != DRM_FORMAT_MOD_NONE) { > > + unsigned int tile_width, tile_height; > > + unsigned int pitch; > > + struct drm_rect r; > > + > > + tile_width = intel_tile_width(dev_priv, fb->modifier[i], cpp); > > + tile_height = tile_size / tile_width; > > + > > + info->plane[i].offset = offset; > > + info->plane[i].stride = DIV_ROUND_UP(fb->pitches[i], tile_width); > > + info->plane[i].width = DIV_ROUND_UP((x + width) * cpp, tile_width); > > + info->plane[i].height = DIV_ROUND_UP(y + height, tile_height); > > + > > + > > + intel_fb->plane[i].rotated.pitch = > > + info->plane[i].height * tile_height; > > + > > + /* how many tiles does this plane need */ > > + size = info->plane[i].stride * info->plane[i].height; > > + /* > > + * If the plane isn't horizontally tile aligned, > > + * we need one more tile. > > + */ > > + if (x != 0) > > + size++; > > + > > + pitch = intel_fb->plane[i].rotated.pitch; > > + > > + /* 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, width, pitch, BIT(DRM_ROTATE_270)); > > + x = r.x1; > > + y = r.y1; > > + > > + intel_rotate_tile_dims(&tile_width, &tile_height, &pitch, > > + cpp, BIT(DRM_ROTATE_270)); > > + > > + /* > > + * We only keep the x/y offsets, so push all of the > > + * gtt offset into the x/y offsets. > > + */ > > + intel_adjust_page_offset(&x, &y, tile_width, tile_height, > > + tile_size, pitch, > > + gtt_offset_rotated * tile_size, 0); > > + > > + gtt_offset_rotated += info->plane[i].width * info->plane[i].height; > > + > > + /* > > + * First pixel of the framebuffer from > > + * the start of the rotated gtt mapping. > > + */ > > + intel_fb->plane[i].rotated.x = x; > > + intel_fb->plane[i].rotated.y = y; > > + } else { > > + size = DIV_ROUND_UP((y + height) * fb->pitches[i] + > > + x * cpp, tile_size); > > + } > > + DRM_DEBUG("%d offset %u, size %u, stride %u, height %u\n", > > + i, offset, size, info->plane[i].stride, info->plane[i].height); > > + > > + /* 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) { > > @@ -2761,7 +2942,7 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, > > struct drm_i915_gem_object *obj; > > int plane = intel_crtc->plane; > > unsigned int rotation; > > - unsigned long linear_offset; > > + unsigned int linear_offset; > > u32 dspcntr; > > u32 reg = DSPCNTR(plane); > > int pixel_size; > > @@ -2839,30 +3020,25 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, > > if (IS_G4X(dev)) > > dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; > > > > - linear_offset = y * fb->pitches[0] + x * pixel_size; > > + 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_page_offset(&x, &y, fb, 0, > > fb->pitches[0], rotation); > > - linear_offset -= intel_crtc->dspaddr_offset; > > - } else { > > - intel_crtc->dspaddr_offset = linear_offset; > > - } > > > > if (crtc->primary->state->rotation == BIT(DRM_ROTATE_180)) { > > dspcntr |= DISPPLANE_ROTATE_180; > > > > x += (intel_crtc->config->pipe_src_w - 1); > > y += (intel_crtc->config->pipe_src_h - 1); > > - > > - /* Finding the last pixel of the last line of the display > > - data and adding to linear_offset*/ > > - linear_offset += > > - (intel_crtc->config->pipe_src_h - 1) * fb->pitches[0] + > > - (intel_crtc->config->pipe_src_w - 1) * pixel_size; > > } > > > > + 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; > > > > @@ -2871,7 +3047,8 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, > > 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_surf_gtt_offset(fb, 0, rotation) + > > + intel_crtc->dspaddr_offset); > > I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); > > I915_WRITE(DSPLINOFF(plane), linear_offset); > > } else > > @@ -2891,7 +3068,7 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, > > struct drm_i915_gem_object *obj; > > int plane = intel_crtc->plane; > > unsigned int rotation; > > - unsigned long linear_offset; > > + unsigned int linear_offset; > > u32 dspcntr; > > u32 reg = DSPCNTR(plane); > > int pixel_size; > > @@ -2946,26 +3123,22 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, > > if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) > > dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; > > > > - linear_offset = y * fb->pitches[0] + x * pixel_size; > > + intel_add_fb_offsets(&x, &y, fb, 0, rotation); > > intel_crtc->dspaddr_offset = > > intel_compute_page_offset(&x, &y, fb, 0, > > fb->pitches[0], rotation); > > - linear_offset -= intel_crtc->dspaddr_offset; > > + > > if (rotation == BIT(DRM_ROTATE_180)) { > > dspcntr |= DISPPLANE_ROTATE_180; > > > > if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) { > > x += (intel_crtc->config->pipe_src_w - 1); > > y += (intel_crtc->config->pipe_src_h - 1); > > - > > - /* Finding the last pixel of the last line of the display > > - data and adding to linear_offset*/ > > - linear_offset += > > - (intel_crtc->config->pipe_src_h - 1) * fb->pitches[0] + > > - (intel_crtc->config->pipe_src_w - 1) * pixel_size; > > } > > } > > > > + linear_offset = intel_fb_xy_to_linear(x, y, fb, 0); > > + > > intel_crtc->adjusted_x = x; > > intel_crtc->adjusted_y = y; > > > > @@ -2973,7 +3146,8 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, > > > > I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); > > I915_WRITE(DSPSURF(plane), > > - i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset); > > + intel_surf_gtt_offset(fb, 0, rotation) + > > + intel_crtc->dspaddr_offset); > > if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { > > I915_WRITE(DSPOFFSET(plane), (y << 16) | x); > > } else { > > @@ -3000,30 +3174,15 @@ u32 intel_fb_stride_alignment(const struct drm_i915_private *dev_priv, > > } > > } > > > > -unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, > > - struct drm_i915_gem_object *obj, > > - unsigned int plane) > > +unsigned int intel_surf_gtt_offset(struct drm_framebuffer *fb, int plane, > > + unsigned int rotation) > > If you want to frob the interface, then I'd replace the fb and rotation > with the plane state. Hmm. Yeah here we should always have a plane state, so could pass that in. It's a bit funky passing in the plane state and the (color) plane index. Usually the latter goes with fb or pixel format. But I think I already have some wm cleanup stuff somewhere that does the same actually, so might as well do it here. I'm also thinking we may want to move a bunch of this coordinate mangling into the check phase of the operation and reduce the commit to just getting the vma offset and adding it with the page_offset computed in check(). But I'll leave that for the future. > > > { > > - const struct i915_ggtt_view *view = &i915_ggtt_view_normal; > > - struct i915_vma *vma; > > - unsigned char *offset; > > + struct drm_i915_gem_object *obj = intel_fb_obj(fb); > > + struct i915_ggtt_view view; > > > > - if (intel_rotation_90_or_270(intel_plane->base.state->rotation)) > > - view = &i915_ggtt_view_rotated; > > + intel_fill_fb_ggtt_view(&view, fb, 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 = (unsigned char *)vma->node.start; > > - > > - if (plane == 1) { > > - offset += vma->ggtt_view.rotated.uv_start_page * > > - PAGE_SIZE; > > - } > > - > > - return (unsigned long)offset; > > + return i915_gem_obj_ggtt_offset_view(obj, &view); > > } > > > > static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id) > > @@ -3142,18 +3301,16 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, > > struct drm_i915_private *dev_priv = dev->dev_private; > > struct intel_crtc *intel_crtc = to_intel_crtc(crtc); > > struct drm_plane *plane = crtc->primary; > > + struct intel_framebuffer *intel_fb; > > bool visible = to_intel_plane_state(plane->state)->visible; > > - struct drm_i915_gem_object *obj; > > int pipe = intel_crtc->pipe; > > u32 plane_ctl, stride_div, stride; > > - u32 tile_height, plane_offset, plane_size; > > unsigned int rotation; > > - int x_offset, y_offset; > > unsigned long surf_addr; > > struct intel_crtc_state *crtc_state = intel_crtc->config; > > struct intel_plane_state *plane_state; > > - int src_x = 0, src_y = 0, src_w = 0, src_h = 0; > > - int dst_x = 0, dst_y = 0, dst_w = 0, dst_h = 0; > > + int src_w, src_h; > > + int dst_x, dst_y, dst_w, dst_h; > > int scaler_id = -1; > > int pixel_size; > > > > @@ -3166,6 +3323,7 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, > > return; > > } > > > > + intel_fb = to_intel_framebuffer(fb); > > pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); > > > > plane_ctl = PLANE_CTL_ENABLE | > > @@ -3179,16 +3337,7 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, > > rotation = plane->state->rotation; > > plane_ctl |= skl_plane_ctl_rotation(rotation); > > > > - obj = intel_fb_obj(fb); > > - 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->src) == 0); > > - > > scaler_id = plane_state->scaler_id; > > - src_x = plane_state->src.x1 >> 16; > > - src_y = plane_state->src.y1 >> 16; > > src_w = drm_rect_width(&plane_state->src) >> 16; > > src_h = drm_rect_height(&plane_state->src) >> 16; > > dst_x = plane_state->dst.x1; > > @@ -3196,31 +3345,48 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, > > dst_w = drm_rect_width(&plane_state->dst); > > dst_h = drm_rect_height(&plane_state->dst); > > > > - WARN_ON(x != src_x || y != src_y); > > - > > if (intel_rotation_90_or_270(rotation)) { > > - /* stride = Surface height in tiles */ > > - tile_height = intel_tile_height(dev_priv, fb->modifier[0], > > - pixel_size); > > - stride = DIV_ROUND_UP(fb->height, tile_height); > > - x_offset = stride * tile_height - y - src_h; > > - y_offset = x; > > - plane_size = (src_w - 1) << 16 | (src_h - 1); > > + struct drm_rect r = { > > + .x1 = x, > > + .x2 = x + src_w, > > + .y1 = y, > > + .y2 = y + src_h, > > + }; > > + > > + /* 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], > > + pixel_size); > > + stride = intel_fb->plane[0].rotated.pitch; > > } else { > > - stride = fb->pitches[0] / stride_div; > > - x_offset = x; > > - y_offset = 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(&x, &y, fb, 0, rotation); > > + surf_addr = intel_compute_page_offset(&x, &y, fb, 0, > > + stride, rotation); > > + > > + /* Sizes are 0 based */ > > + src_w--; > > + src_h--; > > + dst_w--; > > + dst_h--; > > + > > + intel_crtc->adjusted_x = x; > > + intel_crtc->adjusted_y = 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), (y << 16) | 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; > > @@ -3237,7 +3403,8 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, > > 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_surf_gtt_offset(fb, 0, rotation) + surf_addr); > > > > POSTING_READ(PLANE_SURF(pipe, 0)); > > } > > @@ -11521,8 +11688,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_surf_gtt_offset(fb, 0, primary->state->rotation); > > work->gtt_offset += intel_crtc->dspaddr_offset; > > > > if (mmio_flip) { > > @@ -14319,7 +14485,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; > > > > @@ -14443,16 +14608,13 @@ static int intel_framebuffer_init(struct drm_device *dev, > > if (ret) > > return ret; > > > > - 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; > > > > + 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) { > > DRM_ERROR("framebuffer init failed %d\n", ret); > > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h > > index 36d049d..395afd3 100644 > > --- a/drivers/gpu/drm/i915/intel_drv.h > > +++ b/drivers/gpu/drm/i915/intel_drv.h > > @@ -118,6 +118,19 @@ enum intel_output_type { > > struct intel_framebuffer { > > struct drm_framebuffer base; > > struct drm_i915_gem_object *obj; > > + struct intel_rotation_info info; > > + > > + struct { > > + struct { > > + /* pixels */ > > + unsigned int x, y; > > + } normal; > > + struct { > > + /* pixels */ > > + unsigned int x, y; > > + unsigned int pitch; > > + } rotated; > > + } plane[2]; > > }; > > > > struct intel_fbdev { > > @@ -1028,6 +1041,12 @@ void i915_audio_component_init(struct drm_i915_private *dev_priv); > > void i915_audio_component_cleanup(struct drm_i915_private *dev_priv); > > > > /* intel_display.c */ > > +unsigned int intel_rotation_info_size(const struct intel_rotation_info *info); > > +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); > > extern const struct drm_plane_funcs intel_plane_funcs; > > bool intel_has_pending_fb_unpin(struct drm_device *dev); > > int intel_pch_rawclk(struct drm_device *dev); > > @@ -1134,10 +1153,10 @@ void assert_fdi_rx_pll(struct drm_i915_private *dev_priv, > > void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, bool state); > > #define assert_pipe_enabled(d, p) assert_pipe(d, p, true) > > #define assert_pipe_disabled(d, p) assert_pipe(d, p, false) > > -unsigned long intel_compute_page_offset(int *x, int *y, > > - const struct drm_framebuffer *fb, int plane, > > - unsigned int pitch, > > - unsigned int rotation); > > +unsigned int intel_compute_page_offset(int *x, int *y, > > + const struct drm_framebuffer *fb, int plane, > > + unsigned int pitch, > > + unsigned int rotation); > > void intel_prepare_reset(struct drm_device *dev); > > void intel_finish_reset(struct drm_device *dev); > > void hsw_enable_pc8(struct drm_i915_private *dev_priv); > > @@ -1174,9 +1193,8 @@ void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file); > > 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); > > > > -unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, > > - struct drm_i915_gem_object *obj, > > - unsigned int plane); > > +unsigned int intel_surf_gtt_offset(struct drm_framebuffer *fb, int plane, > > + 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 828c3eb..d9d37b0 100644 > > --- a/drivers/gpu/drm/i915/intel_sprite.c > > +++ b/drivers/gpu/drm/i915/intel_sprite.c > > @@ -188,17 +188,15 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, > > struct drm_device *dev = drm_plane->dev; > > struct drm_i915_private *dev_priv = dev->dev_private; > > struct intel_plane *intel_plane = to_intel_plane(drm_plane); > > - 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; > > int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); > > const struct drm_intel_sprite_colorkey *key = > > &to_intel_plane_state(drm_plane->state)->ckey; > > - unsigned long surf_addr; > > - u32 tile_height, plane_offset, plane_size; > > + unsigned int surf_addr; > > unsigned int rotation; > > - int x_offset, y_offset; > > struct intel_crtc_state *crtc_state = to_intel_crtc(crtc)->config; > > int scaler_id; > > > > @@ -215,17 +213,8 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, > > pixel_size, true, > > src_w != crtc_w || src_h != crtc_h); > > > > - stride_div = intel_fb_stride_alignment(dev_priv, fb->modifier[0], > > - fb->pixel_format); > > - > > scaler_id = to_intel_plane_state(drm_plane->state)->scaler_id; > > > > - /* 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); > > @@ -237,27 +226,43 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, > > 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)) { > > - /* stride: Surface height in tiles */ > > - tile_height = intel_tile_height(dev_priv, fb->modifier[0], > > - pixel_size); > > - 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, > > + }; > > + > > + /* 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], pixel_size); > > + stride = intel_fb->plane[0].rotated.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_page_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 (scaler_id >= 0) { > > @@ -279,7 +284,8 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, > > } > > > > I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl); > > - I915_WRITE(PLANE_SURF(pipe, plane), surf_addr); > > + I915_WRITE(PLANE_SURF(pipe, plane), > > + intel_surf_gtt_offset(fb, 0, rotation) + surf_addr); > > POSTING_READ(PLANE_SURF(pipe, plane)); > > } > > > > @@ -355,8 +361,7 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, > > int plane = intel_plane->plane; > > u32 sprctl; > > unsigned int rotation = dplane->state->rotation; > > - unsigned long sprsurf_offset, linear_offset; > > - int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); > > + unsigned int sprsurf_offset, linear_offset; > > const struct drm_intel_sprite_colorkey *key = > > &to_intel_plane_state(dplane->state)->ckey; > > > > @@ -420,19 +425,19 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, > > crtc_w--; > > crtc_h--; > > > > - linear_offset = y * fb->pitches[0] + x * pixel_size; > > + intel_add_fb_offsets(&x, &y, fb, 0, rotation); > > sprsurf_offset = intel_compute_page_offset(&x, &y, fb, 0, > > fb->pitches[0], rotation); > > - linear_offset -= sprsurf_offset; > > > > if (rotation == BIT(DRM_ROTATE_180)) { > > sprctl |= SP_ROTATE_180; > > > > x += src_w; > > y += src_h; > > - linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; > > } > > > > + 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); > > @@ -457,8 +462,8 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, > > > > 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_surf_gtt_offset(fb, 0, rotation) + sprsurf_offset); > > POSTING_READ(SPSURF(pipe, plane)); > > } > > > > @@ -492,7 +497,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, > > enum pipe pipe = intel_plane->pipe; > > u32 sprctl, sprscale = 0; > > unsigned int rotation = plane->state->rotation; > > - unsigned long sprsurf_offset, linear_offset; > > + unsigned int sprsurf_offset, linear_offset; > > int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); > > const struct drm_intel_sprite_colorkey *key = > > &to_intel_plane_state(plane->state)->ckey; > > @@ -552,10 +557,9 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, > > 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 * pixel_size; > > + intel_add_fb_offsets(&x, &y, fb, 0, rotation); > > sprsurf_offset = intel_compute_page_offset(&x, &y, fb, 0, > > fb->pitches[0], rotation); > > - linear_offset -= sprsurf_offset; > > > > if (rotation == BIT(DRM_ROTATE_180)) { > > sprctl |= SPRITE_ROTATE_180; > > @@ -564,11 +568,11 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, > > if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) { > > x += src_w; > > y += src_h; > > - linear_offset += src_h * fb->pitches[0] + > > - src_w * pixel_size; > > } > > } > > > > + 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); > > @@ -597,7 +601,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, > > I915_WRITE(SPRSCALE(pipe), sprscale); > > I915_WRITE(SPRCTL(pipe), sprctl); > > I915_WRITE(SPRSURF(pipe), > > - i915_gem_obj_ggtt_offset(obj) + sprsurf_offset); > > + intel_surf_gtt_offset(fb, 0, rotation) + sprsurf_offset); > > POSTING_READ(SPRSURF(pipe)); > > } > > > > @@ -632,7 +636,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, > > struct drm_i915_gem_object *obj = intel_fb_obj(fb); > > int pipe = intel_plane->pipe; > > unsigned int rotation = plane->state->rotation; > > - unsigned long dvssurf_offset, linear_offset; > > + unsigned int dvssurf_offset, linear_offset; > > u32 dvscntr, dvsscale; > > int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); > > const struct drm_intel_sprite_colorkey *key = > > @@ -689,19 +693,19 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, > > 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 * pixel_size; > > + intel_add_fb_offsets(&x, &y, fb, 0, rotation); > > dvssurf_offset = intel_compute_page_offset(&x, &y, fb, 0, > > fb->pitches[0], rotation); > > - linear_offset -= dvssurf_offset; > > > > if (rotation == BIT(DRM_ROTATE_180)) { > > dvscntr |= DVS_ROTATE_180; > > > > x += src_w; > > y += src_h; > > - linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; > > } > > > > + 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); > > @@ -725,7 +729,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, > > I915_WRITE(DVSSCALE(pipe), dvsscale); > > I915_WRITE(DVSCNTR(pipe), dvscntr); > > I915_WRITE(DVSSURF(pipe), > > - i915_gem_obj_ggtt_offset(obj) + dvssurf_offset); > > + intel_surf_gtt_offset(fb, 0, rotation) + dvssurf_offset); > > POSTING_READ(DVSSURF(pipe)); > > } > > > > -- > > 2.4.9 > > > > _______________________________________________ > > Intel-gfx mailing list > > Intel-gfx@lists.freedesktop.org > > http://lists.freedesktop.org/mailman/listinfo/intel-gfx > > -- > Daniel Vetter > Software Engineer, Intel Corporation > http://blog.ffwll.ch
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index bb95b86..98aee6c 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -3255,11 +3255,6 @@ rotate_pages(const dma_addr_t *in, unsigned int offset, unsigned int column, row; unsigned int src_idx; - if (!sg) { - st->nents = 0; - sg = st->sgl; - } - for (column = 0; column < width; column++) { src_idx = stride * (height - 1) + column; for (row = 0; row < height; row++) { @@ -3280,16 +3275,14 @@ 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 *info, struct drm_i915_gem_object *obj) { - unsigned int size_pages = rot_info->size >> PAGE_SHIFT; - unsigned int size_pages_uv; + unsigned int size = intel_rotation_info_size(info); struct sg_page_iter sg_iter; unsigned long i; dma_addr_t *page_addr_list; struct sg_table *st; - unsigned int uv_start_page; struct scatterlist *sg; int ret = -ENOMEM; @@ -3299,57 +3292,32 @@ 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->size_uv >> PAGE_SHIFT; - 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; /* Populate source page list from the object. */ i = 0; for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { - page_addr_list[i] = sg_page_iter_dma_address(&sg_iter); - i++; + page_addr_list[i++] = sg_page_iter_dma_address(&sg_iter); } - /* Rotate the pages. */ - sg = rotate_pages(page_addr_list, 0, - rot_info->width_pages, rot_info->height_pages, - rot_info->width_pages, - st, NULL); + st->nents = 0; + sg = st->sgl; - /* 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; - - rotate_pages(page_addr_list, uv_start_page, - rot_info->width_pages_uv, - rot_info->height_pages_uv, - rot_info->width_pages_uv, - st, sg); + for (i = 0 ; i < ARRAY_SIZE(info->plane); i++) { + sg = rotate_pages(page_addr_list, info->plane[i].offset, + info->plane[i].width, info->plane[i].height, + info->plane[i].stride, st, sg); } - DRM_DEBUG_KMS( - "Created rotated page mapping for object size %zu (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %u pages (%u plane 0)).\n", - obj->base.size, rot_info->pitch, rot_info->height, - rot_info->pixel_format, rot_info->width_pages, - rot_info->height_pages, 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, info->plane[0].width, info->plane[0].height, size); drm_free_large(page_addr_list); @@ -3360,12 +3328,8 @@ 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) (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %u pages (%u plane 0))\n", - obj->base.size, ret, rot_info->pitch, rot_info->height, - rot_info->pixel_format, rot_info->width_pages, - rot_info->height_pages, 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, info->plane[0].width, info->plane[0].height, size); return ERR_PTR(ret); } @@ -3516,7 +3480,7 @@ i915_ggtt_view_size(struct drm_i915_gem_object *obj, if (view->type == I915_GGTT_VIEW_NORMAL) { return obj->base.size; } else if (view->type == I915_GGTT_VIEW_ROTATED) { - return view->rotated.size; + return intel_rotation_info_size(&view->rotated) << PAGE_SHIFT; } else if (view->type == I915_GGTT_VIEW_PARTIAL) { return view->partial.size << PAGE_SHIFT; } else { diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 68de734..ea28f7d 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -136,16 +136,10 @@ enum i915_ggtt_view_type { }; struct intel_rotation_info { - unsigned int height; - unsigned int pitch; - unsigned int uv_offset; - uint32_t pixel_format; - uint64_t fb_modifier; - unsigned int width_pages, height_pages; - uint64_t size; - unsigned int width_pages_uv, height_pages_uv; - uint64_t size_uv; - unsigned int uv_start_page; + struct { + /* tiles */ + unsigned int width, height, stride, offset; + } plane[2]; }; struct i915_ggtt_view { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 028dc4a..0dcb710 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2274,49 +2274,28 @@ intel_fb_align_height(struct drm_device *dev, unsigned int height, return ALIGN(height, tile_height); } -static int +unsigned int intel_rotation_info_size(const struct intel_rotation_info *info) +{ + unsigned int size = 0; + int i; + + for (i = 0 ; i < ARRAY_SIZE(info->plane); i++) + size += info->plane[i].width * info->plane[i].height; + + return size; +} + +static void intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, const struct drm_framebuffer *fb, unsigned int rotation) { - struct drm_i915_private *dev_priv = to_i915(fb->dev); - struct intel_rotation_info *info = &view->rotated; - unsigned int tile_size, tile_width, tile_height, cpp; - - *view = i915_ggtt_view_normal; - - if (!intel_rotation_90_or_270(rotation)) - return 0; - - *view = i915_ggtt_view_rotated; - - info->height = fb->height; - info->pixel_format = fb->pixel_format; - info->pitch = fb->pitches[0]; - info->uv_offset = fb->offsets[1]; - info->fb_modifier = fb->modifier[0]; - - tile_size = intel_tile_size(dev_priv); - - cpp = drm_format_plane_cpp(fb->pixel_format, 0); - tile_width = intel_tile_width(dev_priv, cpp, fb->modifier[0]); - tile_height = tile_size / tile_width; - - info->width_pages = DIV_ROUND_UP(fb->pitches[0], tile_width); - info->height_pages = DIV_ROUND_UP(fb->height, tile_height); - info->size = info->width_pages * info->height_pages * tile_size; - - if (info->pixel_format == DRM_FORMAT_NV12) { - cpp = drm_format_plane_cpp(fb->pixel_format, 1); - tile_width = intel_tile_width(dev_priv, fb->modifier[1], cpp); - tile_height = tile_size / tile_width; - - info->width_pages_uv = DIV_ROUND_UP(fb->pitches[1], tile_width); - info->height_pages_uv = DIV_ROUND_UP(fb->height / 2, tile_height); - info->size_uv = info->width_pages_uv * info->height_pages_uv * tile_size; + if (intel_rotation_90_or_270(rotation)) { + *view = i915_ggtt_view_rotated; + view->rotated = to_intel_framebuffer(fb)->info; + } else { + *view = i915_ggtt_view_normal; } - - return 0; } static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_priv) @@ -2368,9 +2347,7 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, alignment = intel_surf_alignment(dev_priv, fb->modifier[0]); - ret = intel_fill_fb_ggtt_view(&view, fb, rotation); - if (ret) - return ret; + intel_fill_fb_ggtt_view(&view, fb, rotation); /* Note that the w/a also requires 64 PTE of padding following the * bo. We currently fill all unused PTE with the shadow page and so @@ -2433,18 +2410,31 @@ static void intel_unpin_fb_obj(struct drm_framebuffer *fb, unsigned int rotation { struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct i915_ggtt_view view; - int ret; WARN_ON(!mutex_is_locked(&obj->base.dev->struct_mutex)); - ret = intel_fill_fb_ggtt_view(&view, fb, rotation); - WARN_ONCE(ret, "Couldn't get view from plane state!"); + intel_fill_fb_ggtt_view(&view, fb, rotation); i915_gem_object_unpin_fence(obj); i915_gem_object_unpin_from_display_plane(obj, &view); } /* + * 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. + */ +unsigned int 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; +} + +/* * Return the tile dimensions in pixel units matching * the specified rotation angle. */ @@ -2475,6 +2465,55 @@ static void intel_rotate_tile_dims(unsigned int *tile_width, } /* + * 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 drm_i915_private *dev_priv = to_i915(fb->dev); + const struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, plane); + unsigned int pitch; + + if (intel_rotation_90_or_270(rotation)) { + pitch = intel_fb->plane[plane].rotated.pitch; + + *x += intel_fb->plane[plane].rotated.x; + *y += intel_fb->plane[plane].rotated.y; + } else { + pitch = fb->pitches[plane]; + + *x += intel_fb->plane[plane].normal.x; + *y += intel_fb->plane[plane].normal.y; + } + + /* minimize x */ + if (fb->modifier[plane] != DRM_FORMAT_MOD_NONE) { + unsigned int tile_size, tile_width, tile_height; + + tile_size = intel_tile_size(dev_priv); + tile_width = intel_tile_width(dev_priv, fb->modifier[plane], cpp); + tile_height = tile_size / tile_width; + + intel_rotate_tile_dims(&tile_width, &tile_height, + &pitch, cpp, rotation); + + *y += *x / pitch * tile_height; + *x = *x % pitch; + } else { + /* in pixels */ + pitch /= cpp; + + *y += *x / pitch; + *x = *x % pitch; + } +} + +/* * Adjust the page offset by moving the difference into * the x/y offsets. * @@ -2514,20 +2553,23 @@ static void intel_adjust_page_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. */ -unsigned long intel_compute_page_offset(int *x, int *y, - const struct drm_framebuffer *fb, int plane, - unsigned int pitch, - unsigned int rotation) +static unsigned int _intel_compute_page_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, + unsigned int 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); - unsigned int offset, alignment; - - alignment = intel_surf_alignment(dev_priv, fb_modifier); - if (alignment) - alignment--; + unsigned int offset; if (fb_modifier != DRM_FORMAT_MOD_NONE) { unsigned int tile_size, tile_width, tile_height; @@ -2560,6 +2602,145 @@ unsigned long intel_compute_page_offset(int *x, int *y, return offset & ~alignment; } +unsigned int intel_compute_page_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); + unsigned int alignment = intel_surf_alignment(dev_priv, fb->modifier[plane]); + + return _intel_compute_page_offset(dev_priv, x, y, fb, plane, pitch, + rotation, alignment ? (alignment - 1) : 0); +} + +/* 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]; + unsigned int 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 *info = &intel_fb->info; + unsigned int tile_size; + unsigned int gtt_offset_rotated = 0; + unsigned int max_size = 0; + uint32_t format = fb->pixel_format; + int i, num_planes = drm_format_num_planes(format); + + tile_size = intel_tile_size(dev_priv); + + for (i = 0; i < num_planes; i++) { + unsigned int width, height; + unsigned int cpp, offset, size; + 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->plane[i].normal.x = x; + intel_fb->plane[i].normal.y = y; + + offset = _intel_compute_page_offset(dev_priv, &x, &y, + fb, 0, fb->pitches[i], + BIT(DRM_ROTATE_0), + tile_size); + offset /= tile_size; + DRM_DEBUG("page offset %u pages\n", offset); + + if (fb->modifier[i] != DRM_FORMAT_MOD_NONE) { + unsigned int tile_width, tile_height; + unsigned int pitch; + struct drm_rect r; + + tile_width = intel_tile_width(dev_priv, fb->modifier[i], cpp); + tile_height = tile_size / tile_width; + + info->plane[i].offset = offset; + info->plane[i].stride = DIV_ROUND_UP(fb->pitches[i], tile_width); + info->plane[i].width = DIV_ROUND_UP((x + width) * cpp, tile_width); + info->plane[i].height = DIV_ROUND_UP(y + height, tile_height); + + + intel_fb->plane[i].rotated.pitch = + info->plane[i].height * tile_height; + + /* how many tiles does this plane need */ + size = info->plane[i].stride * info->plane[i].height; + /* + * If the plane isn't horizontally tile aligned, + * we need one more tile. + */ + if (x != 0) + size++; + + pitch = intel_fb->plane[i].rotated.pitch; + + /* 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, width, pitch, BIT(DRM_ROTATE_270)); + x = r.x1; + y = r.y1; + + intel_rotate_tile_dims(&tile_width, &tile_height, &pitch, + cpp, BIT(DRM_ROTATE_270)); + + /* + * We only keep the x/y offsets, so push all of the + * gtt offset into the x/y offsets. + */ + intel_adjust_page_offset(&x, &y, tile_width, tile_height, + tile_size, pitch, + gtt_offset_rotated * tile_size, 0); + + gtt_offset_rotated += info->plane[i].width * info->plane[i].height; + + /* + * First pixel of the framebuffer from + * the start of the rotated gtt mapping. + */ + intel_fb->plane[i].rotated.x = x; + intel_fb->plane[i].rotated.y = y; + } else { + size = DIV_ROUND_UP((y + height) * fb->pitches[i] + + x * cpp, tile_size); + } + DRM_DEBUG("%d offset %u, size %u, stride %u, height %u\n", + i, offset, size, info->plane[i].stride, info->plane[i].height); + + /* 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) { @@ -2761,7 +2942,7 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, struct drm_i915_gem_object *obj; int plane = intel_crtc->plane; unsigned int rotation; - unsigned long linear_offset; + unsigned int linear_offset; u32 dspcntr; u32 reg = DSPCNTR(plane); int pixel_size; @@ -2839,30 +3020,25 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, if (IS_G4X(dev)) dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; - linear_offset = y * fb->pitches[0] + x * pixel_size; + 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_page_offset(&x, &y, fb, 0, fb->pitches[0], rotation); - linear_offset -= intel_crtc->dspaddr_offset; - } else { - intel_crtc->dspaddr_offset = linear_offset; - } if (crtc->primary->state->rotation == BIT(DRM_ROTATE_180)) { dspcntr |= DISPPLANE_ROTATE_180; x += (intel_crtc->config->pipe_src_w - 1); y += (intel_crtc->config->pipe_src_h - 1); - - /* Finding the last pixel of the last line of the display - data and adding to linear_offset*/ - linear_offset += - (intel_crtc->config->pipe_src_h - 1) * fb->pitches[0] + - (intel_crtc->config->pipe_src_w - 1) * pixel_size; } + 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; @@ -2871,7 +3047,8 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, 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_surf_gtt_offset(fb, 0, rotation) + + intel_crtc->dspaddr_offset); I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); I915_WRITE(DSPLINOFF(plane), linear_offset); } else @@ -2891,7 +3068,7 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, struct drm_i915_gem_object *obj; int plane = intel_crtc->plane; unsigned int rotation; - unsigned long linear_offset; + unsigned int linear_offset; u32 dspcntr; u32 reg = DSPCNTR(plane); int pixel_size; @@ -2946,26 +3123,22 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; - linear_offset = y * fb->pitches[0] + x * pixel_size; + intel_add_fb_offsets(&x, &y, fb, 0, rotation); intel_crtc->dspaddr_offset = intel_compute_page_offset(&x, &y, fb, 0, fb->pitches[0], rotation); - linear_offset -= intel_crtc->dspaddr_offset; + if (rotation == BIT(DRM_ROTATE_180)) { dspcntr |= DISPPLANE_ROTATE_180; if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) { x += (intel_crtc->config->pipe_src_w - 1); y += (intel_crtc->config->pipe_src_h - 1); - - /* Finding the last pixel of the last line of the display - data and adding to linear_offset*/ - linear_offset += - (intel_crtc->config->pipe_src_h - 1) * fb->pitches[0] + - (intel_crtc->config->pipe_src_w - 1) * pixel_size; } } + linear_offset = intel_fb_xy_to_linear(x, y, fb, 0); + intel_crtc->adjusted_x = x; intel_crtc->adjusted_y = y; @@ -2973,7 +3146,8 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); I915_WRITE(DSPSURF(plane), - i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset); + intel_surf_gtt_offset(fb, 0, rotation) + + intel_crtc->dspaddr_offset); if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { I915_WRITE(DSPOFFSET(plane), (y << 16) | x); } else { @@ -3000,30 +3174,15 @@ u32 intel_fb_stride_alignment(const struct drm_i915_private *dev_priv, } } -unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, - struct drm_i915_gem_object *obj, - unsigned int plane) +unsigned int intel_surf_gtt_offset(struct drm_framebuffer *fb, int plane, + unsigned int rotation) { - const struct i915_ggtt_view *view = &i915_ggtt_view_normal; - struct i915_vma *vma; - unsigned char *offset; + struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct i915_ggtt_view view; - if (intel_rotation_90_or_270(intel_plane->base.state->rotation)) - view = &i915_ggtt_view_rotated; + intel_fill_fb_ggtt_view(&view, fb, 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 = (unsigned char *)vma->node.start; - - if (plane == 1) { - offset += vma->ggtt_view.rotated.uv_start_page * - PAGE_SIZE; - } - - return (unsigned long)offset; + return i915_gem_obj_ggtt_offset_view(obj, &view); } static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id) @@ -3142,18 +3301,16 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct drm_plane *plane = crtc->primary; + struct intel_framebuffer *intel_fb; bool visible = to_intel_plane_state(plane->state)->visible; - struct drm_i915_gem_object *obj; int pipe = intel_crtc->pipe; u32 plane_ctl, stride_div, stride; - u32 tile_height, plane_offset, plane_size; unsigned int rotation; - int x_offset, y_offset; unsigned long surf_addr; struct intel_crtc_state *crtc_state = intel_crtc->config; struct intel_plane_state *plane_state; - int src_x = 0, src_y = 0, src_w = 0, src_h = 0; - int dst_x = 0, dst_y = 0, dst_w = 0, dst_h = 0; + int src_w, src_h; + int dst_x, dst_y, dst_w, dst_h; int scaler_id = -1; int pixel_size; @@ -3166,6 +3323,7 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, return; } + intel_fb = to_intel_framebuffer(fb); pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); plane_ctl = PLANE_CTL_ENABLE | @@ -3179,16 +3337,7 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, rotation = plane->state->rotation; plane_ctl |= skl_plane_ctl_rotation(rotation); - obj = intel_fb_obj(fb); - 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->src) == 0); - scaler_id = plane_state->scaler_id; - src_x = plane_state->src.x1 >> 16; - src_y = plane_state->src.y1 >> 16; src_w = drm_rect_width(&plane_state->src) >> 16; src_h = drm_rect_height(&plane_state->src) >> 16; dst_x = plane_state->dst.x1; @@ -3196,31 +3345,48 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, dst_w = drm_rect_width(&plane_state->dst); dst_h = drm_rect_height(&plane_state->dst); - WARN_ON(x != src_x || y != src_y); - if (intel_rotation_90_or_270(rotation)) { - /* stride = Surface height in tiles */ - tile_height = intel_tile_height(dev_priv, fb->modifier[0], - pixel_size); - stride = DIV_ROUND_UP(fb->height, tile_height); - x_offset = stride * tile_height - y - src_h; - y_offset = x; - plane_size = (src_w - 1) << 16 | (src_h - 1); + struct drm_rect r = { + .x1 = x, + .x2 = x + src_w, + .y1 = y, + .y2 = y + src_h, + }; + + /* 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], + pixel_size); + stride = intel_fb->plane[0].rotated.pitch; } else { - stride = fb->pitches[0] / stride_div; - x_offset = x; - y_offset = 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(&x, &y, fb, 0, rotation); + surf_addr = intel_compute_page_offset(&x, &y, fb, 0, + stride, rotation); + + /* Sizes are 0 based */ + src_w--; + src_h--; + dst_w--; + dst_h--; + + intel_crtc->adjusted_x = x; + intel_crtc->adjusted_y = 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), (y << 16) | 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; @@ -3237,7 +3403,8 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, 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_surf_gtt_offset(fb, 0, rotation) + surf_addr); POSTING_READ(PLANE_SURF(pipe, 0)); } @@ -11521,8 +11688,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_surf_gtt_offset(fb, 0, primary->state->rotation); work->gtt_offset += intel_crtc->dspaddr_offset; if (mmio_flip) { @@ -14319,7 +14485,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; @@ -14443,16 +14608,13 @@ static int intel_framebuffer_init(struct drm_device *dev, if (ret) return ret; - 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; + 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) { DRM_ERROR("framebuffer init failed %d\n", ret); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 36d049d..395afd3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -118,6 +118,19 @@ enum intel_output_type { struct intel_framebuffer { struct drm_framebuffer base; struct drm_i915_gem_object *obj; + struct intel_rotation_info info; + + struct { + struct { + /* pixels */ + unsigned int x, y; + } normal; + struct { + /* pixels */ + unsigned int x, y; + unsigned int pitch; + } rotated; + } plane[2]; }; struct intel_fbdev { @@ -1028,6 +1041,12 @@ void i915_audio_component_init(struct drm_i915_private *dev_priv); void i915_audio_component_cleanup(struct drm_i915_private *dev_priv); /* intel_display.c */ +unsigned int intel_rotation_info_size(const struct intel_rotation_info *info); +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); extern const struct drm_plane_funcs intel_plane_funcs; bool intel_has_pending_fb_unpin(struct drm_device *dev); int intel_pch_rawclk(struct drm_device *dev); @@ -1134,10 +1153,10 @@ void assert_fdi_rx_pll(struct drm_i915_private *dev_priv, void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, bool state); #define assert_pipe_enabled(d, p) assert_pipe(d, p, true) #define assert_pipe_disabled(d, p) assert_pipe(d, p, false) -unsigned long intel_compute_page_offset(int *x, int *y, - const struct drm_framebuffer *fb, int plane, - unsigned int pitch, - unsigned int rotation); +unsigned int intel_compute_page_offset(int *x, int *y, + const struct drm_framebuffer *fb, int plane, + unsigned int pitch, + unsigned int rotation); void intel_prepare_reset(struct drm_device *dev); void intel_finish_reset(struct drm_device *dev); void hsw_enable_pc8(struct drm_i915_private *dev_priv); @@ -1174,9 +1193,8 @@ void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file); 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); -unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, - struct drm_i915_gem_object *obj, - unsigned int plane); +unsigned int intel_surf_gtt_offset(struct drm_framebuffer *fb, int plane, + 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 828c3eb..d9d37b0 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -188,17 +188,15 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, struct drm_device *dev = drm_plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(drm_plane); - 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; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); const struct drm_intel_sprite_colorkey *key = &to_intel_plane_state(drm_plane->state)->ckey; - unsigned long surf_addr; - u32 tile_height, plane_offset, plane_size; + unsigned int surf_addr; unsigned int rotation; - int x_offset, y_offset; struct intel_crtc_state *crtc_state = to_intel_crtc(crtc)->config; int scaler_id; @@ -215,17 +213,8 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, pixel_size, true, src_w != crtc_w || src_h != crtc_h); - stride_div = intel_fb_stride_alignment(dev_priv, fb->modifier[0], - fb->pixel_format); - scaler_id = to_intel_plane_state(drm_plane->state)->scaler_id; - /* 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); @@ -237,27 +226,43 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, 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)) { - /* stride: Surface height in tiles */ - tile_height = intel_tile_height(dev_priv, fb->modifier[0], - pixel_size); - 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, + }; + + /* 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], pixel_size); + stride = intel_fb->plane[0].rotated.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_page_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 (scaler_id >= 0) { @@ -279,7 +284,8 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, } I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl); - I915_WRITE(PLANE_SURF(pipe, plane), surf_addr); + I915_WRITE(PLANE_SURF(pipe, plane), + intel_surf_gtt_offset(fb, 0, rotation) + surf_addr); POSTING_READ(PLANE_SURF(pipe, plane)); } @@ -355,8 +361,7 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, int plane = intel_plane->plane; u32 sprctl; unsigned int rotation = dplane->state->rotation; - unsigned long sprsurf_offset, linear_offset; - int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + unsigned int sprsurf_offset, linear_offset; const struct drm_intel_sprite_colorkey *key = &to_intel_plane_state(dplane->state)->ckey; @@ -420,19 +425,19 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, crtc_w--; crtc_h--; - linear_offset = y * fb->pitches[0] + x * pixel_size; + intel_add_fb_offsets(&x, &y, fb, 0, rotation); sprsurf_offset = intel_compute_page_offset(&x, &y, fb, 0, fb->pitches[0], rotation); - linear_offset -= sprsurf_offset; if (rotation == BIT(DRM_ROTATE_180)) { sprctl |= SP_ROTATE_180; x += src_w; y += src_h; - linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; } + 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); @@ -457,8 +462,8 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, 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_surf_gtt_offset(fb, 0, rotation) + sprsurf_offset); POSTING_READ(SPSURF(pipe, plane)); } @@ -492,7 +497,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, enum pipe pipe = intel_plane->pipe; u32 sprctl, sprscale = 0; unsigned int rotation = plane->state->rotation; - unsigned long sprsurf_offset, linear_offset; + unsigned int sprsurf_offset, linear_offset; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); const struct drm_intel_sprite_colorkey *key = &to_intel_plane_state(plane->state)->ckey; @@ -552,10 +557,9 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, 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 * pixel_size; + intel_add_fb_offsets(&x, &y, fb, 0, rotation); sprsurf_offset = intel_compute_page_offset(&x, &y, fb, 0, fb->pitches[0], rotation); - linear_offset -= sprsurf_offset; if (rotation == BIT(DRM_ROTATE_180)) { sprctl |= SPRITE_ROTATE_180; @@ -564,11 +568,11 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) { x += src_w; y += src_h; - linear_offset += src_h * fb->pitches[0] + - src_w * pixel_size; } } + 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); @@ -597,7 +601,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, I915_WRITE(SPRSCALE(pipe), sprscale); I915_WRITE(SPRCTL(pipe), sprctl); I915_WRITE(SPRSURF(pipe), - i915_gem_obj_ggtt_offset(obj) + sprsurf_offset); + intel_surf_gtt_offset(fb, 0, rotation) + sprsurf_offset); POSTING_READ(SPRSURF(pipe)); } @@ -632,7 +636,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_i915_gem_object *obj = intel_fb_obj(fb); int pipe = intel_plane->pipe; unsigned int rotation = plane->state->rotation; - unsigned long dvssurf_offset, linear_offset; + unsigned int dvssurf_offset, linear_offset; u32 dvscntr, dvsscale; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); const struct drm_intel_sprite_colorkey *key = @@ -689,19 +693,19 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, 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 * pixel_size; + intel_add_fb_offsets(&x, &y, fb, 0, rotation); dvssurf_offset = intel_compute_page_offset(&x, &y, fb, 0, fb->pitches[0], rotation); - linear_offset -= dvssurf_offset; if (rotation == BIT(DRM_ROTATE_180)) { dvscntr |= DVS_ROTATE_180; x += src_w; y += src_h; - linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; } + 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); @@ -725,7 +729,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, I915_WRITE(DVSSCALE(pipe), dvsscale); I915_WRITE(DVSCNTR(pipe), dvscntr); I915_WRITE(DVSSURF(pipe), - i915_gem_obj_ggtt_offset(obj) + dvssurf_offset); + intel_surf_gtt_offset(fb, 0, rotation) + dvssurf_offset); POSTING_READ(DVSSURF(pipe)); }