[6/8] drm/i915: Support NV12 in rotated GGTT mapping
diff mbox

Message ID 1431086563-4498-7-git-send-email-tvrtko.ursulin@linux.intel.com
State New
Headers show

Commit Message

Tvrtko Ursulin May 8, 2015, 12:02 p.m. UTC
From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

Just adding the rotated UV plane at the end of the rotated Y plane.

Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 drivers/gpu/drm/i915/i915_gem_gtt.c  | 47 ++++++++++++++++++++++++++++++------
 drivers/gpu/drm/i915/i915_gem_gtt.h  |  1 +
 drivers/gpu/drm/i915/intel_display.c |  1 +
 3 files changed, 41 insertions(+), 8 deletions(-)

Patch
diff mbox

diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index d7f2e5d..bf3ee44 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -2693,12 +2693,18 @@  intel_calc_tiled_geometry(struct drm_device *dev,
 			  unsigned int plane)
 {
 	unsigned int tile_height, tile_pitch;
+	unsigned int height;
+
+	if (rot_info->pixel_format == DRM_FORMAT_NV12 && plane == 1)
+		height = rot_info->height / 2;
+	else
+		height = rot_info->height;
 
 	tile_height = intel_tile_height(dev, rot_info->pixel_format,
 					rot_info->fb_modifier, plane);
 	tile_pitch = PAGE_SIZE / tile_height;
 	*width_pages = DIV_ROUND_UP(rot_info->pitch, tile_pitch);
-	*height_pages = DIV_ROUND_UP(rot_info->height, tile_height);
+	*height_pages = DIV_ROUND_UP(height, tile_height);
 
 	return (*width_pages) * (*height_pages);
 }
@@ -2709,12 +2715,15 @@  intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view,
 {
 	struct drm_device *dev = obj->base.dev;
 	struct intel_rotation_info *rot_info = &ggtt_view->rotation_info;
-	unsigned long pages, rot_pages;
+	unsigned long pages, rot_pages, rot_pages_uv = 0;
 	struct sg_page_iter sg_iter;
 	unsigned long i;
 	dma_addr_t *page_addr_list;
 	struct sg_table *st;
 	unsigned int width_pages, height_pages;
+	unsigned int width_pages_uv, height_pages_uv;
+	unsigned int uv_start_page;
+	struct scatterlist *sg;
 	int ret = -ENOMEM;
 
 	pages = obj->base.size / PAGE_SIZE;
@@ -2723,6 +2732,13 @@  intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view,
 	rot_pages = intel_calc_tiled_geometry(dev, rot_info,
 					      &width_pages, &height_pages, 0);
 
+	/* Account for UV plane with NV12. */
+	if (rot_info->pixel_format == DRM_FORMAT_NV12) {
+		rot_pages_uv = intel_calc_tiled_geometry(dev, rot_info,
+							 &width_pages_uv,
+							 &height_pages_uv, 1);
+	}
+
 	/* Allocate a temporary list of source pages for random access. */
 	page_addr_list = drm_malloc_ab(pages, sizeof(dma_addr_t));
 	if (!page_addr_list)
@@ -2733,7 +2749,7 @@  intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view,
 	if (!st)
 		goto err_st_alloc;
 
-	ret = sg_alloc_table(st, rot_pages, GFP_KERNEL);
+	ret = sg_alloc_table(st, rot_pages + rot_pages_uv, GFP_KERNEL);
 	if (ret)
 		goto err_sg_alloc;
 
@@ -2745,13 +2761,28 @@  intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view,
 	}
 
 	/* Rotate the pages. */
-	rotate_pages(page_addr_list, 0, width_pages, height_pages, st, NULL);
+	sg = rotate_pages(page_addr_list, 0,
+			  width_pages, height_pages,
+			  st, NULL);
+
+	/* Append the UV plane if NV12. */
+	if (rot_info->pixel_format == DRM_FORMAT_NV12) {
+		uv_start_page = rot_pages;
+
+		/* Check for tile-row un-alignment. */
+		if (offset_in_page(rot_info->uv_offset))
+			uv_start_page--;
+
+		rotate_pages(page_addr_list, uv_start_page,
+			     width_pages_uv, height_pages_uv,
+			     st, sg);
+	}
 
 	DRM_DEBUG_KMS(
-		      "Created rotated page mapping for object size %lu (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages).\n",
+		      "Created rotated page mapping for object size %lu (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages (%lu plane 0)).\n",
 		      obj->base.size, rot_info->pitch, rot_info->height,
 		      rot_info->pixel_format, width_pages, height_pages,
-		      rot_pages);
+		      rot_pages + rot_pages_uv, rot_pages);
 
 	drm_free_large(page_addr_list);
 
@@ -2763,10 +2794,10 @@  err_st_alloc:
 	drm_free_large(page_addr_list);
 
 	DRM_DEBUG_KMS(
-		      "Failed to create rotated mapping for object size %lu! (%d) (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages)\n",
+		      "Failed to create rotated mapping for object size %lu! (%d) (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages (%lu plane 0))\n",
 		      obj->base.size, ret, rot_info->pitch, rot_info->height,
 		      rot_info->pixel_format, width_pages, height_pages,
-		      rot_pages);
+		      rot_pages + rot_pages_uv, rot_pages);
 	return ERR_PTR(ret);
 }
 
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
index 4e6cac5..5118da1 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.h
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
@@ -123,6 +123,7 @@  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;
 };
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index a87faca..b4bf998 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2346,6 +2346,7 @@  intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb,
 	info->pixel_format = fb->pixel_format;
 	info->pitch = fb->pitches[0];
 	info->fb_modifier = fb->modifier[0];
+	info->uv_offset = fb->offsets[1];
 
 	return 0;
 }