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,
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);
{
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)
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
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));
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);
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));
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;
}
/*
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)
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;
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);
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
}
}
- /* 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;
}
}
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;
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;
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);