File Index
Files and directories
Sign in
FILE

intel_fb.c

File preview with syntax highlighting.

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