aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_gem_gtt.c
diff options
context:
space:
mode:
authorTvrtko Ursulin <tvrtko.ursulin@intel.com>2015-03-23 07:10:36 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2015-03-23 10:06:31 -0400
commit50470bb011c4be278097670bea92462f4e8c8945 (patch)
treeb1c92440ac31320feccbadeb2a2ea573a141e644 /drivers/gpu/drm/i915/i915_gem_gtt.c
parentf64b98cd2e40052c17f67f09a081ff292bac0f77 (diff)
drm/i915/skl: Support secondary (rotated) frame buffer mapping
90/270 rotated scanout needs a rotated GTT view of the framebuffer. This is put in a separate VMA with a dedicated ggtt view and wired such that it is created when a framebuffer is pinned to a 90/270 rotated plane. Rotation is only possible with Yb/Yf buffers and error is propagated to user space in case of a mismatch. Special rotated page view is constructed at the VMA creation time by borrowing the DMA addresses from obj->pages. v2: * Do not bother with pages for rotated sg list, just populate the DMA addresses. (Daniel Vetter) * Checkpatch cleanup. v3: * Rebased on top of new plane handling (create rotated mapping when setting the rotation property). * Unpin rotated VMA on unpinning from display plane. * Simplify rotation check using bitwise AND. (Chris Wilson) v4: * Fix unpinning of optional rotated mapping so it is really considered to be optional. v5: * Rebased for fb modifier changes. * Rebased for atomic commit. * Only pin needed view for display. (Ville Syrjälä, Daniel Vetter) v6: * Rebased after preparatory work has been extracted out. (Daniel Vetter) v7: * Slightly simplified tiling geometry calculation. * Moved rotated GGTT view implementation into i915_gem_gtt.c (Daniel Vetter) v8: * Do not use i915_gem_obj_size to get object size since that actually returns the size of an VMA which may not exist. * Rebased for ggtt view changes. v9: * Rebased after code review changes on the preceding patches. * Tidy function definitions. (Joonas Lahtinen) For: VIZ-4726 Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Michel Thierry <michel.thierry@intel.com> (v4) Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem_gtt.c')
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c117
1 files changed, 113 insertions, 4 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 645c3636c571..fc56c112a7de 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -2500,15 +2500,119 @@ i915_gem_obj_lookup_or_create_ggtt_vma(struct drm_i915_gem_object *obj,
2500 2500
2501} 2501}
2502 2502
2503static void
2504rotate_pages(dma_addr_t *in, unsigned int width, unsigned int height,
2505 struct sg_table *st)
2506{
2507 unsigned int column, row;
2508 unsigned int src_idx;
2509 struct scatterlist *sg = st->sgl;
2510
2511 st->nents = 0;
2512
2513 for (column = 0; column < width; column++) {
2514 src_idx = width * (height - 1) + column;
2515 for (row = 0; row < height; row++) {
2516 st->nents++;
2517 /* We don't need the pages, but need to initialize
2518 * the entries so the sg list can be happily traversed.
2519 * The only thing we need are DMA addresses.
2520 */
2521 sg_set_page(sg, NULL, PAGE_SIZE, 0);
2522 sg_dma_address(sg) = in[src_idx];
2523 sg_dma_len(sg) = PAGE_SIZE;
2524 sg = sg_next(sg);
2525 src_idx -= width;
2526 }
2527 }
2528}
2529
2530static struct sg_table *
2531intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view,
2532 struct drm_i915_gem_object *obj)
2533{
2534 struct drm_device *dev = obj->base.dev;
2535 struct intel_rotation_info *rot_info = &ggtt_view->rotation_info;
2536 unsigned long size, pages, rot_pages;
2537 struct sg_page_iter sg_iter;
2538 unsigned long i;
2539 dma_addr_t *page_addr_list;
2540 struct sg_table *st;
2541 unsigned int tile_pitch, tile_height;
2542 unsigned int width_pages, height_pages;
2543 int ret = ENOMEM;
2544
2545 pages = obj->base.size / PAGE_SIZE;
2546
2547 /* Calculate tiling geometry. */
2548 tile_height = intel_tile_height(dev, rot_info->pixel_format,
2549 rot_info->fb_modifier);
2550 tile_pitch = PAGE_SIZE / tile_height;
2551 width_pages = DIV_ROUND_UP(rot_info->pitch, tile_pitch);
2552 height_pages = DIV_ROUND_UP(rot_info->height, tile_height);
2553 rot_pages = width_pages * height_pages;
2554 size = rot_pages * PAGE_SIZE;
2555
2556 /* Allocate a temporary list of source pages for random access. */
2557 page_addr_list = drm_malloc_ab(pages, sizeof(dma_addr_t));
2558 if (!page_addr_list)
2559 return ERR_PTR(ret);
2560
2561 /* Allocate target SG list. */
2562 st = kmalloc(sizeof(*st), GFP_KERNEL);
2563 if (!st)
2564 goto err_st_alloc;
2565
2566 ret = sg_alloc_table(st, rot_pages, GFP_KERNEL);
2567 if (ret)
2568 goto err_sg_alloc;
2569
2570 /* Populate source page list from the object. */
2571 i = 0;
2572 for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
2573 page_addr_list[i] = sg_page_iter_dma_address(&sg_iter);
2574 i++;
2575 }
2576
2577 /* Rotate the pages. */
2578 rotate_pages(page_addr_list, width_pages, height_pages, st);
2579
2580 DRM_DEBUG_KMS(
2581 "Created rotated page mapping for object size %lu (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages).\n",
2582 size, rot_info->pitch, rot_info->height,
2583 rot_info->pixel_format, width_pages, height_pages,
2584 rot_pages);
2585
2586 drm_free_large(page_addr_list);
2587
2588 return st;
2589
2590err_sg_alloc:
2591 kfree(st);
2592err_st_alloc:
2593 drm_free_large(page_addr_list);
2594
2595 DRM_DEBUG_KMS(
2596 "Failed to create rotated mapping for object size %lu! (%d) (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages)\n",
2597 size, ret, rot_info->pitch, rot_info->height,
2598 rot_info->pixel_format, width_pages, height_pages,
2599 rot_pages);
2600 return ERR_PTR(ret);
2601}
2503 2602
2504static inline 2603static inline int
2505int i915_get_ggtt_vma_pages(struct i915_vma *vma) 2604i915_get_ggtt_vma_pages(struct i915_vma *vma)
2506{ 2605{
2606 int ret = 0;
2607
2507 if (vma->ggtt_view.pages) 2608 if (vma->ggtt_view.pages)
2508 return 0; 2609 return 0;
2509 2610
2510 if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL) 2611 if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL)
2511 vma->ggtt_view.pages = vma->obj->pages; 2612 vma->ggtt_view.pages = vma->obj->pages;
2613 else if (vma->ggtt_view.type == I915_GGTT_VIEW_ROTATED)
2614 vma->ggtt_view.pages =
2615 intel_rotate_fb_obj_pages(&vma->ggtt_view, vma->obj);
2512 else 2616 else
2513 WARN_ONCE(1, "GGTT view %u not implemented!\n", 2617 WARN_ONCE(1, "GGTT view %u not implemented!\n",
2514 vma->ggtt_view.type); 2618 vma->ggtt_view.type);
@@ -2516,10 +2620,15 @@ int i915_get_ggtt_vma_pages(struct i915_vma *vma)
2516 if (!vma->ggtt_view.pages) { 2620 if (!vma->ggtt_view.pages) {
2517 DRM_ERROR("Failed to get pages for GGTT view type %u!\n", 2621 DRM_ERROR("Failed to get pages for GGTT view type %u!\n",
2518 vma->ggtt_view.type); 2622 vma->ggtt_view.type);
2519 return -EINVAL; 2623 ret = -EINVAL;
2624 } else if (IS_ERR(vma->ggtt_view.pages)) {
2625 ret = PTR_ERR(vma->ggtt_view.pages);
2626 vma->ggtt_view.pages = NULL;
2627 DRM_ERROR("Failed to get pages for VMA view type %u (%d)!\n",
2628 vma->ggtt_view.type, ret);
2520 } 2629 }
2521 2630
2522 return 0; 2631 return ret;
2523} 2632}
2524 2633
2525/** 2634/**