drm/i915/fb: move intel_surf_alignment() to intel_fb.c
[platform/kernel/linux-rpi.git] / drivers / gpu / drm / i915 / display / intel_fb.c
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2021 Intel Corporation
4  */
5
6 #include <drm/drm_framebuffer.h>
7
8 #include "intel_display.h"
9 #include "intel_display_types.h"
10 #include "intel_fb.h"
11
12 #define check_array_bounds(i915, a, i) drm_WARN_ON(&(i915)->drm, (i) >= ARRAY_SIZE(a))
13
14 bool is_ccs_plane(const struct drm_framebuffer *fb, int plane)
15 {
16         if (!is_ccs_modifier(fb->modifier))
17                 return false;
18
19         return plane >= fb->format->num_planes / 2;
20 }
21
22 bool is_gen12_ccs_plane(const struct drm_framebuffer *fb, int plane)
23 {
24         return is_gen12_ccs_modifier(fb->modifier) && is_ccs_plane(fb, plane);
25 }
26
27 bool is_gen12_ccs_cc_plane(const struct drm_framebuffer *fb, int plane)
28 {
29         return fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC &&
30                plane == 2;
31 }
32
33 bool is_semiplanar_uv_plane(const struct drm_framebuffer *fb, int color_plane)
34 {
35         return intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) &&
36                 color_plane == 1;
37 }
38
39 bool is_surface_linear(const struct drm_framebuffer *fb, int color_plane)
40 {
41         return fb->modifier == DRM_FORMAT_MOD_LINEAR ||
42                is_gen12_ccs_plane(fb, color_plane);
43 }
44
45 int main_to_ccs_plane(const struct drm_framebuffer *fb, int main_plane)
46 {
47         drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) ||
48                     (main_plane && main_plane >= fb->format->num_planes / 2));
49
50         return fb->format->num_planes / 2 + main_plane;
51 }
52
53 int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane)
54 {
55         drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) ||
56                     ccs_plane < fb->format->num_planes / 2);
57
58         if (is_gen12_ccs_cc_plane(fb, ccs_plane))
59                 return 0;
60
61         return ccs_plane - fb->format->num_planes / 2;
62 }
63
64 int skl_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane)
65 {
66         struct drm_i915_private *i915 = to_i915(fb->dev);
67
68         if (is_ccs_modifier(fb->modifier))
69                 return main_to_ccs_plane(fb, main_plane);
70         else if (DISPLAY_VER(i915) < 11 &&
71                  intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
72                 return 1;
73         else
74                 return 0;
75 }
76
77 unsigned int intel_tile_size(const struct drm_i915_private *i915)
78 {
79         return DISPLAY_VER(i915) == 2 ? 2048 : 4096;
80 }
81
82 unsigned int
83 intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane)
84 {
85         struct drm_i915_private *dev_priv = to_i915(fb->dev);
86         unsigned int cpp = fb->format->cpp[color_plane];
87
88         switch (fb->modifier) {
89         case DRM_FORMAT_MOD_LINEAR:
90                 return intel_tile_size(dev_priv);
91         case I915_FORMAT_MOD_X_TILED:
92                 if (DISPLAY_VER(dev_priv) == 2)
93                         return 128;
94                 else
95                         return 512;
96         case I915_FORMAT_MOD_Y_TILED_CCS:
97                 if (is_ccs_plane(fb, color_plane))
98                         return 128;
99                 fallthrough;
100         case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
101         case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
102         case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
103                 if (is_ccs_plane(fb, color_plane))
104                         return 64;
105                 fallthrough;
106         case I915_FORMAT_MOD_Y_TILED:
107                 if (DISPLAY_VER(dev_priv) == 2 || HAS_128_BYTE_Y_TILING(dev_priv))
108                         return 128;
109                 else
110                         return 512;
111         case I915_FORMAT_MOD_Yf_TILED_CCS:
112                 if (is_ccs_plane(fb, color_plane))
113                         return 128;
114                 fallthrough;
115         case I915_FORMAT_MOD_Yf_TILED:
116                 switch (cpp) {
117                 case 1:
118                         return 64;
119                 case 2:
120                 case 4:
121                         return 128;
122                 case 8:
123                 case 16:
124                         return 256;
125                 default:
126                         MISSING_CASE(cpp);
127                         return cpp;
128                 }
129                 break;
130         default:
131                 MISSING_CASE(fb->modifier);
132                 return cpp;
133         }
134 }
135
136 unsigned int intel_tile_height(const struct drm_framebuffer *fb, int color_plane)
137 {
138         if (is_gen12_ccs_plane(fb, color_plane))
139                 return 1;
140
141         return intel_tile_size(to_i915(fb->dev)) /
142                 intel_tile_width_bytes(fb, color_plane);
143 }
144
145 /* Return the tile dimensions in pixel units */
146 static void intel_tile_dims(const struct drm_framebuffer *fb, int color_plane,
147                             unsigned int *tile_width,
148                             unsigned int *tile_height)
149 {
150         unsigned int tile_width_bytes = intel_tile_width_bytes(fb, color_plane);
151         unsigned int cpp = fb->format->cpp[color_plane];
152
153         *tile_width = tile_width_bytes / cpp;
154         *tile_height = intel_tile_height(fb, color_plane);
155 }
156
157 unsigned int intel_tile_row_size(const struct drm_framebuffer *fb, int color_plane)
158 {
159         unsigned int tile_width, tile_height;
160
161         intel_tile_dims(fb, color_plane, &tile_width, &tile_height);
162
163         return fb->pitches[color_plane] * tile_height;
164 }
165
166 unsigned int
167 intel_fb_align_height(const struct drm_framebuffer *fb,
168                       int color_plane, unsigned int height)
169 {
170         unsigned int tile_height = intel_tile_height(fb, color_plane);
171
172         return ALIGN(height, tile_height);
173 }
174
175 unsigned int intel_cursor_alignment(const struct drm_i915_private *i915)
176 {
177         if (IS_I830(i915))
178                 return 16 * 1024;
179         else if (IS_I85X(i915))
180                 return 256;
181         else if (IS_I845G(i915) || IS_I865G(i915))
182                 return 32;
183         else
184                 return 4 * 1024;
185 }
186
187 static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_priv)
188 {
189         if (DISPLAY_VER(dev_priv) >= 9)
190                 return 256 * 1024;
191         else if (IS_I965G(dev_priv) || IS_I965GM(dev_priv) ||
192                  IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
193                 return 128 * 1024;
194         else if (DISPLAY_VER(dev_priv) >= 4)
195                 return 4 * 1024;
196         else
197                 return 0;
198 }
199
200 unsigned int intel_surf_alignment(const struct drm_framebuffer *fb,
201                                   int color_plane)
202 {
203         struct drm_i915_private *dev_priv = to_i915(fb->dev);
204
205         if (intel_fb_uses_dpt(fb))
206                 return 512 * 4096;
207
208         /* AUX_DIST needs only 4K alignment */
209         if (is_ccs_plane(fb, color_plane))
210                 return 4096;
211
212         if (is_semiplanar_uv_plane(fb, color_plane)) {
213                 /*
214                  * TODO: cross-check wrt. the bspec stride in bytes * 64 bytes
215                  * alignment for linear UV planes on all platforms.
216                  */
217                 if (DISPLAY_VER(dev_priv) >= 12) {
218                         if (fb->modifier == DRM_FORMAT_MOD_LINEAR)
219                                 return intel_linear_alignment(dev_priv);
220
221                         return intel_tile_row_size(fb, color_plane);
222                 }
223
224                 return 4096;
225         }
226
227         drm_WARN_ON(&dev_priv->drm, color_plane != 0);
228
229         switch (fb->modifier) {
230         case DRM_FORMAT_MOD_LINEAR:
231                 return intel_linear_alignment(dev_priv);
232         case I915_FORMAT_MOD_X_TILED:
233                 if (HAS_ASYNC_FLIPS(dev_priv))
234                         return 256 * 1024;
235                 return 0;
236         case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
237         case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
238         case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
239                 return 16 * 1024;
240         case I915_FORMAT_MOD_Y_TILED_CCS:
241         case I915_FORMAT_MOD_Yf_TILED_CCS:
242         case I915_FORMAT_MOD_Y_TILED:
243         case I915_FORMAT_MOD_Yf_TILED:
244                 return 1 * 1024 * 1024;
245         default:
246                 MISSING_CASE(fb->modifier);
247                 return 0;
248         }
249 }
250
251 void intel_fb_plane_get_subsampling(int *hsub, int *vsub,
252                                     const struct drm_framebuffer *fb,
253                                     int color_plane)
254 {
255         int main_plane;
256
257         if (color_plane == 0) {
258                 *hsub = 1;
259                 *vsub = 1;
260
261                 return;
262         }
263
264         /*
265          * TODO: Deduct the subsampling from the char block for all CCS
266          * formats and planes.
267          */
268         if (!is_gen12_ccs_plane(fb, color_plane)) {
269                 *hsub = fb->format->hsub;
270                 *vsub = fb->format->vsub;
271
272                 return;
273         }
274
275         main_plane = skl_ccs_to_main_plane(fb, color_plane);
276         *hsub = drm_format_info_block_width(fb->format, color_plane) /
277                 drm_format_info_block_width(fb->format, main_plane);
278
279         /*
280          * The min stride check in the core framebuffer_check() function
281          * assumes that format->hsub applies to every plane except for the
282          * first plane. That's incorrect for the CCS AUX plane of the first
283          * plane, but for the above check to pass we must define the block
284          * width with that subsampling applied to it. Adjust the width here
285          * accordingly, so we can calculate the actual subsampling factor.
286          */
287         if (main_plane == 0)
288                 *hsub *= fb->format->hsub;
289
290         *vsub = 32;
291 }
292
293 static void intel_fb_plane_dims(const struct intel_framebuffer *fb, int color_plane, int *w, int *h)
294 {
295         int main_plane = is_ccs_plane(&fb->base, color_plane) ?
296                          skl_ccs_to_main_plane(&fb->base, color_plane) : 0;
297         int main_hsub, main_vsub;
298         int hsub, vsub;
299
300         intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, &fb->base, main_plane);
301         intel_fb_plane_get_subsampling(&hsub, &vsub, &fb->base, color_plane);
302         *w = fb->base.width / main_hsub / hsub;
303         *h = fb->base.height / main_vsub / vsub;
304 }
305
306 static u32 intel_adjust_tile_offset(int *x, int *y,
307                                     unsigned int tile_width,
308                                     unsigned int tile_height,
309                                     unsigned int tile_size,
310                                     unsigned int pitch_tiles,
311                                     u32 old_offset,
312                                     u32 new_offset)
313 {
314         unsigned int pitch_pixels = pitch_tiles * tile_width;
315         unsigned int tiles;
316
317         WARN_ON(old_offset & (tile_size - 1));
318         WARN_ON(new_offset & (tile_size - 1));
319         WARN_ON(new_offset > old_offset);
320
321         tiles = (old_offset - new_offset) / tile_size;
322
323         *y += tiles / pitch_tiles * tile_height;
324         *x += tiles % pitch_tiles * tile_width;
325
326         /* minimize x in case it got needlessly big */
327         *y += *x / pitch_pixels * tile_height;
328         *x %= pitch_pixels;
329
330         return new_offset;
331 }
332
333 static u32 intel_adjust_aligned_offset(int *x, int *y,
334                                        const struct drm_framebuffer *fb,
335                                        int color_plane,
336                                        unsigned int rotation,
337                                        unsigned int pitch,
338                                        u32 old_offset, u32 new_offset)
339 {
340         struct drm_i915_private *i915 = to_i915(fb->dev);
341         unsigned int cpp = fb->format->cpp[color_plane];
342
343         drm_WARN_ON(&i915->drm, new_offset > old_offset);
344
345         if (!is_surface_linear(fb, color_plane)) {
346                 unsigned int tile_size, tile_width, tile_height;
347                 unsigned int pitch_tiles;
348
349                 tile_size = intel_tile_size(i915);
350                 intel_tile_dims(fb, color_plane, &tile_width, &tile_height);
351
352                 if (drm_rotation_90_or_270(rotation)) {
353                         pitch_tiles = pitch / tile_height;
354                         swap(tile_width, tile_height);
355                 } else {
356                         pitch_tiles = pitch / (tile_width * cpp);
357                 }
358
359                 intel_adjust_tile_offset(x, y, tile_width, tile_height,
360                                          tile_size, pitch_tiles,
361                                          old_offset, new_offset);
362         } else {
363                 old_offset += *y * pitch + *x * cpp;
364
365                 *y = (old_offset - new_offset) / pitch;
366                 *x = ((old_offset - new_offset) - *y * pitch) / cpp;
367         }
368
369         return new_offset;
370 }
371
372 /*
373  * Adjust the tile offset by moving the difference into
374  * the x/y offsets.
375  */
376 u32 intel_plane_adjust_aligned_offset(int *x, int *y,
377                                       const struct intel_plane_state *state,
378                                       int color_plane,
379                                       u32 old_offset, u32 new_offset)
380 {
381         return intel_adjust_aligned_offset(x, y, state->hw.fb, color_plane,
382                                            state->hw.rotation,
383                                            state->view.color_plane[color_plane].stride,
384                                            old_offset, new_offset);
385 }
386
387 /*
388  * Computes the aligned offset to the base tile and adjusts
389  * x, y. bytes per pixel is assumed to be a power-of-two.
390  *
391  * In the 90/270 rotated case, x and y are assumed
392  * to be already rotated to match the rotated GTT view, and
393  * pitch is the tile_height aligned framebuffer height.
394  *
395  * This function is used when computing the derived information
396  * under intel_framebuffer, so using any of that information
397  * here is not allowed. Anything under drm_framebuffer can be
398  * used. This is why the user has to pass in the pitch since it
399  * is specified in the rotated orientation.
400  */
401 static u32 intel_compute_aligned_offset(struct drm_i915_private *i915,
402                                         int *x, int *y,
403                                         const struct drm_framebuffer *fb,
404                                         int color_plane,
405                                         unsigned int pitch,
406                                         unsigned int rotation,
407                                         u32 alignment)
408 {
409         unsigned int cpp = fb->format->cpp[color_plane];
410         u32 offset, offset_aligned;
411
412         if (!is_surface_linear(fb, color_plane)) {
413                 unsigned int tile_size, tile_width, tile_height;
414                 unsigned int tile_rows, tiles, pitch_tiles;
415
416                 tile_size = intel_tile_size(i915);
417                 intel_tile_dims(fb, color_plane, &tile_width, &tile_height);
418
419                 if (drm_rotation_90_or_270(rotation)) {
420                         pitch_tiles = pitch / tile_height;
421                         swap(tile_width, tile_height);
422                 } else {
423                         pitch_tiles = pitch / (tile_width * cpp);
424                 }
425
426                 tile_rows = *y / tile_height;
427                 *y %= tile_height;
428
429                 tiles = *x / tile_width;
430                 *x %= tile_width;
431
432                 offset = (tile_rows * pitch_tiles + tiles) * tile_size;
433
434                 offset_aligned = offset;
435                 if (alignment)
436                         offset_aligned = rounddown(offset_aligned, alignment);
437
438                 intel_adjust_tile_offset(x, y, tile_width, tile_height,
439                                          tile_size, pitch_tiles,
440                                          offset, offset_aligned);
441         } else {
442                 offset = *y * pitch + *x * cpp;
443                 offset_aligned = offset;
444                 if (alignment) {
445                         offset_aligned = rounddown(offset_aligned, alignment);
446                         *y = (offset % alignment) / pitch;
447                         *x = ((offset % alignment) - *y * pitch) / cpp;
448                 } else {
449                         *y = *x = 0;
450                 }
451         }
452
453         return offset_aligned;
454 }
455
456 u32 intel_plane_compute_aligned_offset(int *x, int *y,
457                                        const struct intel_plane_state *state,
458                                        int color_plane)
459 {
460         struct intel_plane *intel_plane = to_intel_plane(state->uapi.plane);
461         struct drm_i915_private *i915 = to_i915(intel_plane->base.dev);
462         const struct drm_framebuffer *fb = state->hw.fb;
463         unsigned int rotation = state->hw.rotation;
464         int pitch = state->view.color_plane[color_plane].stride;
465         u32 alignment;
466
467         if (intel_plane->id == PLANE_CURSOR)
468                 alignment = intel_cursor_alignment(i915);
469         else
470                 alignment = intel_surf_alignment(fb, color_plane);
471
472         return intel_compute_aligned_offset(i915, x, y, fb, color_plane,
473                                             pitch, rotation, alignment);
474 }
475
476 /* Convert the fb->offset[] into x/y offsets */
477 static int intel_fb_offset_to_xy(int *x, int *y,
478                                  const struct drm_framebuffer *fb,
479                                  int color_plane)
480 {
481         struct drm_i915_private *i915 = to_i915(fb->dev);
482         unsigned int height;
483         u32 alignment;
484
485         /*
486          * All DPT color planes must be 512*4k aligned (the amount mapped by a
487          * single DPT page). For ADL_P CCS FBs this only works by requiring
488          * the allocated offsets to be 2MB aligned.  Once supoort to remap
489          * such FBs is added we can remove this requirement, as then all the
490          * planes can be remapped to an aligned offset.
491          */
492         if (IS_ALDERLAKE_P(i915) && is_ccs_modifier(fb->modifier))
493                 alignment = 512 * 4096;
494         else if (DISPLAY_VER(i915) >= 12 &&
495                  is_semiplanar_uv_plane(fb, color_plane))
496                 alignment = intel_tile_row_size(fb, color_plane);
497         else if (fb->modifier != DRM_FORMAT_MOD_LINEAR)
498                 alignment = intel_tile_size(i915);
499         else
500                 alignment = 0;
501
502         if (alignment != 0 && fb->offsets[color_plane] % alignment) {
503                 drm_dbg_kms(&i915->drm,
504                             "Misaligned offset 0x%08x for color plane %d\n",
505                             fb->offsets[color_plane], color_plane);
506                 return -EINVAL;
507         }
508
509         height = drm_framebuffer_plane_height(fb->height, fb, color_plane);
510         height = ALIGN(height, intel_tile_height(fb, color_plane));
511
512         /* Catch potential overflows early */
513         if (add_overflows_t(u32, mul_u32_u32(height, fb->pitches[color_plane]),
514                             fb->offsets[color_plane])) {
515                 drm_dbg_kms(&i915->drm,
516                             "Bad offset 0x%08x or pitch %d for color plane %d\n",
517                             fb->offsets[color_plane], fb->pitches[color_plane],
518                             color_plane);
519                 return -ERANGE;
520         }
521
522         *x = 0;
523         *y = 0;
524
525         intel_adjust_aligned_offset(x, y,
526                                     fb, color_plane, DRM_MODE_ROTATE_0,
527                                     fb->pitches[color_plane],
528                                     fb->offsets[color_plane], 0);
529
530         return 0;
531 }
532
533 static int intel_fb_check_ccs_xy(const struct drm_framebuffer *fb, int ccs_plane, int x, int y)
534 {
535         struct drm_i915_private *i915 = to_i915(fb->dev);
536         const struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
537         int main_plane;
538         int hsub, vsub;
539         int tile_width, tile_height;
540         int ccs_x, ccs_y;
541         int main_x, main_y;
542
543         if (!is_ccs_plane(fb, ccs_plane) || is_gen12_ccs_cc_plane(fb, ccs_plane))
544                 return 0;
545
546         intel_tile_dims(fb, ccs_plane, &tile_width, &tile_height);
547         intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane);
548
549         tile_width *= hsub;
550         tile_height *= vsub;
551
552         ccs_x = (x * hsub) % tile_width;
553         ccs_y = (y * vsub) % tile_height;
554
555         main_plane = skl_ccs_to_main_plane(fb, ccs_plane);
556         main_x = intel_fb->normal_view.color_plane[main_plane].x % tile_width;
557         main_y = intel_fb->normal_view.color_plane[main_plane].y % tile_height;
558
559         /*
560          * CCS doesn't have its own x/y offset register, so the intra CCS tile
561          * x/y offsets must match between CCS and the main surface.
562          */
563         if (main_x != ccs_x || main_y != ccs_y) {
564                 drm_dbg_kms(&i915->drm,
565                               "Bad CCS x/y (main %d,%d ccs %d,%d) full (main %d,%d ccs %d,%d)\n",
566                               main_x, main_y,
567                               ccs_x, ccs_y,
568                               intel_fb->normal_view.color_plane[main_plane].x,
569                               intel_fb->normal_view.color_plane[main_plane].y,
570                               x, y);
571                 return -EINVAL;
572         }
573
574         return 0;
575 }
576
577 static bool intel_plane_can_remap(const struct intel_plane_state *plane_state)
578 {
579         struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
580         struct drm_i915_private *i915 = to_i915(plane->base.dev);
581         const struct drm_framebuffer *fb = plane_state->hw.fb;
582         int i;
583
584         /* We don't want to deal with remapping with cursors */
585         if (plane->id == PLANE_CURSOR)
586                 return false;
587
588         /*
589          * The display engine limits already match/exceed the
590          * render engine limits, so not much point in remapping.
591          * Would also need to deal with the fence POT alignment
592          * and gen2 2KiB GTT tile size.
593          */
594         if (DISPLAY_VER(i915) < 4)
595                 return false;
596
597         /*
598          * The new CCS hash mode isn't compatible with remapping as
599          * the virtual address of the pages affects the compressed data.
600          */
601         if (is_ccs_modifier(fb->modifier))
602                 return false;
603
604         /* Linear needs a page aligned stride for remapping */
605         if (fb->modifier == DRM_FORMAT_MOD_LINEAR) {
606                 unsigned int alignment = intel_tile_size(i915) - 1;
607
608                 for (i = 0; i < fb->format->num_planes; i++) {
609                         if (fb->pitches[i] & alignment)
610                                 return false;
611                 }
612         }
613
614         return true;
615 }
616
617 bool intel_fb_needs_pot_stride_remap(const struct intel_framebuffer *fb)
618 {
619         struct drm_i915_private *i915 = to_i915(fb->base.dev);
620
621         return IS_ALDERLAKE_P(i915) && fb->base.modifier != DRM_FORMAT_MOD_LINEAR &&
622                !is_ccs_modifier(fb->base.modifier);
623 }
624
625 static int intel_fb_pitch(const struct intel_framebuffer *fb, int color_plane, unsigned int rotation)
626 {
627         if (drm_rotation_90_or_270(rotation))
628                 return fb->rotated_view.color_plane[color_plane].stride;
629         else if (intel_fb_needs_pot_stride_remap(fb))
630                 return fb->remapped_view.color_plane[color_plane].stride;
631         else
632                 return fb->normal_view.color_plane[color_plane].stride;
633 }
634
635 static bool intel_plane_needs_remap(const struct intel_plane_state *plane_state)
636 {
637         struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
638         const struct intel_framebuffer *fb = to_intel_framebuffer(plane_state->hw.fb);
639         unsigned int rotation = plane_state->hw.rotation;
640         u32 stride, max_stride;
641
642         /*
643          * No remapping for invisible planes since we don't have
644          * an actual source viewport to remap.
645          */
646         if (!plane_state->uapi.visible)
647                 return false;
648
649         if (!intel_plane_can_remap(plane_state))
650                 return false;
651
652         /*
653          * FIXME: aux plane limits on gen9+ are
654          * unclear in Bspec, for now no checking.
655          */
656         stride = intel_fb_pitch(fb, 0, rotation);
657         max_stride = plane->max_stride(plane, fb->base.format->format,
658                                        fb->base.modifier, rotation);
659
660         return stride > max_stride;
661 }
662
663 static int convert_plane_offset_to_xy(const struct intel_framebuffer *fb, int color_plane,
664                                       int plane_width, int *x, int *y)
665 {
666         struct drm_i915_gem_object *obj = intel_fb_obj(&fb->base);
667         int ret;
668
669         ret = intel_fb_offset_to_xy(x, y, &fb->base, color_plane);
670         if (ret) {
671                 drm_dbg_kms(fb->base.dev,
672                             "bad fb plane %d offset: 0x%x\n",
673                             color_plane, fb->base.offsets[color_plane]);
674                 return ret;
675         }
676
677         ret = intel_fb_check_ccs_xy(&fb->base, color_plane, *x, *y);
678         if (ret)
679                 return ret;
680
681         /*
682          * The fence (if used) is aligned to the start of the object
683          * so having the framebuffer wrap around across the edge of the
684          * fenced region doesn't really work. We have no API to configure
685          * the fence start offset within the object (nor could we probably
686          * on gen2/3). So it's just easier if we just require that the
687          * fb layout agrees with the fence layout. We already check that the
688          * fb stride matches the fence stride elsewhere.
689          */
690         if (color_plane == 0 && i915_gem_object_is_tiled(obj) &&
691             (*x + plane_width) * fb->base.format->cpp[color_plane] > fb->base.pitches[color_plane]) {
692                 drm_dbg_kms(fb->base.dev,
693                             "bad fb plane %d offset: 0x%x\n",
694                             color_plane, fb->base.offsets[color_plane]);
695                 return -EINVAL;
696         }
697
698         return 0;
699 }
700
701 static u32 calc_plane_aligned_offset(const struct intel_framebuffer *fb, int color_plane, int *x, int *y)
702 {
703         struct drm_i915_private *i915 = to_i915(fb->base.dev);
704         unsigned int tile_size = intel_tile_size(i915);
705         u32 offset;
706
707         offset = intel_compute_aligned_offset(i915, x, y, &fb->base, color_plane,
708                                               fb->base.pitches[color_plane],
709                                               DRM_MODE_ROTATE_0,
710                                               tile_size);
711
712         return offset / tile_size;
713 }
714
715 struct fb_plane_view_dims {
716         unsigned int width, height;
717         unsigned int tile_width, tile_height;
718 };
719
720 static void init_plane_view_dims(const struct intel_framebuffer *fb, int color_plane,
721                                  unsigned int width, unsigned int height,
722                                  struct fb_plane_view_dims *dims)
723 {
724         dims->width = width;
725         dims->height = height;
726
727         intel_tile_dims(&fb->base, color_plane, &dims->tile_width, &dims->tile_height);
728 }
729
730 static unsigned int
731 plane_view_src_stride_tiles(const struct intel_framebuffer *fb, int color_plane,
732                             const struct fb_plane_view_dims *dims)
733 {
734         return DIV_ROUND_UP(fb->base.pitches[color_plane],
735                             dims->tile_width * fb->base.format->cpp[color_plane]);
736 }
737
738 static unsigned int
739 plane_view_dst_stride_tiles(const struct intel_framebuffer *fb, int color_plane,
740                             unsigned int pitch_tiles)
741 {
742         if (intel_fb_needs_pot_stride_remap(fb))
743                 /*
744                  * ADL_P, the only platform needing a POT stride has a minimum
745                  * of 8 stride tiles.
746                  */
747                 return roundup_pow_of_two(max(pitch_tiles, 8u));
748         else
749                 return pitch_tiles;
750 }
751
752 static unsigned int
753 plane_view_width_tiles(const struct intel_framebuffer *fb, int color_plane,
754                        const struct fb_plane_view_dims *dims,
755                        int x)
756 {
757         return DIV_ROUND_UP(x + dims->width, dims->tile_width);
758 }
759
760 static unsigned int
761 plane_view_height_tiles(const struct intel_framebuffer *fb, int color_plane,
762                         const struct fb_plane_view_dims *dims,
763                         int y)
764 {
765         return DIV_ROUND_UP(y + dims->height, dims->tile_height);
766 }
767
768 #define assign_chk_ovf(i915, var, val) ({ \
769         drm_WARN_ON(&(i915)->drm, overflows_type(val, var)); \
770         (var) = (val); \
771 })
772
773 static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_plane,
774                                  const struct fb_plane_view_dims *dims,
775                                  u32 obj_offset, u32 gtt_offset, int x, int y,
776                                  struct intel_fb_view *view)
777 {
778         struct drm_i915_private *i915 = to_i915(fb->base.dev);
779         struct intel_remapped_plane_info *remap_info = &view->gtt.remapped.plane[color_plane];
780         struct i915_color_plane_view *color_plane_info = &view->color_plane[color_plane];
781         unsigned int tile_width = dims->tile_width;
782         unsigned int tile_height = dims->tile_height;
783         unsigned int tile_size = intel_tile_size(i915);
784         struct drm_rect r;
785         u32 size;
786
787         assign_chk_ovf(i915, remap_info->offset, obj_offset);
788         assign_chk_ovf(i915, remap_info->src_stride, plane_view_src_stride_tiles(fb, color_plane, dims));
789         assign_chk_ovf(i915, remap_info->width, plane_view_width_tiles(fb, color_plane, dims, x));
790         assign_chk_ovf(i915, remap_info->height, plane_view_height_tiles(fb, color_plane, dims, y));
791
792         if (view->gtt.type == I915_GGTT_VIEW_ROTATED) {
793                 check_array_bounds(i915, view->gtt.rotated.plane, color_plane);
794
795                 assign_chk_ovf(i915, remap_info->dst_stride,
796                                plane_view_dst_stride_tiles(fb, color_plane, remap_info->height));
797
798                 /* rotate the x/y offsets to match the GTT view */
799                 drm_rect_init(&r, x, y, dims->width, dims->height);
800                 drm_rect_rotate(&r,
801                                 remap_info->width * tile_width,
802                                 remap_info->height * tile_height,
803                                 DRM_MODE_ROTATE_270);
804
805                 color_plane_info->x = r.x1;
806                 color_plane_info->y = r.y1;
807
808                 color_plane_info->stride = remap_info->dst_stride * tile_height;
809
810                 size = remap_info->dst_stride * remap_info->width;
811
812                 /* rotate the tile dimensions to match the GTT view */
813                 swap(tile_width, tile_height);
814         } else {
815                 drm_WARN_ON(&i915->drm, view->gtt.type != I915_GGTT_VIEW_REMAPPED);
816
817                 check_array_bounds(i915, view->gtt.remapped.plane, color_plane);
818
819                 assign_chk_ovf(i915, remap_info->dst_stride,
820                                plane_view_dst_stride_tiles(fb, color_plane, remap_info->width));
821
822                 color_plane_info->x = x;
823                 color_plane_info->y = y;
824
825                 color_plane_info->stride = remap_info->dst_stride * tile_width *
826                                            fb->base.format->cpp[color_plane];
827
828                 size = remap_info->dst_stride * remap_info->height;
829         }
830
831         /*
832          * We only keep the x/y offsets, so push all of the gtt offset into
833          * the x/y offsets.  x,y will hold the first pixel of the framebuffer
834          * plane from the start of the remapped/rotated gtt mapping.
835          */
836         intel_adjust_tile_offset(&color_plane_info->x, &color_plane_info->y,
837                                  tile_width, tile_height,
838                                  tile_size, remap_info->dst_stride,
839                                  gtt_offset * tile_size, 0);
840
841         return size;
842 }
843
844 #undef assign_chk_ovf
845
846 /* Return number of tiles @color_plane needs. */
847 static unsigned int
848 calc_plane_normal_size(const struct intel_framebuffer *fb, int color_plane,
849                        const struct fb_plane_view_dims *dims,
850                        int x, int y)
851 {
852         struct drm_i915_private *i915 = to_i915(fb->base.dev);
853         unsigned int tiles;
854
855         if (is_surface_linear(&fb->base, color_plane)) {
856                 unsigned int size;
857
858                 size = (y + dims->height) * fb->base.pitches[color_plane] +
859                        x * fb->base.format->cpp[color_plane];
860                 tiles = DIV_ROUND_UP(size, intel_tile_size(i915));
861         } else {
862                 tiles = plane_view_src_stride_tiles(fb, color_plane, dims) *
863                         plane_view_height_tiles(fb, color_plane, dims, y);
864                 /*
865                  * If the plane isn't horizontally tile aligned,
866                  * we need one more tile.
867                  */
868                 if (x != 0)
869                         tiles++;
870         }
871
872         return tiles;
873 }
874
875 static void intel_fb_view_init(struct intel_fb_view *view, enum i915_ggtt_view_type view_type)
876 {
877         memset(view, 0, sizeof(*view));
878         view->gtt.type = view_type;
879 }
880
881 bool intel_fb_supports_90_270_rotation(const struct intel_framebuffer *fb)
882 {
883         if (DISPLAY_VER(to_i915(fb->base.dev)) >= 13)
884                 return false;
885
886         return fb->base.modifier == I915_FORMAT_MOD_Y_TILED ||
887                fb->base.modifier == I915_FORMAT_MOD_Yf_TILED;
888 }
889
890 int intel_fill_fb_info(struct drm_i915_private *i915, struct intel_framebuffer *fb)
891 {
892         struct drm_i915_gem_object *obj = intel_fb_obj(&fb->base);
893         u32 gtt_offset_rotated = 0;
894         u32 gtt_offset_remapped = 0;
895         unsigned int max_size = 0;
896         int i, num_planes = fb->base.format->num_planes;
897         unsigned int tile_size = intel_tile_size(i915);
898
899         intel_fb_view_init(&fb->normal_view, I915_GGTT_VIEW_NORMAL);
900
901         drm_WARN_ON(&i915->drm,
902                     intel_fb_supports_90_270_rotation(fb) &&
903                     intel_fb_needs_pot_stride_remap(fb));
904
905         if (intel_fb_supports_90_270_rotation(fb))
906                 intel_fb_view_init(&fb->rotated_view, I915_GGTT_VIEW_ROTATED);
907         if (intel_fb_needs_pot_stride_remap(fb))
908                 intel_fb_view_init(&fb->remapped_view, I915_GGTT_VIEW_REMAPPED);
909
910         for (i = 0; i < num_planes; i++) {
911                 struct fb_plane_view_dims view_dims;
912                 unsigned int width, height;
913                 unsigned int cpp, size;
914                 u32 offset;
915                 int x, y;
916                 int ret;
917
918                 /*
919                  * Plane 2 of Render Compression with Clear Color fb modifier
920                  * is consumed by the driver and not passed to DE. Skip the
921                  * arithmetic related to alignment and offset calculation.
922                  */
923                 if (is_gen12_ccs_cc_plane(&fb->base, i)) {
924                         if (IS_ALIGNED(fb->base.offsets[i], PAGE_SIZE))
925                                 continue;
926                         else
927                                 return -EINVAL;
928                 }
929
930                 cpp = fb->base.format->cpp[i];
931                 intel_fb_plane_dims(fb, i, &width, &height);
932
933                 ret = convert_plane_offset_to_xy(fb, i, width, &x, &y);
934                 if (ret)
935                         return ret;
936
937                 init_plane_view_dims(fb, i, width, height, &view_dims);
938
939                 /*
940                  * First pixel of the framebuffer from
941                  * the start of the normal gtt mapping.
942                  */
943                 fb->normal_view.color_plane[i].x = x;
944                 fb->normal_view.color_plane[i].y = y;
945                 fb->normal_view.color_plane[i].stride = fb->base.pitches[i];
946
947                 offset = calc_plane_aligned_offset(fb, i, &x, &y);
948
949                 if (intel_fb_supports_90_270_rotation(fb))
950                         gtt_offset_rotated += calc_plane_remap_info(fb, i, &view_dims,
951                                                                     offset, gtt_offset_rotated, x, y,
952                                                                     &fb->rotated_view);
953
954                 if (intel_fb_needs_pot_stride_remap(fb))
955                         gtt_offset_remapped += calc_plane_remap_info(fb, i, &view_dims,
956                                                                      offset, gtt_offset_remapped, x, y,
957                                                                      &fb->remapped_view);
958
959                 size = calc_plane_normal_size(fb, i, &view_dims, x, y);
960                 /* how many tiles in total needed in the bo */
961                 max_size = max(max_size, offset + size);
962         }
963
964         if (mul_u32_u32(max_size, tile_size) > obj->base.size) {
965                 drm_dbg_kms(&i915->drm,
966                             "fb too big for bo (need %llu bytes, have %zu bytes)\n",
967                             mul_u32_u32(max_size, tile_size), obj->base.size);
968                 return -EINVAL;
969         }
970
971         return 0;
972 }
973
974 static void intel_plane_remap_gtt(struct intel_plane_state *plane_state)
975 {
976         struct drm_i915_private *i915 =
977                 to_i915(plane_state->uapi.plane->dev);
978         struct drm_framebuffer *fb = plane_state->hw.fb;
979         struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
980         unsigned int rotation = plane_state->hw.rotation;
981         int i, num_planes = fb->format->num_planes;
982         unsigned int src_x, src_y;
983         unsigned int src_w, src_h;
984         u32 gtt_offset = 0;
985
986         intel_fb_view_init(&plane_state->view,
987                            drm_rotation_90_or_270(rotation) ? I915_GGTT_VIEW_ROTATED :
988                                                               I915_GGTT_VIEW_REMAPPED);
989
990         src_x = plane_state->uapi.src.x1 >> 16;
991         src_y = plane_state->uapi.src.y1 >> 16;
992         src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
993         src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
994
995         drm_WARN_ON(&i915->drm, is_ccs_modifier(fb->modifier));
996
997         /* Make src coordinates relative to the viewport */
998         drm_rect_translate(&plane_state->uapi.src,
999                            -(src_x << 16), -(src_y << 16));
1000
1001         /* Rotate src coordinates to match rotated GTT view */
1002         if (drm_rotation_90_or_270(rotation))
1003                 drm_rect_rotate(&plane_state->uapi.src,
1004                                 src_w << 16, src_h << 16,
1005                                 DRM_MODE_ROTATE_270);
1006
1007         for (i = 0; i < num_planes; i++) {
1008                 unsigned int hsub = i ? fb->format->hsub : 1;
1009                 unsigned int vsub = i ? fb->format->vsub : 1;
1010                 struct fb_plane_view_dims view_dims;
1011                 unsigned int width, height;
1012                 unsigned int x, y;
1013                 u32 offset;
1014
1015                 x = src_x / hsub;
1016                 y = src_y / vsub;
1017                 width = src_w / hsub;
1018                 height = src_h / vsub;
1019
1020                 init_plane_view_dims(intel_fb, i, width, height, &view_dims);
1021
1022                 /*
1023                  * First pixel of the src viewport from the
1024                  * start of the normal gtt mapping.
1025                  */
1026                 x += intel_fb->normal_view.color_plane[i].x;
1027                 y += intel_fb->normal_view.color_plane[i].y;
1028
1029                 offset = calc_plane_aligned_offset(intel_fb, i, &x, &y);
1030
1031                 gtt_offset += calc_plane_remap_info(intel_fb, i, &view_dims,
1032                                                     offset, gtt_offset, x, y,
1033                                                     &plane_state->view);
1034         }
1035 }
1036
1037 void intel_fb_fill_view(const struct intel_framebuffer *fb, unsigned int rotation,
1038                         struct intel_fb_view *view)
1039 {
1040         if (drm_rotation_90_or_270(rotation))
1041                 *view = fb->rotated_view;
1042         else if (intel_fb_needs_pot_stride_remap(fb))
1043                 *view = fb->remapped_view;
1044         else
1045                 *view = fb->normal_view;
1046 }
1047
1048 static int intel_plane_check_stride(const struct intel_plane_state *plane_state)
1049 {
1050         struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1051         const struct drm_framebuffer *fb = plane_state->hw.fb;
1052         unsigned int rotation = plane_state->hw.rotation;
1053         u32 stride, max_stride;
1054
1055         /*
1056          * We ignore stride for all invisible planes that
1057          * can be remapped. Otherwise we could end up
1058          * with a false positive when the remapping didn't
1059          * kick in due the plane being invisible.
1060          */
1061         if (intel_plane_can_remap(plane_state) &&
1062             !plane_state->uapi.visible)
1063                 return 0;
1064
1065         /* FIXME other color planes? */
1066         stride = plane_state->view.color_plane[0].stride;
1067         max_stride = plane->max_stride(plane, fb->format->format,
1068                                        fb->modifier, rotation);
1069
1070         if (stride > max_stride) {
1071                 DRM_DEBUG_KMS("[FB:%d] stride (%d) exceeds [PLANE:%d:%s] max stride (%d)\n",
1072                               fb->base.id, stride,
1073                               plane->base.base.id, plane->base.name, max_stride);
1074                 return -EINVAL;
1075         }
1076
1077         return 0;
1078 }
1079
1080 int intel_plane_compute_gtt(struct intel_plane_state *plane_state)
1081 {
1082         const struct intel_framebuffer *fb =
1083                 to_intel_framebuffer(plane_state->hw.fb);
1084         unsigned int rotation = plane_state->hw.rotation;
1085
1086         if (!fb)
1087                 return 0;
1088
1089         if (intel_plane_needs_remap(plane_state)) {
1090                 intel_plane_remap_gtt(plane_state);
1091
1092                 /*
1093                  * Sometimes even remapping can't overcome
1094                  * the stride limitations :( Can happen with
1095                  * big plane sizes and suitably misaligned
1096                  * offsets.
1097                  */
1098                 return intel_plane_check_stride(plane_state);
1099         }
1100
1101         intel_fb_fill_view(fb, rotation, &plane_state->view);
1102
1103         /* Rotate src coordinates to match rotated GTT view */
1104         if (drm_rotation_90_or_270(rotation))
1105                 drm_rect_rotate(&plane_state->uapi.src,
1106                                 fb->base.width << 16, fb->base.height << 16,
1107                                 DRM_MODE_ROTATE_270);
1108
1109         return intel_plane_check_stride(plane_state);
1110 }