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