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