@@ -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);
-
- /* 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;
+ st->nents = 0;
+ sg = st->sgl;
- 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 {
@@ -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 {
@@ -2274,49 +2274,28 @@ intel_fb_align_height(struct drm_device *dev, unsigned int height,
return ALIGN(height, tile_height);
}
-static int
-intel_fill_fb_ggtt_view(struct i915_ggtt_view *view,
- const struct drm_framebuffer *fb,
- unsigned int rotation)
+unsigned int intel_rotation_info_size(const struct intel_rotation_info *info)
{
- 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;
+ unsigned int size = 0;
+ int i;
- 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;
+ for (i = 0 ; i < ARRAY_SIZE(info->plane); i++)
+ size += info->plane[i].width * info->plane[i].height;
- 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;
+ return size;
+}
- 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;
+static void
+intel_fill_fb_ggtt_view(struct i915_ggtt_view *view,
+ const struct drm_framebuffer *fb,
+ unsigned int rotation)
+{
+ 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) {
@@ -2757,11 +2938,12 @@ static void i9xx_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 *primary = crtc->primary;
+ struct intel_framebuffer *intel_fb;
bool visible = to_intel_plane_state(primary->state)->visible;
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;
@@ -2780,6 +2962,7 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc,
if (WARN_ON(obj == NULL))
return;
+ intel_fb = to_intel_framebuffer(fb);
rotation = crtc->primary->state->rotation;
pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
@@ -2839,30 +3022,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 +3049,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
@@ -2887,11 +3066,12 @@ static void ironlake_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 *primary = crtc->primary;
+ struct intel_framebuffer *intel_fb;
bool visible = to_intel_plane_state(primary->state)->visible;
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;
@@ -2907,6 +3087,7 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc,
if (WARN_ON(obj == NULL))
return;
+ intel_fb = to_intel_framebuffer(fb);
rotation = crtc->primary->state->rotation;
pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
@@ -2946,26 +3127,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 +3150,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 +3178,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;
-
- if (intel_rotation_90_or_270(intel_plane->base.state->rotation))
- view = &i915_ggtt_view_rotated;
-
- 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;
+ struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+ struct i915_ggtt_view view;
- if (plane == 1) {
- offset += vma->ggtt_view.rotated.uv_start_page *
- PAGE_SIZE;
- }
+ intel_fill_fb_ggtt_view(&view, fb, rotation);
- 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 +3305,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 +3327,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 +3341,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 +3349,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, 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 +3407,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 +11692,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 +14489,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 +14612,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);
@@ -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);
@@ -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, 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,8 +497,8 @@ 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;
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(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,9 +636,9 @@ 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;
- u32 dvscntr, dvsscale;
int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+ unsigned int dvssurf_offset, linear_offset;
+ u32 dvscntr, dvsscale;
const struct drm_intel_sprite_colorkey *key =
&to_intel_plane_state(plane->state)->ckey;
@@ -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));
}