Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: MIT
0002 /*
0003  * Copyright © 2021 Intel Corporation
0004  */
0005 
0006 #include <drm/drm_blend.h>
0007 #include <drm/drm_framebuffer.h>
0008 #include <drm/drm_modeset_helper.h>
0009 
0010 #include "i915_drv.h"
0011 #include "intel_display.h"
0012 #include "intel_display_types.h"
0013 #include "intel_dpt.h"
0014 #include "intel_fb.h"
0015 
0016 #define check_array_bounds(i915, a, i) drm_WARN_ON(&(i915)->drm, (i) >= ARRAY_SIZE(a))
0017 
0018 /*
0019  * From the Sky Lake PRM:
0020  * "The Color Control Surface (CCS) contains the compression status of
0021  *  the cache-line pairs. The compression state of the cache-line pair
0022  *  is specified by 2 bits in the CCS. Each CCS cache-line represents
0023  *  an area on the main surface of 16 x16 sets of 128 byte Y-tiled
0024  *  cache-line-pairs. CCS is always Y tiled."
0025  *
0026  * Since cache line pairs refers to horizontally adjacent cache lines,
0027  * each cache line in the CCS corresponds to an area of 32x16 cache
0028  * lines on the main surface. Since each pixel is 4 bytes, this gives
0029  * us a ratio of one byte in the CCS for each 8x16 pixels in the
0030  * main surface.
0031  */
0032 static const struct drm_format_info skl_ccs_formats[] = {
0033     { .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 2,
0034       .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
0035     { .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 2,
0036       .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
0037     { .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 2,
0038       .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, .has_alpha = true, },
0039     { .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 2,
0040       .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, .has_alpha = true, },
0041 };
0042 
0043 /*
0044  * Gen-12 compression uses 4 bits of CCS data for each cache line pair in the
0045  * main surface. And each 64B CCS cache line represents an area of 4x1 Y-tiles
0046  * in the main surface. With 4 byte pixels and each Y-tile having dimensions of
0047  * 32x32 pixels, the ratio turns out to 1B in the CCS for every 2x32 pixels in
0048  * the main surface.
0049  */
0050 static const struct drm_format_info gen12_ccs_formats[] = {
0051     { .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 2,
0052       .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
0053       .hsub = 1, .vsub = 1, },
0054     { .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 2,
0055       .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
0056       .hsub = 1, .vsub = 1, },
0057     { .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 2,
0058       .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
0059       .hsub = 1, .vsub = 1, .has_alpha = true },
0060     { .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 2,
0061       .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
0062       .hsub = 1, .vsub = 1, .has_alpha = true },
0063     { .format = DRM_FORMAT_YUYV, .num_planes = 2,
0064       .char_per_block = { 2, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
0065       .hsub = 2, .vsub = 1, .is_yuv = true },
0066     { .format = DRM_FORMAT_YVYU, .num_planes = 2,
0067       .char_per_block = { 2, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
0068       .hsub = 2, .vsub = 1, .is_yuv = true },
0069     { .format = DRM_FORMAT_UYVY, .num_planes = 2,
0070       .char_per_block = { 2, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
0071       .hsub = 2, .vsub = 1, .is_yuv = true },
0072     { .format = DRM_FORMAT_VYUY, .num_planes = 2,
0073       .char_per_block = { 2, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
0074       .hsub = 2, .vsub = 1, .is_yuv = true },
0075     { .format = DRM_FORMAT_XYUV8888, .num_planes = 2,
0076       .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
0077       .hsub = 1, .vsub = 1, .is_yuv = true },
0078     { .format = DRM_FORMAT_NV12, .num_planes = 4,
0079       .char_per_block = { 1, 2, 1, 1 }, .block_w = { 1, 1, 4, 4 }, .block_h = { 1, 1, 1, 1 },
0080       .hsub = 2, .vsub = 2, .is_yuv = true },
0081     { .format = DRM_FORMAT_P010, .num_planes = 4,
0082       .char_per_block = { 2, 4, 1, 1 }, .block_w = { 1, 1, 2, 2 }, .block_h = { 1, 1, 1, 1 },
0083       .hsub = 2, .vsub = 2, .is_yuv = true },
0084     { .format = DRM_FORMAT_P012, .num_planes = 4,
0085       .char_per_block = { 2, 4, 1, 1 }, .block_w = { 1, 1, 2, 2 }, .block_h = { 1, 1, 1, 1 },
0086       .hsub = 2, .vsub = 2, .is_yuv = true },
0087     { .format = DRM_FORMAT_P016, .num_planes = 4,
0088       .char_per_block = { 2, 4, 1, 1 }, .block_w = { 1, 1, 2, 2 }, .block_h = { 1, 1, 1, 1 },
0089       .hsub = 2, .vsub = 2, .is_yuv = true },
0090 };
0091 
0092 /*
0093  * Same as gen12_ccs_formats[] above, but with additional surface used
0094  * to pass Clear Color information in plane 2 with 64 bits of data.
0095  */
0096 static const struct drm_format_info gen12_ccs_cc_formats[] = {
0097     { .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 3,
0098       .char_per_block = { 4, 1, 0 }, .block_w = { 1, 2, 2 }, .block_h = { 1, 1, 1 },
0099       .hsub = 1, .vsub = 1, },
0100     { .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 3,
0101       .char_per_block = { 4, 1, 0 }, .block_w = { 1, 2, 2 }, .block_h = { 1, 1, 1 },
0102       .hsub = 1, .vsub = 1, },
0103     { .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 3,
0104       .char_per_block = { 4, 1, 0 }, .block_w = { 1, 2, 2 }, .block_h = { 1, 1, 1 },
0105       .hsub = 1, .vsub = 1, .has_alpha = true },
0106     { .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 3,
0107       .char_per_block = { 4, 1, 0 }, .block_w = { 1, 2, 2 }, .block_h = { 1, 1, 1 },
0108       .hsub = 1, .vsub = 1, .has_alpha = true },
0109 };
0110 
0111 static const struct drm_format_info gen12_flat_ccs_cc_formats[] = {
0112     { .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 2,
0113       .char_per_block = { 4, 0 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
0114       .hsub = 1, .vsub = 1, },
0115     { .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 2,
0116       .char_per_block = { 4, 0 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
0117       .hsub = 1, .vsub = 1, },
0118     { .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 2,
0119       .char_per_block = { 4, 0 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
0120       .hsub = 1, .vsub = 1, .has_alpha = true },
0121     { .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 2,
0122       .char_per_block = { 4, 0 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
0123       .hsub = 1, .vsub = 1, .has_alpha = true },
0124 };
0125 
0126 struct intel_modifier_desc {
0127     u64 modifier;
0128     struct {
0129         u8 from;
0130         u8 until;
0131     } display_ver;
0132 #define DISPLAY_VER_ALL     { 0, -1 }
0133 
0134     const struct drm_format_info *formats;
0135     int format_count;
0136 #define FORMAT_OVERRIDE(format_list) \
0137     .formats = format_list, \
0138     .format_count = ARRAY_SIZE(format_list)
0139 
0140     u8 plane_caps;
0141 
0142     struct {
0143         u8 cc_planes:3;
0144         u8 packed_aux_planes:4;
0145         u8 planar_aux_planes:4;
0146     } ccs;
0147 };
0148 
0149 #define INTEL_PLANE_CAP_CCS_MASK    (INTEL_PLANE_CAP_CCS_RC | \
0150                      INTEL_PLANE_CAP_CCS_RC_CC | \
0151                      INTEL_PLANE_CAP_CCS_MC)
0152 #define INTEL_PLANE_CAP_TILING_MASK (INTEL_PLANE_CAP_TILING_X | \
0153                      INTEL_PLANE_CAP_TILING_Y | \
0154                      INTEL_PLANE_CAP_TILING_Yf | \
0155                      INTEL_PLANE_CAP_TILING_4)
0156 #define INTEL_PLANE_CAP_TILING_NONE 0
0157 
0158 static const struct intel_modifier_desc intel_modifiers[] = {
0159     {
0160         .modifier = I915_FORMAT_MOD_4_TILED_DG2_MC_CCS,
0161         .display_ver = { 13, 13 },
0162         .plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_CCS_MC,
0163     }, {
0164         .modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC,
0165         .display_ver = { 13, 13 },
0166         .plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_CCS_RC_CC,
0167 
0168         .ccs.cc_planes = BIT(1),
0169 
0170         FORMAT_OVERRIDE(gen12_flat_ccs_cc_formats),
0171     }, {
0172         .modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS,
0173         .display_ver = { 13, 13 },
0174         .plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_CCS_RC,
0175     }, {
0176         .modifier = I915_FORMAT_MOD_4_TILED,
0177         .display_ver = { 13, 13 },
0178         .plane_caps = INTEL_PLANE_CAP_TILING_4,
0179     }, {
0180         .modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS,
0181         .display_ver = { 12, 13 },
0182         .plane_caps = INTEL_PLANE_CAP_TILING_Y | INTEL_PLANE_CAP_CCS_MC,
0183 
0184         .ccs.packed_aux_planes = BIT(1),
0185         .ccs.planar_aux_planes = BIT(2) | BIT(3),
0186 
0187         FORMAT_OVERRIDE(gen12_ccs_formats),
0188     }, {
0189         .modifier = I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
0190         .display_ver = { 12, 13 },
0191         .plane_caps = INTEL_PLANE_CAP_TILING_Y | INTEL_PLANE_CAP_CCS_RC,
0192 
0193         .ccs.packed_aux_planes = BIT(1),
0194 
0195         FORMAT_OVERRIDE(gen12_ccs_formats),
0196     }, {
0197         .modifier = I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC,
0198         .display_ver = { 12, 13 },
0199         .plane_caps = INTEL_PLANE_CAP_TILING_Y | INTEL_PLANE_CAP_CCS_RC_CC,
0200 
0201         .ccs.cc_planes = BIT(2),
0202         .ccs.packed_aux_planes = BIT(1),
0203 
0204         FORMAT_OVERRIDE(gen12_ccs_cc_formats),
0205     }, {
0206         .modifier = I915_FORMAT_MOD_Yf_TILED_CCS,
0207         .display_ver = { 9, 11 },
0208         .plane_caps = INTEL_PLANE_CAP_TILING_Yf | INTEL_PLANE_CAP_CCS_RC,
0209 
0210         .ccs.packed_aux_planes = BIT(1),
0211 
0212         FORMAT_OVERRIDE(skl_ccs_formats),
0213     }, {
0214         .modifier = I915_FORMAT_MOD_Y_TILED_CCS,
0215         .display_ver = { 9, 11 },
0216         .plane_caps = INTEL_PLANE_CAP_TILING_Y | INTEL_PLANE_CAP_CCS_RC,
0217 
0218         .ccs.packed_aux_planes = BIT(1),
0219 
0220         FORMAT_OVERRIDE(skl_ccs_formats),
0221     }, {
0222         .modifier = I915_FORMAT_MOD_Yf_TILED,
0223         .display_ver = { 9, 11 },
0224         .plane_caps = INTEL_PLANE_CAP_TILING_Yf,
0225     }, {
0226         .modifier = I915_FORMAT_MOD_Y_TILED,
0227         .display_ver = { 9, 13 },
0228         .plane_caps = INTEL_PLANE_CAP_TILING_Y,
0229     }, {
0230         .modifier = I915_FORMAT_MOD_X_TILED,
0231         .display_ver = DISPLAY_VER_ALL,
0232         .plane_caps = INTEL_PLANE_CAP_TILING_X,
0233     }, {
0234         .modifier = DRM_FORMAT_MOD_LINEAR,
0235         .display_ver = DISPLAY_VER_ALL,
0236     },
0237 };
0238 
0239 static const struct intel_modifier_desc *lookup_modifier_or_null(u64 modifier)
0240 {
0241     int i;
0242 
0243     for (i = 0; i < ARRAY_SIZE(intel_modifiers); i++)
0244         if (intel_modifiers[i].modifier == modifier)
0245             return &intel_modifiers[i];
0246 
0247     return NULL;
0248 }
0249 
0250 static const struct intel_modifier_desc *lookup_modifier(u64 modifier)
0251 {
0252     const struct intel_modifier_desc *md = lookup_modifier_or_null(modifier);
0253 
0254     if (WARN_ON(!md))
0255         return &intel_modifiers[0];
0256 
0257     return md;
0258 }
0259 
0260 static const struct drm_format_info *
0261 lookup_format_info(const struct drm_format_info formats[],
0262            int num_formats, u32 format)
0263 {
0264     int i;
0265 
0266     for (i = 0; i < num_formats; i++) {
0267         if (formats[i].format == format)
0268             return &formats[i];
0269     }
0270 
0271     return NULL;
0272 }
0273 
0274 /**
0275  * intel_fb_get_format_info: Get a modifier specific format information
0276  * @cmd: FB add command structure
0277  *
0278  * Returns:
0279  * Returns the format information for @cmd->pixel_format specific to @cmd->modifier[0],
0280  * or %NULL if the modifier doesn't override the format.
0281  */
0282 const struct drm_format_info *
0283 intel_fb_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
0284 {
0285     const struct intel_modifier_desc *md = lookup_modifier_or_null(cmd->modifier[0]);
0286 
0287     if (!md || !md->formats)
0288         return NULL;
0289 
0290     return lookup_format_info(md->formats, md->format_count, cmd->pixel_format);
0291 }
0292 
0293 static bool plane_caps_contain_any(u8 caps, u8 mask)
0294 {
0295     return caps & mask;
0296 }
0297 
0298 static bool plane_caps_contain_all(u8 caps, u8 mask)
0299 {
0300     return (caps & mask) == mask;
0301 }
0302 
0303 /**
0304  * intel_fb_is_ccs_modifier: Check if a modifier is a CCS modifier type
0305  * @modifier: Modifier to check
0306  *
0307  * Returns:
0308  * Returns %true if @modifier is a render, render with color clear or
0309  * media compression modifier.
0310  */
0311 bool intel_fb_is_ccs_modifier(u64 modifier)
0312 {
0313     return plane_caps_contain_any(lookup_modifier(modifier)->plane_caps,
0314                       INTEL_PLANE_CAP_CCS_MASK);
0315 }
0316 
0317 /**
0318  * intel_fb_is_rc_ccs_cc_modifier: Check if a modifier is an RC CCS CC modifier type
0319  * @modifier: Modifier to check
0320  *
0321  * Returns:
0322  * Returns %true if @modifier is a render with color clear modifier.
0323  */
0324 bool intel_fb_is_rc_ccs_cc_modifier(u64 modifier)
0325 {
0326     return plane_caps_contain_any(lookup_modifier(modifier)->plane_caps,
0327                       INTEL_PLANE_CAP_CCS_RC_CC);
0328 }
0329 
0330 /**
0331  * intel_fb_is_mc_ccs_modifier: Check if a modifier is an MC CCS modifier type
0332  * @modifier: Modifier to check
0333  *
0334  * Returns:
0335  * Returns %true if @modifier is a media compression modifier.
0336  */
0337 bool intel_fb_is_mc_ccs_modifier(u64 modifier)
0338 {
0339     return plane_caps_contain_any(lookup_modifier(modifier)->plane_caps,
0340                       INTEL_PLANE_CAP_CCS_MC);
0341 }
0342 
0343 static bool check_modifier_display_ver_range(const struct intel_modifier_desc *md,
0344                          u8 display_ver_from, u8 display_ver_until)
0345 {
0346     return md->display_ver.from <= display_ver_until &&
0347         display_ver_from <= md->display_ver.until;
0348 }
0349 
0350 static bool plane_has_modifier(struct drm_i915_private *i915,
0351                    u8 plane_caps,
0352                    const struct intel_modifier_desc *md)
0353 {
0354     if (!IS_DISPLAY_VER(i915, md->display_ver.from, md->display_ver.until))
0355         return false;
0356 
0357     if (!plane_caps_contain_all(plane_caps, md->plane_caps))
0358         return false;
0359 
0360     return true;
0361 }
0362 
0363 /**
0364  * intel_fb_plane_get_modifiers: Get the modifiers for the given platform and plane capabilities
0365  * @i915: i915 device instance
0366  * @plane_caps: capabilities for the plane the modifiers are queried for
0367  *
0368  * Returns:
0369  * Returns the list of modifiers allowed by the @i915 platform and @plane_caps.
0370  * The caller must free the returned buffer.
0371  */
0372 u64 *intel_fb_plane_get_modifiers(struct drm_i915_private *i915,
0373                   u8 plane_caps)
0374 {
0375     u64 *list, *p;
0376     int count = 1;      /* +1 for invalid modifier terminator */
0377     int i;
0378 
0379     for (i = 0; i < ARRAY_SIZE(intel_modifiers); i++) {
0380         if (plane_has_modifier(i915, plane_caps, &intel_modifiers[i]))
0381             count++;
0382     }
0383 
0384     list = kmalloc_array(count, sizeof(*list), GFP_KERNEL);
0385     if (drm_WARN_ON(&i915->drm, !list))
0386         return NULL;
0387 
0388     p = list;
0389     for (i = 0; i < ARRAY_SIZE(intel_modifiers); i++) {
0390         if (plane_has_modifier(i915, plane_caps, &intel_modifiers[i]))
0391             *p++ = intel_modifiers[i].modifier;
0392     }
0393     *p++ = DRM_FORMAT_MOD_INVALID;
0394 
0395     return list;
0396 }
0397 
0398 /**
0399  * intel_fb_plane_supports_modifier: Determine if a modifier is supported by the given plane
0400  * @plane: Plane to check the modifier support for
0401  * @modifier: The modifier to check the support for
0402  *
0403  * Returns:
0404  * %true if the @modifier is supported on @plane.
0405  */
0406 bool intel_fb_plane_supports_modifier(struct intel_plane *plane, u64 modifier)
0407 {
0408     int i;
0409 
0410     for (i = 0; i < plane->base.modifier_count; i++)
0411         if (plane->base.modifiers[i] == modifier)
0412             return true;
0413 
0414     return false;
0415 }
0416 
0417 static bool format_is_yuv_semiplanar(const struct intel_modifier_desc *md,
0418                      const struct drm_format_info *info)
0419 {
0420     if (!info->is_yuv)
0421         return false;
0422 
0423     if (hweight8(md->ccs.planar_aux_planes) == 2)
0424         return info->num_planes == 4;
0425     else
0426         return info->num_planes == 2;
0427 }
0428 
0429 /**
0430  * intel_format_info_is_yuv_semiplanar: Check if the given format is YUV semiplanar
0431  * @info: format to check
0432  * @modifier: modifier used with the format
0433  *
0434  * Returns:
0435  * %true if @info / @modifier is YUV semiplanar.
0436  */
0437 bool intel_format_info_is_yuv_semiplanar(const struct drm_format_info *info,
0438                      u64 modifier)
0439 {
0440     return format_is_yuv_semiplanar(lookup_modifier(modifier), info);
0441 }
0442 
0443 static u8 ccs_aux_plane_mask(const struct intel_modifier_desc *md,
0444                  const struct drm_format_info *format)
0445 {
0446     if (format_is_yuv_semiplanar(md, format))
0447         return md->ccs.planar_aux_planes;
0448     else
0449         return md->ccs.packed_aux_planes;
0450 }
0451 
0452 /**
0453  * intel_fb_is_ccs_aux_plane: Check if a framebuffer color plane is a CCS AUX plane
0454  * @fb: Framebuffer
0455  * @color_plane: color plane index to check
0456  *
0457  * Returns:
0458  * Returns %true if @fb's color plane at index @color_plane is a CCS AUX plane.
0459  */
0460 bool intel_fb_is_ccs_aux_plane(const struct drm_framebuffer *fb, int color_plane)
0461 {
0462     const struct intel_modifier_desc *md = lookup_modifier(fb->modifier);
0463 
0464     return ccs_aux_plane_mask(md, fb->format) & BIT(color_plane);
0465 }
0466 
0467 /**
0468  * intel_fb_is_gen12_ccs_aux_plane: Check if a framebuffer color plane is a GEN12 CCS AUX plane
0469  * @fb: Framebuffer
0470  * @color_plane: color plane index to check
0471  *
0472  * Returns:
0473  * Returns %true if @fb's color plane at index @color_plane is a GEN12 CCS AUX plane.
0474  */
0475 static bool intel_fb_is_gen12_ccs_aux_plane(const struct drm_framebuffer *fb, int color_plane)
0476 {
0477     const struct intel_modifier_desc *md = lookup_modifier(fb->modifier);
0478 
0479     return check_modifier_display_ver_range(md, 12, 13) &&
0480            ccs_aux_plane_mask(md, fb->format) & BIT(color_plane);
0481 }
0482 
0483 /**
0484  * intel_fb_rc_ccs_cc_plane: Get the CCS CC color plane index for a framebuffer
0485  * @fb: Framebuffer
0486  *
0487  * Returns:
0488  * Returns the index of the color clear plane for @fb, or -1 if @fb is not a
0489  * framebuffer using a render compression/color clear modifier.
0490  */
0491 int intel_fb_rc_ccs_cc_plane(const struct drm_framebuffer *fb)
0492 {
0493     const struct intel_modifier_desc *md = lookup_modifier(fb->modifier);
0494 
0495     if (!md->ccs.cc_planes)
0496         return -1;
0497 
0498     drm_WARN_ON_ONCE(fb->dev, hweight8(md->ccs.cc_planes) > 1);
0499 
0500     return ilog2((int)md->ccs.cc_planes);
0501 }
0502 
0503 static bool is_gen12_ccs_cc_plane(const struct drm_framebuffer *fb, int color_plane)
0504 {
0505     return intel_fb_rc_ccs_cc_plane(fb) == color_plane;
0506 }
0507 
0508 static bool is_semiplanar_uv_plane(const struct drm_framebuffer *fb, int color_plane)
0509 {
0510     return intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) &&
0511         color_plane == 1;
0512 }
0513 
0514 bool is_surface_linear(const struct drm_framebuffer *fb, int color_plane)
0515 {
0516     return fb->modifier == DRM_FORMAT_MOD_LINEAR ||
0517            intel_fb_is_gen12_ccs_aux_plane(fb, color_plane) ||
0518            is_gen12_ccs_cc_plane(fb, color_plane);
0519 }
0520 
0521 int main_to_ccs_plane(const struct drm_framebuffer *fb, int main_plane)
0522 {
0523     drm_WARN_ON(fb->dev, !intel_fb_is_ccs_modifier(fb->modifier) ||
0524             (main_plane && main_plane >= fb->format->num_planes / 2));
0525 
0526     return fb->format->num_planes / 2 + main_plane;
0527 }
0528 
0529 int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane)
0530 {
0531     drm_WARN_ON(fb->dev, !intel_fb_is_ccs_modifier(fb->modifier) ||
0532             ccs_plane < fb->format->num_planes / 2);
0533 
0534     if (is_gen12_ccs_cc_plane(fb, ccs_plane))
0535         return 0;
0536 
0537     return ccs_plane - fb->format->num_planes / 2;
0538 }
0539 
0540 static unsigned int gen12_ccs_aux_stride(struct intel_framebuffer *fb, int ccs_plane)
0541 {
0542     int main_plane = skl_ccs_to_main_plane(&fb->base, ccs_plane);
0543     unsigned int main_stride = fb->base.pitches[main_plane];
0544     unsigned int main_tile_width = intel_tile_width_bytes(&fb->base, main_plane);
0545 
0546     return DIV_ROUND_UP(main_stride, 4 * main_tile_width) * 64;
0547 }
0548 
0549 int skl_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane)
0550 {
0551     const struct intel_modifier_desc *md = lookup_modifier(fb->modifier);
0552     struct drm_i915_private *i915 = to_i915(fb->dev);
0553 
0554     if (md->ccs.packed_aux_planes | md->ccs.planar_aux_planes)
0555         return main_to_ccs_plane(fb, main_plane);
0556     else if (DISPLAY_VER(i915) < 11 &&
0557          format_is_yuv_semiplanar(md, fb->format))
0558         return 1;
0559     else
0560         return 0;
0561 }
0562 
0563 unsigned int intel_tile_size(const struct drm_i915_private *i915)
0564 {
0565     return DISPLAY_VER(i915) == 2 ? 2048 : 4096;
0566 }
0567 
0568 unsigned int
0569 intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
0570 {
0571     struct drm_i915_private *dev_priv = to_i915(fb->dev);
0572     unsigned int cpp = fb->format->cpp[color_plane];
0573 
0574     switch (fb->modifier) {
0575     case DRM_FORMAT_MOD_LINEAR:
0576         return intel_tile_size(dev_priv);
0577     case I915_FORMAT_MOD_X_TILED:
0578         if (DISPLAY_VER(dev_priv) == 2)
0579             return 128;
0580         else
0581             return 512;
0582     case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS:
0583     case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC:
0584     case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS:
0585     case I915_FORMAT_MOD_4_TILED:
0586         /*
0587          * Each 4K tile consists of 64B(8*8) subtiles, with
0588          * same shape as Y Tile(i.e 4*16B OWords)
0589          */
0590         return 128;
0591     case I915_FORMAT_MOD_Y_TILED_CCS:
0592         if (intel_fb_is_ccs_aux_plane(fb, color_plane))
0593             return 128;
0594         fallthrough;
0595     case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
0596     case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
0597     case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
0598         if (intel_fb_is_ccs_aux_plane(fb, color_plane) ||
0599             is_gen12_ccs_cc_plane(fb, color_plane))
0600             return 64;
0601         fallthrough;
0602     case I915_FORMAT_MOD_Y_TILED:
0603         if (DISPLAY_VER(dev_priv) == 2 || HAS_128_BYTE_Y_TILING(dev_priv))
0604             return 128;
0605         else
0606             return 512;
0607     case I915_FORMAT_MOD_Yf_TILED_CCS:
0608         if (intel_fb_is_ccs_aux_plane(fb, color_plane))
0609             return 128;
0610         fallthrough;
0611     case I915_FORMAT_MOD_Yf_TILED:
0612         switch (cpp) {
0613         case 1:
0614             return 64;
0615         case 2:
0616         case 4:
0617             return 128;
0618         case 8:
0619         case 16:
0620             return 256;
0621         default:
0622             MISSING_CASE(cpp);
0623             return cpp;
0624         }
0625         break;
0626     default:
0627         MISSING_CASE(fb->modifier);
0628         return cpp;
0629     }
0630 }
0631 
0632 unsigned int intel_tile_height(const struct drm_framebuffer *fb, int color_plane)
0633 {
0634     return intel_tile_size(to_i915(fb->dev)) /
0635         intel_tile_width_bytes(fb, color_plane);
0636 }
0637 
0638 /*
0639  * Return the tile dimensions in pixel units, based on the (2 or 4 kbyte) GTT
0640  * page tile size.
0641  */
0642 static void intel_tile_dims(const struct drm_framebuffer *fb, int color_plane,
0643                 unsigned int *tile_width,
0644                 unsigned int *tile_height)
0645 {
0646     unsigned int tile_width_bytes = intel_tile_width_bytes(fb, color_plane);
0647     unsigned int cpp = fb->format->cpp[color_plane];
0648 
0649     *tile_width = tile_width_bytes / cpp;
0650     *tile_height = intel_tile_height(fb, color_plane);
0651 }
0652 
0653 /*
0654  * Return the tile dimensions in pixel units, based on the tile block size.
0655  * The block covers the full GTT page sized tile on all tiled surfaces and
0656  * it's a 64 byte portion of the tile on TGL+ CCS surfaces.
0657  */
0658 static void intel_tile_block_dims(const struct drm_framebuffer *fb, int color_plane,
0659                   unsigned int *tile_width,
0660                   unsigned int *tile_height)
0661 {
0662     intel_tile_dims(fb, color_plane, tile_width, tile_height);
0663 
0664     if (intel_fb_is_gen12_ccs_aux_plane(fb, color_plane))
0665         *tile_height = 1;
0666 }
0667 
0668 unsigned int intel_tile_row_size(const struct drm_framebuffer *fb, int color_plane)
0669 {
0670     unsigned int tile_width, tile_height;
0671 
0672     intel_tile_dims(fb, color_plane, &tile_width, &tile_height);
0673 
0674     return fb->pitches[color_plane] * tile_height;
0675 }
0676 
0677 unsigned int
0678 intel_fb_align_height(const struct drm_framebuffer *fb,
0679               int color_plane, unsigned int height)
0680 {
0681     unsigned int tile_height = intel_tile_height(fb, color_plane);
0682 
0683     return ALIGN(height, tile_height);
0684 }
0685 
0686 static unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier)
0687 {
0688     u8 tiling_caps = lookup_modifier(fb_modifier)->plane_caps &
0689              INTEL_PLANE_CAP_TILING_MASK;
0690 
0691     switch (tiling_caps) {
0692     case INTEL_PLANE_CAP_TILING_Y:
0693         return I915_TILING_Y;
0694     case INTEL_PLANE_CAP_TILING_X:
0695         return I915_TILING_X;
0696     case INTEL_PLANE_CAP_TILING_4:
0697     case INTEL_PLANE_CAP_TILING_Yf:
0698     case INTEL_PLANE_CAP_TILING_NONE:
0699         return I915_TILING_NONE;
0700     default:
0701         MISSING_CASE(tiling_caps);
0702         return I915_TILING_NONE;
0703     }
0704 }
0705 
0706 static bool intel_modifier_uses_dpt(struct drm_i915_private *i915, u64 modifier)
0707 {
0708     return DISPLAY_VER(i915) >= 13 && modifier != DRM_FORMAT_MOD_LINEAR;
0709 }
0710 
0711 bool intel_fb_uses_dpt(const struct drm_framebuffer *fb)
0712 {
0713     return fb && intel_modifier_uses_dpt(to_i915(fb->dev), fb->modifier);
0714 }
0715 
0716 unsigned int intel_cursor_alignment(const struct drm_i915_private *i915)
0717 {
0718     if (IS_I830(i915))
0719         return 16 * 1024;
0720     else if (IS_I85X(i915))
0721         return 256;
0722     else if (IS_I845G(i915) || IS_I865G(i915))
0723         return 32;
0724     else
0725         return 4 * 1024;
0726 }
0727 
0728 static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_priv)
0729 {
0730     if (DISPLAY_VER(dev_priv) >= 9)
0731         return 256 * 1024;
0732     else if (IS_I965G(dev_priv) || IS_I965GM(dev_priv) ||
0733          IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
0734         return 128 * 1024;
0735     else if (DISPLAY_VER(dev_priv) >= 4)
0736         return 4 * 1024;
0737     else
0738         return 0;
0739 }
0740 
0741 unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
0742                   int color_plane)
0743 {
0744     struct drm_i915_private *dev_priv = to_i915(fb->dev);
0745 
0746     if (intel_fb_uses_dpt(fb))
0747         return 512 * 4096;
0748 
0749     /* AUX_DIST needs only 4K alignment */
0750     if (intel_fb_is_ccs_aux_plane(fb, color_plane))
0751         return 4096;
0752 
0753     if (is_semiplanar_uv_plane(fb, color_plane)) {
0754         /*
0755          * TODO: cross-check wrt. the bspec stride in bytes * 64 bytes
0756          * alignment for linear UV planes on all platforms.
0757          */
0758         if (DISPLAY_VER(dev_priv) >= 12) {
0759             if (fb->modifier == DRM_FORMAT_MOD_LINEAR)
0760                 return intel_linear_alignment(dev_priv);
0761 
0762             return intel_tile_row_size(fb, color_plane);
0763         }
0764 
0765         return 4096;
0766     }
0767 
0768     drm_WARN_ON(&dev_priv->drm, color_plane != 0);
0769 
0770     switch (fb->modifier) {
0771     case DRM_FORMAT_MOD_LINEAR:
0772         return intel_linear_alignment(dev_priv);
0773     case I915_FORMAT_MOD_X_TILED:
0774         if (HAS_ASYNC_FLIPS(dev_priv))
0775             return 256 * 1024;
0776         return 0;
0777     case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
0778     case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
0779     case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
0780         return 16 * 1024;
0781     case I915_FORMAT_MOD_Y_TILED_CCS:
0782     case I915_FORMAT_MOD_Yf_TILED_CCS:
0783     case I915_FORMAT_MOD_Y_TILED:
0784     case I915_FORMAT_MOD_4_TILED:
0785     case I915_FORMAT_MOD_Yf_TILED:
0786         return 1 * 1024 * 1024;
0787     case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS:
0788     case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC:
0789     case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS:
0790         return 16 * 1024;
0791     default:
0792         MISSING_CASE(fb->modifier);
0793         return 0;
0794     }
0795 }
0796 
0797 void intel_fb_plane_get_subsampling(int *hsub, int *vsub,
0798                     const struct drm_framebuffer *fb,
0799                     int color_plane)
0800 {
0801     int main_plane;
0802 
0803     if (color_plane == 0) {
0804         *hsub = 1;
0805         *vsub = 1;
0806 
0807         return;
0808     }
0809 
0810     /*
0811      * TODO: Deduct the subsampling from the char block for all CCS
0812      * formats and planes.
0813      */
0814     if (!intel_fb_is_gen12_ccs_aux_plane(fb, color_plane)) {
0815         *hsub = fb->format->hsub;
0816         *vsub = fb->format->vsub;
0817 
0818         return;
0819     }
0820 
0821     main_plane = skl_ccs_to_main_plane(fb, color_plane);
0822     *hsub = drm_format_info_block_width(fb->format, color_plane) /
0823         drm_format_info_block_width(fb->format, main_plane);
0824 
0825     /*
0826      * The min stride check in the core framebuffer_check() function
0827      * assumes that format->hsub applies to every plane except for the
0828      * first plane. That's incorrect for the CCS AUX plane of the first
0829      * plane, but for the above check to pass we must define the block
0830      * width with that subsampling applied to it. Adjust the width here
0831      * accordingly, so we can calculate the actual subsampling factor.
0832      */
0833     if (main_plane == 0)
0834         *hsub *= fb->format->hsub;
0835 
0836     *vsub = 32;
0837 }
0838 
0839 static void intel_fb_plane_dims(const struct intel_framebuffer *fb, int color_plane, int *w, int *h)
0840 {
0841     int main_plane = intel_fb_is_ccs_aux_plane(&fb->base, color_plane) ?
0842              skl_ccs_to_main_plane(&fb->base, color_plane) : 0;
0843     unsigned int main_width = fb->base.width;
0844     unsigned int main_height = fb->base.height;
0845     int main_hsub, main_vsub;
0846     int hsub, vsub;
0847 
0848     intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, &fb->base, main_plane);
0849     intel_fb_plane_get_subsampling(&hsub, &vsub, &fb->base, color_plane);
0850 
0851     *w = DIV_ROUND_UP(main_width, main_hsub * hsub);
0852     *h = DIV_ROUND_UP(main_height, main_vsub * vsub);
0853 }
0854 
0855 static u32 intel_adjust_tile_offset(int *x, int *y,
0856                     unsigned int tile_width,
0857                     unsigned int tile_height,
0858                     unsigned int tile_size,
0859                     unsigned int pitch_tiles,
0860                     u32 old_offset,
0861                     u32 new_offset)
0862 {
0863     unsigned int pitch_pixels = pitch_tiles * tile_width;
0864     unsigned int tiles;
0865 
0866     WARN_ON(old_offset & (tile_size - 1));
0867     WARN_ON(new_offset & (tile_size - 1));
0868     WARN_ON(new_offset > old_offset);
0869 
0870     tiles = (old_offset - new_offset) / tile_size;
0871 
0872     *y += tiles / pitch_tiles * tile_height;
0873     *x += tiles % pitch_tiles * tile_width;
0874 
0875     /* minimize x in case it got needlessly big */
0876     *y += *x / pitch_pixels * tile_height;
0877     *x %= pitch_pixels;
0878 
0879     return new_offset;
0880 }
0881 
0882 static u32 intel_adjust_linear_offset(int *x, int *y,
0883                       unsigned int cpp,
0884                       unsigned int pitch,
0885                       u32 old_offset,
0886                       u32 new_offset)
0887 {
0888     old_offset += *y * pitch + *x * cpp;
0889 
0890     *y = (old_offset - new_offset) / pitch;
0891     *x = ((old_offset - new_offset) - *y * pitch) / cpp;
0892 
0893     return new_offset;
0894 }
0895 
0896 static u32 intel_adjust_aligned_offset(int *x, int *y,
0897                        const struct drm_framebuffer *fb,
0898                        int color_plane,
0899                        unsigned int rotation,
0900                        unsigned int pitch,
0901                        u32 old_offset, u32 new_offset)
0902 {
0903     struct drm_i915_private *i915 = to_i915(fb->dev);
0904     unsigned int cpp = fb->format->cpp[color_plane];
0905 
0906     drm_WARN_ON(&i915->drm, new_offset > old_offset);
0907 
0908     if (!is_surface_linear(fb, color_plane)) {
0909         unsigned int tile_size, tile_width, tile_height;
0910         unsigned int pitch_tiles;
0911 
0912         tile_size = intel_tile_size(i915);
0913         intel_tile_dims(fb, color_plane, &tile_width, &tile_height);
0914 
0915         if (drm_rotation_90_or_270(rotation)) {
0916             pitch_tiles = pitch / tile_height;
0917             swap(tile_width, tile_height);
0918         } else {
0919             pitch_tiles = pitch / (tile_width * cpp);
0920         }
0921 
0922         intel_adjust_tile_offset(x, y, tile_width, tile_height,
0923                      tile_size, pitch_tiles,
0924                      old_offset, new_offset);
0925     } else {
0926         intel_adjust_linear_offset(x, y, cpp, pitch,
0927                        old_offset, new_offset);
0928     }
0929 
0930     return new_offset;
0931 }
0932 
0933 /*
0934  * Adjust the tile offset by moving the difference into
0935  * the x/y offsets.
0936  */
0937 u32 intel_plane_adjust_aligned_offset(int *x, int *y,
0938                       const struct intel_plane_state *state,
0939                       int color_plane,
0940                       u32 old_offset, u32 new_offset)
0941 {
0942     return intel_adjust_aligned_offset(x, y, state->hw.fb, color_plane,
0943                        state->hw.rotation,
0944                        state->view.color_plane[color_plane].mapping_stride,
0945                        old_offset, new_offset);
0946 }
0947 
0948 /*
0949  * Computes the aligned offset to the base tile and adjusts
0950  * x, y. bytes per pixel is assumed to be a power-of-two.
0951  *
0952  * In the 90/270 rotated case, x and y are assumed
0953  * to be already rotated to match the rotated GTT view, and
0954  * pitch is the tile_height aligned framebuffer height.
0955  *
0956  * This function is used when computing the derived information
0957  * under intel_framebuffer, so using any of that information
0958  * here is not allowed. Anything under drm_framebuffer can be
0959  * used. This is why the user has to pass in the pitch since it
0960  * is specified in the rotated orientation.
0961  */
0962 static u32 intel_compute_aligned_offset(struct drm_i915_private *i915,
0963                     int *x, int *y,
0964                     const struct drm_framebuffer *fb,
0965                     int color_plane,
0966                     unsigned int pitch,
0967                     unsigned int rotation,
0968                     u32 alignment)
0969 {
0970     unsigned int cpp = fb->format->cpp[color_plane];
0971     u32 offset, offset_aligned;
0972 
0973     if (!is_surface_linear(fb, color_plane)) {
0974         unsigned int tile_size, tile_width, tile_height;
0975         unsigned int tile_rows, tiles, pitch_tiles;
0976 
0977         tile_size = intel_tile_size(i915);
0978         intel_tile_dims(fb, color_plane, &tile_width, &tile_height);
0979 
0980         if (drm_rotation_90_or_270(rotation)) {
0981             pitch_tiles = pitch / tile_height;
0982             swap(tile_width, tile_height);
0983         } else {
0984             pitch_tiles = pitch / (tile_width * cpp);
0985         }
0986 
0987         tile_rows = *y / tile_height;
0988         *y %= tile_height;
0989 
0990         tiles = *x / tile_width;
0991         *x %= tile_width;
0992 
0993         offset = (tile_rows * pitch_tiles + tiles) * tile_size;
0994 
0995         offset_aligned = offset;
0996         if (alignment)
0997             offset_aligned = rounddown(offset_aligned, alignment);
0998 
0999         intel_adjust_tile_offset(x, y, tile_width, tile_height,
1000                      tile_size, pitch_tiles,
1001                      offset, offset_aligned);
1002     } else {
1003         offset = *y * pitch + *x * cpp;
1004         offset_aligned = offset;
1005         if (alignment) {
1006             offset_aligned = rounddown(offset_aligned, alignment);
1007             *y = (offset % alignment) / pitch;
1008             *x = ((offset % alignment) - *y * pitch) / cpp;
1009         } else {
1010             *y = *x = 0;
1011         }
1012     }
1013 
1014     return offset_aligned;
1015 }
1016 
1017 u32 intel_plane_compute_aligned_offset(int *x, int *y,
1018                        const struct intel_plane_state *state,
1019                        int color_plane)
1020 {
1021     struct intel_plane *intel_plane = to_intel_plane(state->uapi.plane);
1022     struct drm_i915_private *i915 = to_i915(intel_plane->base.dev);
1023     const struct drm_framebuffer *fb = state->hw.fb;
1024     unsigned int rotation = state->hw.rotation;
1025     int pitch = state->view.color_plane[color_plane].mapping_stride;
1026     u32 alignment;
1027 
1028     if (intel_plane->id == PLANE_CURSOR)
1029         alignment = intel_cursor_alignment(i915);
1030     else
1031         alignment = intel_surf_alignment(fb, color_plane);
1032 
1033     return intel_compute_aligned_offset(i915, x, y, fb, color_plane,
1034                         pitch, rotation, alignment);
1035 }
1036 
1037 /* Convert the fb->offset[] into x/y offsets */
1038 static int intel_fb_offset_to_xy(int *x, int *y,
1039                  const struct drm_framebuffer *fb,
1040                  int color_plane)
1041 {
1042     struct drm_i915_private *i915 = to_i915(fb->dev);
1043     unsigned int height;
1044     u32 alignment;
1045 
1046     if (DISPLAY_VER(i915) >= 12 &&
1047         !intel_fb_needs_pot_stride_remap(to_intel_framebuffer(fb)) &&
1048         is_semiplanar_uv_plane(fb, color_plane))
1049         alignment = intel_tile_row_size(fb, color_plane);
1050     else if (fb->modifier != DRM_FORMAT_MOD_LINEAR)
1051         alignment = intel_tile_size(i915);
1052     else
1053         alignment = 0;
1054 
1055     if (alignment != 0 && fb->offsets[color_plane] % alignment) {
1056         drm_dbg_kms(&i915->drm,
1057                 "Misaligned offset 0x%08x for color plane %d\n",
1058                 fb->offsets[color_plane], color_plane);
1059         return -EINVAL;
1060     }
1061 
1062     height = drm_framebuffer_plane_height(fb->height, fb, color_plane);
1063     height = ALIGN(height, intel_tile_height(fb, color_plane));
1064 
1065     /* Catch potential overflows early */
1066     if (add_overflows_t(u32, mul_u32_u32(height, fb->pitches[color_plane]),
1067                 fb->offsets[color_plane])) {
1068         drm_dbg_kms(&i915->drm,
1069                 "Bad offset 0x%08x or pitch %d for color plane %d\n",
1070                 fb->offsets[color_plane], fb->pitches[color_plane],
1071                 color_plane);
1072         return -ERANGE;
1073     }
1074 
1075     *x = 0;
1076     *y = 0;
1077 
1078     intel_adjust_aligned_offset(x, y,
1079                     fb, color_plane, DRM_MODE_ROTATE_0,
1080                     fb->pitches[color_plane],
1081                     fb->offsets[color_plane], 0);
1082 
1083     return 0;
1084 }
1085 
1086 static int intel_fb_check_ccs_xy(const struct drm_framebuffer *fb, int ccs_plane, int x, int y)
1087 {
1088     struct drm_i915_private *i915 = to_i915(fb->dev);
1089     const struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
1090     int main_plane;
1091     int hsub, vsub;
1092     int tile_width, tile_height;
1093     int ccs_x, ccs_y;
1094     int main_x, main_y;
1095 
1096     if (!intel_fb_is_ccs_aux_plane(fb, ccs_plane))
1097         return 0;
1098 
1099     /*
1100      * While all the tile dimensions are based on a 2k or 4k GTT page size
1101      * here the main and CCS coordinates must match only within a (64 byte
1102      * on TGL+) block inside the tile.
1103      */
1104     intel_tile_block_dims(fb, ccs_plane, &tile_width, &tile_height);
1105     intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane);
1106 
1107     tile_width *= hsub;
1108     tile_height *= vsub;
1109 
1110     ccs_x = (x * hsub) % tile_width;
1111     ccs_y = (y * vsub) % tile_height;
1112 
1113     main_plane = skl_ccs_to_main_plane(fb, ccs_plane);
1114     main_x = intel_fb->normal_view.color_plane[main_plane].x % tile_width;
1115     main_y = intel_fb->normal_view.color_plane[main_plane].y % tile_height;
1116 
1117     /*
1118      * CCS doesn't have its own x/y offset register, so the intra CCS tile
1119      * x/y offsets must match between CCS and the main surface.
1120      */
1121     if (main_x != ccs_x || main_y != ccs_y) {
1122         drm_dbg_kms(&i915->drm,
1123                   "Bad CCS x/y (main %d,%d ccs %d,%d) full (main %d,%d ccs %d,%d)\n",
1124                   main_x, main_y,
1125                   ccs_x, ccs_y,
1126                   intel_fb->normal_view.color_plane[main_plane].x,
1127                   intel_fb->normal_view.color_plane[main_plane].y,
1128                   x, y);
1129         return -EINVAL;
1130     }
1131 
1132     return 0;
1133 }
1134 
1135 static bool intel_plane_can_remap(const struct intel_plane_state *plane_state)
1136 {
1137     struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1138     struct drm_i915_private *i915 = to_i915(plane->base.dev);
1139     const struct drm_framebuffer *fb = plane_state->hw.fb;
1140     int i;
1141 
1142     /* We don't want to deal with remapping with cursors */
1143     if (plane->id == PLANE_CURSOR)
1144         return false;
1145 
1146     /*
1147      * The display engine limits already match/exceed the
1148      * render engine limits, so not much point in remapping.
1149      * Would also need to deal with the fence POT alignment
1150      * and gen2 2KiB GTT tile size.
1151      */
1152     if (DISPLAY_VER(i915) < 4)
1153         return false;
1154 
1155     /*
1156      * The new CCS hash mode isn't compatible with remapping as
1157      * the virtual address of the pages affects the compressed data.
1158      */
1159     if (intel_fb_is_ccs_modifier(fb->modifier))
1160         return false;
1161 
1162     /* Linear needs a page aligned stride for remapping */
1163     if (fb->modifier == DRM_FORMAT_MOD_LINEAR) {
1164         unsigned int alignment = intel_tile_size(i915) - 1;
1165 
1166         for (i = 0; i < fb->format->num_planes; i++) {
1167             if (fb->pitches[i] & alignment)
1168                 return false;
1169         }
1170     }
1171 
1172     return true;
1173 }
1174 
1175 bool intel_fb_needs_pot_stride_remap(const struct intel_framebuffer *fb)
1176 {
1177     struct drm_i915_private *i915 = to_i915(fb->base.dev);
1178 
1179     return IS_ALDERLAKE_P(i915) && fb->base.modifier != DRM_FORMAT_MOD_LINEAR;
1180 }
1181 
1182 static int intel_fb_pitch(const struct intel_framebuffer *fb, int color_plane, unsigned int rotation)
1183 {
1184     if (drm_rotation_90_or_270(rotation))
1185         return fb->rotated_view.color_plane[color_plane].mapping_stride;
1186     else if (intel_fb_needs_pot_stride_remap(fb))
1187         return fb->remapped_view.color_plane[color_plane].mapping_stride;
1188     else
1189         return fb->normal_view.color_plane[color_plane].mapping_stride;
1190 }
1191 
1192 static bool intel_plane_needs_remap(const struct intel_plane_state *plane_state)
1193 {
1194     struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1195     const struct intel_framebuffer *fb = to_intel_framebuffer(plane_state->hw.fb);
1196     unsigned int rotation = plane_state->hw.rotation;
1197     u32 stride, max_stride;
1198 
1199     /*
1200      * No remapping for invisible planes since we don't have
1201      * an actual source viewport to remap.
1202      */
1203     if (!plane_state->uapi.visible)
1204         return false;
1205 
1206     if (!intel_plane_can_remap(plane_state))
1207         return false;
1208 
1209     /*
1210      * FIXME: aux plane limits on gen9+ are
1211      * unclear in Bspec, for now no checking.
1212      */
1213     stride = intel_fb_pitch(fb, 0, rotation);
1214     max_stride = plane->max_stride(plane, fb->base.format->format,
1215                        fb->base.modifier, rotation);
1216 
1217     return stride > max_stride;
1218 }
1219 
1220 static int convert_plane_offset_to_xy(const struct intel_framebuffer *fb, int color_plane,
1221                       int plane_width, int *x, int *y)
1222 {
1223     struct drm_i915_gem_object *obj = intel_fb_obj(&fb->base);
1224     int ret;
1225 
1226     ret = intel_fb_offset_to_xy(x, y, &fb->base, color_plane);
1227     if (ret) {
1228         drm_dbg_kms(fb->base.dev,
1229                 "bad fb plane %d offset: 0x%x\n",
1230                 color_plane, fb->base.offsets[color_plane]);
1231         return ret;
1232     }
1233 
1234     ret = intel_fb_check_ccs_xy(&fb->base, color_plane, *x, *y);
1235     if (ret)
1236         return ret;
1237 
1238     /*
1239      * The fence (if used) is aligned to the start of the object
1240      * so having the framebuffer wrap around across the edge of the
1241      * fenced region doesn't really work. We have no API to configure
1242      * the fence start offset within the object (nor could we probably
1243      * on gen2/3). So it's just easier if we just require that the
1244      * fb layout agrees with the fence layout. We already check that the
1245      * fb stride matches the fence stride elsewhere.
1246      */
1247     if (color_plane == 0 && i915_gem_object_is_tiled(obj) &&
1248         (*x + plane_width) * fb->base.format->cpp[color_plane] > fb->base.pitches[color_plane]) {
1249         drm_dbg_kms(fb->base.dev,
1250                 "bad fb plane %d offset: 0x%x\n",
1251                 color_plane, fb->base.offsets[color_plane]);
1252         return -EINVAL;
1253     }
1254 
1255     return 0;
1256 }
1257 
1258 static u32 calc_plane_aligned_offset(const struct intel_framebuffer *fb, int color_plane, int *x, int *y)
1259 {
1260     struct drm_i915_private *i915 = to_i915(fb->base.dev);
1261     unsigned int tile_size = intel_tile_size(i915);
1262     u32 offset;
1263 
1264     offset = intel_compute_aligned_offset(i915, x, y, &fb->base, color_plane,
1265                           fb->base.pitches[color_plane],
1266                           DRM_MODE_ROTATE_0,
1267                           tile_size);
1268 
1269     return offset / tile_size;
1270 }
1271 
1272 struct fb_plane_view_dims {
1273     unsigned int width, height;
1274     unsigned int tile_width, tile_height;
1275 };
1276 
1277 static void init_plane_view_dims(const struct intel_framebuffer *fb, int color_plane,
1278                  unsigned int width, unsigned int height,
1279                  struct fb_plane_view_dims *dims)
1280 {
1281     dims->width = width;
1282     dims->height = height;
1283 
1284     intel_tile_dims(&fb->base, color_plane, &dims->tile_width, &dims->tile_height);
1285 }
1286 
1287 static unsigned int
1288 plane_view_src_stride_tiles(const struct intel_framebuffer *fb, int color_plane,
1289                 const struct fb_plane_view_dims *dims)
1290 {
1291     return DIV_ROUND_UP(fb->base.pitches[color_plane],
1292                 dims->tile_width * fb->base.format->cpp[color_plane]);
1293 }
1294 
1295 static unsigned int
1296 plane_view_dst_stride_tiles(const struct intel_framebuffer *fb, int color_plane,
1297                 unsigned int pitch_tiles)
1298 {
1299     if (intel_fb_needs_pot_stride_remap(fb)) {
1300         /*
1301          * ADL_P, the only platform needing a POT stride has a minimum
1302          * of 8 main surface tiles.
1303          */
1304         return roundup_pow_of_two(max(pitch_tiles, 8u));
1305     } else {
1306         return pitch_tiles;
1307     }
1308 }
1309 
1310 static unsigned int
1311 plane_view_scanout_stride(const struct intel_framebuffer *fb, int color_plane,
1312               unsigned int tile_width,
1313               unsigned int src_stride_tiles, unsigned int dst_stride_tiles)
1314 {
1315     unsigned int stride_tiles;
1316 
1317     if (IS_ALDERLAKE_P(to_i915(fb->base.dev)))
1318         stride_tiles = src_stride_tiles;
1319     else
1320         stride_tiles = dst_stride_tiles;
1321 
1322     return stride_tiles * tile_width * fb->base.format->cpp[color_plane];
1323 }
1324 
1325 static unsigned int
1326 plane_view_width_tiles(const struct intel_framebuffer *fb, int color_plane,
1327                const struct fb_plane_view_dims *dims,
1328                int x)
1329 {
1330     return DIV_ROUND_UP(x + dims->width, dims->tile_width);
1331 }
1332 
1333 static unsigned int
1334 plane_view_height_tiles(const struct intel_framebuffer *fb, int color_plane,
1335             const struct fb_plane_view_dims *dims,
1336             int y)
1337 {
1338     return DIV_ROUND_UP(y + dims->height, dims->tile_height);
1339 }
1340 
1341 static unsigned int
1342 plane_view_linear_tiles(const struct intel_framebuffer *fb, int color_plane,
1343             const struct fb_plane_view_dims *dims,
1344             int x, int y)
1345 {
1346     struct drm_i915_private *i915 = to_i915(fb->base.dev);
1347     unsigned int size;
1348 
1349     size = (y + dims->height) * fb->base.pitches[color_plane] +
1350         x * fb->base.format->cpp[color_plane];
1351 
1352     return DIV_ROUND_UP(size, intel_tile_size(i915));
1353 }
1354 
1355 #define assign_chk_ovf(i915, var, val) ({ \
1356     drm_WARN_ON(&(i915)->drm, overflows_type(val, var)); \
1357     (var) = (val); \
1358 })
1359 
1360 #define assign_bfld_chk_ovf(i915, var, val) ({ \
1361     (var) = (val); \
1362     drm_WARN_ON(&(i915)->drm, (var) != (val)); \
1363     (var); \
1364 })
1365 
1366 static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_plane,
1367                  const struct fb_plane_view_dims *dims,
1368                  u32 obj_offset, u32 gtt_offset, int x, int y,
1369                  struct intel_fb_view *view)
1370 {
1371     struct drm_i915_private *i915 = to_i915(fb->base.dev);
1372     struct intel_remapped_plane_info *remap_info = &view->gtt.remapped.plane[color_plane];
1373     struct i915_color_plane_view *color_plane_info = &view->color_plane[color_plane];
1374     unsigned int tile_width = dims->tile_width;
1375     unsigned int tile_height = dims->tile_height;
1376     unsigned int tile_size = intel_tile_size(i915);
1377     struct drm_rect r;
1378     u32 size = 0;
1379 
1380     assign_bfld_chk_ovf(i915, remap_info->offset, obj_offset);
1381 
1382     if (intel_fb_is_gen12_ccs_aux_plane(&fb->base, color_plane)) {
1383         remap_info->linear = 1;
1384 
1385         assign_chk_ovf(i915, remap_info->size,
1386                    plane_view_linear_tiles(fb, color_plane, dims, x, y));
1387     } else {
1388         remap_info->linear = 0;
1389 
1390         assign_chk_ovf(i915, remap_info->src_stride,
1391                    plane_view_src_stride_tiles(fb, color_plane, dims));
1392         assign_chk_ovf(i915, remap_info->width,
1393                    plane_view_width_tiles(fb, color_plane, dims, x));
1394         assign_chk_ovf(i915, remap_info->height,
1395                    plane_view_height_tiles(fb, color_plane, dims, y));
1396     }
1397 
1398     if (view->gtt.type == I915_GGTT_VIEW_ROTATED) {
1399         drm_WARN_ON(&i915->drm, remap_info->linear);
1400         check_array_bounds(i915, view->gtt.rotated.plane, color_plane);
1401 
1402         assign_chk_ovf(i915, remap_info->dst_stride,
1403                    plane_view_dst_stride_tiles(fb, color_plane, remap_info->height));
1404 
1405         /* rotate the x/y offsets to match the GTT view */
1406         drm_rect_init(&r, x, y, dims->width, dims->height);
1407         drm_rect_rotate(&r,
1408                 remap_info->width * tile_width,
1409                 remap_info->height * tile_height,
1410                 DRM_MODE_ROTATE_270);
1411 
1412         color_plane_info->x = r.x1;
1413         color_plane_info->y = r.y1;
1414 
1415         color_plane_info->mapping_stride = remap_info->dst_stride * tile_height;
1416         color_plane_info->scanout_stride = color_plane_info->mapping_stride;
1417 
1418         size += remap_info->dst_stride * remap_info->width;
1419 
1420         /* rotate the tile dimensions to match the GTT view */
1421         swap(tile_width, tile_height);
1422     } else {
1423         drm_WARN_ON(&i915->drm, view->gtt.type != I915_GGTT_VIEW_REMAPPED);
1424 
1425         check_array_bounds(i915, view->gtt.remapped.plane, color_plane);
1426 
1427         if (view->gtt.remapped.plane_alignment) {
1428             unsigned int aligned_offset = ALIGN(gtt_offset,
1429                                 view->gtt.remapped.plane_alignment);
1430 
1431             size += aligned_offset - gtt_offset;
1432             gtt_offset = aligned_offset;
1433         }
1434 
1435         color_plane_info->x = x;
1436         color_plane_info->y = y;
1437 
1438         if (remap_info->linear) {
1439             color_plane_info->mapping_stride = fb->base.pitches[color_plane];
1440             color_plane_info->scanout_stride = color_plane_info->mapping_stride;
1441 
1442             size += remap_info->size;
1443         } else {
1444             unsigned int dst_stride = plane_view_dst_stride_tiles(fb, color_plane,
1445                                           remap_info->width);
1446 
1447             assign_chk_ovf(i915, remap_info->dst_stride, dst_stride);
1448             color_plane_info->mapping_stride = dst_stride *
1449                                tile_width *
1450                                fb->base.format->cpp[color_plane];
1451             color_plane_info->scanout_stride =
1452                 plane_view_scanout_stride(fb, color_plane, tile_width,
1453                               remap_info->src_stride,
1454                               dst_stride);
1455 
1456             size += dst_stride * remap_info->height;
1457         }
1458     }
1459 
1460     /*
1461      * We only keep the x/y offsets, so push all of the gtt offset into
1462      * the x/y offsets.  x,y will hold the first pixel of the framebuffer
1463      * plane from the start of the remapped/rotated gtt mapping.
1464      */
1465     if (remap_info->linear)
1466         intel_adjust_linear_offset(&color_plane_info->x, &color_plane_info->y,
1467                        fb->base.format->cpp[color_plane],
1468                        color_plane_info->mapping_stride,
1469                        gtt_offset * tile_size, 0);
1470     else
1471         intel_adjust_tile_offset(&color_plane_info->x, &color_plane_info->y,
1472                      tile_width, tile_height,
1473                      tile_size, remap_info->dst_stride,
1474                      gtt_offset * tile_size, 0);
1475 
1476     return size;
1477 }
1478 
1479 #undef assign_chk_ovf
1480 
1481 /* Return number of tiles @color_plane needs. */
1482 static unsigned int
1483 calc_plane_normal_size(const struct intel_framebuffer *fb, int color_plane,
1484                const struct fb_plane_view_dims *dims,
1485                int x, int y)
1486 {
1487     unsigned int tiles;
1488 
1489     if (is_surface_linear(&fb->base, color_plane)) {
1490         tiles = plane_view_linear_tiles(fb, color_plane, dims, x, y);
1491     } else {
1492         tiles = plane_view_src_stride_tiles(fb, color_plane, dims) *
1493             plane_view_height_tiles(fb, color_plane, dims, y);
1494         /*
1495          * If the plane isn't horizontally tile aligned,
1496          * we need one more tile.
1497          */
1498         if (x != 0)
1499             tiles++;
1500     }
1501 
1502     return tiles;
1503 }
1504 
1505 static void intel_fb_view_init(struct drm_i915_private *i915, struct intel_fb_view *view,
1506                    enum i915_ggtt_view_type view_type)
1507 {
1508     memset(view, 0, sizeof(*view));
1509     view->gtt.type = view_type;
1510 
1511     if (view_type == I915_GGTT_VIEW_REMAPPED && IS_ALDERLAKE_P(i915))
1512         view->gtt.remapped.plane_alignment = SZ_2M / PAGE_SIZE;
1513 }
1514 
1515 bool intel_fb_supports_90_270_rotation(const struct intel_framebuffer *fb)
1516 {
1517     if (DISPLAY_VER(to_i915(fb->base.dev)) >= 13)
1518         return false;
1519 
1520     return fb->base.modifier == I915_FORMAT_MOD_Y_TILED ||
1521            fb->base.modifier == I915_FORMAT_MOD_Yf_TILED;
1522 }
1523 
1524 int intel_fill_fb_info(struct drm_i915_private *i915, struct intel_framebuffer *fb)
1525 {
1526     struct drm_i915_gem_object *obj = intel_fb_obj(&fb->base);
1527     u32 gtt_offset_rotated = 0;
1528     u32 gtt_offset_remapped = 0;
1529     unsigned int max_size = 0;
1530     int i, num_planes = fb->base.format->num_planes;
1531     unsigned int tile_size = intel_tile_size(i915);
1532 
1533     intel_fb_view_init(i915, &fb->normal_view, I915_GGTT_VIEW_NORMAL);
1534 
1535     drm_WARN_ON(&i915->drm,
1536             intel_fb_supports_90_270_rotation(fb) &&
1537             intel_fb_needs_pot_stride_remap(fb));
1538 
1539     if (intel_fb_supports_90_270_rotation(fb))
1540         intel_fb_view_init(i915, &fb->rotated_view, I915_GGTT_VIEW_ROTATED);
1541     if (intel_fb_needs_pot_stride_remap(fb))
1542         intel_fb_view_init(i915, &fb->remapped_view, I915_GGTT_VIEW_REMAPPED);
1543 
1544     for (i = 0; i < num_planes; i++) {
1545         struct fb_plane_view_dims view_dims;
1546         unsigned int width, height;
1547         unsigned int cpp, size;
1548         u32 offset;
1549         int x, y;
1550         int ret;
1551 
1552         /*
1553          * Plane 2 of Render Compression with Clear Color fb modifier
1554          * is consumed by the driver and not passed to DE. Skip the
1555          * arithmetic related to alignment and offset calculation.
1556          */
1557         if (is_gen12_ccs_cc_plane(&fb->base, i)) {
1558             if (IS_ALIGNED(fb->base.offsets[i], PAGE_SIZE))
1559                 continue;
1560             else
1561                 return -EINVAL;
1562         }
1563 
1564         cpp = fb->base.format->cpp[i];
1565         intel_fb_plane_dims(fb, i, &width, &height);
1566 
1567         ret = convert_plane_offset_to_xy(fb, i, width, &x, &y);
1568         if (ret)
1569             return ret;
1570 
1571         init_plane_view_dims(fb, i, width, height, &view_dims);
1572 
1573         /*
1574          * First pixel of the framebuffer from
1575          * the start of the normal gtt mapping.
1576          */
1577         fb->normal_view.color_plane[i].x = x;
1578         fb->normal_view.color_plane[i].y = y;
1579         fb->normal_view.color_plane[i].mapping_stride = fb->base.pitches[i];
1580         fb->normal_view.color_plane[i].scanout_stride =
1581             fb->normal_view.color_plane[i].mapping_stride;
1582 
1583         offset = calc_plane_aligned_offset(fb, i, &x, &y);
1584 
1585         if (intel_fb_supports_90_270_rotation(fb))
1586             gtt_offset_rotated += calc_plane_remap_info(fb, i, &view_dims,
1587                                     offset, gtt_offset_rotated, x, y,
1588                                     &fb->rotated_view);
1589 
1590         if (intel_fb_needs_pot_stride_remap(fb))
1591             gtt_offset_remapped += calc_plane_remap_info(fb, i, &view_dims,
1592                                      offset, gtt_offset_remapped, x, y,
1593                                      &fb->remapped_view);
1594 
1595         size = calc_plane_normal_size(fb, i, &view_dims, x, y);
1596         /* how many tiles in total needed in the bo */
1597         max_size = max(max_size, offset + size);
1598     }
1599 
1600     if (mul_u32_u32(max_size, tile_size) > obj->base.size) {
1601         drm_dbg_kms(&i915->drm,
1602                 "fb too big for bo (need %llu bytes, have %zu bytes)\n",
1603                 mul_u32_u32(max_size, tile_size), obj->base.size);
1604         return -EINVAL;
1605     }
1606 
1607     return 0;
1608 }
1609 
1610 static void intel_plane_remap_gtt(struct intel_plane_state *plane_state)
1611 {
1612     struct drm_i915_private *i915 =
1613         to_i915(plane_state->uapi.plane->dev);
1614     struct drm_framebuffer *fb = plane_state->hw.fb;
1615     struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
1616     unsigned int rotation = plane_state->hw.rotation;
1617     int i, num_planes = fb->format->num_planes;
1618     unsigned int src_x, src_y;
1619     unsigned int src_w, src_h;
1620     u32 gtt_offset = 0;
1621 
1622     intel_fb_view_init(i915, &plane_state->view,
1623                drm_rotation_90_or_270(rotation) ? I915_GGTT_VIEW_ROTATED :
1624                                   I915_GGTT_VIEW_REMAPPED);
1625 
1626     src_x = plane_state->uapi.src.x1 >> 16;
1627     src_y = plane_state->uapi.src.y1 >> 16;
1628     src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
1629     src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
1630 
1631     drm_WARN_ON(&i915->drm, intel_fb_is_ccs_modifier(fb->modifier));
1632 
1633     /* Make src coordinates relative to the viewport */
1634     drm_rect_translate(&plane_state->uapi.src,
1635                -(src_x << 16), -(src_y << 16));
1636 
1637     /* Rotate src coordinates to match rotated GTT view */
1638     if (drm_rotation_90_or_270(rotation))
1639         drm_rect_rotate(&plane_state->uapi.src,
1640                 src_w << 16, src_h << 16,
1641                 DRM_MODE_ROTATE_270);
1642 
1643     for (i = 0; i < num_planes; i++) {
1644         unsigned int hsub = i ? fb->format->hsub : 1;
1645         unsigned int vsub = i ? fb->format->vsub : 1;
1646         struct fb_plane_view_dims view_dims;
1647         unsigned int width, height;
1648         unsigned int x, y;
1649         u32 offset;
1650 
1651         x = src_x / hsub;
1652         y = src_y / vsub;
1653         width = src_w / hsub;
1654         height = src_h / vsub;
1655 
1656         init_plane_view_dims(intel_fb, i, width, height, &view_dims);
1657 
1658         /*
1659          * First pixel of the src viewport from the
1660          * start of the normal gtt mapping.
1661          */
1662         x += intel_fb->normal_view.color_plane[i].x;
1663         y += intel_fb->normal_view.color_plane[i].y;
1664 
1665         offset = calc_plane_aligned_offset(intel_fb, i, &x, &y);
1666 
1667         gtt_offset += calc_plane_remap_info(intel_fb, i, &view_dims,
1668                             offset, gtt_offset, x, y,
1669                             &plane_state->view);
1670     }
1671 }
1672 
1673 void intel_fb_fill_view(const struct intel_framebuffer *fb, unsigned int rotation,
1674             struct intel_fb_view *view)
1675 {
1676     if (drm_rotation_90_or_270(rotation))
1677         *view = fb->rotated_view;
1678     else if (intel_fb_needs_pot_stride_remap(fb))
1679         *view = fb->remapped_view;
1680     else
1681         *view = fb->normal_view;
1682 }
1683 
1684 static
1685 u32 intel_fb_max_stride(struct drm_i915_private *dev_priv,
1686             u32 pixel_format, u64 modifier)
1687 {
1688     /*
1689      * Arbitrary limit for gen4+ chosen to match the
1690      * render engine max stride.
1691      *
1692      * The new CCS hash mode makes remapping impossible
1693      */
1694     if (DISPLAY_VER(dev_priv) < 4 || intel_fb_is_ccs_modifier(modifier) ||
1695         intel_modifier_uses_dpt(dev_priv, modifier))
1696         return intel_plane_fb_max_stride(dev_priv, pixel_format, modifier);
1697     else if (DISPLAY_VER(dev_priv) >= 7)
1698         return 256 * 1024;
1699     else
1700         return 128 * 1024;
1701 }
1702 
1703 static u32
1704 intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane)
1705 {
1706     struct drm_i915_private *dev_priv = to_i915(fb->dev);
1707     u32 tile_width;
1708 
1709     if (is_surface_linear(fb, color_plane)) {
1710         u32 max_stride = intel_plane_fb_max_stride(dev_priv,
1711                                fb->format->format,
1712                                fb->modifier);
1713 
1714         /*
1715          * To make remapping with linear generally feasible
1716          * we need the stride to be page aligned.
1717          */
1718         if (fb->pitches[color_plane] > max_stride &&
1719             !intel_fb_is_ccs_modifier(fb->modifier))
1720             return intel_tile_size(dev_priv);
1721         else
1722             return 64;
1723     }
1724 
1725     tile_width = intel_tile_width_bytes(fb, color_plane);
1726     if (intel_fb_is_ccs_modifier(fb->modifier)) {
1727         /*
1728          * On TGL the surface stride must be 4 tile aligned, mapped by
1729          * one 64 byte cacheline on the CCS AUX surface.
1730          */
1731         if (DISPLAY_VER(dev_priv) >= 12)
1732             tile_width *= 4;
1733         /*
1734          * Display WA #0531: skl,bxt,kbl,glk
1735          *
1736          * Render decompression and plane width > 3840
1737          * combined with horizontal panning requires the
1738          * plane stride to be a multiple of 4. We'll just
1739          * require the entire fb to accommodate that to avoid
1740          * potential runtime errors at plane configuration time.
1741          */
1742         else if ((DISPLAY_VER(dev_priv) == 9 || IS_GEMINILAKE(dev_priv)) &&
1743              color_plane == 0 && fb->width > 3840)
1744             tile_width *= 4;
1745     }
1746     return tile_width;
1747 }
1748 
1749 static int intel_plane_check_stride(const struct intel_plane_state *plane_state)
1750 {
1751     struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1752     const struct drm_framebuffer *fb = plane_state->hw.fb;
1753     unsigned int rotation = plane_state->hw.rotation;
1754     u32 stride, max_stride;
1755 
1756     /*
1757      * We ignore stride for all invisible planes that
1758      * can be remapped. Otherwise we could end up
1759      * with a false positive when the remapping didn't
1760      * kick in due the plane being invisible.
1761      */
1762     if (intel_plane_can_remap(plane_state) &&
1763         !plane_state->uapi.visible)
1764         return 0;
1765 
1766     /* FIXME other color planes? */
1767     stride = plane_state->view.color_plane[0].mapping_stride;
1768     max_stride = plane->max_stride(plane, fb->format->format,
1769                        fb->modifier, rotation);
1770 
1771     if (stride > max_stride) {
1772         DRM_DEBUG_KMS("[FB:%d] stride (%d) exceeds [PLANE:%d:%s] max stride (%d)\n",
1773                   fb->base.id, stride,
1774                   plane->base.base.id, plane->base.name, max_stride);
1775         return -EINVAL;
1776     }
1777 
1778     return 0;
1779 }
1780 
1781 int intel_plane_compute_gtt(struct intel_plane_state *plane_state)
1782 {
1783     const struct intel_framebuffer *fb =
1784         to_intel_framebuffer(plane_state->hw.fb);
1785     unsigned int rotation = plane_state->hw.rotation;
1786 
1787     if (!fb)
1788         return 0;
1789 
1790     if (intel_plane_needs_remap(plane_state)) {
1791         intel_plane_remap_gtt(plane_state);
1792 
1793         /*
1794          * Sometimes even remapping can't overcome
1795          * the stride limitations :( Can happen with
1796          * big plane sizes and suitably misaligned
1797          * offsets.
1798          */
1799         return intel_plane_check_stride(plane_state);
1800     }
1801 
1802     intel_fb_fill_view(fb, rotation, &plane_state->view);
1803 
1804     /* Rotate src coordinates to match rotated GTT view */
1805     if (drm_rotation_90_or_270(rotation))
1806         drm_rect_rotate(&plane_state->uapi.src,
1807                 fb->base.width << 16, fb->base.height << 16,
1808                 DRM_MODE_ROTATE_270);
1809 
1810     return intel_plane_check_stride(plane_state);
1811 }
1812 
1813 static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
1814 {
1815     struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
1816 
1817     drm_framebuffer_cleanup(fb);
1818 
1819     if (intel_fb_uses_dpt(fb))
1820         intel_dpt_destroy(intel_fb->dpt_vm);
1821 
1822     intel_frontbuffer_put(intel_fb->frontbuffer);
1823 
1824     kfree(intel_fb);
1825 }
1826 
1827 static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb,
1828                         struct drm_file *file,
1829                         unsigned int *handle)
1830 {
1831     struct drm_i915_gem_object *obj = intel_fb_obj(fb);
1832     struct drm_i915_private *i915 = to_i915(obj->base.dev);
1833 
1834     if (i915_gem_object_is_userptr(obj)) {
1835         drm_dbg(&i915->drm,
1836             "attempting to use a userptr for a framebuffer, denied\n");
1837         return -EINVAL;
1838     }
1839 
1840     return drm_gem_handle_create(file, &obj->base, handle);
1841 }
1842 
1843 static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb,
1844                     struct drm_file *file,
1845                     unsigned int flags, unsigned int color,
1846                     struct drm_clip_rect *clips,
1847                     unsigned int num_clips)
1848 {
1849     struct drm_i915_gem_object *obj = intel_fb_obj(fb);
1850 
1851     i915_gem_object_flush_if_display(obj);
1852     intel_frontbuffer_flush(to_intel_frontbuffer(fb), ORIGIN_DIRTYFB);
1853 
1854     return 0;
1855 }
1856 
1857 static const struct drm_framebuffer_funcs intel_fb_funcs = {
1858     .destroy = intel_user_framebuffer_destroy,
1859     .create_handle = intel_user_framebuffer_create_handle,
1860     .dirty = intel_user_framebuffer_dirty,
1861 };
1862 
1863 int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
1864                struct drm_i915_gem_object *obj,
1865                struct drm_mode_fb_cmd2 *mode_cmd)
1866 {
1867     struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
1868     struct drm_framebuffer *fb = &intel_fb->base;
1869     u32 max_stride;
1870     unsigned int tiling, stride;
1871     int ret = -EINVAL;
1872     int i;
1873 
1874     intel_fb->frontbuffer = intel_frontbuffer_get(obj);
1875     if (!intel_fb->frontbuffer)
1876         return -ENOMEM;
1877 
1878     i915_gem_object_lock(obj, NULL);
1879     tiling = i915_gem_object_get_tiling(obj);
1880     stride = i915_gem_object_get_stride(obj);
1881     i915_gem_object_unlock(obj);
1882 
1883     if (mode_cmd->flags & DRM_MODE_FB_MODIFIERS) {
1884         /*
1885          * If there's a fence, enforce that
1886          * the fb modifier and tiling mode match.
1887          */
1888         if (tiling != I915_TILING_NONE &&
1889             tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) {
1890             drm_dbg_kms(&dev_priv->drm,
1891                     "tiling_mode doesn't match fb modifier\n");
1892             goto err;
1893         }
1894     } else {
1895         if (tiling == I915_TILING_X) {
1896             mode_cmd->modifier[0] = I915_FORMAT_MOD_X_TILED;
1897         } else if (tiling == I915_TILING_Y) {
1898             drm_dbg_kms(&dev_priv->drm,
1899                     "No Y tiling for legacy addfb\n");
1900             goto err;
1901         }
1902     }
1903 
1904     if (!drm_any_plane_has_format(&dev_priv->drm,
1905                       mode_cmd->pixel_format,
1906                       mode_cmd->modifier[0])) {
1907         drm_dbg_kms(&dev_priv->drm,
1908                 "unsupported pixel format %p4cc / modifier 0x%llx\n",
1909                 &mode_cmd->pixel_format, mode_cmd->modifier[0]);
1910         goto err;
1911     }
1912 
1913     /*
1914      * gen2/3 display engine uses the fence if present,
1915      * so the tiling mode must match the fb modifier exactly.
1916      */
1917     if (DISPLAY_VER(dev_priv) < 4 &&
1918         tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) {
1919         drm_dbg_kms(&dev_priv->drm,
1920                 "tiling_mode must match fb modifier exactly on gen2/3\n");
1921         goto err;
1922     }
1923 
1924     max_stride = intel_fb_max_stride(dev_priv, mode_cmd->pixel_format,
1925                      mode_cmd->modifier[0]);
1926     if (mode_cmd->pitches[0] > max_stride) {
1927         drm_dbg_kms(&dev_priv->drm,
1928                 "%s pitch (%u) must be at most %d\n",
1929                 mode_cmd->modifier[0] != DRM_FORMAT_MOD_LINEAR ?
1930                 "tiled" : "linear",
1931                 mode_cmd->pitches[0], max_stride);
1932         goto err;
1933     }
1934 
1935     /*
1936      * If there's a fence, enforce that
1937      * the fb pitch and fence stride match.
1938      */
1939     if (tiling != I915_TILING_NONE && mode_cmd->pitches[0] != stride) {
1940         drm_dbg_kms(&dev_priv->drm,
1941                 "pitch (%d) must match tiling stride (%d)\n",
1942                 mode_cmd->pitches[0], stride);
1943         goto err;
1944     }
1945 
1946     /* FIXME need to adjust LINOFF/TILEOFF accordingly. */
1947     if (mode_cmd->offsets[0] != 0) {
1948         drm_dbg_kms(&dev_priv->drm,
1949                 "plane 0 offset (0x%08x) must be 0\n",
1950                 mode_cmd->offsets[0]);
1951         goto err;
1952     }
1953 
1954     drm_helper_mode_fill_fb_struct(&dev_priv->drm, fb, mode_cmd);
1955 
1956     for (i = 0; i < fb->format->num_planes; i++) {
1957         u32 stride_alignment;
1958 
1959         if (mode_cmd->handles[i] != mode_cmd->handles[0]) {
1960             drm_dbg_kms(&dev_priv->drm, "bad plane %d handle\n",
1961                     i);
1962             goto err;
1963         }
1964 
1965         stride_alignment = intel_fb_stride_alignment(fb, i);
1966         if (fb->pitches[i] & (stride_alignment - 1)) {
1967             drm_dbg_kms(&dev_priv->drm,
1968                     "plane %d pitch (%d) must be at least %u byte aligned\n",
1969                     i, fb->pitches[i], stride_alignment);
1970             goto err;
1971         }
1972 
1973         if (intel_fb_is_gen12_ccs_aux_plane(fb, i)) {
1974             int ccs_aux_stride = gen12_ccs_aux_stride(intel_fb, i);
1975 
1976             if (fb->pitches[i] != ccs_aux_stride) {
1977                 drm_dbg_kms(&dev_priv->drm,
1978                         "ccs aux plane %d pitch (%d) must be %d\n",
1979                         i,
1980                         fb->pitches[i], ccs_aux_stride);
1981                 goto err;
1982             }
1983         }
1984 
1985         fb->obj[i] = &obj->base;
1986     }
1987 
1988     ret = intel_fill_fb_info(dev_priv, intel_fb);
1989     if (ret)
1990         goto err;
1991 
1992     if (intel_fb_uses_dpt(fb)) {
1993         struct i915_address_space *vm;
1994 
1995         vm = intel_dpt_create(intel_fb);
1996         if (IS_ERR(vm)) {
1997             ret = PTR_ERR(vm);
1998             goto err;
1999         }
2000 
2001         intel_fb->dpt_vm = vm;
2002     }
2003 
2004     ret = drm_framebuffer_init(&dev_priv->drm, fb, &intel_fb_funcs);
2005     if (ret) {
2006         drm_err(&dev_priv->drm, "framebuffer init failed %d\n", ret);
2007         goto err;
2008     }
2009 
2010     return 0;
2011 
2012 err:
2013     intel_frontbuffer_put(intel_fb->frontbuffer);
2014     return ret;
2015 }
2016 
2017 struct drm_framebuffer *
2018 intel_user_framebuffer_create(struct drm_device *dev,
2019                   struct drm_file *filp,
2020                   const struct drm_mode_fb_cmd2 *user_mode_cmd)
2021 {
2022     struct drm_framebuffer *fb;
2023     struct drm_i915_gem_object *obj;
2024     struct drm_mode_fb_cmd2 mode_cmd = *user_mode_cmd;
2025     struct drm_i915_private *i915;
2026 
2027     obj = i915_gem_object_lookup(filp, mode_cmd.handles[0]);
2028     if (!obj)
2029         return ERR_PTR(-ENOENT);
2030 
2031     /* object is backed with LMEM for discrete */
2032     i915 = to_i915(obj->base.dev);
2033     if (HAS_LMEM(i915) && !i915_gem_object_can_migrate(obj, INTEL_REGION_LMEM_0)) {
2034         /* object is "remote", not in local memory */
2035         i915_gem_object_put(obj);
2036         return ERR_PTR(-EREMOTE);
2037     }
2038 
2039     fb = intel_framebuffer_create(obj, &mode_cmd);
2040     i915_gem_object_put(obj);
2041 
2042     return fb;
2043 }
2044 
2045 struct drm_framebuffer *
2046 intel_framebuffer_create(struct drm_i915_gem_object *obj,
2047              struct drm_mode_fb_cmd2 *mode_cmd)
2048 {
2049     struct intel_framebuffer *intel_fb;
2050     int ret;
2051 
2052     intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
2053     if (!intel_fb)
2054         return ERR_PTR(-ENOMEM);
2055 
2056     ret = intel_framebuffer_init(intel_fb, obj, mode_cmd);
2057     if (ret)
2058         goto err;
2059 
2060     return &intel_fb->base;
2061 
2062 err:
2063     kfree(intel_fb);
2064     return ERR_PTR(ret);
2065 }