cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

intel_fb.c (61049B)


      1// SPDX-License-Identifier: MIT
      2/*
      3 * Copyright © 2021 Intel Corporation
      4 */
      5
      6#include <drm/drm_framebuffer.h>
      7#include <drm/drm_modeset_helper.h>
      8
      9#include "i915_drv.h"
     10#include "intel_display.h"
     11#include "intel_display_types.h"
     12#include "intel_dpt.h"
     13#include "intel_fb.h"
     14
     15#define check_array_bounds(i915, a, i) drm_WARN_ON(&(i915)->drm, (i) >= ARRAY_SIZE(a))
     16
     17/*
     18 * From the Sky Lake PRM:
     19 * "The Color Control Surface (CCS) contains the compression status of
     20 *  the cache-line pairs. The compression state of the cache-line pair
     21 *  is specified by 2 bits in the CCS. Each CCS cache-line represents
     22 *  an area on the main surface of 16 x16 sets of 128 byte Y-tiled
     23 *  cache-line-pairs. CCS is always Y tiled."
     24 *
     25 * Since cache line pairs refers to horizontally adjacent cache lines,
     26 * each cache line in the CCS corresponds to an area of 32x16 cache
     27 * lines on the main surface. Since each pixel is 4 bytes, this gives
     28 * us a ratio of one byte in the CCS for each 8x16 pixels in the
     29 * main surface.
     30 */
     31static const struct drm_format_info skl_ccs_formats[] = {
     32	{ .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 2,
     33	  .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
     34	{ .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 2,
     35	  .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, },
     36	{ .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 2,
     37	  .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, .has_alpha = true, },
     38	{ .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 2,
     39	  .cpp = { 4, 1, }, .hsub = 8, .vsub = 16, .has_alpha = true, },
     40};
     41
     42/*
     43 * Gen-12 compression uses 4 bits of CCS data for each cache line pair in the
     44 * main surface. And each 64B CCS cache line represents an area of 4x1 Y-tiles
     45 * in the main surface. With 4 byte pixels and each Y-tile having dimensions of
     46 * 32x32 pixels, the ratio turns out to 1B in the CCS for every 2x32 pixels in
     47 * the main surface.
     48 */
     49static const struct drm_format_info gen12_ccs_formats[] = {
     50	{ .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 2,
     51	  .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
     52	  .hsub = 1, .vsub = 1, },
     53	{ .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 2,
     54	  .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
     55	  .hsub = 1, .vsub = 1, },
     56	{ .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 2,
     57	  .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
     58	  .hsub = 1, .vsub = 1, .has_alpha = true },
     59	{ .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 2,
     60	  .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
     61	  .hsub = 1, .vsub = 1, .has_alpha = true },
     62	{ .format = DRM_FORMAT_YUYV, .num_planes = 2,
     63	  .char_per_block = { 2, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
     64	  .hsub = 2, .vsub = 1, .is_yuv = true },
     65	{ .format = DRM_FORMAT_YVYU, .num_planes = 2,
     66	  .char_per_block = { 2, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
     67	  .hsub = 2, .vsub = 1, .is_yuv = true },
     68	{ .format = DRM_FORMAT_UYVY, .num_planes = 2,
     69	  .char_per_block = { 2, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
     70	  .hsub = 2, .vsub = 1, .is_yuv = true },
     71	{ .format = DRM_FORMAT_VYUY, .num_planes = 2,
     72	  .char_per_block = { 2, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
     73	  .hsub = 2, .vsub = 1, .is_yuv = true },
     74	{ .format = DRM_FORMAT_XYUV8888, .num_planes = 2,
     75	  .char_per_block = { 4, 1 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
     76	  .hsub = 1, .vsub = 1, .is_yuv = true },
     77	{ .format = DRM_FORMAT_NV12, .num_planes = 4,
     78	  .char_per_block = { 1, 2, 1, 1 }, .block_w = { 1, 1, 4, 4 }, .block_h = { 1, 1, 1, 1 },
     79	  .hsub = 2, .vsub = 2, .is_yuv = true },
     80	{ .format = DRM_FORMAT_P010, .num_planes = 4,
     81	  .char_per_block = { 2, 4, 1, 1 }, .block_w = { 1, 1, 2, 2 }, .block_h = { 1, 1, 1, 1 },
     82	  .hsub = 2, .vsub = 2, .is_yuv = true },
     83	{ .format = DRM_FORMAT_P012, .num_planes = 4,
     84	  .char_per_block = { 2, 4, 1, 1 }, .block_w = { 1, 1, 2, 2 }, .block_h = { 1, 1, 1, 1 },
     85	  .hsub = 2, .vsub = 2, .is_yuv = true },
     86	{ .format = DRM_FORMAT_P016, .num_planes = 4,
     87	  .char_per_block = { 2, 4, 1, 1 }, .block_w = { 1, 1, 2, 2 }, .block_h = { 1, 1, 1, 1 },
     88	  .hsub = 2, .vsub = 2, .is_yuv = true },
     89};
     90
     91/*
     92 * Same as gen12_ccs_formats[] above, but with additional surface used
     93 * to pass Clear Color information in plane 2 with 64 bits of data.
     94 */
     95static const struct drm_format_info gen12_ccs_cc_formats[] = {
     96	{ .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 3,
     97	  .char_per_block = { 4, 1, 0 }, .block_w = { 1, 2, 2 }, .block_h = { 1, 1, 1 },
     98	  .hsub = 1, .vsub = 1, },
     99	{ .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 3,
    100	  .char_per_block = { 4, 1, 0 }, .block_w = { 1, 2, 2 }, .block_h = { 1, 1, 1 },
    101	  .hsub = 1, .vsub = 1, },
    102	{ .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 3,
    103	  .char_per_block = { 4, 1, 0 }, .block_w = { 1, 2, 2 }, .block_h = { 1, 1, 1 },
    104	  .hsub = 1, .vsub = 1, .has_alpha = true },
    105	{ .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 3,
    106	  .char_per_block = { 4, 1, 0 }, .block_w = { 1, 2, 2 }, .block_h = { 1, 1, 1 },
    107	  .hsub = 1, .vsub = 1, .has_alpha = true },
    108};
    109
    110static const struct drm_format_info gen12_flat_ccs_cc_formats[] = {
    111	{ .format = DRM_FORMAT_XRGB8888, .depth = 24, .num_planes = 2,
    112	  .char_per_block = { 4, 0 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
    113	  .hsub = 1, .vsub = 1, },
    114	{ .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 2,
    115	  .char_per_block = { 4, 0 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
    116	  .hsub = 1, .vsub = 1, },
    117	{ .format = DRM_FORMAT_ARGB8888, .depth = 32, .num_planes = 2,
    118	  .char_per_block = { 4, 0 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
    119	  .hsub = 1, .vsub = 1, .has_alpha = true },
    120	{ .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 2,
    121	  .char_per_block = { 4, 0 }, .block_w = { 1, 2 }, .block_h = { 1, 1 },
    122	  .hsub = 1, .vsub = 1, .has_alpha = true },
    123};
    124
    125struct intel_modifier_desc {
    126	u64 modifier;
    127	struct {
    128		u8 from;
    129		u8 until;
    130	} display_ver;
    131#define DISPLAY_VER_ALL		{ 0, -1 }
    132
    133	const struct drm_format_info *formats;
    134	int format_count;
    135#define FORMAT_OVERRIDE(format_list) \
    136	.formats = format_list, \
    137	.format_count = ARRAY_SIZE(format_list)
    138
    139	u8 plane_caps;
    140
    141	struct {
    142		u8 cc_planes:3;
    143		u8 packed_aux_planes:4;
    144		u8 planar_aux_planes:4;
    145	} ccs;
    146};
    147
    148#define INTEL_PLANE_CAP_CCS_MASK	(INTEL_PLANE_CAP_CCS_RC | \
    149					 INTEL_PLANE_CAP_CCS_RC_CC | \
    150					 INTEL_PLANE_CAP_CCS_MC)
    151#define INTEL_PLANE_CAP_TILING_MASK	(INTEL_PLANE_CAP_TILING_X | \
    152					 INTEL_PLANE_CAP_TILING_Y | \
    153					 INTEL_PLANE_CAP_TILING_Yf | \
    154					 INTEL_PLANE_CAP_TILING_4)
    155#define INTEL_PLANE_CAP_TILING_NONE	0
    156
    157static const struct intel_modifier_desc intel_modifiers[] = {
    158	{
    159		.modifier = I915_FORMAT_MOD_4_TILED_DG2_MC_CCS,
    160		.display_ver = { 13, 13 },
    161		.plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_CCS_MC,
    162	}, {
    163		.modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC,
    164		.display_ver = { 13, 13 },
    165		.plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_CCS_RC_CC,
    166
    167		.ccs.cc_planes = BIT(1),
    168
    169		FORMAT_OVERRIDE(gen12_flat_ccs_cc_formats),
    170	}, {
    171		.modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS,
    172		.display_ver = { 13, 13 },
    173		.plane_caps = INTEL_PLANE_CAP_TILING_4 | INTEL_PLANE_CAP_CCS_RC,
    174	}, {
    175		.modifier = I915_FORMAT_MOD_4_TILED,
    176		.display_ver = { 13, 13 },
    177		.plane_caps = INTEL_PLANE_CAP_TILING_4,
    178	}, {
    179		.modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS,
    180		.display_ver = { 12, 13 },
    181		.plane_caps = INTEL_PLANE_CAP_TILING_Y | INTEL_PLANE_CAP_CCS_MC,
    182
    183		.ccs.packed_aux_planes = BIT(1),
    184		.ccs.planar_aux_planes = BIT(2) | BIT(3),
    185
    186		FORMAT_OVERRIDE(gen12_ccs_formats),
    187	}, {
    188		.modifier = I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS,
    189		.display_ver = { 12, 13 },
    190		.plane_caps = INTEL_PLANE_CAP_TILING_Y | INTEL_PLANE_CAP_CCS_RC,
    191
    192		.ccs.packed_aux_planes = BIT(1),
    193
    194		FORMAT_OVERRIDE(gen12_ccs_formats),
    195	}, {
    196		.modifier = I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC,
    197		.display_ver = { 12, 13 },
    198		.plane_caps = INTEL_PLANE_CAP_TILING_Y | INTEL_PLANE_CAP_CCS_RC_CC,
    199
    200		.ccs.cc_planes = BIT(2),
    201		.ccs.packed_aux_planes = BIT(1),
    202
    203		FORMAT_OVERRIDE(gen12_ccs_cc_formats),
    204	}, {
    205		.modifier = I915_FORMAT_MOD_Yf_TILED_CCS,
    206		.display_ver = { 9, 11 },
    207		.plane_caps = INTEL_PLANE_CAP_TILING_Yf | INTEL_PLANE_CAP_CCS_RC,
    208
    209		.ccs.packed_aux_planes = BIT(1),
    210
    211		FORMAT_OVERRIDE(skl_ccs_formats),
    212	}, {
    213		.modifier = I915_FORMAT_MOD_Y_TILED_CCS,
    214		.display_ver = { 9, 11 },
    215		.plane_caps = INTEL_PLANE_CAP_TILING_Y | INTEL_PLANE_CAP_CCS_RC,
    216
    217		.ccs.packed_aux_planes = BIT(1),
    218
    219		FORMAT_OVERRIDE(skl_ccs_formats),
    220	}, {
    221		.modifier = I915_FORMAT_MOD_Yf_TILED,
    222		.display_ver = { 9, 11 },
    223		.plane_caps = INTEL_PLANE_CAP_TILING_Yf,
    224	}, {
    225		.modifier = I915_FORMAT_MOD_Y_TILED,
    226		.display_ver = { 9, 13 },
    227		.plane_caps = INTEL_PLANE_CAP_TILING_Y,
    228	}, {
    229		.modifier = I915_FORMAT_MOD_X_TILED,
    230		.display_ver = DISPLAY_VER_ALL,
    231		.plane_caps = INTEL_PLANE_CAP_TILING_X,
    232	}, {
    233		.modifier = DRM_FORMAT_MOD_LINEAR,
    234		.display_ver = DISPLAY_VER_ALL,
    235	},
    236};
    237
    238static const struct intel_modifier_desc *lookup_modifier_or_null(u64 modifier)
    239{
    240	int i;
    241
    242	for (i = 0; i < ARRAY_SIZE(intel_modifiers); i++)
    243		if (intel_modifiers[i].modifier == modifier)
    244			return &intel_modifiers[i];
    245
    246	return NULL;
    247}
    248
    249static const struct intel_modifier_desc *lookup_modifier(u64 modifier)
    250{
    251	const struct intel_modifier_desc *md = lookup_modifier_or_null(modifier);
    252
    253	if (WARN_ON(!md))
    254		return &intel_modifiers[0];
    255
    256	return md;
    257}
    258
    259static const struct drm_format_info *
    260lookup_format_info(const struct drm_format_info formats[],
    261		   int num_formats, u32 format)
    262{
    263	int i;
    264
    265	for (i = 0; i < num_formats; i++) {
    266		if (formats[i].format == format)
    267			return &formats[i];
    268	}
    269
    270	return NULL;
    271}
    272
    273/**
    274 * intel_fb_get_format_info: Get a modifier specific format information
    275 * @cmd: FB add command structure
    276 *
    277 * Returns:
    278 * Returns the format information for @cmd->pixel_format specific to @cmd->modifier[0],
    279 * or %NULL if the modifier doesn't override the format.
    280 */
    281const struct drm_format_info *
    282intel_fb_get_format_info(const struct drm_mode_fb_cmd2 *cmd)
    283{
    284	const struct intel_modifier_desc *md = lookup_modifier_or_null(cmd->modifier[0]);
    285
    286	if (!md || !md->formats)
    287		return NULL;
    288
    289	return lookup_format_info(md->formats, md->format_count, cmd->pixel_format);
    290}
    291
    292static bool plane_caps_contain_any(u8 caps, u8 mask)
    293{
    294	return caps & mask;
    295}
    296
    297static bool plane_caps_contain_all(u8 caps, u8 mask)
    298{
    299	return (caps & mask) == mask;
    300}
    301
    302/**
    303 * intel_fb_is_ccs_modifier: Check if a modifier is a CCS modifier type
    304 * @modifier: Modifier to check
    305 *
    306 * Returns:
    307 * Returns %true if @modifier is a render, render with color clear or
    308 * media compression modifier.
    309 */
    310bool intel_fb_is_ccs_modifier(u64 modifier)
    311{
    312	return plane_caps_contain_any(lookup_modifier(modifier)->plane_caps,
    313				      INTEL_PLANE_CAP_CCS_MASK);
    314}
    315
    316/**
    317 * intel_fb_is_rc_ccs_cc_modifier: Check if a modifier is an RC CCS CC modifier type
    318 * @modifier: Modifier to check
    319 *
    320 * Returns:
    321 * Returns %true if @modifier is a render with color clear modifier.
    322 */
    323bool intel_fb_is_rc_ccs_cc_modifier(u64 modifier)
    324{
    325	return plane_caps_contain_any(lookup_modifier(modifier)->plane_caps,
    326				      INTEL_PLANE_CAP_CCS_RC_CC);
    327}
    328
    329/**
    330 * intel_fb_is_mc_ccs_modifier: Check if a modifier is an MC CCS modifier type
    331 * @modifier: Modifier to check
    332 *
    333 * Returns:
    334 * Returns %true if @modifier is a media compression modifier.
    335 */
    336bool intel_fb_is_mc_ccs_modifier(u64 modifier)
    337{
    338	return plane_caps_contain_any(lookup_modifier(modifier)->plane_caps,
    339				      INTEL_PLANE_CAP_CCS_MC);
    340}
    341
    342static bool check_modifier_display_ver_range(const struct intel_modifier_desc *md,
    343					     u8 display_ver_from, u8 display_ver_until)
    344{
    345	return md->display_ver.from <= display_ver_until &&
    346		display_ver_from <= md->display_ver.until;
    347}
    348
    349static bool plane_has_modifier(struct drm_i915_private *i915,
    350			       u8 plane_caps,
    351			       const struct intel_modifier_desc *md)
    352{
    353	if (!IS_DISPLAY_VER(i915, md->display_ver.from, md->display_ver.until))
    354		return false;
    355
    356	if (!plane_caps_contain_all(plane_caps, md->plane_caps))
    357		return false;
    358
    359	return true;
    360}
    361
    362/**
    363 * intel_fb_plane_get_modifiers: Get the modifiers for the given platform and plane capabilities
    364 * @i915: i915 device instance
    365 * @plane_caps: capabilities for the plane the modifiers are queried for
    366 *
    367 * Returns:
    368 * Returns the list of modifiers allowed by the @i915 platform and @plane_caps.
    369 * The caller must free the returned buffer.
    370 */
    371u64 *intel_fb_plane_get_modifiers(struct drm_i915_private *i915,
    372				  u8 plane_caps)
    373{
    374	u64 *list, *p;
    375	int count = 1;		/* +1 for invalid modifier terminator */
    376	int i;
    377
    378	for (i = 0; i < ARRAY_SIZE(intel_modifiers); i++) {
    379		if (plane_has_modifier(i915, plane_caps, &intel_modifiers[i]))
    380			count++;
    381	}
    382
    383	list = kmalloc_array(count, sizeof(*list), GFP_KERNEL);
    384	if (drm_WARN_ON(&i915->drm, !list))
    385		return NULL;
    386
    387	p = list;
    388	for (i = 0; i < ARRAY_SIZE(intel_modifiers); i++) {
    389		if (plane_has_modifier(i915, plane_caps, &intel_modifiers[i]))
    390			*p++ = intel_modifiers[i].modifier;
    391	}
    392	*p++ = DRM_FORMAT_MOD_INVALID;
    393
    394	return list;
    395}
    396
    397/**
    398 * intel_fb_plane_supports_modifier: Determine if a modifier is supported by the given plane
    399 * @plane: Plane to check the modifier support for
    400 * @modifier: The modifier to check the support for
    401 *
    402 * Returns:
    403 * %true if the @modifier is supported on @plane.
    404 */
    405bool intel_fb_plane_supports_modifier(struct intel_plane *plane, u64 modifier)
    406{
    407	int i;
    408
    409	for (i = 0; i < plane->base.modifier_count; i++)
    410		if (plane->base.modifiers[i] == modifier)
    411			return true;
    412
    413	return false;
    414}
    415
    416static bool format_is_yuv_semiplanar(const struct intel_modifier_desc *md,
    417				     const struct drm_format_info *info)
    418{
    419	if (!info->is_yuv)
    420		return false;
    421
    422	if (hweight8(md->ccs.planar_aux_planes) == 2)
    423		return info->num_planes == 4;
    424	else
    425		return info->num_planes == 2;
    426}
    427
    428/**
    429 * intel_format_info_is_yuv_semiplanar: Check if the given format is YUV semiplanar
    430 * @info: format to check
    431 * @modifier: modifier used with the format
    432 *
    433 * Returns:
    434 * %true if @info / @modifier is YUV semiplanar.
    435 */
    436bool intel_format_info_is_yuv_semiplanar(const struct drm_format_info *info,
    437					 u64 modifier)
    438{
    439	return format_is_yuv_semiplanar(lookup_modifier(modifier), info);
    440}
    441
    442static u8 ccs_aux_plane_mask(const struct intel_modifier_desc *md,
    443			     const struct drm_format_info *format)
    444{
    445	if (format_is_yuv_semiplanar(md, format))
    446		return md->ccs.planar_aux_planes;
    447	else
    448		return md->ccs.packed_aux_planes;
    449}
    450
    451/**
    452 * intel_fb_is_ccs_aux_plane: Check if a framebuffer color plane is a CCS AUX plane
    453 * @fb: Framebuffer
    454 * @color_plane: color plane index to check
    455 *
    456 * Returns:
    457 * Returns %true if @fb's color plane at index @color_plane is a CCS AUX plane.
    458 */
    459bool intel_fb_is_ccs_aux_plane(const struct drm_framebuffer *fb, int color_plane)
    460{
    461	const struct intel_modifier_desc *md = lookup_modifier(fb->modifier);
    462
    463	return ccs_aux_plane_mask(md, fb->format) & BIT(color_plane);
    464}
    465
    466/**
    467 * intel_fb_is_gen12_ccs_aux_plane: Check if a framebuffer color plane is a GEN12 CCS AUX plane
    468 * @fb: Framebuffer
    469 * @color_plane: color plane index to check
    470 *
    471 * Returns:
    472 * Returns %true if @fb's color plane at index @color_plane is a GEN12 CCS AUX plane.
    473 */
    474static bool intel_fb_is_gen12_ccs_aux_plane(const struct drm_framebuffer *fb, int color_plane)
    475{
    476	const struct intel_modifier_desc *md = lookup_modifier(fb->modifier);
    477
    478	return check_modifier_display_ver_range(md, 12, 13) &&
    479	       ccs_aux_plane_mask(md, fb->format) & BIT(color_plane);
    480}
    481
    482/**
    483 * intel_fb_rc_ccs_cc_plane: Get the CCS CC color plane index for a framebuffer
    484 * @fb: Framebuffer
    485 *
    486 * Returns:
    487 * Returns the index of the color clear plane for @fb, or -1 if @fb is not a
    488 * framebuffer using a render compression/color clear modifier.
    489 */
    490int intel_fb_rc_ccs_cc_plane(const struct drm_framebuffer *fb)
    491{
    492	const struct intel_modifier_desc *md = lookup_modifier(fb->modifier);
    493
    494	if (!md->ccs.cc_planes)
    495		return -1;
    496
    497	drm_WARN_ON_ONCE(fb->dev, hweight8(md->ccs.cc_planes) > 1);
    498
    499	return ilog2((int)md->ccs.cc_planes);
    500}
    501
    502static bool is_gen12_ccs_cc_plane(const struct drm_framebuffer *fb, int color_plane)
    503{
    504	return intel_fb_rc_ccs_cc_plane(fb) == color_plane;
    505}
    506
    507static bool is_semiplanar_uv_plane(const struct drm_framebuffer *fb, int color_plane)
    508{
    509	return intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) &&
    510		color_plane == 1;
    511}
    512
    513bool is_surface_linear(const struct drm_framebuffer *fb, int color_plane)
    514{
    515	return fb->modifier == DRM_FORMAT_MOD_LINEAR ||
    516	       intel_fb_is_gen12_ccs_aux_plane(fb, color_plane) ||
    517	       is_gen12_ccs_cc_plane(fb, color_plane);
    518}
    519
    520int main_to_ccs_plane(const struct drm_framebuffer *fb, int main_plane)
    521{
    522	drm_WARN_ON(fb->dev, !intel_fb_is_ccs_modifier(fb->modifier) ||
    523		    (main_plane && main_plane >= fb->format->num_planes / 2));
    524
    525	return fb->format->num_planes / 2 + main_plane;
    526}
    527
    528int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane)
    529{
    530	drm_WARN_ON(fb->dev, !intel_fb_is_ccs_modifier(fb->modifier) ||
    531		    ccs_plane < fb->format->num_planes / 2);
    532
    533	if (is_gen12_ccs_cc_plane(fb, ccs_plane))
    534		return 0;
    535
    536	return ccs_plane - fb->format->num_planes / 2;
    537}
    538
    539static unsigned int gen12_ccs_aux_stride(struct intel_framebuffer *fb, int ccs_plane)
    540{
    541	int main_plane = skl_ccs_to_main_plane(&fb->base, ccs_plane);
    542	unsigned int main_stride = fb->base.pitches[main_plane];
    543	unsigned int main_tile_width = intel_tile_width_bytes(&fb->base, main_plane);
    544
    545	return DIV_ROUND_UP(main_stride, 4 * main_tile_width) * 64;
    546}
    547
    548int skl_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane)
    549{
    550	const struct intel_modifier_desc *md = lookup_modifier(fb->modifier);
    551	struct drm_i915_private *i915 = to_i915(fb->dev);
    552
    553	if (md->ccs.packed_aux_planes | md->ccs.planar_aux_planes)
    554		return main_to_ccs_plane(fb, main_plane);
    555	else if (DISPLAY_VER(i915) < 11 &&
    556		 format_is_yuv_semiplanar(md, fb->format))
    557		return 1;
    558	else
    559		return 0;
    560}
    561
    562unsigned int intel_tile_size(const struct drm_i915_private *i915)
    563{
    564	return DISPLAY_VER(i915) == 2 ? 2048 : 4096;
    565}
    566
    567unsigned int
    568intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
    569{
    570	struct drm_i915_private *dev_priv = to_i915(fb->dev);
    571	unsigned int cpp = fb->format->cpp[color_plane];
    572
    573	switch (fb->modifier) {
    574	case DRM_FORMAT_MOD_LINEAR:
    575		return intel_tile_size(dev_priv);
    576	case I915_FORMAT_MOD_X_TILED:
    577		if (DISPLAY_VER(dev_priv) == 2)
    578			return 128;
    579		else
    580			return 512;
    581	case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS:
    582	case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC:
    583	case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS:
    584	case I915_FORMAT_MOD_4_TILED:
    585		/*
    586		 * Each 4K tile consists of 64B(8*8) subtiles, with
    587		 * same shape as Y Tile(i.e 4*16B OWords)
    588		 */
    589		return 128;
    590	case I915_FORMAT_MOD_Y_TILED_CCS:
    591		if (intel_fb_is_ccs_aux_plane(fb, color_plane))
    592			return 128;
    593		fallthrough;
    594	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
    595	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
    596	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
    597		if (intel_fb_is_ccs_aux_plane(fb, color_plane) ||
    598		    is_gen12_ccs_cc_plane(fb, color_plane))
    599			return 64;
    600		fallthrough;
    601	case I915_FORMAT_MOD_Y_TILED:
    602		if (DISPLAY_VER(dev_priv) == 2 || HAS_128_BYTE_Y_TILING(dev_priv))
    603			return 128;
    604		else
    605			return 512;
    606	case I915_FORMAT_MOD_Yf_TILED_CCS:
    607		if (intel_fb_is_ccs_aux_plane(fb, color_plane))
    608			return 128;
    609		fallthrough;
    610	case I915_FORMAT_MOD_Yf_TILED:
    611		switch (cpp) {
    612		case 1:
    613			return 64;
    614		case 2:
    615		case 4:
    616			return 128;
    617		case 8:
    618		case 16:
    619			return 256;
    620		default:
    621			MISSING_CASE(cpp);
    622			return cpp;
    623		}
    624		break;
    625	default:
    626		MISSING_CASE(fb->modifier);
    627		return cpp;
    628	}
    629}
    630
    631unsigned int intel_tile_height(const struct drm_framebuffer *fb, int color_plane)
    632{
    633	return intel_tile_size(to_i915(fb->dev)) /
    634		intel_tile_width_bytes(fb, color_plane);
    635}
    636
    637/*
    638 * Return the tile dimensions in pixel units, based on the (2 or 4 kbyte) GTT
    639 * page tile size.
    640 */
    641static void intel_tile_dims(const struct drm_framebuffer *fb, int color_plane,
    642			    unsigned int *tile_width,
    643			    unsigned int *tile_height)
    644{
    645	unsigned int tile_width_bytes = intel_tile_width_bytes(fb, color_plane);
    646	unsigned int cpp = fb->format->cpp[color_plane];
    647
    648	*tile_width = tile_width_bytes / cpp;
    649	*tile_height = intel_tile_height(fb, color_plane);
    650}
    651
    652/*
    653 * Return the tile dimensions in pixel units, based on the tile block size.
    654 * The block covers the full GTT page sized tile on all tiled surfaces and
    655 * it's a 64 byte portion of the tile on TGL+ CCS surfaces.
    656 */
    657static void intel_tile_block_dims(const struct drm_framebuffer *fb, int color_plane,
    658				  unsigned int *tile_width,
    659				  unsigned int *tile_height)
    660{
    661	intel_tile_dims(fb, color_plane, tile_width, tile_height);
    662
    663	if (intel_fb_is_gen12_ccs_aux_plane(fb, color_plane))
    664		*tile_height = 1;
    665}
    666
    667unsigned int intel_tile_row_size(const struct drm_framebuffer *fb, int color_plane)
    668{
    669	unsigned int tile_width, tile_height;
    670
    671	intel_tile_dims(fb, color_plane, &tile_width, &tile_height);
    672
    673	return fb->pitches[color_plane] * tile_height;
    674}
    675
    676unsigned int
    677intel_fb_align_height(const struct drm_framebuffer *fb,
    678		      int color_plane, unsigned int height)
    679{
    680	unsigned int tile_height = intel_tile_height(fb, color_plane);
    681
    682	return ALIGN(height, tile_height);
    683}
    684
    685static unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier)
    686{
    687	u8 tiling_caps = lookup_modifier(fb_modifier)->plane_caps &
    688			 INTEL_PLANE_CAP_TILING_MASK;
    689
    690	switch (tiling_caps) {
    691	case INTEL_PLANE_CAP_TILING_Y:
    692		return I915_TILING_Y;
    693	case INTEL_PLANE_CAP_TILING_X:
    694		return I915_TILING_X;
    695	case INTEL_PLANE_CAP_TILING_4:
    696	case INTEL_PLANE_CAP_TILING_Yf:
    697	case INTEL_PLANE_CAP_TILING_NONE:
    698		return I915_TILING_NONE;
    699	default:
    700		MISSING_CASE(tiling_caps);
    701		return I915_TILING_NONE;
    702	}
    703}
    704
    705static bool intel_modifier_uses_dpt(struct drm_i915_private *i915, u64 modifier)
    706{
    707	return DISPLAY_VER(i915) >= 13 && modifier != DRM_FORMAT_MOD_LINEAR;
    708}
    709
    710bool intel_fb_uses_dpt(const struct drm_framebuffer *fb)
    711{
    712	return fb && intel_modifier_uses_dpt(to_i915(fb->dev), fb->modifier);
    713}
    714
    715unsigned int intel_cursor_alignment(const struct drm_i915_private *i915)
    716{
    717	if (IS_I830(i915))
    718		return 16 * 1024;
    719	else if (IS_I85X(i915))
    720		return 256;
    721	else if (IS_I845G(i915) || IS_I865G(i915))
    722		return 32;
    723	else
    724		return 4 * 1024;
    725}
    726
    727static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_priv)
    728{
    729	if (DISPLAY_VER(dev_priv) >= 9)
    730		return 256 * 1024;
    731	else if (IS_I965G(dev_priv) || IS_I965GM(dev_priv) ||
    732		 IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
    733		return 128 * 1024;
    734	else if (DISPLAY_VER(dev_priv) >= 4)
    735		return 4 * 1024;
    736	else
    737		return 0;
    738}
    739
    740unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
    741				  int color_plane)
    742{
    743	struct drm_i915_private *dev_priv = to_i915(fb->dev);
    744
    745	if (intel_fb_uses_dpt(fb))
    746		return 512 * 4096;
    747
    748	/* AUX_DIST needs only 4K alignment */
    749	if (intel_fb_is_ccs_aux_plane(fb, color_plane))
    750		return 4096;
    751
    752	if (is_semiplanar_uv_plane(fb, color_plane)) {
    753		/*
    754		 * TODO: cross-check wrt. the bspec stride in bytes * 64 bytes
    755		 * alignment for linear UV planes on all platforms.
    756		 */
    757		if (DISPLAY_VER(dev_priv) >= 12) {
    758			if (fb->modifier == DRM_FORMAT_MOD_LINEAR)
    759				return intel_linear_alignment(dev_priv);
    760
    761			return intel_tile_row_size(fb, color_plane);
    762		}
    763
    764		return 4096;
    765	}
    766
    767	drm_WARN_ON(&dev_priv->drm, color_plane != 0);
    768
    769	switch (fb->modifier) {
    770	case DRM_FORMAT_MOD_LINEAR:
    771		return intel_linear_alignment(dev_priv);
    772	case I915_FORMAT_MOD_X_TILED:
    773		if (HAS_ASYNC_FLIPS(dev_priv))
    774			return 256 * 1024;
    775		return 0;
    776	case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
    777	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
    778	case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
    779		return 16 * 1024;
    780	case I915_FORMAT_MOD_Y_TILED_CCS:
    781	case I915_FORMAT_MOD_Yf_TILED_CCS:
    782	case I915_FORMAT_MOD_Y_TILED:
    783	case I915_FORMAT_MOD_4_TILED:
    784	case I915_FORMAT_MOD_Yf_TILED:
    785		return 1 * 1024 * 1024;
    786	case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS:
    787	case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC:
    788	case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS:
    789		return 16 * 1024;
    790	default:
    791		MISSING_CASE(fb->modifier);
    792		return 0;
    793	}
    794}
    795
    796void intel_fb_plane_get_subsampling(int *hsub, int *vsub,
    797				    const struct drm_framebuffer *fb,
    798				    int color_plane)
    799{
    800	int main_plane;
    801
    802	if (color_plane == 0) {
    803		*hsub = 1;
    804		*vsub = 1;
    805
    806		return;
    807	}
    808
    809	/*
    810	 * TODO: Deduct the subsampling from the char block for all CCS
    811	 * formats and planes.
    812	 */
    813	if (!intel_fb_is_gen12_ccs_aux_plane(fb, color_plane)) {
    814		*hsub = fb->format->hsub;
    815		*vsub = fb->format->vsub;
    816
    817		return;
    818	}
    819
    820	main_plane = skl_ccs_to_main_plane(fb, color_plane);
    821	*hsub = drm_format_info_block_width(fb->format, color_plane) /
    822		drm_format_info_block_width(fb->format, main_plane);
    823
    824	/*
    825	 * The min stride check in the core framebuffer_check() function
    826	 * assumes that format->hsub applies to every plane except for the
    827	 * first plane. That's incorrect for the CCS AUX plane of the first
    828	 * plane, but for the above check to pass we must define the block
    829	 * width with that subsampling applied to it. Adjust the width here
    830	 * accordingly, so we can calculate the actual subsampling factor.
    831	 */
    832	if (main_plane == 0)
    833		*hsub *= fb->format->hsub;
    834
    835	*vsub = 32;
    836}
    837
    838static void intel_fb_plane_dims(const struct intel_framebuffer *fb, int color_plane, int *w, int *h)
    839{
    840	int main_plane = intel_fb_is_ccs_aux_plane(&fb->base, color_plane) ?
    841			 skl_ccs_to_main_plane(&fb->base, color_plane) : 0;
    842	unsigned int main_width = fb->base.width;
    843	unsigned int main_height = fb->base.height;
    844	int main_hsub, main_vsub;
    845	int hsub, vsub;
    846
    847	intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, &fb->base, main_plane);
    848	intel_fb_plane_get_subsampling(&hsub, &vsub, &fb->base, color_plane);
    849
    850	*w = DIV_ROUND_UP(main_width, main_hsub * hsub);
    851	*h = DIV_ROUND_UP(main_height, main_vsub * vsub);
    852}
    853
    854static u32 intel_adjust_tile_offset(int *x, int *y,
    855				    unsigned int tile_width,
    856				    unsigned int tile_height,
    857				    unsigned int tile_size,
    858				    unsigned int pitch_tiles,
    859				    u32 old_offset,
    860				    u32 new_offset)
    861{
    862	unsigned int pitch_pixels = pitch_tiles * tile_width;
    863	unsigned int tiles;
    864
    865	WARN_ON(old_offset & (tile_size - 1));
    866	WARN_ON(new_offset & (tile_size - 1));
    867	WARN_ON(new_offset > old_offset);
    868
    869	tiles = (old_offset - new_offset) / tile_size;
    870
    871	*y += tiles / pitch_tiles * tile_height;
    872	*x += tiles % pitch_tiles * tile_width;
    873
    874	/* minimize x in case it got needlessly big */
    875	*y += *x / pitch_pixels * tile_height;
    876	*x %= pitch_pixels;
    877
    878	return new_offset;
    879}
    880
    881static u32 intel_adjust_linear_offset(int *x, int *y,
    882				      unsigned int cpp,
    883				      unsigned int pitch,
    884				      u32 old_offset,
    885				      u32 new_offset)
    886{
    887	old_offset += *y * pitch + *x * cpp;
    888
    889	*y = (old_offset - new_offset) / pitch;
    890	*x = ((old_offset - new_offset) - *y * pitch) / cpp;
    891
    892	return new_offset;
    893}
    894
    895static u32 intel_adjust_aligned_offset(int *x, int *y,
    896				       const struct drm_framebuffer *fb,
    897				       int color_plane,
    898				       unsigned int rotation,
    899				       unsigned int pitch,
    900				       u32 old_offset, u32 new_offset)
    901{
    902	struct drm_i915_private *i915 = to_i915(fb->dev);
    903	unsigned int cpp = fb->format->cpp[color_plane];
    904
    905	drm_WARN_ON(&i915->drm, new_offset > old_offset);
    906
    907	if (!is_surface_linear(fb, color_plane)) {
    908		unsigned int tile_size, tile_width, tile_height;
    909		unsigned int pitch_tiles;
    910
    911		tile_size = intel_tile_size(i915);
    912		intel_tile_dims(fb, color_plane, &tile_width, &tile_height);
    913
    914		if (drm_rotation_90_or_270(rotation)) {
    915			pitch_tiles = pitch / tile_height;
    916			swap(tile_width, tile_height);
    917		} else {
    918			pitch_tiles = pitch / (tile_width * cpp);
    919		}
    920
    921		intel_adjust_tile_offset(x, y, tile_width, tile_height,
    922					 tile_size, pitch_tiles,
    923					 old_offset, new_offset);
    924	} else {
    925		intel_adjust_linear_offset(x, y, cpp, pitch,
    926					   old_offset, new_offset);
    927	}
    928
    929	return new_offset;
    930}
    931
    932/*
    933 * Adjust the tile offset by moving the difference into
    934 * the x/y offsets.
    935 */
    936u32 intel_plane_adjust_aligned_offset(int *x, int *y,
    937				      const struct intel_plane_state *state,
    938				      int color_plane,
    939				      u32 old_offset, u32 new_offset)
    940{
    941	return intel_adjust_aligned_offset(x, y, state->hw.fb, color_plane,
    942					   state->hw.rotation,
    943					   state->view.color_plane[color_plane].mapping_stride,
    944					   old_offset, new_offset);
    945}
    946
    947/*
    948 * Computes the aligned offset to the base tile and adjusts
    949 * x, y. bytes per pixel is assumed to be a power-of-two.
    950 *
    951 * In the 90/270 rotated case, x and y are assumed
    952 * to be already rotated to match the rotated GTT view, and
    953 * pitch is the tile_height aligned framebuffer height.
    954 *
    955 * This function is used when computing the derived information
    956 * under intel_framebuffer, so using any of that information
    957 * here is not allowed. Anything under drm_framebuffer can be
    958 * used. This is why the user has to pass in the pitch since it
    959 * is specified in the rotated orientation.
    960 */
    961static u32 intel_compute_aligned_offset(struct drm_i915_private *i915,
    962					int *x, int *y,
    963					const struct drm_framebuffer *fb,
    964					int color_plane,
    965					unsigned int pitch,
    966					unsigned int rotation,
    967					u32 alignment)
    968{
    969	unsigned int cpp = fb->format->cpp[color_plane];
    970	u32 offset, offset_aligned;
    971
    972	if (!is_surface_linear(fb, color_plane)) {
    973		unsigned int tile_size, tile_width, tile_height;
    974		unsigned int tile_rows, tiles, pitch_tiles;
    975
    976		tile_size = intel_tile_size(i915);
    977		intel_tile_dims(fb, color_plane, &tile_width, &tile_height);
    978
    979		if (drm_rotation_90_or_270(rotation)) {
    980			pitch_tiles = pitch / tile_height;
    981			swap(tile_width, tile_height);
    982		} else {
    983			pitch_tiles = pitch / (tile_width * cpp);
    984		}
    985
    986		tile_rows = *y / tile_height;
    987		*y %= tile_height;
    988
    989		tiles = *x / tile_width;
    990		*x %= tile_width;
    991
    992		offset = (tile_rows * pitch_tiles + tiles) * tile_size;
    993
    994		offset_aligned = offset;
    995		if (alignment)
    996			offset_aligned = rounddown(offset_aligned, alignment);
    997
    998		intel_adjust_tile_offset(x, y, tile_width, tile_height,
    999					 tile_size, pitch_tiles,
   1000					 offset, offset_aligned);
   1001	} else {
   1002		offset = *y * pitch + *x * cpp;
   1003		offset_aligned = offset;
   1004		if (alignment) {
   1005			offset_aligned = rounddown(offset_aligned, alignment);
   1006			*y = (offset % alignment) / pitch;
   1007			*x = ((offset % alignment) - *y * pitch) / cpp;
   1008		} else {
   1009			*y = *x = 0;
   1010		}
   1011	}
   1012
   1013	return offset_aligned;
   1014}
   1015
   1016u32 intel_plane_compute_aligned_offset(int *x, int *y,
   1017				       const struct intel_plane_state *state,
   1018				       int color_plane)
   1019{
   1020	struct intel_plane *intel_plane = to_intel_plane(state->uapi.plane);
   1021	struct drm_i915_private *i915 = to_i915(intel_plane->base.dev);
   1022	const struct drm_framebuffer *fb = state->hw.fb;
   1023	unsigned int rotation = state->hw.rotation;
   1024	int pitch = state->view.color_plane[color_plane].mapping_stride;
   1025	u32 alignment;
   1026
   1027	if (intel_plane->id == PLANE_CURSOR)
   1028		alignment = intel_cursor_alignment(i915);
   1029	else
   1030		alignment = intel_surf_alignment(fb, color_plane);
   1031
   1032	return intel_compute_aligned_offset(i915, x, y, fb, color_plane,
   1033					    pitch, rotation, alignment);
   1034}
   1035
   1036/* Convert the fb->offset[] into x/y offsets */
   1037static int intel_fb_offset_to_xy(int *x, int *y,
   1038				 const struct drm_framebuffer *fb,
   1039				 int color_plane)
   1040{
   1041	struct drm_i915_private *i915 = to_i915(fb->dev);
   1042	unsigned int height;
   1043	u32 alignment;
   1044
   1045	if (DISPLAY_VER(i915) >= 12 &&
   1046	    !intel_fb_needs_pot_stride_remap(to_intel_framebuffer(fb)) &&
   1047	    is_semiplanar_uv_plane(fb, color_plane))
   1048		alignment = intel_tile_row_size(fb, color_plane);
   1049	else if (fb->modifier != DRM_FORMAT_MOD_LINEAR)
   1050		alignment = intel_tile_size(i915);
   1051	else
   1052		alignment = 0;
   1053
   1054	if (alignment != 0 && fb->offsets[color_plane] % alignment) {
   1055		drm_dbg_kms(&i915->drm,
   1056			    "Misaligned offset 0x%08x for color plane %d\n",
   1057			    fb->offsets[color_plane], color_plane);
   1058		return -EINVAL;
   1059	}
   1060
   1061	height = drm_framebuffer_plane_height(fb->height, fb, color_plane);
   1062	height = ALIGN(height, intel_tile_height(fb, color_plane));
   1063
   1064	/* Catch potential overflows early */
   1065	if (add_overflows_t(u32, mul_u32_u32(height, fb->pitches[color_plane]),
   1066			    fb->offsets[color_plane])) {
   1067		drm_dbg_kms(&i915->drm,
   1068			    "Bad offset 0x%08x or pitch %d for color plane %d\n",
   1069			    fb->offsets[color_plane], fb->pitches[color_plane],
   1070			    color_plane);
   1071		return -ERANGE;
   1072	}
   1073
   1074	*x = 0;
   1075	*y = 0;
   1076
   1077	intel_adjust_aligned_offset(x, y,
   1078				    fb, color_plane, DRM_MODE_ROTATE_0,
   1079				    fb->pitches[color_plane],
   1080				    fb->offsets[color_plane], 0);
   1081
   1082	return 0;
   1083}
   1084
   1085static int intel_fb_check_ccs_xy(const struct drm_framebuffer *fb, int ccs_plane, int x, int y)
   1086{
   1087	struct drm_i915_private *i915 = to_i915(fb->dev);
   1088	const struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
   1089	int main_plane;
   1090	int hsub, vsub;
   1091	int tile_width, tile_height;
   1092	int ccs_x, ccs_y;
   1093	int main_x, main_y;
   1094
   1095	if (!intel_fb_is_ccs_aux_plane(fb, ccs_plane))
   1096		return 0;
   1097
   1098	/*
   1099	 * While all the tile dimensions are based on a 2k or 4k GTT page size
   1100	 * here the main and CCS coordinates must match only within a (64 byte
   1101	 * on TGL+) block inside the tile.
   1102	 */
   1103	intel_tile_block_dims(fb, ccs_plane, &tile_width, &tile_height);
   1104	intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane);
   1105
   1106	tile_width *= hsub;
   1107	tile_height *= vsub;
   1108
   1109	ccs_x = (x * hsub) % tile_width;
   1110	ccs_y = (y * vsub) % tile_height;
   1111
   1112	main_plane = skl_ccs_to_main_plane(fb, ccs_plane);
   1113	main_x = intel_fb->normal_view.color_plane[main_plane].x % tile_width;
   1114	main_y = intel_fb->normal_view.color_plane[main_plane].y % tile_height;
   1115
   1116	/*
   1117	 * CCS doesn't have its own x/y offset register, so the intra CCS tile
   1118	 * x/y offsets must match between CCS and the main surface.
   1119	 */
   1120	if (main_x != ccs_x || main_y != ccs_y) {
   1121		drm_dbg_kms(&i915->drm,
   1122			      "Bad CCS x/y (main %d,%d ccs %d,%d) full (main %d,%d ccs %d,%d)\n",
   1123			      main_x, main_y,
   1124			      ccs_x, ccs_y,
   1125			      intel_fb->normal_view.color_plane[main_plane].x,
   1126			      intel_fb->normal_view.color_plane[main_plane].y,
   1127			      x, y);
   1128		return -EINVAL;
   1129	}
   1130
   1131	return 0;
   1132}
   1133
   1134static bool intel_plane_can_remap(const struct intel_plane_state *plane_state)
   1135{
   1136	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
   1137	struct drm_i915_private *i915 = to_i915(plane->base.dev);
   1138	const struct drm_framebuffer *fb = plane_state->hw.fb;
   1139	int i;
   1140
   1141	/* We don't want to deal with remapping with cursors */
   1142	if (plane->id == PLANE_CURSOR)
   1143		return false;
   1144
   1145	/*
   1146	 * The display engine limits already match/exceed the
   1147	 * render engine limits, so not much point in remapping.
   1148	 * Would also need to deal with the fence POT alignment
   1149	 * and gen2 2KiB GTT tile size.
   1150	 */
   1151	if (DISPLAY_VER(i915) < 4)
   1152		return false;
   1153
   1154	/*
   1155	 * The new CCS hash mode isn't compatible with remapping as
   1156	 * the virtual address of the pages affects the compressed data.
   1157	 */
   1158	if (intel_fb_is_ccs_modifier(fb->modifier))
   1159		return false;
   1160
   1161	/* Linear needs a page aligned stride for remapping */
   1162	if (fb->modifier == DRM_FORMAT_MOD_LINEAR) {
   1163		unsigned int alignment = intel_tile_size(i915) - 1;
   1164
   1165		for (i = 0; i < fb->format->num_planes; i++) {
   1166			if (fb->pitches[i] & alignment)
   1167				return false;
   1168		}
   1169	}
   1170
   1171	return true;
   1172}
   1173
   1174bool intel_fb_needs_pot_stride_remap(const struct intel_framebuffer *fb)
   1175{
   1176	struct drm_i915_private *i915 = to_i915(fb->base.dev);
   1177
   1178	return IS_ALDERLAKE_P(i915) && fb->base.modifier != DRM_FORMAT_MOD_LINEAR;
   1179}
   1180
   1181static int intel_fb_pitch(const struct intel_framebuffer *fb, int color_plane, unsigned int rotation)
   1182{
   1183	if (drm_rotation_90_or_270(rotation))
   1184		return fb->rotated_view.color_plane[color_plane].mapping_stride;
   1185	else if (intel_fb_needs_pot_stride_remap(fb))
   1186		return fb->remapped_view.color_plane[color_plane].mapping_stride;
   1187	else
   1188		return fb->normal_view.color_plane[color_plane].mapping_stride;
   1189}
   1190
   1191static bool intel_plane_needs_remap(const struct intel_plane_state *plane_state)
   1192{
   1193	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
   1194	const struct intel_framebuffer *fb = to_intel_framebuffer(plane_state->hw.fb);
   1195	unsigned int rotation = plane_state->hw.rotation;
   1196	u32 stride, max_stride;
   1197
   1198	/*
   1199	 * No remapping for invisible planes since we don't have
   1200	 * an actual source viewport to remap.
   1201	 */
   1202	if (!plane_state->uapi.visible)
   1203		return false;
   1204
   1205	if (!intel_plane_can_remap(plane_state))
   1206		return false;
   1207
   1208	/*
   1209	 * FIXME: aux plane limits on gen9+ are
   1210	 * unclear in Bspec, for now no checking.
   1211	 */
   1212	stride = intel_fb_pitch(fb, 0, rotation);
   1213	max_stride = plane->max_stride(plane, fb->base.format->format,
   1214				       fb->base.modifier, rotation);
   1215
   1216	return stride > max_stride;
   1217}
   1218
   1219static int convert_plane_offset_to_xy(const struct intel_framebuffer *fb, int color_plane,
   1220				      int plane_width, int *x, int *y)
   1221{
   1222	struct drm_i915_gem_object *obj = intel_fb_obj(&fb->base);
   1223	int ret;
   1224
   1225	ret = intel_fb_offset_to_xy(x, y, &fb->base, color_plane);
   1226	if (ret) {
   1227		drm_dbg_kms(fb->base.dev,
   1228			    "bad fb plane %d offset: 0x%x\n",
   1229			    color_plane, fb->base.offsets[color_plane]);
   1230		return ret;
   1231	}
   1232
   1233	ret = intel_fb_check_ccs_xy(&fb->base, color_plane, *x, *y);
   1234	if (ret)
   1235		return ret;
   1236
   1237	/*
   1238	 * The fence (if used) is aligned to the start of the object
   1239	 * so having the framebuffer wrap around across the edge of the
   1240	 * fenced region doesn't really work. We have no API to configure
   1241	 * the fence start offset within the object (nor could we probably
   1242	 * on gen2/3). So it's just easier if we just require that the
   1243	 * fb layout agrees with the fence layout. We already check that the
   1244	 * fb stride matches the fence stride elsewhere.
   1245	 */
   1246	if (color_plane == 0 && i915_gem_object_is_tiled(obj) &&
   1247	    (*x + plane_width) * fb->base.format->cpp[color_plane] > fb->base.pitches[color_plane]) {
   1248		drm_dbg_kms(fb->base.dev,
   1249			    "bad fb plane %d offset: 0x%x\n",
   1250			    color_plane, fb->base.offsets[color_plane]);
   1251		return -EINVAL;
   1252	}
   1253
   1254	return 0;
   1255}
   1256
   1257static u32 calc_plane_aligned_offset(const struct intel_framebuffer *fb, int color_plane, int *x, int *y)
   1258{
   1259	struct drm_i915_private *i915 = to_i915(fb->base.dev);
   1260	unsigned int tile_size = intel_tile_size(i915);
   1261	u32 offset;
   1262
   1263	offset = intel_compute_aligned_offset(i915, x, y, &fb->base, color_plane,
   1264					      fb->base.pitches[color_plane],
   1265					      DRM_MODE_ROTATE_0,
   1266					      tile_size);
   1267
   1268	return offset / tile_size;
   1269}
   1270
   1271struct fb_plane_view_dims {
   1272	unsigned int width, height;
   1273	unsigned int tile_width, tile_height;
   1274};
   1275
   1276static void init_plane_view_dims(const struct intel_framebuffer *fb, int color_plane,
   1277				 unsigned int width, unsigned int height,
   1278				 struct fb_plane_view_dims *dims)
   1279{
   1280	dims->width = width;
   1281	dims->height = height;
   1282
   1283	intel_tile_dims(&fb->base, color_plane, &dims->tile_width, &dims->tile_height);
   1284}
   1285
   1286static unsigned int
   1287plane_view_src_stride_tiles(const struct intel_framebuffer *fb, int color_plane,
   1288			    const struct fb_plane_view_dims *dims)
   1289{
   1290	return DIV_ROUND_UP(fb->base.pitches[color_plane],
   1291			    dims->tile_width * fb->base.format->cpp[color_plane]);
   1292}
   1293
   1294static unsigned int
   1295plane_view_dst_stride_tiles(const struct intel_framebuffer *fb, int color_plane,
   1296			    unsigned int pitch_tiles)
   1297{
   1298	if (intel_fb_needs_pot_stride_remap(fb)) {
   1299		/*
   1300		 * ADL_P, the only platform needing a POT stride has a minimum
   1301		 * of 8 main surface tiles.
   1302		 */
   1303		return roundup_pow_of_two(max(pitch_tiles, 8u));
   1304	} else {
   1305		return pitch_tiles;
   1306	}
   1307}
   1308
   1309static unsigned int
   1310plane_view_scanout_stride(const struct intel_framebuffer *fb, int color_plane,
   1311			  unsigned int tile_width,
   1312			  unsigned int src_stride_tiles, unsigned int dst_stride_tiles)
   1313{
   1314	unsigned int stride_tiles;
   1315
   1316	if (IS_ALDERLAKE_P(to_i915(fb->base.dev)))
   1317		stride_tiles = src_stride_tiles;
   1318	else
   1319		stride_tiles = dst_stride_tiles;
   1320
   1321	return stride_tiles * tile_width * fb->base.format->cpp[color_plane];
   1322}
   1323
   1324static unsigned int
   1325plane_view_width_tiles(const struct intel_framebuffer *fb, int color_plane,
   1326		       const struct fb_plane_view_dims *dims,
   1327		       int x)
   1328{
   1329	return DIV_ROUND_UP(x + dims->width, dims->tile_width);
   1330}
   1331
   1332static unsigned int
   1333plane_view_height_tiles(const struct intel_framebuffer *fb, int color_plane,
   1334			const struct fb_plane_view_dims *dims,
   1335			int y)
   1336{
   1337	return DIV_ROUND_UP(y + dims->height, dims->tile_height);
   1338}
   1339
   1340static unsigned int
   1341plane_view_linear_tiles(const struct intel_framebuffer *fb, int color_plane,
   1342			const struct fb_plane_view_dims *dims,
   1343			int x, int y)
   1344{
   1345	struct drm_i915_private *i915 = to_i915(fb->base.dev);
   1346	unsigned int size;
   1347
   1348	size = (y + dims->height) * fb->base.pitches[color_plane] +
   1349		x * fb->base.format->cpp[color_plane];
   1350
   1351	return DIV_ROUND_UP(size, intel_tile_size(i915));
   1352}
   1353
   1354#define assign_chk_ovf(i915, var, val) ({ \
   1355	drm_WARN_ON(&(i915)->drm, overflows_type(val, var)); \
   1356	(var) = (val); \
   1357})
   1358
   1359#define assign_bfld_chk_ovf(i915, var, val) ({ \
   1360	(var) = (val); \
   1361	drm_WARN_ON(&(i915)->drm, (var) != (val)); \
   1362	(var); \
   1363})
   1364
   1365static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_plane,
   1366				 const struct fb_plane_view_dims *dims,
   1367				 u32 obj_offset, u32 gtt_offset, int x, int y,
   1368				 struct intel_fb_view *view)
   1369{
   1370	struct drm_i915_private *i915 = to_i915(fb->base.dev);
   1371	struct intel_remapped_plane_info *remap_info = &view->gtt.remapped.plane[color_plane];
   1372	struct i915_color_plane_view *color_plane_info = &view->color_plane[color_plane];
   1373	unsigned int tile_width = dims->tile_width;
   1374	unsigned int tile_height = dims->tile_height;
   1375	unsigned int tile_size = intel_tile_size(i915);
   1376	struct drm_rect r;
   1377	u32 size = 0;
   1378
   1379	assign_bfld_chk_ovf(i915, remap_info->offset, obj_offset);
   1380
   1381	if (intel_fb_is_gen12_ccs_aux_plane(&fb->base, color_plane)) {
   1382		remap_info->linear = 1;
   1383
   1384		assign_chk_ovf(i915, remap_info->size,
   1385			       plane_view_linear_tiles(fb, color_plane, dims, x, y));
   1386	} else {
   1387		remap_info->linear = 0;
   1388
   1389		assign_chk_ovf(i915, remap_info->src_stride,
   1390			       plane_view_src_stride_tiles(fb, color_plane, dims));
   1391		assign_chk_ovf(i915, remap_info->width,
   1392			       plane_view_width_tiles(fb, color_plane, dims, x));
   1393		assign_chk_ovf(i915, remap_info->height,
   1394			       plane_view_height_tiles(fb, color_plane, dims, y));
   1395	}
   1396
   1397	if (view->gtt.type == I915_GGTT_VIEW_ROTATED) {
   1398		drm_WARN_ON(&i915->drm, remap_info->linear);
   1399		check_array_bounds(i915, view->gtt.rotated.plane, color_plane);
   1400
   1401		assign_chk_ovf(i915, remap_info->dst_stride,
   1402			       plane_view_dst_stride_tiles(fb, color_plane, remap_info->height));
   1403
   1404		/* rotate the x/y offsets to match the GTT view */
   1405		drm_rect_init(&r, x, y, dims->width, dims->height);
   1406		drm_rect_rotate(&r,
   1407				remap_info->width * tile_width,
   1408				remap_info->height * tile_height,
   1409				DRM_MODE_ROTATE_270);
   1410
   1411		color_plane_info->x = r.x1;
   1412		color_plane_info->y = r.y1;
   1413
   1414		color_plane_info->mapping_stride = remap_info->dst_stride * tile_height;
   1415		color_plane_info->scanout_stride = color_plane_info->mapping_stride;
   1416
   1417		size += remap_info->dst_stride * remap_info->width;
   1418
   1419		/* rotate the tile dimensions to match the GTT view */
   1420		swap(tile_width, tile_height);
   1421	} else {
   1422		drm_WARN_ON(&i915->drm, view->gtt.type != I915_GGTT_VIEW_REMAPPED);
   1423
   1424		check_array_bounds(i915, view->gtt.remapped.plane, color_plane);
   1425
   1426		if (view->gtt.remapped.plane_alignment) {
   1427			unsigned int aligned_offset = ALIGN(gtt_offset,
   1428							    view->gtt.remapped.plane_alignment);
   1429
   1430			size += aligned_offset - gtt_offset;
   1431			gtt_offset = aligned_offset;
   1432		}
   1433
   1434		color_plane_info->x = x;
   1435		color_plane_info->y = y;
   1436
   1437		if (remap_info->linear) {
   1438			color_plane_info->mapping_stride = fb->base.pitches[color_plane];
   1439			color_plane_info->scanout_stride = color_plane_info->mapping_stride;
   1440
   1441			size += remap_info->size;
   1442		} else {
   1443			unsigned int dst_stride = plane_view_dst_stride_tiles(fb, color_plane,
   1444									      remap_info->width);
   1445
   1446			assign_chk_ovf(i915, remap_info->dst_stride, dst_stride);
   1447			color_plane_info->mapping_stride = dst_stride *
   1448							   tile_width *
   1449							   fb->base.format->cpp[color_plane];
   1450			color_plane_info->scanout_stride =
   1451				plane_view_scanout_stride(fb, color_plane, tile_width,
   1452							  remap_info->src_stride,
   1453							  dst_stride);
   1454
   1455			size += dst_stride * remap_info->height;
   1456		}
   1457	}
   1458
   1459	/*
   1460	 * We only keep the x/y offsets, so push all of the gtt offset into
   1461	 * the x/y offsets.  x,y will hold the first pixel of the framebuffer
   1462	 * plane from the start of the remapped/rotated gtt mapping.
   1463	 */
   1464	if (remap_info->linear)
   1465		intel_adjust_linear_offset(&color_plane_info->x, &color_plane_info->y,
   1466					   fb->base.format->cpp[color_plane],
   1467					   color_plane_info->mapping_stride,
   1468					   gtt_offset * tile_size, 0);
   1469	else
   1470		intel_adjust_tile_offset(&color_plane_info->x, &color_plane_info->y,
   1471					 tile_width, tile_height,
   1472					 tile_size, remap_info->dst_stride,
   1473					 gtt_offset * tile_size, 0);
   1474
   1475	return size;
   1476}
   1477
   1478#undef assign_chk_ovf
   1479
   1480/* Return number of tiles @color_plane needs. */
   1481static unsigned int
   1482calc_plane_normal_size(const struct intel_framebuffer *fb, int color_plane,
   1483		       const struct fb_plane_view_dims *dims,
   1484		       int x, int y)
   1485{
   1486	unsigned int tiles;
   1487
   1488	if (is_surface_linear(&fb->base, color_plane)) {
   1489		tiles = plane_view_linear_tiles(fb, color_plane, dims, x, y);
   1490	} else {
   1491		tiles = plane_view_src_stride_tiles(fb, color_plane, dims) *
   1492			plane_view_height_tiles(fb, color_plane, dims, y);
   1493		/*
   1494		 * If the plane isn't horizontally tile aligned,
   1495		 * we need one more tile.
   1496		 */
   1497		if (x != 0)
   1498			tiles++;
   1499	}
   1500
   1501	return tiles;
   1502}
   1503
   1504static void intel_fb_view_init(struct drm_i915_private *i915, struct intel_fb_view *view,
   1505			       enum i915_ggtt_view_type view_type)
   1506{
   1507	memset(view, 0, sizeof(*view));
   1508	view->gtt.type = view_type;
   1509
   1510	if (view_type == I915_GGTT_VIEW_REMAPPED && IS_ALDERLAKE_P(i915))
   1511		view->gtt.remapped.plane_alignment = SZ_2M / PAGE_SIZE;
   1512}
   1513
   1514bool intel_fb_supports_90_270_rotation(const struct intel_framebuffer *fb)
   1515{
   1516	if (DISPLAY_VER(to_i915(fb->base.dev)) >= 13)
   1517		return false;
   1518
   1519	return fb->base.modifier == I915_FORMAT_MOD_Y_TILED ||
   1520	       fb->base.modifier == I915_FORMAT_MOD_Yf_TILED;
   1521}
   1522
   1523int intel_fill_fb_info(struct drm_i915_private *i915, struct intel_framebuffer *fb)
   1524{
   1525	struct drm_i915_gem_object *obj = intel_fb_obj(&fb->base);
   1526	u32 gtt_offset_rotated = 0;
   1527	u32 gtt_offset_remapped = 0;
   1528	unsigned int max_size = 0;
   1529	int i, num_planes = fb->base.format->num_planes;
   1530	unsigned int tile_size = intel_tile_size(i915);
   1531
   1532	intel_fb_view_init(i915, &fb->normal_view, I915_GGTT_VIEW_NORMAL);
   1533
   1534	drm_WARN_ON(&i915->drm,
   1535		    intel_fb_supports_90_270_rotation(fb) &&
   1536		    intel_fb_needs_pot_stride_remap(fb));
   1537
   1538	if (intel_fb_supports_90_270_rotation(fb))
   1539		intel_fb_view_init(i915, &fb->rotated_view, I915_GGTT_VIEW_ROTATED);
   1540	if (intel_fb_needs_pot_stride_remap(fb))
   1541		intel_fb_view_init(i915, &fb->remapped_view, I915_GGTT_VIEW_REMAPPED);
   1542
   1543	for (i = 0; i < num_planes; i++) {
   1544		struct fb_plane_view_dims view_dims;
   1545		unsigned int width, height;
   1546		unsigned int cpp, size;
   1547		u32 offset;
   1548		int x, y;
   1549		int ret;
   1550
   1551		/*
   1552		 * Plane 2 of Render Compression with Clear Color fb modifier
   1553		 * is consumed by the driver and not passed to DE. Skip the
   1554		 * arithmetic related to alignment and offset calculation.
   1555		 */
   1556		if (is_gen12_ccs_cc_plane(&fb->base, i)) {
   1557			if (IS_ALIGNED(fb->base.offsets[i], PAGE_SIZE))
   1558				continue;
   1559			else
   1560				return -EINVAL;
   1561		}
   1562
   1563		cpp = fb->base.format->cpp[i];
   1564		intel_fb_plane_dims(fb, i, &width, &height);
   1565
   1566		ret = convert_plane_offset_to_xy(fb, i, width, &x, &y);
   1567		if (ret)
   1568			return ret;
   1569
   1570		init_plane_view_dims(fb, i, width, height, &view_dims);
   1571
   1572		/*
   1573		 * First pixel of the framebuffer from
   1574		 * the start of the normal gtt mapping.
   1575		 */
   1576		fb->normal_view.color_plane[i].x = x;
   1577		fb->normal_view.color_plane[i].y = y;
   1578		fb->normal_view.color_plane[i].mapping_stride = fb->base.pitches[i];
   1579		fb->normal_view.color_plane[i].scanout_stride =
   1580			fb->normal_view.color_plane[i].mapping_stride;
   1581
   1582		offset = calc_plane_aligned_offset(fb, i, &x, &y);
   1583
   1584		if (intel_fb_supports_90_270_rotation(fb))
   1585			gtt_offset_rotated += calc_plane_remap_info(fb, i, &view_dims,
   1586								    offset, gtt_offset_rotated, x, y,
   1587								    &fb->rotated_view);
   1588
   1589		if (intel_fb_needs_pot_stride_remap(fb))
   1590			gtt_offset_remapped += calc_plane_remap_info(fb, i, &view_dims,
   1591								     offset, gtt_offset_remapped, x, y,
   1592								     &fb->remapped_view);
   1593
   1594		size = calc_plane_normal_size(fb, i, &view_dims, x, y);
   1595		/* how many tiles in total needed in the bo */
   1596		max_size = max(max_size, offset + size);
   1597	}
   1598
   1599	if (mul_u32_u32(max_size, tile_size) > obj->base.size) {
   1600		drm_dbg_kms(&i915->drm,
   1601			    "fb too big for bo (need %llu bytes, have %zu bytes)\n",
   1602			    mul_u32_u32(max_size, tile_size), obj->base.size);
   1603		return -EINVAL;
   1604	}
   1605
   1606	return 0;
   1607}
   1608
   1609static void intel_plane_remap_gtt(struct intel_plane_state *plane_state)
   1610{
   1611	struct drm_i915_private *i915 =
   1612		to_i915(plane_state->uapi.plane->dev);
   1613	struct drm_framebuffer *fb = plane_state->hw.fb;
   1614	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
   1615	unsigned int rotation = plane_state->hw.rotation;
   1616	int i, num_planes = fb->format->num_planes;
   1617	unsigned int src_x, src_y;
   1618	unsigned int src_w, src_h;
   1619	u32 gtt_offset = 0;
   1620
   1621	intel_fb_view_init(i915, &plane_state->view,
   1622			   drm_rotation_90_or_270(rotation) ? I915_GGTT_VIEW_ROTATED :
   1623							      I915_GGTT_VIEW_REMAPPED);
   1624
   1625	src_x = plane_state->uapi.src.x1 >> 16;
   1626	src_y = plane_state->uapi.src.y1 >> 16;
   1627	src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
   1628	src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
   1629
   1630	drm_WARN_ON(&i915->drm, intel_fb_is_ccs_modifier(fb->modifier));
   1631
   1632	/* Make src coordinates relative to the viewport */
   1633	drm_rect_translate(&plane_state->uapi.src,
   1634			   -(src_x << 16), -(src_y << 16));
   1635
   1636	/* Rotate src coordinates to match rotated GTT view */
   1637	if (drm_rotation_90_or_270(rotation))
   1638		drm_rect_rotate(&plane_state->uapi.src,
   1639				src_w << 16, src_h << 16,
   1640				DRM_MODE_ROTATE_270);
   1641
   1642	for (i = 0; i < num_planes; i++) {
   1643		unsigned int hsub = i ? fb->format->hsub : 1;
   1644		unsigned int vsub = i ? fb->format->vsub : 1;
   1645		struct fb_plane_view_dims view_dims;
   1646		unsigned int width, height;
   1647		unsigned int x, y;
   1648		u32 offset;
   1649
   1650		x = src_x / hsub;
   1651		y = src_y / vsub;
   1652		width = src_w / hsub;
   1653		height = src_h / vsub;
   1654
   1655		init_plane_view_dims(intel_fb, i, width, height, &view_dims);
   1656
   1657		/*
   1658		 * First pixel of the src viewport from the
   1659		 * start of the normal gtt mapping.
   1660		 */
   1661		x += intel_fb->normal_view.color_plane[i].x;
   1662		y += intel_fb->normal_view.color_plane[i].y;
   1663
   1664		offset = calc_plane_aligned_offset(intel_fb, i, &x, &y);
   1665
   1666		gtt_offset += calc_plane_remap_info(intel_fb, i, &view_dims,
   1667						    offset, gtt_offset, x, y,
   1668						    &plane_state->view);
   1669	}
   1670}
   1671
   1672void intel_fb_fill_view(const struct intel_framebuffer *fb, unsigned int rotation,
   1673			struct intel_fb_view *view)
   1674{
   1675	if (drm_rotation_90_or_270(rotation))
   1676		*view = fb->rotated_view;
   1677	else if (intel_fb_needs_pot_stride_remap(fb))
   1678		*view = fb->remapped_view;
   1679	else
   1680		*view = fb->normal_view;
   1681}
   1682
   1683static
   1684u32 intel_fb_max_stride(struct drm_i915_private *dev_priv,
   1685			u32 pixel_format, u64 modifier)
   1686{
   1687	/*
   1688	 * Arbitrary limit for gen4+ chosen to match the
   1689	 * render engine max stride.
   1690	 *
   1691	 * The new CCS hash mode makes remapping impossible
   1692	 */
   1693	if (DISPLAY_VER(dev_priv) < 4 || intel_fb_is_ccs_modifier(modifier) ||
   1694	    intel_modifier_uses_dpt(dev_priv, modifier))
   1695		return intel_plane_fb_max_stride(dev_priv, pixel_format, modifier);
   1696	else if (DISPLAY_VER(dev_priv) >= 7)
   1697		return 256 * 1024;
   1698	else
   1699		return 128 * 1024;
   1700}
   1701
   1702static u32
   1703intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane)
   1704{
   1705	struct drm_i915_private *dev_priv = to_i915(fb->dev);
   1706	u32 tile_width;
   1707
   1708	if (is_surface_linear(fb, color_plane)) {
   1709		u32 max_stride = intel_plane_fb_max_stride(dev_priv,
   1710							   fb->format->format,
   1711							   fb->modifier);
   1712
   1713		/*
   1714		 * To make remapping with linear generally feasible
   1715		 * we need the stride to be page aligned.
   1716		 */
   1717		if (fb->pitches[color_plane] > max_stride &&
   1718		    !intel_fb_is_ccs_modifier(fb->modifier))
   1719			return intel_tile_size(dev_priv);
   1720		else
   1721			return 64;
   1722	}
   1723
   1724	tile_width = intel_tile_width_bytes(fb, color_plane);
   1725	if (intel_fb_is_ccs_modifier(fb->modifier)) {
   1726		/*
   1727		 * On TGL the surface stride must be 4 tile aligned, mapped by
   1728		 * one 64 byte cacheline on the CCS AUX surface.
   1729		 */
   1730		if (DISPLAY_VER(dev_priv) >= 12)
   1731			tile_width *= 4;
   1732		/*
   1733		 * Display WA #0531: skl,bxt,kbl,glk
   1734		 *
   1735		 * Render decompression and plane width > 3840
   1736		 * combined with horizontal panning requires the
   1737		 * plane stride to be a multiple of 4. We'll just
   1738		 * require the entire fb to accommodate that to avoid
   1739		 * potential runtime errors at plane configuration time.
   1740		 */
   1741		else if ((DISPLAY_VER(dev_priv) == 9 || IS_GEMINILAKE(dev_priv)) &&
   1742			 color_plane == 0 && fb->width > 3840)
   1743			tile_width *= 4;
   1744	}
   1745	return tile_width;
   1746}
   1747
   1748static int intel_plane_check_stride(const struct intel_plane_state *plane_state)
   1749{
   1750	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
   1751	const struct drm_framebuffer *fb = plane_state->hw.fb;
   1752	unsigned int rotation = plane_state->hw.rotation;
   1753	u32 stride, max_stride;
   1754
   1755	/*
   1756	 * We ignore stride for all invisible planes that
   1757	 * can be remapped. Otherwise we could end up
   1758	 * with a false positive when the remapping didn't
   1759	 * kick in due the plane being invisible.
   1760	 */
   1761	if (intel_plane_can_remap(plane_state) &&
   1762	    !plane_state->uapi.visible)
   1763		return 0;
   1764
   1765	/* FIXME other color planes? */
   1766	stride = plane_state->view.color_plane[0].mapping_stride;
   1767	max_stride = plane->max_stride(plane, fb->format->format,
   1768				       fb->modifier, rotation);
   1769
   1770	if (stride > max_stride) {
   1771		DRM_DEBUG_KMS("[FB:%d] stride (%d) exceeds [PLANE:%d:%s] max stride (%d)\n",
   1772			      fb->base.id, stride,
   1773			      plane->base.base.id, plane->base.name, max_stride);
   1774		return -EINVAL;
   1775	}
   1776
   1777	return 0;
   1778}
   1779
   1780int intel_plane_compute_gtt(struct intel_plane_state *plane_state)
   1781{
   1782	const struct intel_framebuffer *fb =
   1783		to_intel_framebuffer(plane_state->hw.fb);
   1784	unsigned int rotation = plane_state->hw.rotation;
   1785
   1786	if (!fb)
   1787		return 0;
   1788
   1789	if (intel_plane_needs_remap(plane_state)) {
   1790		intel_plane_remap_gtt(plane_state);
   1791
   1792		/*
   1793		 * Sometimes even remapping can't overcome
   1794		 * the stride limitations :( Can happen with
   1795		 * big plane sizes and suitably misaligned
   1796		 * offsets.
   1797		 */
   1798		return intel_plane_check_stride(plane_state);
   1799	}
   1800
   1801	intel_fb_fill_view(fb, rotation, &plane_state->view);
   1802
   1803	/* Rotate src coordinates to match rotated GTT view */
   1804	if (drm_rotation_90_or_270(rotation))
   1805		drm_rect_rotate(&plane_state->uapi.src,
   1806				fb->base.width << 16, fb->base.height << 16,
   1807				DRM_MODE_ROTATE_270);
   1808
   1809	return intel_plane_check_stride(plane_state);
   1810}
   1811
   1812static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
   1813{
   1814	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
   1815
   1816	drm_framebuffer_cleanup(fb);
   1817
   1818	if (intel_fb_uses_dpt(fb))
   1819		intel_dpt_destroy(intel_fb->dpt_vm);
   1820
   1821	intel_frontbuffer_put(intel_fb->frontbuffer);
   1822
   1823	kfree(intel_fb);
   1824}
   1825
   1826static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb,
   1827						struct drm_file *file,
   1828						unsigned int *handle)
   1829{
   1830	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
   1831	struct drm_i915_private *i915 = to_i915(obj->base.dev);
   1832
   1833	if (i915_gem_object_is_userptr(obj)) {
   1834		drm_dbg(&i915->drm,
   1835			"attempting to use a userptr for a framebuffer, denied\n");
   1836		return -EINVAL;
   1837	}
   1838
   1839	return drm_gem_handle_create(file, &obj->base, handle);
   1840}
   1841
   1842static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb,
   1843					struct drm_file *file,
   1844					unsigned int flags, unsigned int color,
   1845					struct drm_clip_rect *clips,
   1846					unsigned int num_clips)
   1847{
   1848	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
   1849
   1850	i915_gem_object_flush_if_display(obj);
   1851	intel_frontbuffer_flush(to_intel_frontbuffer(fb), ORIGIN_DIRTYFB);
   1852
   1853	return 0;
   1854}
   1855
   1856static const struct drm_framebuffer_funcs intel_fb_funcs = {
   1857	.destroy = intel_user_framebuffer_destroy,
   1858	.create_handle = intel_user_framebuffer_create_handle,
   1859	.dirty = intel_user_framebuffer_dirty,
   1860};
   1861
   1862int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
   1863			   struct drm_i915_gem_object *obj,
   1864			   struct drm_mode_fb_cmd2 *mode_cmd)
   1865{
   1866	struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
   1867	struct drm_framebuffer *fb = &intel_fb->base;
   1868	u32 max_stride;
   1869	unsigned int tiling, stride;
   1870	int ret = -EINVAL;
   1871	int i;
   1872
   1873	intel_fb->frontbuffer = intel_frontbuffer_get(obj);
   1874	if (!intel_fb->frontbuffer)
   1875		return -ENOMEM;
   1876
   1877	i915_gem_object_lock(obj, NULL);
   1878	tiling = i915_gem_object_get_tiling(obj);
   1879	stride = i915_gem_object_get_stride(obj);
   1880	i915_gem_object_unlock(obj);
   1881
   1882	if (mode_cmd->flags & DRM_MODE_FB_MODIFIERS) {
   1883		/*
   1884		 * If there's a fence, enforce that
   1885		 * the fb modifier and tiling mode match.
   1886		 */
   1887		if (tiling != I915_TILING_NONE &&
   1888		    tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) {
   1889			drm_dbg_kms(&dev_priv->drm,
   1890				    "tiling_mode doesn't match fb modifier\n");
   1891			goto err;
   1892		}
   1893	} else {
   1894		if (tiling == I915_TILING_X) {
   1895			mode_cmd->modifier[0] = I915_FORMAT_MOD_X_TILED;
   1896		} else if (tiling == I915_TILING_Y) {
   1897			drm_dbg_kms(&dev_priv->drm,
   1898				    "No Y tiling for legacy addfb\n");
   1899			goto err;
   1900		}
   1901	}
   1902
   1903	if (!drm_any_plane_has_format(&dev_priv->drm,
   1904				      mode_cmd->pixel_format,
   1905				      mode_cmd->modifier[0])) {
   1906		drm_dbg_kms(&dev_priv->drm,
   1907			    "unsupported pixel format %p4cc / modifier 0x%llx\n",
   1908			    &mode_cmd->pixel_format, mode_cmd->modifier[0]);
   1909		goto err;
   1910	}
   1911
   1912	/*
   1913	 * gen2/3 display engine uses the fence if present,
   1914	 * so the tiling mode must match the fb modifier exactly.
   1915	 */
   1916	if (DISPLAY_VER(dev_priv) < 4 &&
   1917	    tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) {
   1918		drm_dbg_kms(&dev_priv->drm,
   1919			    "tiling_mode must match fb modifier exactly on gen2/3\n");
   1920		goto err;
   1921	}
   1922
   1923	max_stride = intel_fb_max_stride(dev_priv, mode_cmd->pixel_format,
   1924					 mode_cmd->modifier[0]);
   1925	if (mode_cmd->pitches[0] > max_stride) {
   1926		drm_dbg_kms(&dev_priv->drm,
   1927			    "%s pitch (%u) must be at most %d\n",
   1928			    mode_cmd->modifier[0] != DRM_FORMAT_MOD_LINEAR ?
   1929			    "tiled" : "linear",
   1930			    mode_cmd->pitches[0], max_stride);
   1931		goto err;
   1932	}
   1933
   1934	/*
   1935	 * If there's a fence, enforce that
   1936	 * the fb pitch and fence stride match.
   1937	 */
   1938	if (tiling != I915_TILING_NONE && mode_cmd->pitches[0] != stride) {
   1939		drm_dbg_kms(&dev_priv->drm,
   1940			    "pitch (%d) must match tiling stride (%d)\n",
   1941			    mode_cmd->pitches[0], stride);
   1942		goto err;
   1943	}
   1944
   1945	/* FIXME need to adjust LINOFF/TILEOFF accordingly. */
   1946	if (mode_cmd->offsets[0] != 0) {
   1947		drm_dbg_kms(&dev_priv->drm,
   1948			    "plane 0 offset (0x%08x) must be 0\n",
   1949			    mode_cmd->offsets[0]);
   1950		goto err;
   1951	}
   1952
   1953	drm_helper_mode_fill_fb_struct(&dev_priv->drm, fb, mode_cmd);
   1954
   1955	for (i = 0; i < fb->format->num_planes; i++) {
   1956		u32 stride_alignment;
   1957
   1958		if (mode_cmd->handles[i] != mode_cmd->handles[0]) {
   1959			drm_dbg_kms(&dev_priv->drm, "bad plane %d handle\n",
   1960				    i);
   1961			goto err;
   1962		}
   1963
   1964		stride_alignment = intel_fb_stride_alignment(fb, i);
   1965		if (fb->pitches[i] & (stride_alignment - 1)) {
   1966			drm_dbg_kms(&dev_priv->drm,
   1967				    "plane %d pitch (%d) must be at least %u byte aligned\n",
   1968				    i, fb->pitches[i], stride_alignment);
   1969			goto err;
   1970		}
   1971
   1972		if (intel_fb_is_gen12_ccs_aux_plane(fb, i)) {
   1973			int ccs_aux_stride = gen12_ccs_aux_stride(intel_fb, i);
   1974
   1975			if (fb->pitches[i] != ccs_aux_stride) {
   1976				drm_dbg_kms(&dev_priv->drm,
   1977					    "ccs aux plane %d pitch (%d) must be %d\n",
   1978					    i,
   1979					    fb->pitches[i], ccs_aux_stride);
   1980				goto err;
   1981			}
   1982		}
   1983
   1984		fb->obj[i] = &obj->base;
   1985	}
   1986
   1987	ret = intel_fill_fb_info(dev_priv, intel_fb);
   1988	if (ret)
   1989		goto err;
   1990
   1991	if (intel_fb_uses_dpt(fb)) {
   1992		struct i915_address_space *vm;
   1993
   1994		vm = intel_dpt_create(intel_fb);
   1995		if (IS_ERR(vm)) {
   1996			ret = PTR_ERR(vm);
   1997			goto err;
   1998		}
   1999
   2000		intel_fb->dpt_vm = vm;
   2001	}
   2002
   2003	ret = drm_framebuffer_init(&dev_priv->drm, fb, &intel_fb_funcs);
   2004	if (ret) {
   2005		drm_err(&dev_priv->drm, "framebuffer init failed %d\n", ret);
   2006		goto err;
   2007	}
   2008
   2009	return 0;
   2010
   2011err:
   2012	intel_frontbuffer_put(intel_fb->frontbuffer);
   2013	return ret;
   2014}
   2015
   2016struct drm_framebuffer *
   2017intel_user_framebuffer_create(struct drm_device *dev,
   2018			      struct drm_file *filp,
   2019			      const struct drm_mode_fb_cmd2 *user_mode_cmd)
   2020{
   2021	struct drm_framebuffer *fb;
   2022	struct drm_i915_gem_object *obj;
   2023	struct drm_mode_fb_cmd2 mode_cmd = *user_mode_cmd;
   2024	struct drm_i915_private *i915;
   2025
   2026	obj = i915_gem_object_lookup(filp, mode_cmd.handles[0]);
   2027	if (!obj)
   2028		return ERR_PTR(-ENOENT);
   2029
   2030	/* object is backed with LMEM for discrete */
   2031	i915 = to_i915(obj->base.dev);
   2032	if (HAS_LMEM(i915) && !i915_gem_object_can_migrate(obj, INTEL_REGION_LMEM_0)) {
   2033		/* object is "remote", not in local memory */
   2034		i915_gem_object_put(obj);
   2035		return ERR_PTR(-EREMOTE);
   2036	}
   2037
   2038	fb = intel_framebuffer_create(obj, &mode_cmd);
   2039	i915_gem_object_put(obj);
   2040
   2041	return fb;
   2042}
   2043
   2044struct drm_framebuffer *
   2045intel_framebuffer_create(struct drm_i915_gem_object *obj,
   2046			 struct drm_mode_fb_cmd2 *mode_cmd)
   2047{
   2048	struct intel_framebuffer *intel_fb;
   2049	int ret;
   2050
   2051	intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
   2052	if (!intel_fb)
   2053		return ERR_PTR(-ENOMEM);
   2054
   2055	ret = intel_framebuffer_init(intel_fb, obj, mode_cmd);
   2056	if (ret)
   2057		goto err;
   2058
   2059	return &intel_fb->base;
   2060
   2061err:
   2062	kfree(intel_fb);
   2063	return ERR_PTR(ret);
   2064}