drm/i915/adlp: Add support for remapping CCS FBs
authorImre Deak <imre.deak@intel.com>
Mon, 6 Sep 2021 18:27:14 +0000 (21:27 +0300)
committerImre Deak <imre.deak@intel.com>
Thu, 23 Sep 2021 14:36:01 +0000 (17:36 +0300)
Add support for remapping CCS FBs on ADL-P to remove the restriction
of the power-of-two sized stride and the 2MB surface offset alignment
for these FBs.

We can only remap the tiles on the main surface, not the tiles on the
CCS surface, so userspace has to generate the CCS surface aligning to
the POT size padded main surface stride (by programming the AUX
pagetable accordingly). For the required AUX pagetable setup, this
requires that either the main surface stride is 8 tiles or that the
stride is 16 tiles aligned (= 64 kbytes, the area mapped by one AUX
PTE).

v2:
- Init intel_remapped_info::plane_alignment only for remapped views and
  do this from intel_fb_view_init().

Cc: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com>
Signed-off-by: Imre Deak <imre.deak@intel.com>
Reviewed-by: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210906182715.3915100-6-imre.deak@intel.com
drivers/gpu/drm/i915/display/intel_display.c
drivers/gpu/drm/i915/display/intel_display_types.h
drivers/gpu/drm/i915/display/intel_fb.c
drivers/gpu/drm/i915/gt/intel_ggtt.c
drivers/gpu/drm/i915/i915_vma_types.h

index 23b1e0ccc72de040641a7230a72cad05f2727310..49d99915b44048f5e33522c02064485eedd13e9c 100644 (file)
@@ -899,8 +899,11 @@ unsigned int intel_remapped_info_size(const struct intel_remapped_info *rem_info
        unsigned int size = 0;
        int i;
 
-       for (i = 0 ; i < ARRAY_SIZE(rem_info->plane); i++)
+       for (i = 0 ; i < ARRAY_SIZE(rem_info->plane); i++) {
+               if (rem_info->plane_alignment)
+                       size = ALIGN(size, rem_info->plane_alignment);
                size += rem_info->plane[i].dst_stride * rem_info->plane[i].height;
+       }
 
        return size;
 }
