1// SPDX-License-Identifier: MIT
2/*
3 * Copyright © 2020 Intel Corporation
4 */
5
6#include <drm/drm_atomic_helper.h>
7#include <drm/drm_blend.h>
8#include <drm/drm_damage_helper.h>
9#include <drm/drm_fourcc.h>
10
11#include "pxp/intel_pxp.h"
12#include "i915_drv.h"
13#include "i915_utils.h"
14#include "intel_bo.h"
15#include "intel_de.h"
16#include "intel_display_irq.h"
17#include "intel_display_regs.h"
18#include "intel_display_types.h"
19#include "intel_dpt.h"
20#include "intel_fb.h"
21#include "intel_fbc.h"
22#include "intel_frontbuffer.h"
23#include "intel_panic.h"
24#include "intel_plane.h"
25#include "intel_psr.h"
26#include "intel_psr_regs.h"
27#include "skl_scaler.h"
28#include "skl_universal_plane.h"
29#include "skl_universal_plane_regs.h"
30#include "skl_watermark.h"
31
32static const u32 skl_plane_formats[] = {
33 DRM_FORMAT_C8,
34 DRM_FORMAT_RGB565,
35 DRM_FORMAT_XRGB8888,
36 DRM_FORMAT_XBGR8888,
37 DRM_FORMAT_ARGB8888,
38 DRM_FORMAT_ABGR8888,
39 DRM_FORMAT_XRGB2101010,
40 DRM_FORMAT_XBGR2101010,
41 DRM_FORMAT_XRGB16161616F,
42 DRM_FORMAT_XBGR16161616F,
43 DRM_FORMAT_YUYV,
44 DRM_FORMAT_YVYU,
45 DRM_FORMAT_UYVY,
46 DRM_FORMAT_VYUY,
47 DRM_FORMAT_XYUV8888,
48};
49
50static const u32 skl_planar_formats[] = {
51 DRM_FORMAT_C8,
52 DRM_FORMAT_RGB565,
53 DRM_FORMAT_XRGB8888,
54 DRM_FORMAT_XBGR8888,
55 DRM_FORMAT_ARGB8888,
56 DRM_FORMAT_ABGR8888,
57 DRM_FORMAT_XRGB2101010,
58 DRM_FORMAT_XBGR2101010,
59 DRM_FORMAT_XRGB16161616F,
60 DRM_FORMAT_XBGR16161616F,
61 DRM_FORMAT_YUYV,
62 DRM_FORMAT_YVYU,
63 DRM_FORMAT_UYVY,
64 DRM_FORMAT_VYUY,
65 DRM_FORMAT_NV12,
66 DRM_FORMAT_XYUV8888,
67};
68
69static const u32 glk_planar_formats[] = {
70 DRM_FORMAT_C8,
71 DRM_FORMAT_RGB565,
72 DRM_FORMAT_XRGB8888,
73 DRM_FORMAT_XBGR8888,
74 DRM_FORMAT_ARGB8888,
75 DRM_FORMAT_ABGR8888,
76 DRM_FORMAT_XRGB2101010,
77 DRM_FORMAT_XBGR2101010,
78 DRM_FORMAT_XRGB16161616F,
79 DRM_FORMAT_XBGR16161616F,
80 DRM_FORMAT_YUYV,
81 DRM_FORMAT_YVYU,
82 DRM_FORMAT_UYVY,
83 DRM_FORMAT_VYUY,
84 DRM_FORMAT_NV12,
85 DRM_FORMAT_XYUV8888,
86 DRM_FORMAT_P010,
87 DRM_FORMAT_P012,
88 DRM_FORMAT_P016,
89};
90
91static const u32 icl_sdr_y_plane_formats[] = {
92 DRM_FORMAT_C8,
93 DRM_FORMAT_RGB565,
94 DRM_FORMAT_XRGB8888,
95 DRM_FORMAT_XBGR8888,
96 DRM_FORMAT_ARGB8888,
97 DRM_FORMAT_ABGR8888,
98 DRM_FORMAT_XRGB2101010,
99 DRM_FORMAT_XBGR2101010,
100 DRM_FORMAT_ARGB2101010,
101 DRM_FORMAT_ABGR2101010,
102 DRM_FORMAT_YUYV,
103 DRM_FORMAT_YVYU,
104 DRM_FORMAT_UYVY,
105 DRM_FORMAT_VYUY,
106 DRM_FORMAT_Y210,
107 DRM_FORMAT_Y212,
108 DRM_FORMAT_Y216,
109 DRM_FORMAT_XYUV8888,
110 DRM_FORMAT_XVYU2101010,
111};
112
113static const u32 icl_sdr_uv_plane_formats[] = {
114 DRM_FORMAT_C8,
115 DRM_FORMAT_RGB565,
116 DRM_FORMAT_XRGB8888,
117 DRM_FORMAT_XBGR8888,
118 DRM_FORMAT_ARGB8888,
119 DRM_FORMAT_ABGR8888,
120 DRM_FORMAT_XRGB2101010,
121 DRM_FORMAT_XBGR2101010,
122 DRM_FORMAT_ARGB2101010,
123 DRM_FORMAT_ABGR2101010,
124 DRM_FORMAT_YUYV,
125 DRM_FORMAT_YVYU,
126 DRM_FORMAT_UYVY,
127 DRM_FORMAT_VYUY,
128 DRM_FORMAT_NV12,
129 DRM_FORMAT_P010,
130 DRM_FORMAT_P012,
131 DRM_FORMAT_P016,
132 DRM_FORMAT_Y210,
133 DRM_FORMAT_Y212,
134 DRM_FORMAT_Y216,
135 DRM_FORMAT_XYUV8888,
136 DRM_FORMAT_XVYU2101010,
137};
138
139static const u32 icl_hdr_plane_formats[] = {
140 DRM_FORMAT_C8,
141 DRM_FORMAT_RGB565,
142 DRM_FORMAT_XRGB8888,
143 DRM_FORMAT_XBGR8888,
144 DRM_FORMAT_ARGB8888,
145 DRM_FORMAT_ABGR8888,
146 DRM_FORMAT_XRGB2101010,
147 DRM_FORMAT_XBGR2101010,
148 DRM_FORMAT_ARGB2101010,
149 DRM_FORMAT_ABGR2101010,
150 DRM_FORMAT_XRGB16161616F,
151 DRM_FORMAT_XBGR16161616F,
152 DRM_FORMAT_ARGB16161616F,
153 DRM_FORMAT_ABGR16161616F,
154 DRM_FORMAT_YUYV,
155 DRM_FORMAT_YVYU,
156 DRM_FORMAT_UYVY,
157 DRM_FORMAT_VYUY,
158 DRM_FORMAT_NV12,
159 DRM_FORMAT_P010,
160 DRM_FORMAT_P012,
161 DRM_FORMAT_P016,
162 DRM_FORMAT_Y210,
163 DRM_FORMAT_Y212,
164 DRM_FORMAT_Y216,
165 DRM_FORMAT_XYUV8888,
166 DRM_FORMAT_XVYU2101010,
167 DRM_FORMAT_XVYU12_16161616,
168 DRM_FORMAT_XVYU16161616,
169};
170
171int skl_format_to_fourcc(int format, bool rgb_order, bool alpha)
172{
173 switch (format) {
174 case PLANE_CTL_FORMAT_RGB_565:
175 return DRM_FORMAT_RGB565;
176 case PLANE_CTL_FORMAT_NV12:
177 return DRM_FORMAT_NV12;
178 case PLANE_CTL_FORMAT_XYUV:
179 return DRM_FORMAT_XYUV8888;
180 case PLANE_CTL_FORMAT_P010:
181 return DRM_FORMAT_P010;
182 case PLANE_CTL_FORMAT_P012:
183 return DRM_FORMAT_P012;
184 case PLANE_CTL_FORMAT_P016:
185 return DRM_FORMAT_P016;
186 case PLANE_CTL_FORMAT_Y210:
187 return DRM_FORMAT_Y210;
188 case PLANE_CTL_FORMAT_Y212:
189 return DRM_FORMAT_Y212;
190 case PLANE_CTL_FORMAT_Y216:
191 return DRM_FORMAT_Y216;
192 case PLANE_CTL_FORMAT_Y410:
193 return DRM_FORMAT_XVYU2101010;
194 case PLANE_CTL_FORMAT_Y412:
195 return DRM_FORMAT_XVYU12_16161616;
196 case PLANE_CTL_FORMAT_Y416:
197 return DRM_FORMAT_XVYU16161616;
198 default:
199 case PLANE_CTL_FORMAT_XRGB_8888:
200 if (rgb_order) {
201 if (alpha)
202 return DRM_FORMAT_ABGR8888;
203 else
204 return DRM_FORMAT_XBGR8888;
205 } else {
206 if (alpha)
207 return DRM_FORMAT_ARGB8888;
208 else
209 return DRM_FORMAT_XRGB8888;
210 }
211 case PLANE_CTL_FORMAT_XRGB_2101010:
212 if (rgb_order) {
213 if (alpha)
214 return DRM_FORMAT_ABGR2101010;
215 else
216 return DRM_FORMAT_XBGR2101010;
217 } else {
218 if (alpha)
219 return DRM_FORMAT_ARGB2101010;
220 else
221 return DRM_FORMAT_XRGB2101010;
222 }
223 case PLANE_CTL_FORMAT_XRGB_16161616F:
224 if (rgb_order) {
225 if (alpha)
226 return DRM_FORMAT_ABGR16161616F;
227 else
228 return DRM_FORMAT_XBGR16161616F;
229 } else {
230 if (alpha)
231 return DRM_FORMAT_ARGB16161616F;
232 else
233 return DRM_FORMAT_XRGB16161616F;
234 }
235 }
236}
237
238static u8 icl_nv12_y_plane_mask(struct intel_display *display)
239{
240 if (DISPLAY_VER(display) >= 13 || HAS_D12_PLANE_MINIMIZATION(display))
241 return BIT(PLANE_4) | BIT(PLANE_5);
242 else
243 return BIT(PLANE_6) | BIT(PLANE_7);
244}
245
246bool icl_is_nv12_y_plane(struct intel_display *display,
247 enum plane_id plane_id)
248{
249 return DISPLAY_VER(display) >= 11 &&
250 icl_nv12_y_plane_mask(display) & BIT(plane_id);
251}
252
253u8 icl_hdr_plane_mask(void)
254{
255 return BIT(PLANE_1) | BIT(PLANE_2) | BIT(PLANE_3);
256}
257
258bool icl_is_hdr_plane(struct intel_display *display, enum plane_id plane_id)
259{
260 return DISPLAY_VER(display) >= 11 &&
261 icl_hdr_plane_mask() & BIT(plane_id);
262}
263
264static int icl_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
265 const struct intel_plane_state *plane_state)
266{
267 unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state);
268
269 /* two pixels per clock */
270 return DIV_ROUND_UP(pixel_rate, 2);
271}
272
273static void
274glk_plane_ratio(const struct intel_plane_state *plane_state,
275 unsigned int *num, unsigned int *den)
276{
277 const struct drm_framebuffer *fb = plane_state->hw.fb;
278
279 if (fb->format->cpp[0] == 8) {
280 *num = 10;
281 *den = 8;
282 } else {
283 *num = 1;
284 *den = 1;
285 }
286}
287
288static int glk_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
289 const struct intel_plane_state *plane_state)
290{
291 unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state);
292 unsigned int num, den;
293
294 glk_plane_ratio(plane_state, num: &num, den: &den);
295
296 /* two pixels per clock */
297 return DIV_ROUND_UP(pixel_rate * num, 2 * den);
298}
299
300static void
301skl_plane_ratio(const struct intel_plane_state *plane_state,
302 unsigned int *num, unsigned int *den)
303{
304 const struct drm_framebuffer *fb = plane_state->hw.fb;
305
306 if (fb->format->cpp[0] == 8) {
307 *num = 9;
308 *den = 8;
309 } else {
310 *num = 1;
311 *den = 1;
312 }
313}
314
315static int skl_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
316 const struct intel_plane_state *plane_state)
317{
318 unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state);
319 unsigned int num, den;
320
321 skl_plane_ratio(plane_state, num: &num, den: &den);
322
323 return DIV_ROUND_UP(pixel_rate * num, den);
324}
325
326static int skl_plane_max_width(const struct drm_framebuffer *fb,
327 int color_plane,
328 unsigned int rotation)
329{
330 int cpp = fb->format->cpp[color_plane];
331
332 switch (fb->modifier) {
333 case DRM_FORMAT_MOD_LINEAR:
334 case I915_FORMAT_MOD_X_TILED:
335 /*
336 * Validated limit is 4k, but has 5k should
337 * work apart from the following features:
338 * - Ytile (already limited to 4k)
339 * - FP16 (already limited to 4k)
340 * - render compression (already limited to 4k)
341 * - KVMR sprite and cursor (don't care)
342 * - horizontal panning (TODO verify this)
343 * - pipe and plane scaling (TODO verify this)
344 */
345 if (cpp == 8)
346 return 4096;
347 else
348 return 5120;
349 case I915_FORMAT_MOD_Y_TILED_CCS:
350 case I915_FORMAT_MOD_Yf_TILED_CCS:
351 /* FIXME AUX plane? */
352 case I915_FORMAT_MOD_Y_TILED:
353 case I915_FORMAT_MOD_Yf_TILED:
354 if (cpp == 8)
355 return 2048;
356 else
357 return 4096;
358 default:
359 MISSING_CASE(fb->modifier);
360 return 2048;
361 }
362}
363
364static int glk_plane_max_width(const struct drm_framebuffer *fb,
365 int color_plane,
366 unsigned int rotation)
367{
368 int cpp = fb->format->cpp[color_plane];
369
370 switch (fb->modifier) {
371 case DRM_FORMAT_MOD_LINEAR:
372 case I915_FORMAT_MOD_X_TILED:
373 if (cpp == 8)
374 return 4096;
375 else
376 return 5120;
377 case I915_FORMAT_MOD_Y_TILED_CCS:
378 case I915_FORMAT_MOD_Yf_TILED_CCS:
379 /* FIXME AUX plane? */
380 case I915_FORMAT_MOD_Y_TILED:
381 case I915_FORMAT_MOD_Yf_TILED:
382 if (cpp == 8)
383 return 2048;
384 else
385 return 5120;
386 default:
387 MISSING_CASE(fb->modifier);
388 return 2048;
389 }
390}
391
392static int icl_plane_min_width(const struct drm_framebuffer *fb,
393 int color_plane,
394 unsigned int rotation)
395{
396 /* Wa_14011264657, Wa_14011050563: gen11+ */
397 switch (fb->format->format) {
398 case DRM_FORMAT_C8:
399 return 18;
400 case DRM_FORMAT_RGB565:
401 return 10;
402 case DRM_FORMAT_XRGB8888:
403 case DRM_FORMAT_XBGR8888:
404 case DRM_FORMAT_ARGB8888:
405 case DRM_FORMAT_ABGR8888:
406 case DRM_FORMAT_XRGB2101010:
407 case DRM_FORMAT_XBGR2101010:
408 case DRM_FORMAT_ARGB2101010:
409 case DRM_FORMAT_ABGR2101010:
410 case DRM_FORMAT_XVYU2101010:
411 case DRM_FORMAT_Y212:
412 case DRM_FORMAT_Y216:
413 return 6;
414 case DRM_FORMAT_NV12:
415 return 20;
416 case DRM_FORMAT_P010:
417 case DRM_FORMAT_P012:
418 case DRM_FORMAT_P016:
419 return 12;
420 case DRM_FORMAT_XRGB16161616F:
421 case DRM_FORMAT_XBGR16161616F:
422 case DRM_FORMAT_ARGB16161616F:
423 case DRM_FORMAT_ABGR16161616F:
424 case DRM_FORMAT_XVYU12_16161616:
425 case DRM_FORMAT_XVYU16161616:
426 return 4;
427 default:
428 return 1;
429 }
430}
431
432static int xe3_plane_max_width(const struct drm_framebuffer *fb,
433 int color_plane,
434 unsigned int rotation)
435{
436 if (intel_format_info_is_yuv_semiplanar(info: fb->format, modifier: fb->modifier))
437 return 4096;
438 else
439 return 6144;
440}
441
442static int icl_hdr_plane_max_width(const struct drm_framebuffer *fb,
443 int color_plane,
444 unsigned int rotation)
445{
446 if (intel_format_info_is_yuv_semiplanar(info: fb->format, modifier: fb->modifier))
447 return 4096;
448 else
449 return 5120;
450}
451
452static int icl_sdr_plane_max_width(const struct drm_framebuffer *fb,
453 int color_plane,
454 unsigned int rotation)
455{
456 return 5120;
457}
458
459static int skl_plane_max_height(const struct drm_framebuffer *fb,
460 int color_plane,
461 unsigned int rotation)
462{
463 return 4096;
464}
465
466static int icl_plane_max_height(const struct drm_framebuffer *fb,
467 int color_plane,
468 unsigned int rotation)
469{
470 return 4320;
471}
472
473static unsigned int
474plane_max_stride(struct intel_plane *plane,
475 u32 pixel_format, u64 modifier,
476 unsigned int rotation,
477 unsigned int max_pixels,
478 unsigned int max_bytes)
479{
480 const struct drm_format_info *info = drm_format_info(format: pixel_format);
481 int cpp = info->cpp[0];
482
483 if (drm_rotation_90_or_270(rotation))
484 return min(max_pixels, max_bytes / cpp);
485 else
486 return min(max_pixels * cpp, max_bytes);
487}
488
489static unsigned int
490adl_plane_max_stride(struct intel_plane *plane,
491 u32 pixel_format, u64 modifier,
492 unsigned int rotation)
493{
494 unsigned int max_pixels = 65536; /* PLANE_OFFSET limit */
495 unsigned int max_bytes = 128 * 1024;
496
497 return plane_max_stride(plane, pixel_format,
498 modifier, rotation,
499 max_pixels, max_bytes);
500}
501
502static unsigned int
503skl_plane_max_stride(struct intel_plane *plane,
504 u32 pixel_format, u64 modifier,
505 unsigned int rotation)
506{
507 unsigned int max_pixels = 8192; /* PLANE_OFFSET limit */
508 unsigned int max_bytes = 32 * 1024;
509
510 return plane_max_stride(plane, pixel_format,
511 modifier, rotation,
512 max_pixels, max_bytes);
513}
514
515static bool tgl_plane_can_async_flip(u64 modifier)
516{
517 switch (modifier) {
518 case DRM_FORMAT_MOD_LINEAR:
519 case I915_FORMAT_MOD_X_TILED:
520 case I915_FORMAT_MOD_Y_TILED:
521 case I915_FORMAT_MOD_4_TILED:
522 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
523 case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS:
524 case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS:
525 case I915_FORMAT_MOD_4_TILED_BMG_CCS:
526 case I915_FORMAT_MOD_4_TILED_LNL_CCS:
527 return true;
528 case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
529 case I915_FORMAT_MOD_4_TILED_MTL_MC_CCS:
530 case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS:
531 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
532 case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS_CC:
533 case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC:
534 return false;
535 default:
536 return false;
537 }
538}
539
540static bool icl_plane_can_async_flip(u64 modifier)
541{
542 switch (modifier) {
543 case DRM_FORMAT_MOD_LINEAR:
544 /*
545 * FIXME: Async on Linear buffer is supported on ICL
546 * but with additional alignment and fbc restrictions
547 * need to be taken care of.
548 */
549 return false;
550 case I915_FORMAT_MOD_X_TILED:
551 case I915_FORMAT_MOD_Y_TILED:
552 case I915_FORMAT_MOD_Yf_TILED:
553 case I915_FORMAT_MOD_Y_TILED_CCS:
554 case I915_FORMAT_MOD_Yf_TILED_CCS:
555 return true;
556 default:
557 return false;
558 }
559}
560
561static bool skl_plane_can_async_flip(u64 modifier)
562{
563 switch (modifier) {
564 case DRM_FORMAT_MOD_LINEAR:
565 return false;
566 case I915_FORMAT_MOD_X_TILED:
567 case I915_FORMAT_MOD_Y_TILED:
568 case I915_FORMAT_MOD_Yf_TILED:
569 return true;
570 case I915_FORMAT_MOD_Y_TILED_CCS:
571 case I915_FORMAT_MOD_Yf_TILED_CCS:
572 /*
573 * Display WA #0731: skl
574 * WaDisableRCWithAsyncFlip: skl
575 * "When render decompression is enabled, hardware
576 * internally converts the Async flips to Sync flips."
577 *
578 * Display WA #1159: glk
579 * "Async flip with render compression may result in
580 * intermittent underrun corruption."
581 */
582 return false;
583 default:
584 return false;
585 }
586}
587
588static u32 tgl_plane_min_alignment(struct intel_plane *plane,
589 const struct drm_framebuffer *fb,
590 int color_plane)
591{
592 struct intel_display *display = to_intel_display(plane);
593 /* PLANE_SURF GGTT -> DPT alignment */
594 int mult = intel_fb_uses_dpt(fb) ? 512 : 1;
595
596 /* AUX_DIST needs only 4K alignment */
597 if (intel_fb_is_ccs_aux_plane(fb, color_plane))
598 return mult * 4 * 1024;
599
600 /*
601 * FIXME ADL sees GGTT/DMAR faults with async
602 * flips unless we align to 16k at least.
603 * Figure out what's going on here...
604 */
605 if (display->platform.alderlake_p &&
606 intel_plane_can_async_flip(plane, format: fb->format->format, modifier: fb->modifier))
607 return mult * 16 * 1024;
608
609 switch (fb->modifier) {
610 case DRM_FORMAT_MOD_LINEAR:
611 case I915_FORMAT_MOD_X_TILED:
612 case I915_FORMAT_MOD_Y_TILED:
613 case I915_FORMAT_MOD_4_TILED:
614 return mult * 4 * 1024;
615 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
616 case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS:
617 case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS:
618 case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
619 case I915_FORMAT_MOD_4_TILED_MTL_MC_CCS:
620 case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS:
621 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
622 case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS_CC:
623 case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC:
624 case I915_FORMAT_MOD_4_TILED_BMG_CCS:
625 case I915_FORMAT_MOD_4_TILED_LNL_CCS:
626 /*
627 * Align to at least 4x1 main surface
628 * tiles (16K) to match 64B of AUX.
629 */
630 return max(mult * 4 * 1024, 16 * 1024);
631 default:
632 MISSING_CASE(fb->modifier);
633 return 0;
634 }
635}
636
637static u32 skl_plane_min_alignment(struct intel_plane *plane,
638 const struct drm_framebuffer *fb,
639 int color_plane)
640{
641 /*
642 * AUX_DIST needs only 4K alignment,
643 * as does ICL UV PLANE_SURF.
644 */
645 if (color_plane != 0)
646 return 4 * 1024;
647
648 /*
649 * VT-d needs at least 256k alignment,
650 * but that's already covered below.
651 */
652 switch (fb->modifier) {
653 case DRM_FORMAT_MOD_LINEAR:
654 case I915_FORMAT_MOD_X_TILED:
655 return 256 * 1024;
656 case I915_FORMAT_MOD_Y_TILED_CCS:
657 case I915_FORMAT_MOD_Yf_TILED_CCS:
658 case I915_FORMAT_MOD_Y_TILED:
659 case I915_FORMAT_MOD_Yf_TILED:
660 return 1 * 1024 * 1024;
661 default:
662 MISSING_CASE(fb->modifier);
663 return 0;
664 }
665}
666
667/* Preoffset values for YUV to RGB Conversion */
668#define PREOFF_YUV_TO_RGB_HI 0x1800
669#define PREOFF_YUV_TO_RGB_ME 0x0000
670#define PREOFF_YUV_TO_RGB_LO 0x1800
671
672#define ROFF(x) (((x) & 0xffff) << 16)
673#define GOFF(x) (((x) & 0xffff) << 0)
674#define BOFF(x) (((x) & 0xffff) << 16)
675
676/*
677 * Programs the input color space conversion stage for ICL HDR planes.
678 * Note that it is assumed that this stage always happens after YUV
679 * range correction. Thus, the input to this stage is assumed to be
680 * in full-range YCbCr.
681 */
682static void
683icl_program_input_csc(struct intel_dsb *dsb,
684 struct intel_plane *plane,
685 const struct intel_plane_state *plane_state)
686{
687 struct intel_display *display = to_intel_display(plane);
688 enum pipe pipe = plane->pipe;
689 enum plane_id plane_id = plane->id;
690
691 static const u16 input_csc_matrix[][9] = {
692 /*
693 * BT.601 full range YCbCr -> full range RGB
694 * The matrix required is :
695 * [1.000, 0.000, 1.371,
696 * 1.000, -0.336, -0.698,
697 * 1.000, 1.732, 0.0000]
698 */
699 [DRM_COLOR_YCBCR_BT601] = {
700 0x7AF8, 0x7800, 0x0,
701 0x8B28, 0x7800, 0x9AC0,
702 0x0, 0x7800, 0x7DD8,
703 },
704 /*
705 * BT.709 full range YCbCr -> full range RGB
706 * The matrix required is :
707 * [1.000, 0.000, 1.574,
708 * 1.000, -0.187, -0.468,
709 * 1.000, 1.855, 0.0000]
710 */
711 [DRM_COLOR_YCBCR_BT709] = {
712 0x7C98, 0x7800, 0x0,
713 0x9EF8, 0x7800, 0xAC00,
714 0x0, 0x7800, 0x7ED8,
715 },
716 /*
717 * BT.2020 full range YCbCr -> full range RGB
718 * The matrix required is :
719 * [1.000, 0.000, 1.474,
720 * 1.000, -0.1645, -0.5713,
721 * 1.000, 1.8814, 0.0000]
722 */
723 [DRM_COLOR_YCBCR_BT2020] = {
724 0x7BC8, 0x7800, 0x0,
725 0x8928, 0x7800, 0xAA88,
726 0x0, 0x7800, 0x7F10,
727 },
728 };
729 const u16 *csc = input_csc_matrix[plane_state->hw.color_encoding];
730
731 intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 0),
732 ROFF(csc[0]) | GOFF(csc[1]));
733 intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 1),
734 BOFF(csc[2]));
735 intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 2),
736 ROFF(csc[3]) | GOFF(csc[4]));
737 intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 3),
738 BOFF(csc[5]));
739 intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 4),
740 ROFF(csc[6]) | GOFF(csc[7]));
741 intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 5),
742 BOFF(csc[8]));
743
744 intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 0),
745 PREOFF_YUV_TO_RGB_HI);
746 intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1),
747 PREOFF_YUV_TO_RGB_ME);
748 intel_de_write_dsb(display, dsb, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 2),
749 PREOFF_YUV_TO_RGB_LO);
750 intel_de_write_dsb(display, dsb,
751 PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 0), val: 0x0);
752 intel_de_write_dsb(display, dsb,
753 PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 1), val: 0x0);
754 intel_de_write_dsb(display, dsb,
755 PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 2), val: 0x0);
756}
757
758static unsigned int skl_plane_stride_mult(const struct drm_framebuffer *fb,
759 int color_plane, unsigned int rotation)
760{
761 /*
762 * The stride is either expressed as a multiple of 64 bytes chunks for
763 * linear buffers or in number of tiles for tiled buffers.
764 */
765 if (is_surface_linear(fb, color_plane))
766 return 64;
767 else if (drm_rotation_90_or_270(rotation))
768 return intel_tile_height(fb, color_plane);
769 else
770 return intel_tile_width_bytes(fb, color_plane);
771}
772
773static u32 skl_plane_stride(const struct intel_plane_state *plane_state,
774 int color_plane)
775{
776 const struct drm_framebuffer *fb = plane_state->hw.fb;
777 unsigned int rotation = plane_state->hw.rotation;
778 u32 stride = plane_state->view.color_plane[color_plane].scanout_stride;
779
780 if (color_plane >= fb->format->num_planes)
781 return 0;
782
783 return stride / skl_plane_stride_mult(fb, color_plane, rotation);
784}
785
786static u32 skl_plane_ddb_reg_val(const struct skl_ddb_entry *entry)
787{
788 if (!entry->end)
789 return 0;
790
791 return PLANE_BUF_END(entry->end - 1) |
792 PLANE_BUF_START(entry->start);
793}
794
795static u32 xe3_plane_min_ddb_reg_val(const u16 *min_ddb,
796 const u16 *interim_ddb)
797{
798 u32 val = 0;
799
800 if (*min_ddb)
801 val |= PLANE_MIN_DBUF_BLOCKS(*min_ddb);
802
803 if (*interim_ddb)
804 val |= PLANE_INTERIM_DBUF_BLOCKS(*interim_ddb);
805
806 val |= val ? PLANE_AUTO_MIN_DBUF_EN : 0;
807
808 return val;
809}
810
811static u32 skl_plane_wm_reg_val(const struct skl_wm_level *level)
812{
813 u32 val = 0;
814
815 if (level->enable)
816 val |= PLANE_WM_EN;
817 if (level->ignore_lines)
818 val |= PLANE_WM_IGNORE_LINES;
819 if (level->auto_min_alloc_wm_enable)
820 val |= PLANE_WM_AUTO_MIN_ALLOC_EN;
821
822 val |= REG_FIELD_PREP(PLANE_WM_BLOCKS_MASK, level->blocks);
823 val |= REG_FIELD_PREP(PLANE_WM_LINES_MASK, level->lines);
824
825 return val;
826}
827
828static void skl_write_plane_wm(struct intel_dsb *dsb,
829 struct intel_plane *plane,
830 const struct intel_crtc_state *crtc_state)
831{
832 struct intel_display *display = to_intel_display(plane);
833 enum plane_id plane_id = plane->id;
834 enum pipe pipe = plane->pipe;
835 const struct skl_pipe_wm *pipe_wm = &crtc_state->wm.skl.optimal;
836 const struct skl_ddb_entry *ddb =
837 &crtc_state->wm.skl.plane_ddb[plane_id];
838 const struct skl_ddb_entry *ddb_y =
839 &crtc_state->wm.skl.plane_ddb_y[plane_id];
840 const u16 *min_ddb = &crtc_state->wm.skl.plane_min_ddb[plane_id];
841 const u16 *interim_ddb =
842 &crtc_state->wm.skl.plane_interim_ddb[plane_id];
843 int level;
844
845 for (level = 0; level < display->wm.num_levels; level++)
846 intel_de_write_dsb(display, dsb, PLANE_WM(pipe, plane_id, level),
847 val: skl_plane_wm_reg_val(level: skl_plane_wm_level(pipe_wm, plane_id, level)));
848
849 intel_de_write_dsb(display, dsb, PLANE_WM_TRANS(pipe, plane_id),
850 val: skl_plane_wm_reg_val(level: skl_plane_trans_wm(pipe_wm, plane_id)));
851
852 if (HAS_HW_SAGV_WM(display)) {
853 const struct skl_plane_wm *wm = &pipe_wm->planes[plane_id];
854
855 intel_de_write_dsb(display, dsb, PLANE_WM_SAGV(pipe, plane_id),
856 val: skl_plane_wm_reg_val(level: &wm->sagv.wm0));
857 intel_de_write_dsb(display, dsb, PLANE_WM_SAGV_TRANS(pipe, plane_id),
858 val: skl_plane_wm_reg_val(level: &wm->sagv.trans_wm));
859 }
860
861 intel_de_write_dsb(display, dsb, PLANE_BUF_CFG(pipe, plane_id),
862 val: skl_plane_ddb_reg_val(entry: ddb));
863
864 if (DISPLAY_VER(display) < 11)
865 intel_de_write_dsb(display, dsb, PLANE_NV12_BUF_CFG(pipe, plane_id),
866 val: skl_plane_ddb_reg_val(entry: ddb_y));
867
868 if (DISPLAY_VER(display) >= 30)
869 intel_de_write_dsb(display, dsb, PLANE_MIN_BUF_CFG(pipe, plane_id),
870 val: xe3_plane_min_ddb_reg_val(min_ddb, interim_ddb));
871}
872
873static void
874skl_plane_disable_arm(struct intel_dsb *dsb,
875 struct intel_plane *plane,
876 const struct intel_crtc_state *crtc_state)
877{
878 struct intel_display *display = to_intel_display(plane);
879 enum plane_id plane_id = plane->id;
880 enum pipe pipe = plane->pipe;
881
882 skl_write_plane_wm(dsb, plane, crtc_state);
883
884 intel_de_write_dsb(display, dsb, PLANE_CTL(pipe, plane_id), val: 0);
885 intel_de_write_dsb(display, dsb, PLANE_SURF(pipe, plane_id), val: 0);
886}
887
888static void icl_plane_disable_sel_fetch_arm(struct intel_dsb *dsb,
889 struct intel_plane *plane,
890 const struct intel_crtc_state *crtc_state)
891{
892 struct intel_display *display = to_intel_display(plane);
893 enum pipe pipe = plane->pipe;
894
895 if (!crtc_state->enable_psr2_sel_fetch)
896 return;
897
898 intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_CTL(pipe, plane->id), val: 0);
899}
900
901static void
902icl_plane_disable_arm(struct intel_dsb *dsb,
903 struct intel_plane *plane,
904 const struct intel_crtc_state *crtc_state)
905{
906 struct intel_display *display = to_intel_display(plane);
907 enum plane_id plane_id = plane->id;
908 enum pipe pipe = plane->pipe;
909
910 if (icl_is_hdr_plane(display, plane_id))
911 intel_de_write_dsb(display, dsb, PLANE_CUS_CTL(pipe, plane_id), val: 0);
912
913 skl_write_plane_wm(dsb, plane, crtc_state);
914
915 icl_plane_disable_sel_fetch_arm(dsb, plane, crtc_state);
916 intel_de_write_dsb(display, dsb, PLANE_CTL(pipe, plane_id), val: 0);
917 intel_de_write_dsb(display, dsb, PLANE_SURF(pipe, plane_id), val: 0);
918}
919
920static bool
921skl_plane_get_hw_state(struct intel_plane *plane,
922 enum pipe *pipe)
923{
924 struct intel_display *display = to_intel_display(plane);
925 enum intel_display_power_domain power_domain;
926 enum plane_id plane_id = plane->id;
927 intel_wakeref_t wakeref;
928 bool ret;
929
930 power_domain = POWER_DOMAIN_PIPE(plane->pipe);
931 wakeref = intel_display_power_get_if_enabled(display, domain: power_domain);
932 if (!wakeref)
933 return false;
934
935 ret = intel_de_read(display, PLANE_CTL(plane->pipe, plane_id)) & PLANE_CTL_ENABLE;
936
937 *pipe = plane->pipe;
938
939 intel_display_power_put(display, domain: power_domain, wakeref);
940
941 return ret;
942}
943
944static u32 skl_plane_ctl_format(u32 pixel_format)
945{
946 switch (pixel_format) {
947 case DRM_FORMAT_C8:
948 return PLANE_CTL_FORMAT_INDEXED;
949 case DRM_FORMAT_RGB565:
950 return PLANE_CTL_FORMAT_RGB_565;
951 case DRM_FORMAT_XBGR8888:
952 case DRM_FORMAT_ABGR8888:
953 return PLANE_CTL_FORMAT_XRGB_8888 | PLANE_CTL_ORDER_RGBX;
954 case DRM_FORMAT_XRGB8888:
955 case DRM_FORMAT_ARGB8888:
956 return PLANE_CTL_FORMAT_XRGB_8888;
957 case DRM_FORMAT_XBGR2101010:
958 case DRM_FORMAT_ABGR2101010:
959 return PLANE_CTL_FORMAT_XRGB_2101010 | PLANE_CTL_ORDER_RGBX;
960 case DRM_FORMAT_XRGB2101010:
961 case DRM_FORMAT_ARGB2101010:
962 return PLANE_CTL_FORMAT_XRGB_2101010;
963 case DRM_FORMAT_XBGR16161616F:
964 case DRM_FORMAT_ABGR16161616F:
965 return PLANE_CTL_FORMAT_XRGB_16161616F | PLANE_CTL_ORDER_RGBX;
966 case DRM_FORMAT_XRGB16161616F:
967 case DRM_FORMAT_ARGB16161616F:
968 return PLANE_CTL_FORMAT_XRGB_16161616F;
969 case DRM_FORMAT_XYUV8888:
970 return PLANE_CTL_FORMAT_XYUV;
971 case DRM_FORMAT_YUYV:
972 return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_ORDER_YUYV;
973 case DRM_FORMAT_YVYU:
974 return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_ORDER_YVYU;
975 case DRM_FORMAT_UYVY:
976 return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_ORDER_UYVY;
977 case DRM_FORMAT_VYUY:
978 return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_ORDER_VYUY;
979 case DRM_FORMAT_NV12:
980 return PLANE_CTL_FORMAT_NV12;
981 case DRM_FORMAT_P010:
982 return PLANE_CTL_FORMAT_P010;
983 case DRM_FORMAT_P012:
984 return PLANE_CTL_FORMAT_P012;
985 case DRM_FORMAT_P016:
986 return PLANE_CTL_FORMAT_P016;
987 case DRM_FORMAT_Y210:
988 return PLANE_CTL_FORMAT_Y210;
989 case DRM_FORMAT_Y212:
990 return PLANE_CTL_FORMAT_Y212;
991 case DRM_FORMAT_Y216:
992 return PLANE_CTL_FORMAT_Y216;
993 case DRM_FORMAT_XVYU2101010:
994 return PLANE_CTL_FORMAT_Y410;
995 case DRM_FORMAT_XVYU12_16161616:
996 return PLANE_CTL_FORMAT_Y412;
997 case DRM_FORMAT_XVYU16161616:
998 return PLANE_CTL_FORMAT_Y416;
999 default:
1000 MISSING_CASE(pixel_format);
1001 }
1002
1003 return 0;
1004}
1005
1006static u32 skl_plane_ctl_alpha(const struct intel_plane_state *plane_state)
1007{
1008 if (!plane_state->hw.fb->format->has_alpha)
1009 return PLANE_CTL_ALPHA_DISABLE;
1010
1011 switch (plane_state->hw.pixel_blend_mode) {
1012 case DRM_MODE_BLEND_PIXEL_NONE:
1013 return PLANE_CTL_ALPHA_DISABLE;
1014 case DRM_MODE_BLEND_PREMULTI:
1015 return PLANE_CTL_ALPHA_SW_PREMULTIPLY;
1016 case DRM_MODE_BLEND_COVERAGE:
1017 return PLANE_CTL_ALPHA_HW_PREMULTIPLY;
1018 default:
1019 MISSING_CASE(plane_state->hw.pixel_blend_mode);
1020 return PLANE_CTL_ALPHA_DISABLE;
1021 }
1022}
1023
1024static u32 glk_plane_color_ctl_alpha(const struct intel_plane_state *plane_state)
1025{
1026 if (!plane_state->hw.fb->format->has_alpha)
1027 return PLANE_COLOR_ALPHA_DISABLE;
1028
1029 switch (plane_state->hw.pixel_blend_mode) {
1030 case DRM_MODE_BLEND_PIXEL_NONE:
1031 return PLANE_COLOR_ALPHA_DISABLE;
1032 case DRM_MODE_BLEND_PREMULTI:
1033 return PLANE_COLOR_ALPHA_SW_PREMULTIPLY;
1034 case DRM_MODE_BLEND_COVERAGE:
1035 return PLANE_COLOR_ALPHA_HW_PREMULTIPLY;
1036 default:
1037 MISSING_CASE(plane_state->hw.pixel_blend_mode);
1038 return PLANE_COLOR_ALPHA_DISABLE;
1039 }
1040}
1041
1042static u32 skl_plane_ctl_tiling(u64 fb_modifier)
1043{
1044 switch (fb_modifier) {
1045 case DRM_FORMAT_MOD_LINEAR:
1046 break;
1047 case I915_FORMAT_MOD_X_TILED:
1048 return PLANE_CTL_TILED_X;
1049 case I915_FORMAT_MOD_Y_TILED:
1050 return PLANE_CTL_TILED_Y;
1051 case I915_FORMAT_MOD_4_TILED:
1052 return PLANE_CTL_TILED_4;
1053 case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS:
1054 return PLANE_CTL_TILED_4 |
1055 PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
1056 PLANE_CTL_CLEAR_COLOR_DISABLE;
1057 case I915_FORMAT_MOD_4_TILED_DG2_MC_CCS:
1058 return PLANE_CTL_TILED_4 |
1059 PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE |
1060 PLANE_CTL_CLEAR_COLOR_DISABLE;
1061 case I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC:
1062 return PLANE_CTL_TILED_4 | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
1063 case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS:
1064 return PLANE_CTL_TILED_4 |
1065 PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
1066 PLANE_CTL_CLEAR_COLOR_DISABLE;
1067 case I915_FORMAT_MOD_4_TILED_MTL_RC_CCS_CC:
1068 return PLANE_CTL_TILED_4 | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
1069 case I915_FORMAT_MOD_4_TILED_MTL_MC_CCS:
1070 return PLANE_CTL_TILED_4 | PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE;
1071 case I915_FORMAT_MOD_4_TILED_BMG_CCS:
1072 case I915_FORMAT_MOD_4_TILED_LNL_CCS:
1073 return PLANE_CTL_TILED_4 | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
1074 case I915_FORMAT_MOD_Y_TILED_CCS:
1075 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC:
1076 return PLANE_CTL_TILED_Y | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
1077 case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS:
1078 return PLANE_CTL_TILED_Y |
1079 PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
1080 PLANE_CTL_CLEAR_COLOR_DISABLE;
1081 case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
1082 return PLANE_CTL_TILED_Y | PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE;
1083 case I915_FORMAT_MOD_Yf_TILED:
1084 return PLANE_CTL_TILED_YF;
1085 case I915_FORMAT_MOD_Yf_TILED_CCS:
1086 return PLANE_CTL_TILED_YF | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
1087 default:
1088 MISSING_CASE(fb_modifier);
1089 }
1090
1091 return 0;
1092}
1093
1094static u32 skl_plane_ctl_rotate(unsigned int rotate)
1095{
1096 switch (rotate) {
1097 case DRM_MODE_ROTATE_0:
1098 break;
1099 /*
1100 * DRM_MODE_ROTATE_ is counter clockwise to stay compatible with Xrandr
1101 * while i915 HW rotation is clockwise, that's why this swapping.
1102 */
1103 case DRM_MODE_ROTATE_90:
1104 return PLANE_CTL_ROTATE_270;
1105 case DRM_MODE_ROTATE_180:
1106 return PLANE_CTL_ROTATE_180;
1107 case DRM_MODE_ROTATE_270:
1108 return PLANE_CTL_ROTATE_90;
1109 default:
1110 MISSING_CASE(rotate);
1111 }
1112
1113 return 0;
1114}
1115
1116static u32 icl_plane_ctl_flip(unsigned int reflect)
1117{
1118 switch (reflect) {
1119 case 0:
1120 break;
1121 case DRM_MODE_REFLECT_X:
1122 return PLANE_CTL_FLIP_HORIZONTAL;
1123 case DRM_MODE_REFLECT_Y:
1124 default:
1125 MISSING_CASE(reflect);
1126 }
1127
1128 return 0;
1129}
1130
1131static u32 adlp_plane_ctl_arb_slots(const struct intel_plane_state *plane_state)
1132{
1133 const struct drm_framebuffer *fb = plane_state->hw.fb;
1134
1135 if (intel_format_info_is_yuv_semiplanar(info: fb->format, modifier: fb->modifier)) {
1136 switch (fb->format->cpp[0]) {
1137 case 2:
1138 return PLANE_CTL_ARB_SLOTS(1);
1139 default:
1140 return PLANE_CTL_ARB_SLOTS(0);
1141 }
1142 } else {
1143 switch (fb->format->cpp[0]) {
1144 case 8:
1145 return PLANE_CTL_ARB_SLOTS(3);
1146 case 4:
1147 return PLANE_CTL_ARB_SLOTS(1);
1148 default:
1149 return PLANE_CTL_ARB_SLOTS(0);
1150 }
1151 }
1152}
1153
1154static u32 skl_plane_ctl_crtc(const struct intel_crtc_state *crtc_state)
1155{
1156 struct intel_display *display = to_intel_display(crtc_state);
1157 u32 plane_ctl = 0;
1158
1159 if (DISPLAY_VER(display) >= 10)
1160 return plane_ctl;
1161
1162 if (crtc_state->gamma_enable)
1163 plane_ctl |= PLANE_CTL_PIPE_GAMMA_ENABLE;
1164
1165 if (crtc_state->csc_enable)
1166 plane_ctl |= PLANE_CTL_PIPE_CSC_ENABLE;
1167
1168 return plane_ctl;
1169}
1170
1171static u32 skl_plane_ctl(const struct intel_plane_state *plane_state)
1172{
1173 struct intel_display *display = to_intel_display(plane_state);
1174 const struct drm_framebuffer *fb = plane_state->hw.fb;
1175 unsigned int rotation = plane_state->hw.rotation;
1176 const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
1177 u32 plane_ctl;
1178
1179 plane_ctl = PLANE_CTL_ENABLE;
1180
1181 if (DISPLAY_VER(display) < 10) {
1182 plane_ctl |= skl_plane_ctl_alpha(plane_state);
1183 plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE;
1184
1185 if (plane_state->hw.color_encoding == DRM_COLOR_YCBCR_BT709)
1186 plane_ctl |= PLANE_CTL_YUV_TO_RGB_CSC_FORMAT_BT709;
1187
1188 if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
1189 plane_ctl |= PLANE_CTL_YUV_RANGE_CORRECTION_DISABLE;
1190 }
1191
1192 plane_ctl |= skl_plane_ctl_format(pixel_format: fb->format->format);
1193 plane_ctl |= skl_plane_ctl_tiling(fb_modifier: fb->modifier);
1194 plane_ctl |= skl_plane_ctl_rotate(rotate: rotation & DRM_MODE_ROTATE_MASK);
1195
1196 if (DISPLAY_VER(display) >= 11)
1197 plane_ctl |= icl_plane_ctl_flip(reflect: rotation &
1198 DRM_MODE_REFLECT_MASK);
1199
1200 if (key->flags & I915_SET_COLORKEY_DESTINATION)
1201 plane_ctl |= PLANE_CTL_KEY_ENABLE_DESTINATION;
1202 else if (key->flags & I915_SET_COLORKEY_SOURCE)
1203 plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE;
1204
1205 /* Wa_22012358565:adl-p */
1206 if (DISPLAY_VER(display) == 13)
1207 plane_ctl |= adlp_plane_ctl_arb_slots(plane_state);
1208
1209 return plane_ctl;
1210}
1211
1212static u32 glk_plane_color_ctl_crtc(const struct intel_crtc_state *crtc_state)
1213{
1214 struct intel_display *display = to_intel_display(crtc_state);
1215 u32 plane_color_ctl = 0;
1216
1217 if (DISPLAY_VER(display) >= 11)
1218 return plane_color_ctl;
1219
1220 if (crtc_state->gamma_enable)
1221 plane_color_ctl |= PLANE_COLOR_PIPE_GAMMA_ENABLE;
1222
1223 if (crtc_state->csc_enable)
1224 plane_color_ctl |= PLANE_COLOR_PIPE_CSC_ENABLE;
1225
1226 return plane_color_ctl;
1227}
1228
1229static u32 glk_plane_color_ctl(const struct intel_plane_state *plane_state)
1230{
1231 struct intel_display *display = to_intel_display(plane_state);
1232 const struct drm_framebuffer *fb = plane_state->hw.fb;
1233 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1234 u32 plane_color_ctl = 0;
1235
1236 plane_color_ctl |= PLANE_COLOR_PLANE_GAMMA_DISABLE;
1237 plane_color_ctl |= glk_plane_color_ctl_alpha(plane_state);
1238
1239 if (fb->format->is_yuv && !icl_is_hdr_plane(display, plane_id: plane->id)) {
1240 switch (plane_state->hw.color_encoding) {
1241 case DRM_COLOR_YCBCR_BT709:
1242 plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709;
1243 break;
1244 case DRM_COLOR_YCBCR_BT2020:
1245 plane_color_ctl |=
1246 PLANE_COLOR_CSC_MODE_YUV2020_TO_RGB2020;
1247 break;
1248 default:
1249 plane_color_ctl |=
1250 PLANE_COLOR_CSC_MODE_YUV601_TO_RGB601;
1251 }
1252 if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
1253 plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE;
1254 } else if (fb->format->is_yuv) {
1255 plane_color_ctl |= PLANE_COLOR_INPUT_CSC_ENABLE;
1256 if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
1257 plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE;
1258 }
1259
1260 if (plane_state->force_black)
1261 plane_color_ctl |= PLANE_COLOR_PLANE_CSC_ENABLE;
1262
1263 return plane_color_ctl;
1264}
1265
1266static u32 skl_surf_address(const struct intel_plane_state *plane_state,
1267 int color_plane)
1268{
1269 struct intel_display *display = to_intel_display(plane_state);
1270 const struct drm_framebuffer *fb = plane_state->hw.fb;
1271 u32 offset = plane_state->view.color_plane[color_plane].offset;
1272
1273 if (intel_fb_uses_dpt(fb)) {
1274 drm_WARN_ON(display->drm, offset & 0x1fffff);
1275 return offset >> 9;
1276 } else {
1277 drm_WARN_ON(display->drm, offset & 0xfff);
1278 return offset;
1279 }
1280}
1281
1282static int icl_plane_color_plane(const struct intel_plane_state *plane_state)
1283{
1284 if (plane_state->planar_linked_plane && !plane_state->is_y_plane)
1285 return 1;
1286 else
1287 return 0;
1288}
1289
1290static u32 skl_plane_surf_offset(const struct intel_plane_state *plane_state)
1291{
1292 int color_plane = icl_plane_color_plane(plane_state);
1293 u32 plane_surf;
1294
1295 plane_surf = skl_surf_address(plane_state, color_plane);
1296
1297 if (plane_state->decrypt)
1298 plane_surf |= PLANE_SURF_DECRYPT;
1299
1300 return plane_surf;
1301}
1302
1303u32 skl_plane_aux_dist(const struct intel_plane_state *plane_state,
1304 int color_plane)
1305{
1306 struct intel_display *display = to_intel_display(plane_state);
1307 const struct drm_framebuffer *fb = plane_state->hw.fb;
1308 int aux_plane = skl_main_to_aux_plane(fb, main_plane: color_plane);
1309 u32 aux_dist;
1310
1311 if (!aux_plane)
1312 return 0;
1313
1314 aux_dist = skl_surf_address(plane_state, color_plane: aux_plane) -
1315 skl_surf_address(plane_state, color_plane);
1316
1317 if (DISPLAY_VER(display) < 12)
1318 aux_dist |= PLANE_AUX_STRIDE(skl_plane_stride(plane_state, aux_plane));
1319
1320 return aux_dist;
1321}
1322
1323static u32 skl_plane_keyval(const struct intel_plane_state *plane_state)
1324{
1325 const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
1326
1327 return key->min_value;
1328}
1329
1330static u32 skl_plane_keymax(const struct intel_plane_state *plane_state)
1331{
1332 const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
1333 u8 alpha = plane_state->hw.alpha >> 8;
1334
1335 return (key->max_value & 0xffffff) | PLANE_KEYMAX_ALPHA(alpha);
1336}
1337
1338static u32 skl_plane_keymsk(const struct intel_plane_state *plane_state)
1339{
1340 const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
1341 u8 alpha = plane_state->hw.alpha >> 8;
1342 u32 keymsk;
1343
1344 keymsk = key->channel_mask & 0x7ffffff;
1345 if (alpha < 0xff)
1346 keymsk |= PLANE_KEYMSK_ALPHA_ENABLE;
1347
1348 return keymsk;
1349}
1350
1351static void icl_plane_csc_load_black(struct intel_dsb *dsb,
1352 struct intel_plane *plane,
1353 const struct intel_crtc_state *crtc_state)
1354{
1355 struct intel_display *display = to_intel_display(plane);
1356 enum plane_id plane_id = plane->id;
1357 enum pipe pipe = plane->pipe;
1358
1359 intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane_id, 0), val: 0);
1360 intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane_id, 1), val: 0);
1361
1362 intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane_id, 2), val: 0);
1363 intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane_id, 3), val: 0);
1364
1365 intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane_id, 4), val: 0);
1366 intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane_id, 5), val: 0);
1367
1368 intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane_id, 0), val: 0);
1369 intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane_id, 1), val: 0);
1370 intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane_id, 2), val: 0);
1371
1372 intel_de_write_dsb(display, dsb, PLANE_CSC_POSTOFF(pipe, plane_id, 0), val: 0);
1373 intel_de_write_dsb(display, dsb, PLANE_CSC_POSTOFF(pipe, plane_id, 1), val: 0);
1374 intel_de_write_dsb(display, dsb, PLANE_CSC_POSTOFF(pipe, plane_id, 2), val: 0);
1375}
1376
1377static void
1378skl_plane_update_noarm(struct intel_dsb *dsb,
1379 struct intel_plane *plane,
1380 const struct intel_crtc_state *crtc_state,
1381 const struct intel_plane_state *plane_state)
1382{
1383 struct intel_display *display = to_intel_display(plane);
1384 enum plane_id plane_id = plane->id;
1385 enum pipe pipe = plane->pipe;
1386 u32 stride = skl_plane_stride(plane_state, color_plane: 0);
1387 int crtc_x = plane_state->uapi.dst.x1;
1388 int crtc_y = plane_state->uapi.dst.y1;
1389 u32 src_w = drm_rect_width(r: &plane_state->uapi.src) >> 16;
1390 u32 src_h = drm_rect_height(r: &plane_state->uapi.src) >> 16;
1391
1392 /* The scaler will handle the output position */
1393 if (plane_state->scaler_id >= 0) {
1394 crtc_x = 0;
1395 crtc_y = 0;
1396 }
1397
1398 intel_de_write_dsb(display, dsb, PLANE_STRIDE(pipe, plane_id),
1399 PLANE_STRIDE_(stride));
1400 intel_de_write_dsb(display, dsb, PLANE_POS(pipe, plane_id),
1401 PLANE_POS_Y(crtc_y) | PLANE_POS_X(crtc_x));
1402 intel_de_write_dsb(display, dsb, PLANE_SIZE(pipe, plane_id),
1403 PLANE_HEIGHT(src_h - 1) | PLANE_WIDTH(src_w - 1));
1404
1405 skl_write_plane_wm(dsb, plane, crtc_state);
1406}
1407
1408static void
1409skl_plane_update_arm(struct intel_dsb *dsb,
1410 struct intel_plane *plane,
1411 const struct intel_crtc_state *crtc_state,
1412 const struct intel_plane_state *plane_state)
1413{
1414 struct intel_display *display = to_intel_display(plane);
1415 enum plane_id plane_id = plane->id;
1416 enum pipe pipe = plane->pipe;
1417 u32 x = plane_state->view.color_plane[0].x;
1418 u32 y = plane_state->view.color_plane[0].y;
1419 u32 plane_ctl, plane_color_ctl = 0;
1420
1421 plane_ctl = plane_state->ctl |
1422 skl_plane_ctl_crtc(crtc_state);
1423
1424 /* see intel_plane_atomic_calc_changes() */
1425 if (plane->need_async_flip_toggle_wa &&
1426 crtc_state->async_flip_planes & BIT(plane->id))
1427 plane_ctl |= PLANE_CTL_ASYNC_FLIP;
1428
1429 if (DISPLAY_VER(display) >= 10)
1430 plane_color_ctl = plane_state->color_ctl |
1431 glk_plane_color_ctl_crtc(crtc_state);
1432
1433 intel_de_write_dsb(display, dsb, PLANE_KEYVAL(pipe, plane_id),
1434 val: skl_plane_keyval(plane_state));
1435 intel_de_write_dsb(display, dsb, PLANE_KEYMSK(pipe, plane_id),
1436 val: skl_plane_keymsk(plane_state));
1437 intel_de_write_dsb(display, dsb, PLANE_KEYMAX(pipe, plane_id),
1438 val: skl_plane_keymax(plane_state));
1439
1440 intel_de_write_dsb(display, dsb, PLANE_OFFSET(pipe, plane_id),
1441 PLANE_OFFSET_Y(y) | PLANE_OFFSET_X(x));
1442
1443 intel_de_write_dsb(display, dsb, PLANE_AUX_DIST(pipe, plane_id),
1444 val: skl_plane_aux_dist(plane_state, color_plane: 0));
1445
1446 intel_de_write_dsb(display, dsb, PLANE_AUX_OFFSET(pipe, plane_id),
1447 PLANE_OFFSET_Y(plane_state->view.color_plane[1].y) |
1448 PLANE_OFFSET_X(plane_state->view.color_plane[1].x));
1449
1450 if (DISPLAY_VER(display) >= 10)
1451 intel_de_write_dsb(display, dsb, PLANE_COLOR_CTL(pipe, plane_id),
1452 val: plane_color_ctl);
1453
1454 /*
1455 * Enable the scaler before the plane so that we don't
1456 * get a catastrophic underrun even if the two operations
1457 * end up happening in two different frames.
1458 *
1459 * TODO: split into noarm+arm pair
1460 */
1461 if (plane_state->scaler_id >= 0)
1462 skl_program_plane_scaler(dsb, plane, crtc_state, plane_state);
1463
1464 /*
1465 * The control register self-arms if the plane was previously
1466 * disabled. Try to make the plane enable atomic by writing
1467 * the control register just before the surface register.
1468 */
1469 intel_de_write_dsb(display, dsb, PLANE_CTL(pipe, plane_id),
1470 val: plane_ctl);
1471 intel_de_write_dsb(display, dsb, PLANE_SURF(pipe, plane_id),
1472 val: plane_state->surf);
1473}
1474
1475static void icl_plane_update_sel_fetch_noarm(struct intel_dsb *dsb,
1476 struct intel_plane *plane,
1477 const struct intel_crtc_state *crtc_state,
1478 const struct intel_plane_state *plane_state,
1479 int color_plane)
1480{
1481 struct intel_display *display = to_intel_display(plane);
1482 enum pipe pipe = plane->pipe;
1483 const struct drm_rect *clip;
1484 u32 val;
1485 int x, y;
1486
1487 if (!crtc_state->enable_psr2_sel_fetch)
1488 return;
1489
1490 clip = &plane_state->psr2_sel_fetch_area;
1491
1492 if (crtc_state->enable_psr2_su_region_et)
1493 y = max(0, plane_state->uapi.dst.y1 - crtc_state->psr2_su_area.y1);
1494 else
1495 y = (clip->y1 + plane_state->uapi.dst.y1);
1496 val = y << 16;
1497 val |= plane_state->uapi.dst.x1;
1498 intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_POS(pipe, plane->id), val);
1499
1500 x = plane_state->view.color_plane[color_plane].x;
1501
1502 /*
1503 * From Bspec: UV surface Start Y Position = half of Y plane Y
1504 * start position.
1505 */
1506 if (!color_plane)
1507 y = plane_state->view.color_plane[color_plane].y + clip->y1;
1508 else
1509 y = plane_state->view.color_plane[color_plane].y + clip->y1 / 2;
1510
1511 val = y << 16 | x;
1512
1513 intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_OFFSET(pipe, plane->id), val);
1514
1515 /* Sizes are 0 based */
1516 val = (drm_rect_height(r: clip) - 1) << 16;
1517 val |= (drm_rect_width(r: &plane_state->uapi.src) >> 16) - 1;
1518 intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_SIZE(pipe, plane->id), val);
1519}
1520
1521static void
1522icl_plane_update_noarm(struct intel_dsb *dsb,
1523 struct intel_plane *plane,
1524 const struct intel_crtc_state *crtc_state,
1525 const struct intel_plane_state *plane_state)
1526{
1527 struct intel_display *display = to_intel_display(plane);
1528 enum plane_id plane_id = plane->id;
1529 enum pipe pipe = plane->pipe;
1530 int color_plane = icl_plane_color_plane(plane_state);
1531 u32 stride = skl_plane_stride(plane_state, color_plane);
1532 const struct drm_framebuffer *fb = plane_state->hw.fb;
1533 int crtc_x = plane_state->uapi.dst.x1;
1534 int crtc_y = plane_state->uapi.dst.y1;
1535 int x = plane_state->view.color_plane[color_plane].x;
1536 int y = plane_state->view.color_plane[color_plane].y;
1537 int src_w = drm_rect_width(r: &plane_state->uapi.src) >> 16;
1538 int src_h = drm_rect_height(r: &plane_state->uapi.src) >> 16;
1539 u32 plane_color_ctl;
1540
1541 plane_color_ctl = plane_state->color_ctl |
1542 glk_plane_color_ctl_crtc(crtc_state);
1543
1544 /* The scaler will handle the output position */
1545 if (plane_state->scaler_id >= 0) {
1546 crtc_x = 0;
1547 crtc_y = 0;
1548 }
1549
1550 intel_de_write_dsb(display, dsb, PLANE_STRIDE(pipe, plane_id),
1551 PLANE_STRIDE_(stride));
1552 intel_de_write_dsb(display, dsb, PLANE_POS(pipe, plane_id),
1553 PLANE_POS_Y(crtc_y) | PLANE_POS_X(crtc_x));
1554 intel_de_write_dsb(display, dsb, PLANE_SIZE(pipe, plane_id),
1555 PLANE_HEIGHT(src_h - 1) | PLANE_WIDTH(src_w - 1));
1556
1557 intel_de_write_dsb(display, dsb, PLANE_KEYVAL(pipe, plane_id),
1558 val: skl_plane_keyval(plane_state));
1559 intel_de_write_dsb(display, dsb, PLANE_KEYMSK(pipe, plane_id),
1560 val: skl_plane_keymsk(plane_state));
1561 intel_de_write_dsb(display, dsb, PLANE_KEYMAX(pipe, plane_id),
1562 val: skl_plane_keymax(plane_state));
1563
1564 intel_de_write_dsb(display, dsb, PLANE_OFFSET(pipe, plane_id),
1565 PLANE_OFFSET_Y(y) | PLANE_OFFSET_X(x));
1566
1567 if (intel_fb_is_rc_ccs_cc_modifier(modifier: fb->modifier)) {
1568 intel_de_write_dsb(display, dsb, PLANE_CC_VAL(pipe, plane_id, 0),
1569 lower_32_bits(plane_state->ccval));
1570 intel_de_write_dsb(display, dsb, PLANE_CC_VAL(pipe, plane_id, 1),
1571 upper_32_bits(plane_state->ccval));
1572 }
1573
1574 /* FLAT CCS doesn't need to program AUX_DIST */
1575 if (!HAS_FLAT_CCS(to_i915(display->drm)) && DISPLAY_VER(display) < 20)
1576 intel_de_write_dsb(display, dsb, PLANE_AUX_DIST(pipe, plane_id),
1577 val: skl_plane_aux_dist(plane_state, color_plane));
1578
1579 if (icl_is_hdr_plane(display, plane_id))
1580 intel_de_write_dsb(display, dsb, PLANE_CUS_CTL(pipe, plane_id),
1581 val: plane_state->cus_ctl);
1582
1583 intel_de_write_dsb(display, dsb, PLANE_COLOR_CTL(pipe, plane_id),
1584 val: plane_color_ctl);
1585
1586 if (fb->format->is_yuv && icl_is_hdr_plane(display, plane_id))
1587 icl_program_input_csc(dsb, plane, plane_state);
1588
1589 skl_write_plane_wm(dsb, plane, crtc_state);
1590
1591 /*
1592 * FIXME: pxp session invalidation can hit any time even at time of commit
1593 * or after the commit, display content will be garbage.
1594 */
1595 if (plane_state->force_black)
1596 icl_plane_csc_load_black(dsb, plane, crtc_state);
1597
1598 icl_plane_update_sel_fetch_noarm(dsb, plane, crtc_state, plane_state, color_plane);
1599}
1600
1601static void icl_plane_update_sel_fetch_arm(struct intel_dsb *dsb,
1602 struct intel_plane *plane,
1603 const struct intel_crtc_state *crtc_state,
1604 const struct intel_plane_state *plane_state)
1605{
1606 struct intel_display *display = to_intel_display(plane);
1607 enum pipe pipe = plane->pipe;
1608
1609 if (!crtc_state->enable_psr2_sel_fetch)
1610 return;
1611
1612 if (drm_rect_height(r: &plane_state->psr2_sel_fetch_area) > 0)
1613 intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_CTL(pipe, plane->id),
1614 SEL_FETCH_PLANE_CTL_ENABLE);
1615 else
1616 icl_plane_disable_sel_fetch_arm(dsb, plane, crtc_state);
1617}
1618
1619static void
1620icl_plane_update_arm(struct intel_dsb *dsb,
1621 struct intel_plane *plane,
1622 const struct intel_crtc_state *crtc_state,
1623 const struct intel_plane_state *plane_state)
1624{
1625 struct intel_display *display = to_intel_display(plane);
1626 enum plane_id plane_id = plane->id;
1627 enum pipe pipe = plane->pipe;
1628 u32 plane_ctl;
1629
1630 plane_ctl = plane_state->ctl |
1631 skl_plane_ctl_crtc(crtc_state);
1632
1633 /*
1634 * Enable the scaler before the plane so that we don't
1635 * get a catastrophic underrun even if the two operations
1636 * end up happening in two different frames.
1637 *
1638 * TODO: split into noarm+arm pair
1639 */
1640 if (plane_state->scaler_id >= 0)
1641 skl_program_plane_scaler(dsb, plane, crtc_state, plane_state);
1642
1643 icl_plane_update_sel_fetch_arm(dsb, plane, crtc_state, plane_state);
1644
1645 /*
1646 * The control register self-arms if the plane was previously
1647 * disabled. Try to make the plane enable atomic by writing
1648 * the control register just before the surface register.
1649 */
1650 intel_de_write_dsb(display, dsb, PLANE_CTL(pipe, plane_id),
1651 val: plane_ctl);
1652 intel_de_write_dsb(display, dsb, PLANE_SURF(pipe, plane_id),
1653 val: plane_state->surf);
1654}
1655
1656static void skl_plane_capture_error(struct intel_crtc *crtc,
1657 struct intel_plane *plane,
1658 struct intel_plane_error *error)
1659{
1660 struct intel_display *display = to_intel_display(plane);
1661
1662 error->ctl = intel_de_read(display, PLANE_CTL(crtc->pipe, plane->id));
1663 error->surf = intel_de_read(display, PLANE_SURF(crtc->pipe, plane->id));
1664 error->surflive = intel_de_read(display, PLANE_SURFLIVE(crtc->pipe, plane->id));
1665}
1666
1667static void
1668skl_plane_async_flip(struct intel_dsb *dsb,
1669 struct intel_plane *plane,
1670 const struct intel_crtc_state *crtc_state,
1671 const struct intel_plane_state *plane_state,
1672 bool async_flip)
1673{
1674 struct intel_display *display = to_intel_display(plane);
1675 enum plane_id plane_id = plane->id;
1676 enum pipe pipe = plane->pipe;
1677 u32 plane_ctl = plane_state->ctl;
1678 u32 plane_surf = plane_state->surf;
1679
1680 plane_ctl |= skl_plane_ctl_crtc(crtc_state);
1681
1682 if (async_flip) {
1683 if (DISPLAY_VER(display) >= 30)
1684 plane_surf |= PLANE_SURF_ASYNC_UPDATE;
1685 else
1686 plane_ctl |= PLANE_CTL_ASYNC_FLIP;
1687 }
1688
1689 intel_de_write_dsb(display, dsb, PLANE_CTL(pipe, plane_id),
1690 val: plane_ctl);
1691 intel_de_write_dsb(display, dsb, PLANE_SURF(pipe, plane_id),
1692 val: plane_surf);
1693}
1694
1695static bool intel_format_is_p01x(u32 format)
1696{
1697 switch (format) {
1698 case DRM_FORMAT_P010:
1699 case DRM_FORMAT_P012:
1700 case DRM_FORMAT_P016:
1701 return true;
1702 default:
1703 return false;
1704 }
1705}
1706
1707static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state,
1708 const struct intel_plane_state *plane_state)
1709{
1710 struct intel_display *display = to_intel_display(plane_state);
1711 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1712 const struct drm_framebuffer *fb = plane_state->hw.fb;
1713 unsigned int rotation = plane_state->hw.rotation;
1714
1715 if (!fb)
1716 return 0;
1717
1718 if (rotation & ~(DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180) &&
1719 intel_fb_is_ccs_modifier(modifier: fb->modifier)) {
1720 drm_dbg_kms(display->drm,
1721 "[PLANE:%d:%s] RC support only with 0/180 degree rotation (%x)\n",
1722 plane->base.base.id, plane->base.name, rotation);
1723 return -EINVAL;
1724 }
1725
1726 if (rotation & DRM_MODE_REFLECT_X &&
1727 fb->modifier == DRM_FORMAT_MOD_LINEAR) {
1728 drm_dbg_kms(display->drm,
1729 "[PLANE:%d:%s] horizontal flip is not supported with linear surface formats\n",
1730 plane->base.base.id, plane->base.name);
1731 return -EINVAL;
1732 }
1733
1734 /*
1735 * Display20 onward tile4 hflip is not supported
1736 */
1737 if (rotation & DRM_MODE_REFLECT_X &&
1738 intel_fb_is_tile4_modifier(modifier: fb->modifier) &&
1739 DISPLAY_VER(display) >= 20) {
1740 drm_dbg_kms(display->drm,
1741 "[PLANE:%d:%s] horizontal flip is not supported with tile4 surface formats\n",
1742 plane->base.base.id, plane->base.name);
1743 return -EINVAL;
1744 }
1745
1746 if (drm_rotation_90_or_270(rotation)) {
1747 if (!intel_fb_supports_90_270_rotation(to_intel_framebuffer(fb))) {
1748 drm_dbg_kms(display->drm,
1749 "[PLANE:%d:%s] Y/Yf tiling required for 90/270!\n",
1750 plane->base.base.id, plane->base.name);
1751 return -EINVAL;
1752 }
1753
1754 /*
1755 * 90/270 is not allowed with RGB64 16:16:16:16 and
1756 * Indexed 8-bit. RGB 16-bit 5:6:5 is allowed gen11 onwards.
1757 */
1758 switch (fb->format->format) {
1759 case DRM_FORMAT_RGB565:
1760 if (DISPLAY_VER(display) >= 11)
1761 break;
1762 fallthrough;
1763 case DRM_FORMAT_C8:
1764 case DRM_FORMAT_XRGB16161616F:
1765 case DRM_FORMAT_XBGR16161616F:
1766 case DRM_FORMAT_ARGB16161616F:
1767 case DRM_FORMAT_ABGR16161616F:
1768 case DRM_FORMAT_Y210:
1769 case DRM_FORMAT_Y212:
1770 case DRM_FORMAT_Y216:
1771 case DRM_FORMAT_XVYU12_16161616:
1772 case DRM_FORMAT_XVYU16161616:
1773 drm_dbg_kms(display->drm,
1774 "[PLANE:%d:%s] unsupported pixel format %p4cc for 90/270!\n",
1775 plane->base.base.id, plane->base.name, &fb->format->format);
1776 return -EINVAL;
1777 default:
1778 break;
1779 }
1780 }
1781
1782 /* Y-tiling is not supported in IF-ID Interlace mode */
1783 if (crtc_state->hw.enable &&
1784 crtc_state->hw.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE &&
1785 fb->modifier != DRM_FORMAT_MOD_LINEAR &&
1786 fb->modifier != I915_FORMAT_MOD_X_TILED) {
1787 drm_dbg_kms(display->drm,
1788 "[PLANE:%d:%s] Y/Yf tiling not supported in IF-ID mode\n",
1789 plane->base.base.id, plane->base.name);
1790 return -EINVAL;
1791 }
1792
1793 /* Wa_1606054188:tgl,adl-s */
1794 if ((display->platform.alderlake_s || display->platform.tigerlake) &&
1795 plane_state->ckey.flags & I915_SET_COLORKEY_SOURCE &&
1796 intel_format_is_p01x(format: fb->format->format)) {
1797 drm_dbg_kms(display->drm,
1798 "[PLANE:%d:%s] source color keying not supported with P01x formats\n",
1799 plane->base.base.id, plane->base.name);
1800 return -EINVAL;
1801 }
1802
1803 return 0;
1804}
1805
1806static int skl_plane_check_dst_coordinates(const struct intel_crtc_state *crtc_state,
1807 const struct intel_plane_state *plane_state)
1808{
1809 struct intel_display *display = to_intel_display(plane_state);
1810 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1811 int crtc_x = plane_state->uapi.dst.x1;
1812 int crtc_w = drm_rect_width(r: &plane_state->uapi.dst);
1813 int pipe_src_w = drm_rect_width(r: &crtc_state->pipe_src);
1814
1815 /*
1816 * Display WA #1175: glk
1817 * Planes other than the cursor may cause FIFO underflow and display
1818 * corruption if starting less than 4 pixels from the right edge of
1819 * the screen.
1820 * Besides the above WA fix the similar problem, where planes other
1821 * than the cursor ending less than 4 pixels from the left edge of the
1822 * screen may cause FIFO underflow and display corruption.
1823 */
1824 if (DISPLAY_VER(display) == 10 &&
1825 (crtc_x + crtc_w < 4 || crtc_x > pipe_src_w - 4)) {
1826 drm_dbg_kms(display->drm,
1827 "[PLANE:%d:%s] requested plane X %s position %d invalid (valid range %d-%d)\n",
1828 plane->base.base.id, plane->base.name,
1829 crtc_x + crtc_w < 4 ? "end" : "start",
1830 crtc_x + crtc_w < 4 ? crtc_x + crtc_w : crtc_x,
1831 4, pipe_src_w - 4);
1832 return -ERANGE;
1833 }
1834
1835 return 0;
1836}
1837
1838static int skl_plane_check_nv12_rotation(const struct intel_plane_state *plane_state)
1839{
1840 struct intel_display *display = to_intel_display(plane_state);
1841 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1842 const struct drm_framebuffer *fb = plane_state->hw.fb;
1843 unsigned int rotation = plane_state->hw.rotation;
1844 int src_w = drm_rect_width(r: &plane_state->uapi.src) >> 16;
1845
1846 /* Display WA #1106 */
1847 if (intel_format_info_is_yuv_semiplanar(info: fb->format, modifier: fb->modifier) &&
1848 src_w & 3 &&
1849 (rotation == DRM_MODE_ROTATE_270 ||
1850 rotation == (DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90))) {
1851 drm_dbg_kms(display->drm,
1852 "[PLANE:%d:%s] src width must be multiple of 4 for rotated planar YUV\n",
1853 plane->base.base.id, plane->base.name);
1854 return -EINVAL;
1855 }
1856
1857 return 0;
1858}
1859
1860static int skl_plane_max_scale(struct intel_display *display,
1861 const struct drm_framebuffer *fb)
1862{
1863 /*
1864 * We don't yet know the final source width nor
1865 * whether we can use the HQ scaler mode. Assume
1866 * the best case.
1867 * FIXME need to properly check this later.
1868 */
1869 if (DISPLAY_VER(display) >= 10 ||
1870 !intel_format_info_is_yuv_semiplanar(info: fb->format, modifier: fb->modifier))
1871 return 0x30000 - 1;
1872 else
1873 return 0x20000 - 1;
1874}
1875
1876static int intel_plane_min_width(struct intel_plane *plane,
1877 const struct drm_framebuffer *fb,
1878 int color_plane,
1879 unsigned int rotation)
1880{
1881 if (plane->min_width)
1882 return plane->min_width(fb, color_plane, rotation);
1883 else
1884 return 1;
1885}
1886
1887static int intel_plane_max_width(struct intel_plane *plane,
1888 const struct drm_framebuffer *fb,
1889 int color_plane,
1890 unsigned int rotation)
1891{
1892 if (plane->max_width)
1893 return plane->max_width(fb, color_plane, rotation);
1894 else
1895 return INT_MAX;
1896}
1897
1898static int intel_plane_max_height(struct intel_plane *plane,
1899 const struct drm_framebuffer *fb,
1900 int color_plane,
1901 unsigned int rotation)
1902{
1903 if (plane->max_height)
1904 return plane->max_height(fb, color_plane, rotation);
1905 else
1906 return INT_MAX;
1907}
1908
1909static bool
1910skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state,
1911 int main_x, int main_y, u32 main_offset,
1912 int ccs_plane)
1913{
1914 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1915 const struct drm_framebuffer *fb = plane_state->hw.fb;
1916 int aux_x = plane_state->view.color_plane[ccs_plane].x;
1917 int aux_y = plane_state->view.color_plane[ccs_plane].y;
1918 u32 aux_offset = plane_state->view.color_plane[ccs_plane].offset;
1919 unsigned int alignment = plane->min_alignment(plane, fb, ccs_plane);
1920 int hsub;
1921 int vsub;
1922
1923 intel_fb_plane_get_subsampling(hsub: &hsub, vsub: &vsub, fb, color_plane: ccs_plane);
1924 while (aux_offset >= main_offset && aux_y <= main_y) {
1925 int x, y;
1926
1927 if (aux_x == main_x && aux_y == main_y)
1928 break;
1929
1930 if (aux_offset == 0)
1931 break;
1932
1933 x = aux_x / hsub;
1934 y = aux_y / vsub;
1935 aux_offset = intel_plane_adjust_aligned_offset(x: &x, y: &y,
1936 plane_state,
1937 color_plane: ccs_plane,
1938 old_offset: aux_offset,
1939 new_offset: aux_offset - alignment);
1940 aux_x = x * hsub + aux_x % hsub;
1941 aux_y = y * vsub + aux_y % vsub;
1942 }
1943
1944 if (aux_x != main_x || aux_y != main_y)
1945 return false;
1946
1947 plane_state->view.color_plane[ccs_plane].offset = aux_offset;
1948 plane_state->view.color_plane[ccs_plane].x = aux_x;
1949 plane_state->view.color_plane[ccs_plane].y = aux_y;
1950
1951 return true;
1952}
1953
1954
1955int skl_calc_main_surface_offset(const struct intel_plane_state *plane_state,
1956 int *x, int *y, u32 *offset)
1957{
1958 struct intel_display *display = to_intel_display(plane_state);
1959 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1960 const struct drm_framebuffer *fb = plane_state->hw.fb;
1961 int aux_plane = skl_main_to_aux_plane(fb, main_plane: 0);
1962 u32 aux_offset = plane_state->view.color_plane[aux_plane].offset;
1963 unsigned int alignment = plane->min_alignment(plane, fb, 0);
1964 int w = drm_rect_width(r: &plane_state->uapi.src) >> 16;
1965
1966 intel_add_fb_offsets(x, y, plane_state, color_plane: 0);
1967 *offset = intel_plane_compute_aligned_offset(x, y, plane_state, color_plane: 0);
1968 if (drm_WARN_ON(display->drm, alignment && !is_power_of_2(alignment)))
1969 return -EINVAL;
1970
1971 /*
1972 * AUX surface offset is specified as the distance from the
1973 * main surface offset, and it must be non-negative. Make
1974 * sure that is what we will get.
1975 */
1976 if (aux_plane && *offset > aux_offset)
1977 *offset = intel_plane_adjust_aligned_offset(x, y, plane_state, color_plane: 0,
1978 old_offset: *offset,
1979 new_offset: aux_offset & ~(alignment - 1));
1980
1981 /*
1982 * When using an X-tiled surface, the plane blows up
1983 * if the x offset + width exceed the stride.
1984 *
1985 * TODO: linear and Y-tiled seem fine, Yf untested,
1986 */
1987 if (fb->modifier == I915_FORMAT_MOD_X_TILED) {
1988 int cpp = fb->format->cpp[0];
1989
1990 while ((*x + w) * cpp > plane_state->view.color_plane[0].mapping_stride) {
1991 if (*offset == 0) {
1992 drm_dbg_kms(display->drm,
1993 "[PLANE:%d:%s] unable to find suitable display surface offset due to X-tiling\n",
1994 plane->base.base.id, plane->base.name);
1995 return -EINVAL;
1996 }
1997
1998 *offset = intel_plane_adjust_aligned_offset(x, y, plane_state, color_plane: 0,
1999 old_offset: *offset,
2000 new_offset: *offset - alignment);
2001 }
2002 }
2003
2004 return 0;
2005}
2006
2007static int skl_check_main_surface(struct intel_plane_state *plane_state)
2008{
2009 struct intel_display *display = to_intel_display(plane_state);
2010 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
2011 const struct drm_framebuffer *fb = plane_state->hw.fb;
2012 unsigned int rotation = plane_state->hw.rotation;
2013 int x = plane_state->uapi.src.x1 >> 16;
2014 int y = plane_state->uapi.src.y1 >> 16;
2015 int w = drm_rect_width(r: &plane_state->uapi.src) >> 16;
2016 int h = drm_rect_height(r: &plane_state->uapi.src) >> 16;
2017 int min_width = intel_plane_min_width(plane, fb, color_plane: 0, rotation);
2018 int max_width = intel_plane_max_width(plane, fb, color_plane: 0, rotation);
2019 int max_height = intel_plane_max_height(plane, fb, color_plane: 0, rotation);
2020 unsigned int alignment = plane->min_alignment(plane, fb, 0);
2021 int aux_plane = skl_main_to_aux_plane(fb, main_plane: 0);
2022 u32 offset;
2023 int ret;
2024
2025 if (w > max_width || w < min_width || h > max_height || h < 1) {
2026 drm_dbg_kms(display->drm,
2027 "[PLANE:%d:%s] requested Y/RGB source size %dx%d outside limits (min: %dx1 max: %dx%d)\n",
2028 plane->base.base.id, plane->base.name,
2029 w, h, min_width, max_width, max_height);
2030 return -EINVAL;
2031 }
2032
2033 ret = skl_calc_main_surface_offset(plane_state, x: &x, y: &y, offset: &offset);
2034 if (ret)
2035 return ret;
2036
2037 /*
2038 * CCS AUX surface doesn't have its own x/y offsets, we must make sure
2039 * they match with the main surface x/y offsets. On DG2
2040 * there's no aux plane on fb so skip this checking.
2041 */
2042 if (intel_fb_is_ccs_modifier(modifier: fb->modifier) && aux_plane) {
2043 while (!skl_check_main_ccs_coordinates(plane_state, main_x: x, main_y: y,
2044 main_offset: offset, ccs_plane: aux_plane)) {
2045 if (offset == 0)
2046 break;
2047
2048 offset = intel_plane_adjust_aligned_offset(x: &x, y: &y, plane_state, color_plane: 0,
2049 old_offset: offset, new_offset: offset - alignment);
2050 }
2051
2052 if (x != plane_state->view.color_plane[aux_plane].x ||
2053 y != plane_state->view.color_plane[aux_plane].y) {
2054 drm_dbg_kms(display->drm,
2055 "[PLANE:%d:%s] unable to find suitable display surface offset due to CCS\n",
2056 plane->base.base.id, plane->base.name);
2057 return -EINVAL;
2058 }
2059 }
2060
2061 if (DISPLAY_VER(display) >= 13)
2062 drm_WARN_ON(display->drm, x > 65535 || y > 65535);
2063 else
2064 drm_WARN_ON(display->drm, x > 8191 || y > 8191);
2065
2066 plane_state->view.color_plane[0].offset = offset;
2067 plane_state->view.color_plane[0].x = x;
2068 plane_state->view.color_plane[0].y = y;
2069
2070 /*
2071 * Put the final coordinates back so that the src
2072 * coordinate checks will see the right values.
2073 */
2074 drm_rect_translate_to(r: &plane_state->uapi.src,
2075 x: x << 16, y: y << 16);
2076
2077 return 0;
2078}
2079
2080static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
2081{
2082 struct intel_display *display = to_intel_display(plane_state);
2083 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
2084 const struct drm_framebuffer *fb = plane_state->hw.fb;
2085 unsigned int rotation = plane_state->hw.rotation;
2086 int uv_plane = 1;
2087 int ccs_plane = intel_fb_is_ccs_modifier(modifier: fb->modifier) ?
2088 skl_main_to_aux_plane(fb, main_plane: uv_plane) : 0;
2089 int max_width = intel_plane_max_width(plane, fb, color_plane: uv_plane, rotation);
2090 int max_height = intel_plane_max_height(plane, fb, color_plane: uv_plane, rotation);
2091 int x = plane_state->uapi.src.x1 >> 17;
2092 int y = plane_state->uapi.src.y1 >> 17;
2093 int w = drm_rect_width(r: &plane_state->uapi.src) >> 17;
2094 int h = drm_rect_height(r: &plane_state->uapi.src) >> 17;
2095 u32 offset;
2096
2097 /* FIXME not quite sure how/if these apply to the chroma plane */
2098 if (w > max_width || h > max_height) {
2099 drm_dbg_kms(display->drm,
2100 "[PLANE:%d:%s] CbCr source size %dx%d too big (limit %dx%d)\n",
2101 plane->base.base.id, plane->base.name,
2102 w, h, max_width, max_height);
2103 return -EINVAL;
2104 }
2105
2106 intel_add_fb_offsets(x: &x, y: &y, plane_state, color_plane: uv_plane);
2107 offset = intel_plane_compute_aligned_offset(x: &x, y: &y,
2108 plane_state, color_plane: uv_plane);
2109
2110 if (ccs_plane) {
2111 u32 aux_offset = plane_state->view.color_plane[ccs_plane].offset;
2112 unsigned int alignment = plane->min_alignment(plane, fb, uv_plane);
2113
2114 if (offset > aux_offset)
2115 offset = intel_plane_adjust_aligned_offset(x: &x, y: &y,
2116 plane_state,
2117 color_plane: uv_plane,
2118 old_offset: offset,
2119 new_offset: aux_offset & ~(alignment - 1));
2120
2121 while (!skl_check_main_ccs_coordinates(plane_state, main_x: x, main_y: y,
2122 main_offset: offset, ccs_plane)) {
2123 if (offset == 0)
2124 break;
2125
2126 offset = intel_plane_adjust_aligned_offset(x: &x, y: &y,
2127 plane_state,
2128 color_plane: uv_plane,
2129 old_offset: offset, new_offset: offset - alignment);
2130 }
2131
2132 if (x != plane_state->view.color_plane[ccs_plane].x ||
2133 y != plane_state->view.color_plane[ccs_plane].y) {
2134 drm_dbg_kms(display->drm,
2135 "[PLANE:%d:%s] unable to find suitable display surface offset due to CCS\n",
2136 plane->base.base.id, plane->base.name);
2137 return -EINVAL;
2138 }
2139 }
2140
2141 if (DISPLAY_VER(display) >= 13)
2142 drm_WARN_ON(display->drm, x > 65535 || y > 65535);
2143 else
2144 drm_WARN_ON(display->drm, x > 8191 || y > 8191);
2145
2146 plane_state->view.color_plane[uv_plane].offset = offset;
2147 plane_state->view.color_plane[uv_plane].x = x;
2148 plane_state->view.color_plane[uv_plane].y = y;
2149
2150 return 0;
2151}
2152
2153static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state)
2154{
2155 const struct drm_framebuffer *fb = plane_state->hw.fb;
2156 int src_x = plane_state->uapi.src.x1 >> 16;
2157 int src_y = plane_state->uapi.src.y1 >> 16;
2158 u32 offset;
2159 int ccs_plane;
2160
2161 for (ccs_plane = 0; ccs_plane < fb->format->num_planes; ccs_plane++) {
2162 int main_hsub, main_vsub;
2163 int hsub, vsub;
2164 int x, y;
2165
2166 if (!intel_fb_is_ccs_aux_plane(fb, color_plane: ccs_plane))
2167 continue;
2168
2169 intel_fb_plane_get_subsampling(hsub: &main_hsub, vsub: &main_vsub, fb,
2170 color_plane: skl_ccs_to_main_plane(fb, ccs_plane));
2171 intel_fb_plane_get_subsampling(hsub: &hsub, vsub: &vsub, fb, color_plane: ccs_plane);
2172
2173 hsub *= main_hsub;
2174 vsub *= main_vsub;
2175 x = src_x / hsub;
2176 y = src_y / vsub;
2177
2178 intel_add_fb_offsets(x: &x, y: &y, plane_state, color_plane: ccs_plane);
2179
2180 offset = intel_plane_compute_aligned_offset(x: &x, y: &y,
2181 plane_state,
2182 color_plane: ccs_plane);
2183
2184 plane_state->view.color_plane[ccs_plane].offset = offset;
2185 plane_state->view.color_plane[ccs_plane].x = (x * hsub + src_x % hsub) / main_hsub;
2186 plane_state->view.color_plane[ccs_plane].y = (y * vsub + src_y % vsub) / main_vsub;
2187 }
2188
2189 return 0;
2190}
2191
2192static int skl_check_plane_surface(struct intel_plane_state *plane_state)
2193{
2194 const struct drm_framebuffer *fb = plane_state->hw.fb;
2195 int ret;
2196
2197 ret = intel_plane_compute_gtt(plane_state);
2198 if (ret)
2199 return ret;
2200
2201 if (!plane_state->uapi.visible)
2202 return 0;
2203
2204 /*
2205 * Handle the AUX surface first since the main surface setup depends on
2206 * it.
2207 */
2208 if (intel_fb_is_ccs_modifier(modifier: fb->modifier)) {
2209 ret = skl_check_ccs_aux_surface(plane_state);
2210 if (ret)
2211 return ret;
2212 }
2213
2214 if (intel_format_info_is_yuv_semiplanar(info: fb->format,
2215 modifier: fb->modifier)) {
2216 ret = skl_check_nv12_aux_surface(plane_state);
2217 if (ret)
2218 return ret;
2219 }
2220
2221 ret = skl_check_main_surface(plane_state);
2222 if (ret)
2223 return ret;
2224
2225 return 0;
2226}
2227
2228static bool skl_fb_scalable(const struct drm_framebuffer *fb)
2229{
2230 struct intel_display *display;
2231
2232 if (!fb)
2233 return false;
2234
2235 display = to_intel_display(fb->dev);
2236
2237 switch (fb->format->format) {
2238 case DRM_FORMAT_C8:
2239 return false;
2240 case DRM_FORMAT_XRGB16161616F:
2241 case DRM_FORMAT_ARGB16161616F:
2242 case DRM_FORMAT_XBGR16161616F:
2243 case DRM_FORMAT_ABGR16161616F:
2244 return DISPLAY_VER(display) >= 11;
2245 default:
2246 return true;
2247 }
2248}
2249
2250static void check_protection(struct intel_plane_state *plane_state)
2251{
2252 struct intel_display *display = to_intel_display(plane_state);
2253 const struct drm_framebuffer *fb = plane_state->hw.fb;
2254 struct drm_gem_object *obj = intel_fb_bo(fb);
2255
2256 if (DISPLAY_VER(display) < 11)
2257 return;
2258
2259 plane_state->decrypt = intel_pxp_key_check(obj, assign: false) == 0;
2260 plane_state->force_black = intel_bo_is_protected(obj) &&
2261 !plane_state->decrypt;
2262}
2263
2264static void
2265make_damage_viewport_relative(struct intel_plane_state *plane_state)
2266{
2267 const struct drm_framebuffer *fb = plane_state->hw.fb;
2268 const struct drm_rect *src = &plane_state->uapi.src;
2269 unsigned int rotation = plane_state->hw.rotation;
2270 struct drm_rect *damage = &plane_state->damage;
2271
2272 if (!drm_rect_visible(r: damage))
2273 return;
2274
2275 if (!fb || !plane_state->uapi.visible) {
2276 plane_state->damage = DRM_RECT_INIT(0, 0, 0, 0);
2277 return;
2278 }
2279
2280 if (drm_rotation_90_or_270(rotation)) {
2281 drm_rect_rotate(r: damage, width: fb->width, height: fb->height,
2282 DRM_MODE_ROTATE_270);
2283 drm_rect_translate(r: damage, dx: -(src->y1 >> 16), dy: -(src->x1 >> 16));
2284 } else {
2285 drm_rect_translate(r: damage, dx: -(src->x1 >> 16), dy: -(src->y1 >> 16));
2286 }
2287}
2288
2289static void clip_damage(struct intel_plane_state *plane_state)
2290{
2291 struct drm_rect *damage = &plane_state->damage;
2292 struct drm_rect src;
2293
2294 if (!drm_rect_visible(r: damage))
2295 return;
2296
2297 drm_rect_fp_to_int(dst: &src, src: &plane_state->uapi.src);
2298 drm_rect_translate(r: damage, dx: src.x1, dy: src.y1);
2299 drm_rect_intersect(r: damage, clip: &src);
2300}
2301
2302static int skl_plane_check(struct intel_crtc_state *crtc_state,
2303 struct intel_plane_state *plane_state)
2304{
2305 struct intel_display *display = to_intel_display(plane_state);
2306 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
2307 const struct drm_framebuffer *fb = plane_state->hw.fb;
2308 int min_scale = DRM_PLANE_NO_SCALING;
2309 int max_scale = DRM_PLANE_NO_SCALING;
2310 int ret;
2311
2312 ret = skl_plane_check_fb(crtc_state, plane_state);
2313 if (ret)
2314 return ret;
2315
2316 /* use scaler when colorkey is not required */
2317 if (!plane_state->ckey.flags && skl_fb_scalable(fb)) {
2318 min_scale = 1;
2319 max_scale = skl_plane_max_scale(display, fb);
2320 }
2321
2322 ret = intel_plane_check_clipping(plane_state, crtc_state,
2323 min_scale, max_scale, can_position: true);
2324 if (ret)
2325 return ret;
2326
2327 make_damage_viewport_relative(plane_state);
2328
2329 ret = skl_check_plane_surface(plane_state);
2330 if (ret)
2331 return ret;
2332
2333 if (!plane_state->uapi.visible)
2334 return 0;
2335
2336 ret = skl_plane_check_dst_coordinates(crtc_state, plane_state);
2337 if (ret)
2338 return ret;
2339
2340 ret = intel_plane_check_src_coordinates(plane_state);
2341 if (ret)
2342 return ret;
2343
2344 clip_damage(plane_state);
2345
2346 ret = skl_plane_check_nv12_rotation(plane_state);
2347 if (ret)
2348 return ret;
2349
2350 check_protection(plane_state);
2351
2352 /* HW only has 8 bits pixel precision, disable plane if invisible */
2353 if (!(plane_state->hw.alpha >> 8)) {
2354 plane_state->uapi.visible = false;
2355 plane_state->damage = DRM_RECT_INIT(0, 0, 0, 0);
2356 }
2357
2358 plane_state->ctl = skl_plane_ctl(plane_state);
2359
2360 if (DISPLAY_VER(display) >= 10)
2361 plane_state->color_ctl = glk_plane_color_ctl(plane_state);
2362
2363 if (intel_format_info_is_yuv_semiplanar(info: fb->format, modifier: fb->modifier) &&
2364 icl_is_hdr_plane(display, plane_id: plane->id))
2365 /* Enable and use MPEG-2 chroma siting */
2366 plane_state->cus_ctl = PLANE_CUS_ENABLE |
2367 PLANE_CUS_HPHASE_0 |
2368 PLANE_CUS_VPHASE_SIGN_NEGATIVE | PLANE_CUS_VPHASE_0_25;
2369 else
2370 plane_state->cus_ctl = 0;
2371
2372 return 0;
2373}
2374
2375void icl_link_nv12_planes(struct intel_plane_state *uv_plane_state,
2376 struct intel_plane_state *y_plane_state)
2377{
2378 struct intel_display *display = to_intel_display(uv_plane_state);
2379 struct intel_plane *uv_plane = to_intel_plane(uv_plane_state->uapi.plane);
2380 struct intel_plane *y_plane = to_intel_plane(y_plane_state->uapi.plane);
2381
2382 drm_WARN_ON(display->drm, icl_is_nv12_y_plane(display, uv_plane->id));
2383 drm_WARN_ON(display->drm, !icl_is_nv12_y_plane(display, y_plane->id));
2384
2385 y_plane_state->ctl |= PLANE_CTL_YUV420_Y_PLANE;
2386
2387 if (icl_is_hdr_plane(display, plane_id: uv_plane->id)) {
2388 switch (y_plane->id) {
2389 case PLANE_7:
2390 uv_plane_state->cus_ctl |= PLANE_CUS_Y_PLANE_7_ICL;
2391 break;
2392 case PLANE_6:
2393 uv_plane_state->cus_ctl |= PLANE_CUS_Y_PLANE_6_ICL;
2394 break;
2395 case PLANE_5:
2396 uv_plane_state->cus_ctl |= PLANE_CUS_Y_PLANE_5_RKL;
2397 break;
2398 case PLANE_4:
2399 uv_plane_state->cus_ctl |= PLANE_CUS_Y_PLANE_4_RKL;
2400 break;
2401 default:
2402 MISSING_CASE(y_plane->id);
2403 }
2404 }
2405}
2406
2407static enum intel_fbc_id skl_fbc_id_for_pipe(enum pipe pipe)
2408{
2409 return pipe - PIPE_A + INTEL_FBC_A;
2410}
2411
2412static bool skl_plane_has_fbc(struct intel_display *display,
2413 enum intel_fbc_id fbc_id, enum plane_id plane_id)
2414{
2415 if ((DISPLAY_RUNTIME_INFO(display)->fbc_mask & BIT(fbc_id)) == 0)
2416 return false;
2417
2418 if (DISPLAY_VER(display) >= 20)
2419 return icl_is_hdr_plane(display, plane_id);
2420 else
2421 return plane_id == PLANE_1;
2422}
2423
2424static struct intel_fbc *skl_plane_fbc(struct intel_display *display,
2425 enum pipe pipe, enum plane_id plane_id)
2426{
2427 enum intel_fbc_id fbc_id = skl_fbc_id_for_pipe(pipe);
2428
2429 if (skl_plane_has_fbc(display, fbc_id, plane_id))
2430 return display->fbc[fbc_id];
2431 else
2432 return NULL;
2433}
2434
2435static bool skl_plane_has_planar(struct intel_display *display,
2436 enum pipe pipe, enum plane_id plane_id)
2437{
2438 /* Display WA #0870: skl, bxt */
2439 if (display->platform.skylake || display->platform.broxton)
2440 return false;
2441
2442 if (DISPLAY_VER(display) == 9 && pipe == PIPE_C)
2443 return false;
2444
2445 if (plane_id != PLANE_1 && plane_id != PLANE_2)
2446 return false;
2447
2448 return true;
2449}
2450
2451static const u32 *skl_get_plane_formats(struct intel_display *display,
2452 enum pipe pipe, enum plane_id plane_id,
2453 int *num_formats)
2454{
2455 if (skl_plane_has_planar(display, pipe, plane_id)) {
2456 *num_formats = ARRAY_SIZE(skl_planar_formats);
2457 return skl_planar_formats;
2458 } else {
2459 *num_formats = ARRAY_SIZE(skl_plane_formats);
2460 return skl_plane_formats;
2461 }
2462}
2463
2464static const u32 *glk_get_plane_formats(struct intel_display *display,
2465 enum pipe pipe, enum plane_id plane_id,
2466 int *num_formats)
2467{
2468 if (skl_plane_has_planar(display, pipe, plane_id)) {
2469 *num_formats = ARRAY_SIZE(glk_planar_formats);
2470 return glk_planar_formats;
2471 } else {
2472 *num_formats = ARRAY_SIZE(skl_plane_formats);
2473 return skl_plane_formats;
2474 }
2475}
2476
2477static const u32 *icl_get_plane_formats(struct intel_display *display,
2478 enum pipe pipe, enum plane_id plane_id,
2479 int *num_formats)
2480{
2481 if (icl_is_hdr_plane(display, plane_id)) {
2482 *num_formats = ARRAY_SIZE(icl_hdr_plane_formats);
2483 return icl_hdr_plane_formats;
2484 } else if (icl_is_nv12_y_plane(display, plane_id)) {
2485 *num_formats = ARRAY_SIZE(icl_sdr_y_plane_formats);
2486 return icl_sdr_y_plane_formats;
2487 } else {
2488 *num_formats = ARRAY_SIZE(icl_sdr_uv_plane_formats);
2489 return icl_sdr_uv_plane_formats;
2490 }
2491}
2492
2493static bool skl_plane_format_mod_supported(struct drm_plane *_plane,
2494 u32 format, u64 modifier)
2495{
2496 struct intel_plane *plane = to_intel_plane(_plane);
2497
2498 if (!intel_fb_plane_supports_modifier(plane, modifier))
2499 return false;
2500
2501 switch (format) {
2502 case DRM_FORMAT_XRGB8888:
2503 case DRM_FORMAT_XBGR8888:
2504 case DRM_FORMAT_ARGB8888:
2505 case DRM_FORMAT_ABGR8888:
2506 if (intel_fb_is_ccs_modifier(modifier))
2507 return true;
2508 fallthrough;
2509 case DRM_FORMAT_RGB565:
2510 case DRM_FORMAT_XRGB2101010:
2511 case DRM_FORMAT_XBGR2101010:
2512 case DRM_FORMAT_ARGB2101010:
2513 case DRM_FORMAT_ABGR2101010:
2514 case DRM_FORMAT_YUYV:
2515 case DRM_FORMAT_YVYU:
2516 case DRM_FORMAT_UYVY:
2517 case DRM_FORMAT_VYUY:
2518 case DRM_FORMAT_NV12:
2519 case DRM_FORMAT_XYUV8888:
2520 case DRM_FORMAT_P010:
2521 case DRM_FORMAT_P012:
2522 case DRM_FORMAT_P016:
2523 case DRM_FORMAT_XVYU2101010:
2524 if (modifier == I915_FORMAT_MOD_Yf_TILED)
2525 return true;
2526 fallthrough;
2527 case DRM_FORMAT_C8:
2528 case DRM_FORMAT_XBGR16161616F:
2529 case DRM_FORMAT_ABGR16161616F:
2530 case DRM_FORMAT_XRGB16161616F:
2531 case DRM_FORMAT_ARGB16161616F:
2532 case DRM_FORMAT_Y210:
2533 case DRM_FORMAT_Y212:
2534 case DRM_FORMAT_Y216:
2535 case DRM_FORMAT_XVYU12_16161616:
2536 case DRM_FORMAT_XVYU16161616:
2537 if (modifier == DRM_FORMAT_MOD_LINEAR ||
2538 modifier == I915_FORMAT_MOD_X_TILED ||
2539 modifier == I915_FORMAT_MOD_Y_TILED)
2540 return true;
2541 fallthrough;
2542 default:
2543 return false;
2544 }
2545}
2546
2547static bool icl_plane_format_mod_supported(struct drm_plane *_plane,
2548 u32 format, u64 modifier)
2549{
2550 struct intel_plane *plane = to_intel_plane(_plane);
2551
2552 if (!intel_fb_plane_supports_modifier(plane, modifier))
2553 return false;
2554
2555 switch (format) {
2556 case DRM_FORMAT_XRGB8888:
2557 case DRM_FORMAT_XBGR8888:
2558 case DRM_FORMAT_ARGB8888:
2559 case DRM_FORMAT_ABGR8888:
2560 case DRM_FORMAT_XRGB2101010:
2561 case DRM_FORMAT_XBGR2101010:
2562 case DRM_FORMAT_ARGB2101010:
2563 case DRM_FORMAT_ABGR2101010:
2564 if (intel_fb_is_ccs_modifier(modifier))
2565 return true;
2566 fallthrough;
2567 case DRM_FORMAT_RGB565:
2568 case DRM_FORMAT_YUYV:
2569 case DRM_FORMAT_YVYU:
2570 case DRM_FORMAT_UYVY:
2571 case DRM_FORMAT_VYUY:
2572 case DRM_FORMAT_NV12:
2573 case DRM_FORMAT_XYUV8888:
2574 case DRM_FORMAT_P010:
2575 case DRM_FORMAT_P012:
2576 case DRM_FORMAT_P016:
2577 case DRM_FORMAT_XVYU2101010:
2578 if (modifier == I915_FORMAT_MOD_Yf_TILED)
2579 return true;
2580 fallthrough;
2581 case DRM_FORMAT_C8:
2582 case DRM_FORMAT_XBGR16161616F:
2583 case DRM_FORMAT_ABGR16161616F:
2584 case DRM_FORMAT_XRGB16161616F:
2585 case DRM_FORMAT_ARGB16161616F:
2586 case DRM_FORMAT_Y210:
2587 case DRM_FORMAT_Y212:
2588 case DRM_FORMAT_Y216:
2589 case DRM_FORMAT_XVYU12_16161616:
2590 case DRM_FORMAT_XVYU16161616:
2591 if (modifier == DRM_FORMAT_MOD_LINEAR ||
2592 modifier == I915_FORMAT_MOD_X_TILED ||
2593 modifier == I915_FORMAT_MOD_Y_TILED)
2594 return true;
2595 fallthrough;
2596 default:
2597 return false;
2598 }
2599}
2600
2601static bool tgl_plane_format_mod_supported(struct drm_plane *_plane,
2602 u32 format, u64 modifier)
2603{
2604 struct intel_plane *plane = to_intel_plane(_plane);
2605
2606 if (!intel_fb_plane_supports_modifier(plane, modifier))
2607 return false;
2608
2609 switch (format) {
2610 case DRM_FORMAT_XRGB8888:
2611 case DRM_FORMAT_XBGR8888:
2612 case DRM_FORMAT_ARGB8888:
2613 case DRM_FORMAT_ABGR8888:
2614 case DRM_FORMAT_XRGB2101010:
2615 case DRM_FORMAT_XBGR2101010:
2616 case DRM_FORMAT_ARGB2101010:
2617 case DRM_FORMAT_ABGR2101010:
2618 case DRM_FORMAT_XBGR16161616F:
2619 case DRM_FORMAT_ABGR16161616F:
2620 case DRM_FORMAT_XRGB16161616F:
2621 case DRM_FORMAT_ARGB16161616F:
2622 if (intel_fb_is_ccs_modifier(modifier))
2623 return true;
2624 fallthrough;
2625 case DRM_FORMAT_YUYV:
2626 case DRM_FORMAT_YVYU:
2627 case DRM_FORMAT_UYVY:
2628 case DRM_FORMAT_VYUY:
2629 case DRM_FORMAT_NV12:
2630 case DRM_FORMAT_XYUV8888:
2631 case DRM_FORMAT_P010:
2632 case DRM_FORMAT_P012:
2633 case DRM_FORMAT_P016:
2634 if (intel_fb_is_mc_ccs_modifier(modifier))
2635 return true;
2636 fallthrough;
2637 case DRM_FORMAT_RGB565:
2638 case DRM_FORMAT_XVYU2101010:
2639 case DRM_FORMAT_C8:
2640 case DRM_FORMAT_Y210:
2641 case DRM_FORMAT_Y212:
2642 case DRM_FORMAT_Y216:
2643 case DRM_FORMAT_XVYU12_16161616:
2644 case DRM_FORMAT_XVYU16161616:
2645 if (!intel_fb_is_ccs_modifier(modifier))
2646 return true;
2647 fallthrough;
2648 default:
2649 return false;
2650 }
2651}
2652
2653static const struct drm_plane_funcs skl_plane_funcs = {
2654 .update_plane = drm_atomic_helper_update_plane,
2655 .disable_plane = drm_atomic_helper_disable_plane,
2656 .destroy = intel_plane_destroy,
2657 .atomic_duplicate_state = intel_plane_duplicate_state,
2658 .atomic_destroy_state = intel_plane_destroy_state,
2659 .format_mod_supported = skl_plane_format_mod_supported,
2660 .format_mod_supported_async = intel_plane_format_mod_supported_async,
2661};
2662
2663static const struct drm_plane_funcs icl_plane_funcs = {
2664 .update_plane = drm_atomic_helper_update_plane,
2665 .disable_plane = drm_atomic_helper_disable_plane,
2666 .destroy = intel_plane_destroy,
2667 .atomic_duplicate_state = intel_plane_duplicate_state,
2668 .atomic_destroy_state = intel_plane_destroy_state,
2669 .format_mod_supported = icl_plane_format_mod_supported,
2670 .format_mod_supported_async = intel_plane_format_mod_supported_async,
2671};
2672
2673static const struct drm_plane_funcs tgl_plane_funcs = {
2674 .update_plane = drm_atomic_helper_update_plane,
2675 .disable_plane = drm_atomic_helper_disable_plane,
2676 .destroy = intel_plane_destroy,
2677 .atomic_duplicate_state = intel_plane_duplicate_state,
2678 .atomic_destroy_state = intel_plane_destroy_state,
2679 .format_mod_supported = tgl_plane_format_mod_supported,
2680 .format_mod_supported_async = intel_plane_format_mod_supported_async,
2681};
2682
2683static void
2684skl_plane_enable_flip_done(struct intel_plane *plane)
2685{
2686 struct intel_display *display = to_intel_display(plane);
2687 enum pipe pipe = plane->pipe;
2688
2689 spin_lock_irq(lock: &display->irq.lock);
2690 bdw_enable_pipe_irq(display, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id));
2691 spin_unlock_irq(lock: &display->irq.lock);
2692}
2693
2694static void
2695skl_plane_disable_flip_done(struct intel_plane *plane)
2696{
2697 struct intel_display *display = to_intel_display(plane);
2698 enum pipe pipe = plane->pipe;
2699
2700 spin_lock_irq(lock: &display->irq.lock);
2701 bdw_disable_pipe_irq(display, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id));
2702 spin_unlock_irq(lock: &display->irq.lock);
2703}
2704
2705static bool skl_plane_has_rc_ccs(struct intel_display *display,
2706 enum pipe pipe, enum plane_id plane_id)
2707{
2708 return pipe != PIPE_C &&
2709 (plane_id == PLANE_1 || plane_id == PLANE_2);
2710}
2711
2712static u8 skl_plane_caps(struct intel_display *display,
2713 enum pipe pipe, enum plane_id plane_id)
2714{
2715 u8 caps = INTEL_PLANE_CAP_TILING_X |
2716 INTEL_PLANE_CAP_TILING_Y |
2717 INTEL_PLANE_CAP_TILING_Yf;
2718
2719 if (skl_plane_has_rc_ccs(display, pipe, plane_id))
2720 caps |= INTEL_PLANE_CAP_CCS_RC;
2721
2722 return caps;
2723}
2724
2725static bool glk_plane_has_rc_ccs(struct intel_display *display,
2726 enum pipe pipe)
2727{
2728 return pipe != PIPE_C;
2729}
2730
2731static u8 glk_plane_caps(struct intel_display *display,
2732 enum pipe pipe, enum plane_id plane_id)
2733{
2734 u8 caps = INTEL_PLANE_CAP_TILING_X |
2735 INTEL_PLANE_CAP_TILING_Y |
2736 INTEL_PLANE_CAP_TILING_Yf;
2737
2738 if (glk_plane_has_rc_ccs(display, pipe))
2739 caps |= INTEL_PLANE_CAP_CCS_RC;
2740
2741 return caps;
2742}
2743
2744static u8 icl_plane_caps(struct intel_display *display,
2745 enum pipe pipe, enum plane_id plane_id)
2746{
2747 return INTEL_PLANE_CAP_TILING_X |
2748 INTEL_PLANE_CAP_TILING_Y |
2749 INTEL_PLANE_CAP_TILING_Yf |
2750 INTEL_PLANE_CAP_CCS_RC;
2751}
2752
2753static bool tgl_plane_has_mc_ccs(struct intel_display *display,
2754 enum plane_id plane_id)
2755{
2756 /* Wa_14010477008 */
2757 if (display->platform.dg1 || display->platform.rocketlake ||
2758 (display->platform.tigerlake && IS_DISPLAY_STEP(display, STEP_A0, STEP_D0)))
2759 return false;
2760
2761 return plane_id < PLANE_6;
2762}
2763
2764static u8 tgl_plane_caps(struct intel_display *display,
2765 enum pipe pipe, enum plane_id plane_id)
2766{
2767 u8 caps = INTEL_PLANE_CAP_TILING_X |
2768 INTEL_PLANE_CAP_CCS_RC |
2769 INTEL_PLANE_CAP_CCS_RC_CC;
2770
2771 if (HAS_4TILE(display))
2772 caps |= INTEL_PLANE_CAP_TILING_4;
2773 else
2774 caps |= INTEL_PLANE_CAP_TILING_Y;
2775
2776 if (tgl_plane_has_mc_ccs(display, plane_id))
2777 caps |= INTEL_PLANE_CAP_CCS_MC;
2778
2779 if (DISPLAY_VER(display) >= 14 && display->platform.dgfx)
2780 caps |= INTEL_PLANE_CAP_NEED64K_PHYS;
2781
2782 return caps;
2783}
2784
2785static void skl_disable_tiling(struct intel_plane *plane)
2786{
2787 struct intel_plane_state *state = to_intel_plane_state(plane->base.state);
2788 struct intel_display *display = to_intel_display(plane);
2789 const struct drm_framebuffer *fb = state->hw.fb;
2790 u32 plane_ctl;
2791
2792 plane_ctl = intel_de_read(display, PLANE_CTL(plane->pipe, plane->id));
2793
2794 if (intel_fb_uses_dpt(fb)) {
2795 /* if DPT is enabled, keep tiling, but disable compression */
2796 plane_ctl &= ~PLANE_CTL_RENDER_DECOMPRESSION_ENABLE;
2797 } else {
2798 /* if DPT is not supported, disable tiling, and update stride */
2799 u32 stride = state->view.color_plane[0].scanout_stride / 64;
2800
2801 plane_ctl &= ~PLANE_CTL_TILED_MASK;
2802 intel_de_write_fw(display, PLANE_STRIDE(plane->pipe, plane->id),
2803 PLANE_STRIDE_(stride));
2804 }
2805 intel_de_write_fw(display, PLANE_CTL(plane->pipe, plane->id), val: plane_ctl);
2806
2807 intel_de_write_fw(display, PLANE_SURF(plane->pipe, plane->id),
2808 val: state->surf);
2809}
2810
2811struct intel_plane *
2812skl_universal_plane_create(struct intel_display *display,
2813 enum pipe pipe, enum plane_id plane_id)
2814{
2815 const struct drm_plane_funcs *plane_funcs;
2816 struct intel_plane *plane;
2817 enum drm_plane_type plane_type;
2818 unsigned int supported_rotations;
2819 unsigned int supported_csc;
2820 const u64 *modifiers;
2821 const u32 *formats;
2822 int num_formats;
2823 int ret;
2824 u8 caps;
2825
2826 plane = intel_plane_alloc();
2827 if (IS_ERR(ptr: plane))
2828 return plane;
2829
2830 plane->pipe = pipe;
2831 plane->id = plane_id;
2832 plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane_id);
2833
2834 intel_fbc_add_plane(fbc: skl_plane_fbc(display, pipe, plane_id), plane);
2835
2836 if (DISPLAY_VER(display) >= 30) {
2837 plane->max_width = xe3_plane_max_width;
2838 plane->max_height = icl_plane_max_height;
2839 plane->min_cdclk = icl_plane_min_cdclk;
2840 } else if (DISPLAY_VER(display) >= 11) {
2841 plane->min_width = icl_plane_min_width;
2842 if (icl_is_hdr_plane(display, plane_id))
2843 plane->max_width = icl_hdr_plane_max_width;
2844 else
2845 plane->max_width = icl_sdr_plane_max_width;
2846 plane->max_height = icl_plane_max_height;
2847 plane->min_cdclk = icl_plane_min_cdclk;
2848 } else if (DISPLAY_VER(display) >= 10) {
2849 plane->max_width = glk_plane_max_width;
2850 plane->max_height = skl_plane_max_height;
2851 plane->min_cdclk = glk_plane_min_cdclk;
2852 } else {
2853 plane->max_width = skl_plane_max_width;
2854 plane->max_height = skl_plane_max_height;
2855 plane->min_cdclk = skl_plane_min_cdclk;
2856 }
2857 plane->disable_tiling = skl_disable_tiling;
2858
2859 plane->surf_offset = skl_plane_surf_offset;
2860
2861 if (DISPLAY_VER(display) >= 13)
2862 plane->max_stride = adl_plane_max_stride;
2863 else
2864 plane->max_stride = skl_plane_max_stride;
2865
2866 if (DISPLAY_VER(display) >= 12)
2867 plane->min_alignment = tgl_plane_min_alignment;
2868 else
2869 plane->min_alignment = skl_plane_min_alignment;
2870
2871 if (intel_scanout_needs_vtd_wa(display))
2872 plane->vtd_guard = DISPLAY_VER(display) >= 10 ? 168 : 136;
2873
2874 if (DISPLAY_VER(display) >= 11) {
2875 plane->update_noarm = icl_plane_update_noarm;
2876 plane->update_arm = icl_plane_update_arm;
2877 plane->disable_arm = icl_plane_disable_arm;
2878 } else {
2879 plane->update_noarm = skl_plane_update_noarm;
2880 plane->update_arm = skl_plane_update_arm;
2881 plane->disable_arm = skl_plane_disable_arm;
2882 }
2883 plane->capture_error = skl_plane_capture_error;
2884 plane->get_hw_state = skl_plane_get_hw_state;
2885 plane->check_plane = skl_plane_check;
2886
2887 if (HAS_ASYNC_FLIPS(display) && plane_id == PLANE_1) {
2888 plane->need_async_flip_toggle_wa = IS_DISPLAY_VER(display, 9, 10);
2889 plane->async_flip = skl_plane_async_flip;
2890 plane->enable_flip_done = skl_plane_enable_flip_done;
2891 plane->disable_flip_done = skl_plane_disable_flip_done;
2892
2893 if (DISPLAY_VER(display) >= 12)
2894 plane->can_async_flip = tgl_plane_can_async_flip;
2895 else if (DISPLAY_VER(display) == 11)
2896 plane->can_async_flip = icl_plane_can_async_flip;
2897 else
2898 plane->can_async_flip = skl_plane_can_async_flip;
2899 }
2900
2901 if (DISPLAY_VER(display) >= 11)
2902 formats = icl_get_plane_formats(display, pipe,
2903 plane_id, num_formats: &num_formats);
2904 else if (DISPLAY_VER(display) >= 10)
2905 formats = glk_get_plane_formats(display, pipe,
2906 plane_id, num_formats: &num_formats);
2907 else
2908 formats = skl_get_plane_formats(display, pipe,
2909 plane_id, num_formats: &num_formats);
2910
2911 if (DISPLAY_VER(display) >= 12)
2912 plane_funcs = &tgl_plane_funcs;
2913 else if (DISPLAY_VER(display) == 11)
2914 plane_funcs = &icl_plane_funcs;
2915 else
2916 plane_funcs = &skl_plane_funcs;
2917
2918 if (plane_id == PLANE_1)
2919 plane_type = DRM_PLANE_TYPE_PRIMARY;
2920 else
2921 plane_type = DRM_PLANE_TYPE_OVERLAY;
2922
2923 if (DISPLAY_VER(display) >= 12)
2924 caps = tgl_plane_caps(display, pipe, plane_id);
2925 else if (DISPLAY_VER(display) == 11)
2926 caps = icl_plane_caps(display, pipe, plane_id);
2927 else if (DISPLAY_VER(display) == 10)
2928 caps = glk_plane_caps(display, pipe, plane_id);
2929 else
2930 caps = skl_plane_caps(display, pipe, plane_id);
2931
2932 /* FIXME: xe has problems with AUX */
2933 if (!IS_ENABLED(I915) && !HAS_FLAT_CCS(to_i915(display->drm)))
2934 caps &= ~(INTEL_PLANE_CAP_CCS_RC |
2935 INTEL_PLANE_CAP_CCS_RC_CC |
2936 INTEL_PLANE_CAP_CCS_MC);
2937
2938 modifiers = intel_fb_plane_get_modifiers(display, plane_caps: caps);
2939
2940 ret = drm_universal_plane_init(dev: display->drm, plane: &plane->base,
2941 possible_crtcs: 0, funcs: plane_funcs,
2942 formats, format_count: num_formats, format_modifiers: modifiers,
2943 type: plane_type,
2944 name: "plane %d%c", plane_id + 1,
2945 pipe_name(pipe));
2946
2947 kfree(objp: modifiers);
2948
2949 if (ret)
2950 goto fail;
2951
2952 if (DISPLAY_VER(display) >= 13)
2953 supported_rotations = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
2954 else
2955 supported_rotations =
2956 DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
2957 DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270;
2958
2959 if (DISPLAY_VER(display) >= 11)
2960 supported_rotations |= DRM_MODE_REFLECT_X;
2961
2962 drm_plane_create_rotation_property(plane: &plane->base,
2963 DRM_MODE_ROTATE_0,
2964 supported_rotations);
2965
2966 supported_csc = BIT(DRM_COLOR_YCBCR_BT601) | BIT(DRM_COLOR_YCBCR_BT709);
2967
2968 if (DISPLAY_VER(display) >= 10)
2969 supported_csc |= BIT(DRM_COLOR_YCBCR_BT2020);
2970
2971 drm_plane_create_color_properties(plane: &plane->base,
2972 supported_encodings: supported_csc,
2973 BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
2974 BIT(DRM_COLOR_YCBCR_FULL_RANGE),
2975 default_encoding: DRM_COLOR_YCBCR_BT709,
2976 default_range: DRM_COLOR_YCBCR_LIMITED_RANGE);
2977
2978 drm_plane_create_alpha_property(plane: &plane->base);
2979 drm_plane_create_blend_mode_property(plane: &plane->base,
2980 BIT(DRM_MODE_BLEND_PIXEL_NONE) |
2981 BIT(DRM_MODE_BLEND_PREMULTI) |
2982 BIT(DRM_MODE_BLEND_COVERAGE));
2983
2984 drm_plane_create_zpos_immutable_property(plane: &plane->base, zpos: plane_id);
2985
2986 if (DISPLAY_VER(display) >= 12)
2987 drm_plane_enable_fb_damage_clips(plane: &plane->base);
2988
2989 if (DISPLAY_VER(display) >= 11)
2990 drm_plane_create_scaling_filter_property(plane: &plane->base,
2991 BIT(DRM_SCALING_FILTER_DEFAULT) |
2992 BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
2993
2994 intel_plane_helper_add(plane);
2995
2996 return plane;
2997
2998fail:
2999 intel_plane_free(plane);
3000
3001 return ERR_PTR(error: ret);
3002}
3003
3004void
3005skl_get_initial_plane_config(struct intel_crtc *crtc,
3006 struct intel_initial_plane_config *plane_config)
3007{
3008 struct intel_display *display = to_intel_display(crtc);
3009 struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state);
3010 struct intel_plane *plane = to_intel_plane(crtc->base.primary);
3011 enum plane_id plane_id = plane->id;
3012 enum pipe pipe;
3013 u32 val, base, offset, stride_mult, tiling, alpha;
3014 int fourcc, pixel_format;
3015 unsigned int aligned_height;
3016 struct drm_framebuffer *fb;
3017 struct intel_framebuffer *intel_fb;
3018 static_assert(PLANE_CTL_TILED_YF == PLANE_CTL_TILED_4);
3019
3020 if (!plane->get_hw_state(plane, &pipe))
3021 return;
3022
3023 drm_WARN_ON(display->drm, pipe != crtc->pipe);
3024
3025 if (crtc_state->joiner_pipes) {
3026 drm_dbg_kms(display->drm,
3027 "[CRTC:%d:%s] Unsupported joiner configuration for initial FB\n",
3028 crtc->base.base.id, crtc->base.name);
3029 return;
3030 }
3031
3032 intel_fb = intel_framebuffer_alloc();
3033 if (!intel_fb) {
3034 drm_dbg_kms(display->drm, "failed to alloc fb\n");
3035 return;
3036 }
3037
3038 fb = &intel_fb->base;
3039
3040 fb->dev = display->drm;
3041
3042 val = intel_de_read(display, PLANE_CTL(pipe, plane_id));
3043
3044 if (DISPLAY_VER(display) >= 11)
3045 pixel_format = val & PLANE_CTL_FORMAT_MASK_ICL;
3046 else
3047 pixel_format = val & PLANE_CTL_FORMAT_MASK_SKL;
3048
3049 if (DISPLAY_VER(display) >= 10) {
3050 u32 color_ctl;
3051
3052 color_ctl = intel_de_read(display, PLANE_COLOR_CTL(pipe, plane_id));
3053 alpha = REG_FIELD_GET(PLANE_COLOR_ALPHA_MASK, color_ctl);
3054 } else {
3055 alpha = REG_FIELD_GET(PLANE_CTL_ALPHA_MASK, val);
3056 }
3057
3058 fourcc = skl_format_to_fourcc(format: pixel_format,
3059 rgb_order: val & PLANE_CTL_ORDER_RGBX, alpha);
3060 fb->format = drm_format_info(format: fourcc);
3061
3062 tiling = val & PLANE_CTL_TILED_MASK;
3063 switch (tiling) {
3064 case PLANE_CTL_TILED_LINEAR:
3065 fb->modifier = DRM_FORMAT_MOD_LINEAR;
3066 break;
3067 case PLANE_CTL_TILED_X:
3068 plane_config->tiling = I915_TILING_X;
3069 fb->modifier = I915_FORMAT_MOD_X_TILED;
3070 break;
3071 case PLANE_CTL_TILED_Y:
3072 plane_config->tiling = I915_TILING_Y;
3073 if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE)
3074 if (DISPLAY_VER(display) >= 14)
3075 fb->modifier = I915_FORMAT_MOD_4_TILED_MTL_RC_CCS;
3076 else if (DISPLAY_VER(display) >= 12)
3077 fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS;
3078 else
3079 fb->modifier = I915_FORMAT_MOD_Y_TILED_CCS;
3080 else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE)
3081 if (DISPLAY_VER(display) >= 14)
3082 fb->modifier = I915_FORMAT_MOD_4_TILED_MTL_MC_CCS;
3083 else
3084 fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
3085 else
3086 fb->modifier = I915_FORMAT_MOD_Y_TILED;
3087 break;
3088 case PLANE_CTL_TILED_YF: /* aka PLANE_CTL_TILED_4 on XE_LPD+ */
3089 if (HAS_4TILE(display)) {
3090 u32 rc_mask = PLANE_CTL_RENDER_DECOMPRESSION_ENABLE |
3091 PLANE_CTL_CLEAR_COLOR_DISABLE;
3092
3093 if ((val & rc_mask) == rc_mask)
3094 fb->modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS;
3095 else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE)
3096 fb->modifier = I915_FORMAT_MOD_4_TILED_DG2_MC_CCS;
3097 else if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE)
3098 fb->modifier = I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC;
3099 else
3100 fb->modifier = I915_FORMAT_MOD_4_TILED;
3101 } else {
3102 if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE)
3103 fb->modifier = I915_FORMAT_MOD_Yf_TILED_CCS;
3104 else
3105 fb->modifier = I915_FORMAT_MOD_Yf_TILED;
3106 }
3107 break;
3108 default:
3109 MISSING_CASE(tiling);
3110 goto error;
3111 }
3112
3113 if (!display->params.enable_dpt &&
3114 intel_fb_modifier_uses_dpt(display, modifier: fb->modifier)) {
3115 drm_dbg_kms(display->drm, "DPT disabled, skipping initial FB\n");
3116 goto error;
3117 }
3118
3119 /*
3120 * DRM_MODE_ROTATE_ is counter clockwise to stay compatible with Xrandr
3121 * while i915 HW rotation is clockwise, that's why this swapping.
3122 */
3123 switch (val & PLANE_CTL_ROTATE_MASK) {
3124 case PLANE_CTL_ROTATE_0:
3125 plane_config->rotation = DRM_MODE_ROTATE_0;
3126 break;
3127 case PLANE_CTL_ROTATE_90:
3128 plane_config->rotation = DRM_MODE_ROTATE_270;
3129 break;
3130 case PLANE_CTL_ROTATE_180:
3131 plane_config->rotation = DRM_MODE_ROTATE_180;
3132 break;
3133 case PLANE_CTL_ROTATE_270:
3134 plane_config->rotation = DRM_MODE_ROTATE_90;
3135 break;
3136 }
3137
3138 if (DISPLAY_VER(display) >= 11 && val & PLANE_CTL_FLIP_HORIZONTAL)
3139 plane_config->rotation |= DRM_MODE_REFLECT_X;
3140
3141 /* 90/270 degree rotation would require extra work */
3142 if (drm_rotation_90_or_270(rotation: plane_config->rotation))
3143 goto error;
3144
3145 base = intel_de_read(display, PLANE_SURF(pipe, plane_id)) & PLANE_SURF_ADDR_MASK;
3146 plane_config->base = base;
3147
3148 offset = intel_de_read(display, PLANE_OFFSET(pipe, plane_id));
3149 drm_WARN_ON(display->drm, offset != 0);
3150
3151 val = intel_de_read(display, PLANE_SIZE(pipe, plane_id));
3152 fb->height = REG_FIELD_GET(PLANE_HEIGHT_MASK, val) + 1;
3153 fb->width = REG_FIELD_GET(PLANE_WIDTH_MASK, val) + 1;
3154
3155 val = intel_de_read(display, PLANE_STRIDE(pipe, plane_id));
3156 stride_mult = skl_plane_stride_mult(fb, color_plane: 0, DRM_MODE_ROTATE_0);
3157
3158 fb->pitches[0] = REG_FIELD_GET(PLANE_STRIDE__MASK, val) * stride_mult;
3159
3160 aligned_height = intel_fb_align_height(fb, color_plane: 0, height: fb->height);
3161
3162 plane_config->size = fb->pitches[0] * aligned_height;
3163
3164 drm_dbg_kms(display->drm,
3165 "[CRTC:%d:%s][PLANE:%d:%s] with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
3166 crtc->base.base.id, crtc->base.name,
3167 plane->base.base.id, plane->base.name,
3168 fb->width, fb->height, fb->format->cpp[0] * 8,
3169 base, fb->pitches[0], plane_config->size);
3170
3171 plane_config->fb = intel_fb;
3172 return;
3173
3174error:
3175 kfree(objp: intel_fb);
3176}
3177
3178bool skl_fixup_initial_plane_config(struct intel_crtc *crtc,
3179 const struct intel_initial_plane_config *plane_config)
3180{
3181 struct intel_display *display = to_intel_display(crtc);
3182 struct intel_plane *plane = to_intel_plane(crtc->base.primary);
3183 const struct intel_plane_state *plane_state =
3184 to_intel_plane_state(plane->base.state);
3185 enum plane_id plane_id = plane->id;
3186 enum pipe pipe = crtc->pipe;
3187
3188 if (!plane_state->uapi.visible)
3189 return false;
3190
3191 /*
3192 * We may have moved the surface to a different
3193 * part of ggtt, make the plane aware of that.
3194 */
3195 if (plane_config->base == plane_state->surf)
3196 return false;
3197
3198 intel_de_write(display, PLANE_SURF(pipe, plane_id), val: plane_state->surf);
3199
3200 return true;
3201}
3202