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