index e9e806d90eec4341de1d25e75e13370c954d6d8f..73930c24d7fb236a4585a88cfa9f579c1751de65 100644 (file)
@@ -103,8 +103,6 @@ struct intel_fb_view {
         * in the rotated and remapped GTT view all no-CCS formats (up to 2
         * color planes) are supported.
         *
-        * TODO: add support for CCS formats in the remapped GTT view.
-        *
         * The view information shared by all FB color planes in the FB,
         * like dst x/y and src/dst width, is stored separately in
         * intel_plane_state.
index 479c76c7958ceacadc14df4229c8a1f5351ae005..fa1f375e696bfb57523e49e6b3127d11ea6bf730 100644 (file)
@@ -357,15 +357,29 @@ void intel_fb_plane_get_subsampling(int *hsub, int *vsub,
 
 static void intel_fb_plane_dims(const struct intel_framebuffer *fb, int color_plane, int *w, int *h)
 {
+       struct drm_i915_private *i915 = to_i915(fb->base.dev);
        int main_plane = is_ccs_plane(&fb->base, color_plane) ?
                         skl_ccs_to_main_plane(&fb->base, color_plane) : 0;
+       unsigned int main_width = fb->base.width;
+       unsigned int main_height = fb->base.height;
        int main_hsub, main_vsub;
        int hsub, vsub;
 
+       /*
+        * On ADL-P the CCS AUX surface layout always aligns with the
+        * power-of-two aligned main surface stride. The main surface
+        * stride in the allocated FB object may not be power-of-two
+        * sized, in which case it is auto-padded to the POT size.
+        */
+       if (IS_ALDERLAKE_P(i915) && is_ccs_plane(&fb->base, color_plane))
+               main_width = gen12_aligned_scanout_stride(fb, 0) /
+                            fb->base.format->cpp[0];
+
        intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, &fb->base, main_plane);
        intel_fb_plane_get_subsampling(&hsub, &vsub, &fb->base, color_plane);
-       *w = fb->base.width / main_hsub / hsub;
-       *h = fb->base.height / main_vsub / vsub;
+
+       *w = main_width / main_hsub / hsub;
+       *h = main_height / main_vsub / vsub;
 }
 
 static u32 intel_adjust_tile_offset(int *x, int *y,
@@ -547,17 +561,8 @@ static int intel_fb_offset_to_xy(int *x, int *y,
        unsigned int height;
        u32 alignment;
 
-       /*
-        * All DPT color planes must be 512*4k aligned (the amount mapped by a
-        * single DPT page). For ADL_P CCS FBs this only works by requiring
-        * the allocated offsets to be 2MB aligned.  Once supoort to remap
-        * such FBs is added we can remove this requirement, as then all the
-        * planes can be remapped to an aligned offset.
-        */
-       if (IS_ALDERLAKE_P(i915) && is_ccs_modifier(fb->modifier))
-               alignment = 512 * 4096;
-       else if (DISPLAY_VER(i915) >= 12 &&
-                is_semiplanar_uv_plane(fb, color_plane))
+       if (DISPLAY_VER(i915) >= 12 &&
+           is_semiplanar_uv_plane(fb, color_plane))
                alignment = intel_tile_row_size(fb, color_plane);
        else if (fb->modifier != DRM_FORMAT_MOD_LINEAR)
                alignment = intel_tile_size(i915);
@@ -688,8 +693,7 @@ bool intel_fb_needs_pot_stride_remap(const struct intel_framebuffer *fb)
 {
        struct drm_i915_private *i915 = to_i915(fb->base.dev);
 
-       return IS_ALDERLAKE_P(i915) && fb->base.modifier != DRM_FORMAT_MOD_LINEAR &&
-              !is_ccs_modifier(fb->base.modifier);
+       return IS_ALDERLAKE_P(i915) && fb->base.modifier != DRM_FORMAT_MOD_LINEAR;
 }
 
 static int intel_fb_pitch(const struct intel_framebuffer *fb, int color_plane, unsigned int rotation)
@@ -809,14 +813,16 @@ static unsigned int
 plane_view_dst_stride_tiles(const struct intel_framebuffer *fb, int color_plane,
                            unsigned int pitch_tiles)
 {
-       if (intel_fb_needs_pot_stride_remap(fb))
+       if (intel_fb_needs_pot_stride_remap(fb)) {
+               unsigned int min_stride = is_ccs_plane(&fb->base, color_plane) ? 2 : 8;
                /*
                 * ADL_P, the only platform needing a POT stride has a minimum
-                * of 8 stride tiles.
+                * of 8 main surface and 2 CCS AUX stride tiles.
                 */
-               return roundup_pow_of_two(max(pitch_tiles, 8u));
-       else
+               return roundup_pow_of_two(max(pitch_tiles, min_stride));
+       } else {
                return pitch_tiles;
+       }
 }
 
 static unsigned int
@@ -852,7 +858,7 @@ static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_p
        unsigned int tile_height = dims->tile_height;
        unsigned int tile_size = intel_tile_size(i915);
        struct drm_rect r;
-       u32 size;
+       u32 size = 0;
 
        assign_chk_ovf(i915, remap_info->offset, obj_offset);
        assign_chk_ovf(i915, remap_info->src_stride, plane_view_src_stride_tiles(fb, color_plane, dims));
@@ -877,7 +883,7 @@ static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_p
 
                color_plane_info->stride = remap_info->dst_stride * tile_height;
 
-               size = remap_info->dst_stride * remap_info->width;
+               size += remap_info->dst_stride * remap_info->width;
 
                /* rotate the tile dimensions to match the GTT view */
                swap(tile_width, tile_height);
@@ -886,6 +892,14 @@ static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_p
 
                check_array_bounds(i915, view->gtt.remapped.plane, color_plane);
 
+               if (view->gtt.remapped.plane_alignment) {
+                       unsigned int aligned_offset = ALIGN(gtt_offset,
+                                                           view->gtt.remapped.plane_alignment);
+
+                       size += aligned_offset - gtt_offset;
+                       gtt_offset = aligned_offset;
+               }
+
                assign_chk_ovf(i915, remap_info->dst_stride,
                               plane_view_dst_stride_tiles(fb, color_plane, remap_info->width));
 
@@ -895,7 +909,7 @@ static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_p
                color_plane_info->stride = remap_info->dst_stride * tile_width *
                                           fb->base.format->cpp[color_plane];
 
-               size = remap_info->dst_stride * remap_info->height;
+               size += remap_info->dst_stride * remap_info->height;
        }
 
        /*
@@ -942,10 +956,14 @@ calc_plane_normal_size(const struct intel_framebuffer *fb, int color_plane,
        return tiles;
 }
 
-static void intel_fb_view_init(struct intel_fb_view *view, enum i915_ggtt_view_type view_type)
+static void intel_fb_view_init(struct drm_i915_private *i915, struct intel_fb_view *view,
+                              enum i915_ggtt_view_type view_type)
 {
        memset(view, 0, sizeof(*view));
        view->gtt.type = view_type;
+
+       if (view_type == I915_GGTT_VIEW_REMAPPED && IS_ALDERLAKE_P(i915))
+               view->gtt.remapped.plane_alignment = SZ_2M / PAGE_SIZE;
 }
 
 bool intel_fb_supports_90_270_rotation(const struct intel_framebuffer *fb)
@@ -966,16 +984,16 @@ int intel_fill_fb_info(struct drm_i915_private *i915, struct intel_framebuffer *
        int i, num_planes = fb->base.format->num_planes;
        unsigned int tile_size = intel_tile_size(i915);
 
-       intel_fb_view_init(&fb->normal_view, I915_GGTT_VIEW_NORMAL);
+       intel_fb_view_init(i915, &fb->normal_view, I915_GGTT_VIEW_NORMAL);
 
        drm_WARN_ON(&i915->drm,
                    intel_fb_supports_90_270_rotation(fb) &&
                    intel_fb_needs_pot_stride_remap(fb));
 
        if (intel_fb_supports_90_270_rotation(fb))
-               intel_fb_view_init(&fb->rotated_view, I915_GGTT_VIEW_ROTATED);
+               intel_fb_view_init(i915, &fb->rotated_view, I915_GGTT_VIEW_ROTATED);
        if (intel_fb_needs_pot_stride_remap(fb))
-               intel_fb_view_init(&fb->remapped_view, I915_GGTT_VIEW_REMAPPED);
+               intel_fb_view_init(i915, &fb->remapped_view, I915_GGTT_VIEW_REMAPPED);
 
        for (i = 0; i < num_planes; i++) {
                struct fb_plane_view_dims view_dims;
@@ -1053,7 +1071,7 @@ static void intel_plane_remap_gtt(struct intel_plane_state *plane_state)
        unsigned int src_w, src_h;
        u32 gtt_offset = 0;
 
-       intel_fb_view_init(&plane_state->view,
+       intel_fb_view_init(i915, &plane_state->view,
                           drm_rotation_90_or_270(rotation) ? I915_GGTT_VIEW_ROTATED :
                                                              I915_GGTT_VIEW_REMAPPED);
 
@@ -1158,11 +1176,19 @@ intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane)
 
        tile_width = intel_tile_width_bytes(fb, color_plane);
        if (is_ccs_modifier(fb->modifier)) {
+               /*
+                * On ADL-P the stride must be either 8 tiles or a stride
+                * that is aligned to 16 tiles, required by the 16 tiles =
+                * 64 kbyte CCS AUX PTE granularity, allowing CCS FBs to be
+                * remapped.
+                */
+               if (IS_ALDERLAKE_P(dev_priv))
+                       tile_width *= fb->pitches[0] <= tile_width * 8 ? 8 : 16;
                /*
                 * On TGL the surface stride must be 4 tile aligned, mapped by
                 * one 64 byte cacheline on the CCS AUX surface.
                 */
-               if (DISPLAY_VER(dev_priv) >= 12)
+               else if (DISPLAY_VER(dev_priv) >= 12)
                        tile_width *= 4;
                /*
                 * Display WA #0531: skl,bxt,kbl,glk
@@ -1416,17 +1442,6 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
                        }
                }
 
-               /* TODO: Add POT stride remapping support for CCS formats as well. */
-               if (IS_ALDERLAKE_P(dev_priv) &&
-                   mode_cmd->modifier[i] != DRM_FORMAT_MOD_LINEAR &&
-                   !intel_fb_needs_pot_stride_remap(intel_fb) &&
-                   !is_power_of_2(mode_cmd->pitches[i])) {
-                       drm_dbg_kms(&dev_priv->drm,
-                                   "plane %d pitch (%d) must be power of two for tiled buffers\n",
-                                   i, mode_cmd->pitches[i]);
-                       goto err;
-               }
-
                fb->obj[i] = &obj->base;
        }
 
index de3ac58fceec3dd59968b744a258188f4939da81..cbd0e1010a467a1e3eb706841dc4fd9a5b9556f3 100644 (file)
@@ -1373,13 +1373,28 @@ err_st_alloc:
 }
 
 static struct scatterlist *
