1
2
3
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
14bool 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
22bool 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
27bool 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
33bool is_aux_plane(const struct drm_framebuffer *fb, int plane)
34{
35 if (is_ccs_modifier(fb->modifier))
36 return is_ccs_plane(fb, plane);
37
38 return plane == 1;
39}
40
41bool is_semiplanar_uv_plane(const struct drm_framebuffer *fb, int color_plane)
42{
43 return intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) &&
44 color_plane == 1;
45}
46
47bool is_surface_linear(const struct drm_framebuffer *fb, int color_plane)
48{
49 return fb->modifier == DRM_FORMAT_MOD_LINEAR ||
50 is_gen12_ccs_plane(fb, color_plane);
51}
52
53int main_to_ccs_plane(const struct drm_framebuffer *fb, int main_plane)
54{
55 drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) ||
56 (main_plane && main_plane >= fb->format->num_planes / 2));
57
58 return fb->format->num_planes / 2 + main_plane;
59}
60
61int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane)
62{
63 drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) ||
64 ccs_plane < fb->format->num_planes / 2);
65
66 if (is_gen12_ccs_cc_plane(fb, ccs_plane))
67 return 0;
68
69 return ccs_plane - fb->format->num_planes / 2;
70}
71
72int skl_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane)
73{
74 struct drm_i915_private *i915 = to_i915(fb->dev);
75
76 if (is_ccs_modifier(fb->modifier))
77 return main_to_ccs_plane(fb, main_plane);
78 else if (DISPLAY_VER(i915) < 11 &&
79 intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
80 return 1;
81 else
82 return 0;
83}
84
85unsigned int intel_tile_size(const struct drm_i915_private *i915)
86{
87 return IS_DISPLAY_VER(i915, 2) ? 2048 : 4096;
88}
89
90unsigned int intel_tile_height(const struct drm_framebuffer *fb, int color_plane)
91{
92 if (is_gen12_ccs_plane(fb, color_plane))
93 return 1;
94
95 return intel_tile_size(to_i915(fb->dev)) /
96 intel_tile_width_bytes(fb, color_plane);
97}
98
99
100static void intel_tile_dims(const struct drm_framebuffer *fb, int color_plane,
101 unsigned int *tile_width,
102 unsigned int *tile_height)
103{
104 unsigned int tile_width_bytes = intel_tile_width_bytes(fb, color_plane);
105 unsigned int cpp = fb->format->cpp[color_plane];
106
107 *tile_width = tile_width_bytes / cpp;
108 *tile_height = intel_tile_height(fb, color_plane);
109}
110
111unsigned int intel_tile_row_size(const struct drm_framebuffer *fb, int color_plane)
112{
113 unsigned int tile_width, tile_height;
114
115 intel_tile_dims(fb, color_plane, &tile_width, &tile_height);
116
117 return fb->pitches[color_plane] * tile_height;
118}
119
120unsigned int intel_cursor_alignment(const struct drm_i915_private *i915)
121{
122 if (IS_I830(i915))
123 return 16 * 1024;
124 else if (IS_I85X(i915))
125 return 256;
126 else if (IS_I845G(i915) || IS_I865G(i915))
127 return 32;
128 else
129 return 4 * 1024;
130}
131
132void intel_fb_plane_get_subsampling(int *hsub, int *vsub,
133 const struct drm_framebuffer *fb,
134 int color_plane)
135{
136 int main_plane;
137
138 if (color_plane == 0) {
139 *hsub = 1;
140 *vsub = 1;
141
142 return;
143 }
144
145
146
147
148
149 if (!is_gen12_ccs_plane(fb, color_plane)) {
150 *hsub = fb->format->hsub;
151 *vsub = fb->format->vsub;
152
153 return;
154 }
155
156 main_plane = skl_ccs_to_main_plane(fb, color_plane);
157 *hsub = drm_format_info_block_width(fb->format, color_plane) /
158 drm_format_info_block_width(fb->format, main_plane);
159
160
161
162
163
164
165
166
167
168 if (main_plane == 0)
169 *hsub *= fb->format->hsub;
170
171 *vsub = 32;
172}
173
174static void intel_fb_plane_dims(int *w, int *h, struct drm_framebuffer *fb, int color_plane)
175{
176 int main_plane = is_ccs_plane(fb, color_plane) ?
177 skl_ccs_to_main_plane(fb, color_plane) : 0;
178 int main_hsub, main_vsub;
179 int hsub, vsub;
180
181 intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, fb, main_plane);
182 intel_fb_plane_get_subsampling(&hsub, &vsub, fb, color_plane);
183 *w = fb->width / main_hsub / hsub;
184 *h = fb->height / main_vsub / vsub;
185}
186
187static u32 intel_adjust_tile_offset(int *x, int *y,
188 unsigned int tile_width,
189 unsigned int tile_height,
190 unsigned int tile_size,
191 unsigned int pitch_tiles,
192 u32 old_offset,
193 u32 new_offset)
194{
195 unsigned int pitch_pixels = pitch_tiles * tile_width;
196 unsigned int tiles;
197
198 WARN_ON(old_offset & (tile_size - 1));
199 WARN_ON(new_offset & (tile_size - 1));
200 WARN_ON(new_offset > old_offset);
201
202 tiles = (old_offset - new_offset) / tile_size;
203
204 *y += tiles / pitch_tiles * tile_height;
205 *x += tiles % pitch_tiles * tile_width;
206
207
208 *y += *x / pitch_pixels * tile_height;
209 *x %= pitch_pixels;
210
211 return new_offset;
212}
213
214static u32 intel_adjust_aligned_offset(int *x, int *y,
215 const struct drm_framebuffer *fb,
216 int color_plane,
217 unsigned int rotation,
218 unsigned int pitch,
219 u32 old_offset, u32 new_offset)
220{
221 struct drm_i915_private *i915 = to_i915(fb->dev);
222 unsigned int cpp = fb->format->cpp[color_plane];
223
224 drm_WARN_ON(&i915->drm, new_offset > old_offset);
225
226 if (!is_surface_linear(fb, color_plane)) {
227 unsigned int tile_size, tile_width, tile_height;
228 unsigned int pitch_tiles;
229
230 tile_size = intel_tile_size(i915);
231 intel_tile_dims(fb, color_plane, &tile_width, &tile_height);
232
233 if (drm_rotation_90_or_270(rotation)) {
234 pitch_tiles = pitch / tile_height;
235 swap(tile_width, tile_height);
236 } else {
237 pitch_tiles = pitch / (tile_width * cpp);
238 }
239
240 intel_adjust_tile_offset(x, y, tile_width, tile_height,
241 tile_size, pitch_tiles,
242 old_offset, new_offset);
243 } else {
244 old_offset += *y * pitch + *x * cpp;
245
246 *y = (old_offset - new_offset) / pitch;
247 *x = ((old_offset - new_offset) - *y * pitch) / cpp;
248 }
249
250 return new_offset;
251}
252
253
254
255
256
257u32 intel_plane_adjust_aligned_offset(int *x, int *y,
258 const struct intel_plane_state *state,
259 int color_plane,
260 u32 old_offset, u32 new_offset)
261{
262 return intel_adjust_aligned_offset(x, y, state->hw.fb, color_plane,
263 state->hw.rotation,
264 state->view.color_plane[color_plane].stride,
265 old_offset, new_offset);
266}
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282static u32 intel_compute_aligned_offset(struct drm_i915_private *i915,
283 int *x, int *y,
284 const struct drm_framebuffer *fb,
285 int color_plane,
286 unsigned int pitch,
287 unsigned int rotation,
288 u32 alignment)
289{
290 unsigned int cpp = fb->format->cpp[color_plane];
291 u32 offset, offset_aligned;
292
293 if (!is_surface_linear(fb, color_plane)) {
294 unsigned int tile_size, tile_width, tile_height;
295 unsigned int tile_rows, tiles, pitch_tiles;
296
297 tile_size = intel_tile_size(i915);
298 intel_tile_dims(fb, color_plane, &tile_width, &tile_height);
299
300 if (drm_rotation_90_or_270(rotation)) {
301 pitch_tiles = pitch / tile_height;
302 swap(tile_width, tile_height);
303 } else {
304 pitch_tiles = pitch / (tile_width * cpp);
305 }
306
307 tile_rows = *y / tile_height;
308 *y %= tile_height;
309
310 tiles = *x / tile_width;
311 *x %= tile_width;
312
313 offset = (tile_rows * pitch_tiles + tiles) * tile_size;
314
315 offset_aligned = offset;
316 if (alignment)
317 offset_aligned = rounddown(offset_aligned, alignment);
318
319 intel_adjust_tile_offset(x, y, tile_width, tile_height,
320 tile_size, pitch_tiles,
321 offset, offset_aligned);
322 } else {
323 offset = *y * pitch + *x * cpp;
324 offset_aligned = offset;
325 if (alignment) {
326 offset_aligned = rounddown(offset_aligned, alignment);
327 *y = (offset % alignment) / pitch;
328 *x = ((offset % alignment) - *y * pitch) / cpp;
329 } else {
330 *y = *x = 0;
331 }
332 }
333
334 return offset_aligned;
335}
336
337u32 intel_plane_compute_aligned_offset(int *x, int *y,
338 const struct intel_plane_state *state,
339 int color_plane)
340{
341 struct intel_plane *intel_plane = to_intel_plane(state->uapi.plane);
342 struct drm_i915_private *i915 = to_i915(intel_plane->base.dev);
343 const struct drm_framebuffer *fb = state->hw.fb;
344 unsigned int rotation = state->hw.rotation;
345 int pitch = state->view.color_plane[color_plane].stride;
346 u32 alignment;
347
348 if (intel_plane->id == PLANE_CURSOR)
349 alignment = intel_cursor_alignment(i915);
350 else
351 alignment = intel_surf_alignment(fb, color_plane);
352
353 return intel_compute_aligned_offset(i915, x, y, fb, color_plane,
354 pitch, rotation, alignment);
355}
356
357
358static int intel_fb_offset_to_xy(int *x, int *y,
359 const struct drm_framebuffer *fb,
360 int color_plane)
361{
362 struct drm_i915_private *i915 = to_i915(fb->dev);
363 unsigned int height;
364 u32 alignment;
365
366 if (DISPLAY_VER(i915) >= 12 &&
367 is_semiplanar_uv_plane(fb, color_plane))
368 alignment = intel_tile_row_size(fb, color_plane);
369 else if (fb->modifier != DRM_FORMAT_MOD_LINEAR)
370 alignment = intel_tile_size(i915);
371 else
372 alignment = 0;
373
374 if (alignment != 0 && fb->offsets[color_plane] % alignment) {
375 drm_dbg_kms(&i915->drm,
376 "Misaligned offset 0x%08x for color plane %d\n",
377 fb->offsets[color_plane], color_plane);
378 return -EINVAL;
379 }
380
381 height = drm_framebuffer_plane_height(fb->height, fb, color_plane);
382 height = ALIGN(height, intel_tile_height(fb, color_plane));
383
384
385 if (add_overflows_t(u32, mul_u32_u32(height, fb->pitches[color_plane]),
386 fb->offsets[color_plane])) {
387 drm_dbg_kms(&i915->drm,
388 "Bad offset 0x%08x or pitch %d for color plane %d\n",
389 fb->offsets[color_plane], fb->pitches[color_plane],
390 color_plane);
391 return -ERANGE;
392 }
393
394 *x = 0;
395 *y = 0;
396
397 intel_adjust_aligned_offset(x, y,
398 fb, color_plane, DRM_MODE_ROTATE_0,
399 fb->pitches[color_plane],
400 fb->offsets[color_plane], 0);
401
402 return 0;
403}
404
405static int intel_fb_check_ccs_xy(const struct drm_framebuffer *fb, int ccs_plane, int x, int y)
406{
407 struct drm_i915_private *i915 = to_i915(fb->dev);
408 const struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
409 int main_plane;
410 int hsub, vsub;
411 int tile_width, tile_height;
412 int ccs_x, ccs_y;
413 int main_x, main_y;
414
415 if (!is_ccs_plane(fb, ccs_plane) || is_gen12_ccs_cc_plane(fb, ccs_plane))
416 return 0;
417
418 intel_tile_dims(fb, ccs_plane, &tile_width, &tile_height);
419 intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane);
420
421 tile_width *= hsub;
422 tile_height *= vsub;
423
424 ccs_x = (x * hsub) % tile_width;
425 ccs_y = (y * vsub) % tile_height;
426
427 main_plane = skl_ccs_to_main_plane(fb, ccs_plane);
428 main_x = intel_fb->normal_view.color_plane[main_plane].x % tile_width;
429 main_y = intel_fb->normal_view.color_plane[main_plane].y % tile_height;
430
431
432
433
434
435 if (main_x != ccs_x || main_y != ccs_y) {
436 drm_dbg_kms(&i915->drm,
437 "Bad CCS x/y (main %d,%d ccs %d,%d) full (main %d,%d ccs %d,%d)\n",
438 main_x, main_y,
439 ccs_x, ccs_y,
440 intel_fb->normal_view.color_plane[main_plane].x,
441 intel_fb->normal_view.color_plane[main_plane].y,
442 x, y);
443 return -EINVAL;
444 }
445
446 return 0;
447}
448
449static bool intel_plane_can_remap(const struct intel_plane_state *plane_state)
450{
451 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
452 struct drm_i915_private *i915 = to_i915(plane->base.dev);
453 const struct drm_framebuffer *fb = plane_state->hw.fb;
454 int i;
455
456
457 if (plane->id == PLANE_CURSOR)
458 return false;
459
460
461
462
463
464
465
466 if (DISPLAY_VER(i915) < 4)
467 return false;
468
469
470
471
472
473 if (is_ccs_modifier(fb->modifier))
474 return false;
475
476
477 if (fb->modifier == DRM_FORMAT_MOD_LINEAR) {
478 unsigned int alignment = intel_tile_size(i915) - 1;
479
480 for (i = 0; i < fb->format->num_planes; i++) {
481 if (fb->pitches[i] & alignment)
482 return false;
483 }
484 }
485
486 return true;
487}
488
489static bool intel_fb_needs_pot_stride_remap(const struct intel_framebuffer *fb)
490{
491 return false;
492}
493
494static int intel_fb_pitch(const struct intel_framebuffer *fb, int color_plane, unsigned int rotation)
495{
496 if (drm_rotation_90_or_270(rotation))
497 return fb->rotated_view.color_plane[color_plane].stride;
498 else if (intel_fb_needs_pot_stride_remap(fb))
499 return fb->remapped_view.color_plane[color_plane].stride;
500 else
501 return fb->normal_view.color_plane[color_plane].stride;
502}
503
504static bool intel_plane_needs_remap(const struct intel_plane_state *plane_state)
505{
506 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
507 const struct intel_framebuffer *fb = to_intel_framebuffer(plane_state->hw.fb);
508 unsigned int rotation = plane_state->hw.rotation;
509 u32 stride, max_stride;
510
511
512
513
514
515 if (!plane_state->uapi.visible)
516 return false;
517
518 if (!intel_plane_can_remap(plane_state))
519 return false;
520
521
522
523
524
525 stride = intel_fb_pitch(fb, 0, rotation);
526 max_stride = plane->max_stride(plane, fb->base.format->format,
527 fb->base.modifier, rotation);
528
529 return stride > max_stride;
530}
531
532static int convert_plane_offset_to_xy(const struct intel_framebuffer *fb, int color_plane,
533 int plane_width, int *x, int *y)
534{
535 struct drm_i915_gem_object *obj = intel_fb_obj(&fb->base);
536 int ret;
537
538 ret = intel_fb_offset_to_xy(x, y, &fb->base, color_plane);
539 if (ret) {
540 drm_dbg_kms(fb->base.dev,
541 "bad fb plane %d offset: 0x%x\n",
542 color_plane, fb->base.offsets[color_plane]);
543 return ret;
544 }
545
546 ret = intel_fb_check_ccs_xy(&fb->base, color_plane, *x, *y);
547 if (ret)
548 return ret;
549
550
551
552
553
554
555
556
557
558
559 if (color_plane == 0 && i915_gem_object_is_tiled(obj) &&
560 (*x + plane_width) * fb->base.format->cpp[color_plane] > fb->base.pitches[color_plane]) {
561 drm_dbg_kms(fb->base.dev,
562 "bad fb plane %d offset: 0x%x\n",
563 color_plane, fb->base.offsets[color_plane]);
564 return -EINVAL;
565 }
566
567 return 0;
568}
569
570static u32 calc_plane_aligned_offset(const struct intel_framebuffer *fb, int color_plane, int *x, int *y)
571{
572 struct drm_i915_private *i915 = to_i915(fb->base.dev);
573 unsigned int tile_size = intel_tile_size(i915);
574 u32 offset;
575
576 offset = intel_compute_aligned_offset(i915, x, y, &fb->base, color_plane,
577 fb->base.pitches[color_plane],
578 DRM_MODE_ROTATE_0,
579 tile_size);
580
581 return offset / tile_size;
582}
583
584struct fb_plane_view_dims {
585 unsigned int width, height;
586 unsigned int tile_width, tile_height;
587};
588
589static void init_plane_view_dims(const struct intel_framebuffer *fb, int color_plane,
590 unsigned int width, unsigned int height,
591 struct fb_plane_view_dims *dims)
592{
593 dims->width = width;
594 dims->height = height;
595
596 intel_tile_dims(&fb->base, color_plane, &dims->tile_width, &dims->tile_height);
597}
598
599static unsigned int
600plane_view_src_stride_tiles(const struct intel_framebuffer *fb, int color_plane,
601 const struct fb_plane_view_dims *dims)
602{
603 return DIV_ROUND_UP(fb->base.pitches[color_plane],
604 dims->tile_width * fb->base.format->cpp[color_plane]);
605}
606
607static unsigned int
608plane_view_dst_stride_tiles(const struct intel_framebuffer *fb, int color_plane,
609 unsigned int pitch_tiles)
610{
611 if (intel_fb_needs_pot_stride_remap(fb))
612 return roundup_pow_of_two(pitch_tiles);
613 else
614 return pitch_tiles;
615}
616
617static unsigned int
618plane_view_width_tiles(const struct intel_framebuffer *fb, int color_plane,
619 const struct fb_plane_view_dims *dims,
620 int x)
621{
622 return DIV_ROUND_UP(x + dims->width, dims->tile_width);
623}
624
625static unsigned int
626plane_view_height_tiles(const struct intel_framebuffer *fb, int color_plane,
627 const struct fb_plane_view_dims *dims,
628 int y)
629{
630 return DIV_ROUND_UP(y + dims->height, dims->tile_height);
631}
632
633#define assign_chk_ovf(i915, var, val) ({ \
634 drm_WARN_ON(&(i915)->drm, overflows_type(val, var)); \
635 (var) = (val); \
636})
637
638static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_plane,
639 const struct fb_plane_view_dims *dims,
640 u32 obj_offset, u32 gtt_offset, int x, int y,
641 struct intel_fb_view *view)
642{
643 struct drm_i915_private *i915 = to_i915(fb->base.dev);
644 struct intel_remapped_plane_info *remap_info = &view->gtt.remapped.plane[color_plane];
645 struct i915_color_plane_view *color_plane_info = &view->color_plane[color_plane];
646 unsigned int tile_width = dims->tile_width;
647 unsigned int tile_height = dims->tile_height;
648 unsigned int tile_size = intel_tile_size(i915);
649 struct drm_rect r;
650 u32 size;
651
652 assign_chk_ovf(i915, remap_info->offset, obj_offset);
653 assign_chk_ovf(i915, remap_info->src_stride, plane_view_src_stride_tiles(fb, color_plane, dims));
654 assign_chk_ovf(i915, remap_info->width, plane_view_width_tiles(fb, color_plane, dims, x));
655 assign_chk_ovf(i915, remap_info->height, plane_view_height_tiles(fb, color_plane, dims, y));
656
657 if (view->gtt.type == I915_GGTT_VIEW_ROTATED) {
658 check_array_bounds(i915, view->gtt.rotated.plane, color_plane);
659
660 assign_chk_ovf(i915, remap_info->dst_stride,
661 plane_view_dst_stride_tiles(fb, color_plane, remap_info->height));
662
663
664 drm_rect_init(&r, x, y, dims->width, dims->height);
665 drm_rect_rotate(&r,
666 remap_info->width * tile_width,
667 remap_info->height * tile_height,
668 DRM_MODE_ROTATE_270);
669
670 color_plane_info->x = r.x1;
671 color_plane_info->y = r.y1;
672
673 color_plane_info->stride = remap_info->dst_stride * tile_height;
674
675 size = remap_info->dst_stride * remap_info->width;
676
677
678 swap(tile_width, tile_height);
679 } else {
680 drm_WARN_ON(&i915->drm, view->gtt.type != I915_GGTT_VIEW_REMAPPED);
681
682 check_array_bounds(i915, view->gtt.remapped.plane, color_plane);
683
684 assign_chk_ovf(i915, remap_info->dst_stride,
685 plane_view_dst_stride_tiles(fb, color_plane, remap_info->width));
686
687 color_plane_info->x = x;
688 color_plane_info->y = y;
689
690 color_plane_info->stride = remap_info->dst_stride * tile_width *
691 fb->base.format->cpp[color_plane];
692
693 size = remap_info->dst_stride * remap_info->height;
694 }
695
696
697
698
699
700
701 intel_adjust_tile_offset(&color_plane_info->x, &color_plane_info->y,
702 tile_width, tile_height,
703 tile_size, remap_info->dst_stride,
704 gtt_offset * tile_size, 0);
705
706 return size;
707}
708
709#undef assign_chk_ovf
710
711
712static unsigned int
713calc_plane_normal_size(const struct intel_framebuffer *fb, int color_plane,
714 const struct fb_plane_view_dims *dims,
715 int x, int y)
716{
717 struct drm_i915_private *i915 = to_i915(fb->base.dev);
718 unsigned int tiles;
719
720 if (is_surface_linear(&fb->base, color_plane)) {
721 unsigned int size;
722
723 size = (y + dims->height) * fb->base.pitches[color_plane] +
724 x * fb->base.format->cpp[color_plane];
725 tiles = DIV_ROUND_UP(size, intel_tile_size(i915));
726 } else {
727 tiles = plane_view_src_stride_tiles(fb, color_plane, dims) *
728 plane_view_height_tiles(fb, color_plane, dims, y);
729
730
731
732
733 if (x != 0)
734 tiles++;
735 }
736
737 return tiles;
738}
739
740static void intel_fb_view_init(struct intel_fb_view *view, enum i915_ggtt_view_type view_type)
741{
742 memset(view, 0, sizeof(*view));
743 view->gtt.type = view_type;
744}
745
746int intel_fill_fb_info(struct drm_i915_private *i915, struct drm_framebuffer *fb)
747{
748 struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
749 struct drm_i915_gem_object *obj = intel_fb_obj(fb);
750 u32 gtt_offset_rotated = 0;
751 u32 gtt_offset_remapped = 0;
752 unsigned int max_size = 0;
753 int i, num_planes = fb->format->num_planes;
754 unsigned int tile_size = intel_tile_size(i915);
755
756 intel_fb_view_init(&intel_fb->normal_view, I915_GGTT_VIEW_NORMAL);
757 intel_fb_view_init(&intel_fb->rotated_view, I915_GGTT_VIEW_ROTATED);
758 intel_fb_view_init(&intel_fb->remapped_view, I915_GGTT_VIEW_REMAPPED);
759
760 for (i = 0; i < num_planes; i++) {
761 struct fb_plane_view_dims view_dims;
762 unsigned int width, height;
763 unsigned int cpp, size;
764 u32 offset;
765 int x, y;
766 int ret;
767
768
769
770
771
772
773 if (is_gen12_ccs_cc_plane(fb, i)) {
774 if (IS_ALIGNED(fb->offsets[i], PAGE_SIZE))
775 continue;
776 else
777 return -EINVAL;
778 }
779
780 cpp = fb->format->cpp[i];
781 intel_fb_plane_dims(&width, &height, fb, i);
782
783 ret = convert_plane_offset_to_xy(intel_fb, i, width, &x, &y);
784 if (ret)
785 return ret;
786
787 init_plane_view_dims(intel_fb, i, width, height, &view_dims);
788
789
790
791
792
793 intel_fb->normal_view.color_plane[i].x = x;
794 intel_fb->normal_view.color_plane[i].y = y;
795 intel_fb->normal_view.color_plane[i].stride = intel_fb->base.pitches[i];
796
797 offset = calc_plane_aligned_offset(intel_fb, i, &x, &y);
798
799
800 if (fb->modifier == I915_FORMAT_MOD_Y_TILED ||
801 fb->modifier == I915_FORMAT_MOD_Yf_TILED)
802 gtt_offset_rotated += calc_plane_remap_info(intel_fb, i, &view_dims,
803 offset, gtt_offset_rotated, x, y,
804 &intel_fb->rotated_view);
805
806 if (intel_fb_needs_pot_stride_remap(intel_fb))
807 gtt_offset_remapped += calc_plane_remap_info(intel_fb, i, &view_dims,
808 offset, gtt_offset_remapped, x, y,
809 &intel_fb->remapped_view);
810
811 size = calc_plane_normal_size(intel_fb, i, &view_dims, x, y);
812
813 max_size = max(max_size, offset + size);
814 }
815
816 if (mul_u32_u32(max_size, tile_size) > obj->base.size) {
817 drm_dbg_kms(&i915->drm,
818 "fb too big for bo (need %llu bytes, have %zu bytes)\n",
819 mul_u32_u32(max_size, tile_size), obj->base.size);
820 return -EINVAL;
821 }
822
823 return 0;
824}
825
826static void intel_plane_remap_gtt(struct intel_plane_state *plane_state)
827{
828 struct drm_i915_private *i915 =
829 to_i915(plane_state->uapi.plane->dev);
830 struct drm_framebuffer *fb = plane_state->hw.fb;
831 struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
832 unsigned int rotation = plane_state->hw.rotation;
833 int i, num_planes = fb->format->num_planes;
834 unsigned int src_x, src_y;
835 unsigned int src_w, src_h;
836 u32 gtt_offset = 0;
837
838 intel_fb_view_init(&plane_state->view,
839 drm_rotation_90_or_270(rotation) ? I915_GGTT_VIEW_ROTATED :
840 I915_GGTT_VIEW_REMAPPED);
841
842 src_x = plane_state->uapi.src.x1 >> 16;
843 src_y = plane_state->uapi.src.y1 >> 16;
844 src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
845 src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
846
847 drm_WARN_ON(&i915->drm, is_ccs_modifier(fb->modifier));
848
849
850 drm_rect_translate(&plane_state->uapi.src,
851 -(src_x << 16), -(src_y << 16));
852
853
854 if (drm_rotation_90_or_270(rotation))
855 drm_rect_rotate(&plane_state->uapi.src,
856 src_w << 16, src_h << 16,
857 DRM_MODE_ROTATE_270);
858
859 for (i = 0; i < num_planes; i++) {
860 unsigned int hsub = i ? fb->format->hsub : 1;
861 unsigned int vsub = i ? fb->format->vsub : 1;
862 struct fb_plane_view_dims view_dims;
863 unsigned int width, height;
864 unsigned int x, y;
865 u32 offset;
866
867 x = src_x / hsub;
868 y = src_y / vsub;
869 width = src_w / hsub;
870 height = src_h / vsub;
871
872 init_plane_view_dims(intel_fb, i, width, height, &view_dims);
873
874
875
876
877
878 x += intel_fb->normal_view.color_plane[i].x;
879 y += intel_fb->normal_view.color_plane[i].y;
880
881 offset = calc_plane_aligned_offset(intel_fb, i, &x, &y);
882
883 gtt_offset += calc_plane_remap_info(intel_fb, i, &view_dims,
884 offset, gtt_offset, x, y,
885 &plane_state->view);
886 }
887}
888
889void intel_fb_fill_view(const struct intel_framebuffer *fb, unsigned int rotation,
890 struct intel_fb_view *view)
891{
892 if (drm_rotation_90_or_270(rotation))
893 *view = fb->rotated_view;
894 else if (intel_fb_needs_pot_stride_remap(fb))
895 *view = fb->remapped_view;
896 else
897 *view = fb->normal_view;
898}
899
900static int intel_plane_check_stride(const struct intel_plane_state *plane_state)
901{
902 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
903 const struct drm_framebuffer *fb = plane_state->hw.fb;
904 unsigned int rotation = plane_state->hw.rotation;
905 u32 stride, max_stride;
906
907
908
909
910
911
912
913 if (intel_plane_can_remap(plane_state) &&
914 !plane_state->uapi.visible)
915 return 0;
916
917
918 stride = plane_state->view.color_plane[0].stride;
919 max_stride = plane->max_stride(plane, fb->format->format,
920 fb->modifier, rotation);
921
922 if (stride > max_stride) {
923 DRM_DEBUG_KMS("[FB:%d] stride (%d) exceeds [PLANE:%d:%s] max stride (%d)\n",
924 fb->base.id, stride,
925 plane->base.base.id, plane->base.name, max_stride);
926 return -EINVAL;
927 }
928
929 return 0;
930}
931
932int intel_plane_compute_gtt(struct intel_plane_state *plane_state)
933{
934 const struct intel_framebuffer *fb =
935 to_intel_framebuffer(plane_state->hw.fb);
936 unsigned int rotation = plane_state->hw.rotation;
937
938 if (!fb)
939 return 0;
940
941 if (intel_plane_needs_remap(plane_state)) {
942 intel_plane_remap_gtt(plane_state);
943
944
945
946
947
948
949
950 return intel_plane_check_stride(plane_state);
951 }
952
953 intel_fb_fill_view(fb, rotation, &plane_state->view);
954
955
956 if (drm_rotation_90_or_270(rotation))
957 drm_rect_rotate(&plane_state->uapi.src,
958 fb->base.width << 16, fb->base.height << 16,
959 DRM_MODE_ROTATE_270);
960
961 return intel_plane_check_stride(plane_state);
962}
963