-remap_pages(struct drm_i915_gem_object *obj, unsigned int offset,
+remap_pages(struct drm_i915_gem_object *obj,
+           unsigned int offset, unsigned int alignment_pad,
            unsigned int width, unsigned int height,
            unsigned int src_stride, unsigned int dst_stride,
            struct sg_table *st, struct scatterlist *sg)
 {
        unsigned int row;
 
+       if (alignment_pad) {
+               st->nents++;
+
+               /*
+                * The DE ignores the PTEs for the padding tiles, the sg entry
+                * here is just a convenience to indicate how many padding PTEs
+                * to insert at this spot.
+                */
+               sg_set_page(sg, NULL, alignment_pad * 4096, 0);
+               sg_dma_address(sg) = 0;
+               sg_dma_len(sg) = alignment_pad * 4096;
+               sg = sg_next(sg);
+       }
+
        for (row = 0; row < height; row++) {
                unsigned int left = width * I915_GTT_PAGE_SIZE;
 
@@ -1439,6 +1454,7 @@ intel_remap_pages(struct intel_remapped_info *rem_info,
        struct drm_i915_private *i915 = to_i915(obj->base.dev);
        struct sg_table *st;
        struct scatterlist *sg;
+       unsigned int gtt_offset = 0;
        int ret = -ENOMEM;
        int i;
 
@@ -1455,10 +1471,19 @@ intel_remap_pages(struct intel_remapped_info *rem_info,
        sg = st->sgl;
 
        for (i = 0 ; i < ARRAY_SIZE(rem_info->plane); i++) {
-               sg = remap_pages(obj, rem_info->plane[i].offset,
+               unsigned int alignment_pad = 0;
+
+               if (rem_info->plane_alignment)
+                       alignment_pad = ALIGN(gtt_offset, rem_info->plane_alignment) - gtt_offset;
+
+               sg = remap_pages(obj,
+                                rem_info->plane[i].offset, alignment_pad,
                                 rem_info->plane[i].width, rem_info->plane[i].height,
                                 rem_info->plane[i].src_stride, rem_info->plane[i].dst_stride,
                                 st, sg);
+
+               gtt_offset += alignment_pad +
+                             rem_info->plane[i].dst_stride * rem_info->plane[i].height;
        }
 
        i915_sg_trim(st);
index 995b502d7e5d9c16acb7e0fc8834795b6815e1e6..80e93bf00f2e5f42abc804f8d36bc98fef7b1831 100644 (file)
@@ -105,8 +105,9 @@ struct intel_remapped_plane_info {
 } __packed;
 
 struct intel_remapped_info {
-       struct intel_remapped_plane_info plane[2];
-       u32 unused_mbz;
+       struct intel_remapped_plane_info plane[4];
+       /* in gtt pages */
+       u32 plane_alignment;
 } __packed;
 
 struct intel_rotation_info {
@@ -129,7 +130,7 @@ static inline void assert_i915_gem_gtt_types(void)
 {
        BUILD_BUG_ON(sizeof(struct intel_rotation_info) != 2 * sizeof(u32) + 8 * sizeof(u16));
        BUILD_BUG_ON(sizeof(struct intel_partial_info) != sizeof(u64) + sizeof(unsigned int));
-       BUILD_BUG_ON(sizeof(struct intel_remapped_info) != 3 * sizeof(u32) + 8 * sizeof(u16));
+       BUILD_BUG_ON(sizeof(struct intel_remapped_info) != 5 * sizeof(u32) + 16 * sizeof(u16));
 
        /* Check that rotation/remapped shares offsets for simplicity */
        BUILD_BUG_ON(offsetof(struct intel_remapped_info, plane[0]) !=