1/*
2 * Copyright © 2011 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 * Jesse Barnes <jbarnes@virtuousgeek.org>
25 *
26 * New plane/sprite handling.
27 *
28 * The older chips had a separate interface for programming plane related
29 * registers; newer ones are much simpler and we can use the new DRM plane
30 * support.
31 */
32
33#include <linux/string_helpers.h>
34
35#include <drm/drm_atomic_helper.h>
36#include <drm/drm_blend.h>
37#include <drm/drm_color_mgmt.h>
38#include <drm/drm_fourcc.h>
39#include <drm/drm_print.h>
40#include <drm/drm_rect.h>
41
42#include "i915_utils.h"
43#include "i9xx_plane.h"
44#include "intel_de.h"
45#include "intel_display_types.h"
46#include "intel_fb.h"
47#include "intel_frontbuffer.h"
48#include "intel_plane.h"
49#include "intel_sprite.h"
50#include "intel_sprite_regs.h"
51
52static char sprite_name(struct intel_display *display, enum pipe pipe, int sprite)
53{
54 return pipe * DISPLAY_RUNTIME_INFO(display)->num_sprites[pipe] + sprite + 'A';
55}
56
57static void i9xx_plane_linear_gamma(u16 gamma[8])
58{
59 /* The points are not evenly spaced. */
60 static const u8 in[8] = { 0, 1, 2, 4, 8, 16, 24, 32 };
61 int i;
62
63 for (i = 0; i < 8; i++)
64 gamma[i] = (in[i] << 8) / 32;
65}
66
67static void
68chv_sprite_update_csc(const struct intel_plane_state *plane_state)
69{
70 struct intel_display *display = to_intel_display(plane_state);
71 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
72 const struct drm_framebuffer *fb = plane_state->hw.fb;
73 enum plane_id plane_id = plane->id;
74 /*
75 * |r| | c0 c1 c2 | |cr|
76 * |g| = | c3 c4 c5 | x |y |
77 * |b| | c6 c7 c8 | |cb|
78 *
79 * Coefficients are s3.12.
80 *
81 * Cb and Cr apparently come in as signed already, and
82 * we always get full range data in on account of CLRC0/1.
83 */
84 static const s16 csc_matrix[][9] = {
85 /* BT.601 full range YCbCr -> full range RGB */
86 [DRM_COLOR_YCBCR_BT601] = {
87 5743, 4096, 0,
88 -2925, 4096, -1410,
89 0, 4096, 7258,
90 },
91 /* BT.709 full range YCbCr -> full range RGB */
92 [DRM_COLOR_YCBCR_BT709] = {
93 6450, 4096, 0,
94 -1917, 4096, -767,
95 0, 4096, 7601,
96 },
97 };
98 const s16 *csc = csc_matrix[plane_state->hw.color_encoding];
99
100 /* Seems RGB data bypasses the CSC always */
101 if (!fb->format->is_yuv)
102 return;
103
104 intel_de_write_fw(display, SPCSCYGOFF(plane_id),
105 SPCSC_OOFF(0) | SPCSC_IOFF(0));
106 intel_de_write_fw(display, SPCSCCBOFF(plane_id),
107 SPCSC_OOFF(0) | SPCSC_IOFF(0));
108 intel_de_write_fw(display, SPCSCCROFF(plane_id),
109 SPCSC_OOFF(0) | SPCSC_IOFF(0));
110
111 intel_de_write_fw(display, SPCSCC01(plane_id),
112 SPCSC_C1(csc[1]) | SPCSC_C0(csc[0]));
113 intel_de_write_fw(display, SPCSCC23(plane_id),
114 SPCSC_C1(csc[3]) | SPCSC_C0(csc[2]));
115 intel_de_write_fw(display, SPCSCC45(plane_id),
116 SPCSC_C1(csc[5]) | SPCSC_C0(csc[4]));
117 intel_de_write_fw(display, SPCSCC67(plane_id),
118 SPCSC_C1(csc[7]) | SPCSC_C0(csc[6]));
119 intel_de_write_fw(display, SPCSCC8(plane_id), SPCSC_C0(csc[8]));
120
121 intel_de_write_fw(display, SPCSCYGICLAMP(plane_id),
122 SPCSC_IMAX(1023) | SPCSC_IMIN(0));
123 intel_de_write_fw(display, SPCSCCBICLAMP(plane_id),
124 SPCSC_IMAX(512) | SPCSC_IMIN(-512));
125 intel_de_write_fw(display, SPCSCCRICLAMP(plane_id),
126 SPCSC_IMAX(512) | SPCSC_IMIN(-512));
127
128 intel_de_write_fw(display, SPCSCYGOCLAMP(plane_id),
129 SPCSC_OMAX(1023) | SPCSC_OMIN(0));
130 intel_de_write_fw(display, SPCSCCBOCLAMP(plane_id),
131 SPCSC_OMAX(1023) | SPCSC_OMIN(0));
132 intel_de_write_fw(display, SPCSCCROCLAMP(plane_id),
133 SPCSC_OMAX(1023) | SPCSC_OMIN(0));
134}
135
136#define SIN_0 0
137#define COS_0 1
138
139static void
140vlv_sprite_update_clrc(const struct intel_plane_state *plane_state)
141{
142 struct intel_display *display = to_intel_display(plane_state);
143 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
144 const struct drm_framebuffer *fb = plane_state->hw.fb;
145 enum pipe pipe = plane->pipe;
146 enum plane_id plane_id = plane->id;
147 int contrast, brightness, sh_scale, sh_sin, sh_cos;
148
149 if (fb->format->is_yuv &&
150 plane_state->hw.color_range == DRM_COLOR_YCBCR_LIMITED_RANGE) {
151 /*
152 * Expand limited range to full range:
153 * Contrast is applied first and is used to expand Y range.
154 * Brightness is applied second and is used to remove the
155 * offset from Y. Saturation/hue is used to expand CbCr range.
156 */
157 contrast = DIV_ROUND_CLOSEST(255 << 6, 235 - 16);
158 brightness = -DIV_ROUND_CLOSEST(16 * 255, 235 - 16);
159 sh_scale = DIV_ROUND_CLOSEST(128 << 7, 240 - 128);
160 sh_sin = SIN_0 * sh_scale;
161 sh_cos = COS_0 * sh_scale;
162 } else {
163 /* Pass-through everything. */
164 contrast = 1 << 6;
165 brightness = 0;
166 sh_scale = 1 << 7;
167 sh_sin = SIN_0 * sh_scale;
168 sh_cos = COS_0 * sh_scale;
169 }
170
171 /* FIXME these register are single buffered :( */
172 intel_de_write_fw(display, SPCLRC0(pipe, plane_id),
173 SP_CONTRAST(contrast) | SP_BRIGHTNESS(brightness));
174 intel_de_write_fw(display, SPCLRC1(pipe, plane_id),
175 SP_SH_SIN(sh_sin) | SP_SH_COS(sh_cos));
176}
177
178static void
179vlv_plane_ratio(const struct intel_crtc_state *crtc_state,
180 const struct intel_plane_state *plane_state,
181 unsigned int *num, unsigned int *den)
182{
183 u8 active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR);
184 const struct drm_framebuffer *fb = plane_state->hw.fb;
185 unsigned int cpp = fb->format->cpp[0];
186
187 /*
188 * VLV bspec only considers cases where all three planes are
189 * enabled, and cases where the primary and one sprite is enabled.
190 * Let's assume the case with just two sprites enabled also
191 * maps to the latter case.
192 */
193 if (hweight8(active_planes) == 3) {
194 switch (cpp) {
195 case 8:
196 *num = 11;
197 *den = 8;
198 break;
199 case 4:
200 *num = 18;
201 *den = 16;
202 break;
203 default:
204 *num = 1;
205 *den = 1;
206 break;
207 }
208 } else if (hweight8(active_planes) == 2) {
209 switch (cpp) {
210 case 8:
211 *num = 10;
212 *den = 8;
213 break;
214 case 4:
215 *num = 17;
216 *den = 16;
217 break;
218 default:
219 *num = 1;
220 *den = 1;
221 break;
222 }
223 } else {
224 switch (cpp) {
225 case 8:
226 *num = 10;
227 *den = 8;
228 break;
229 default:
230 *num = 1;
231 *den = 1;
232 break;
233 }
234 }
235}
236
237int vlv_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
238 const struct intel_plane_state *plane_state)
239{
240 unsigned int pixel_rate;
241 unsigned int num, den;
242
243 /*
244 * Note that crtc_state->pixel_rate accounts for both
245 * horizontal and vertical panel fitter downscaling factors.
246 * Pre-HSW bspec tells us to only consider the horizontal
247 * downscaling factor here. We ignore that and just consider
248 * both for simplicity.
249 */
250 pixel_rate = crtc_state->pixel_rate;
251
252 vlv_plane_ratio(crtc_state, plane_state, num: &num, den: &den);
253
254 return DIV_ROUND_UP(pixel_rate * num, den);
255}
256
257static u32 vlv_sprite_ctl_crtc(const struct intel_crtc_state *crtc_state)
258{
259 u32 sprctl = 0;
260
261 if (crtc_state->gamma_enable)
262 sprctl |= SP_PIPE_GAMMA_ENABLE;
263
264 return sprctl;
265}
266
267static u32 vlv_sprite_ctl(const struct intel_plane_state *plane_state)
268{
269 const struct drm_framebuffer *fb = plane_state->hw.fb;
270 unsigned int rotation = plane_state->hw.rotation;
271 const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
272 u32 sprctl;
273
274 sprctl = SP_ENABLE;
275
276 switch (fb->format->format) {
277 case DRM_FORMAT_YUYV:
278 sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YUYV;
279 break;
280 case DRM_FORMAT_YVYU:
281 sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YVYU;
282 break;
283 case DRM_FORMAT_UYVY:
284 sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_UYVY;
285 break;
286 case DRM_FORMAT_VYUY:
287 sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_VYUY;
288 break;
289 case DRM_FORMAT_C8:
290 sprctl |= SP_FORMAT_8BPP;
291 break;
292 case DRM_FORMAT_RGB565:
293 sprctl |= SP_FORMAT_BGR565;
294 break;
295 case DRM_FORMAT_XRGB8888:
296 sprctl |= SP_FORMAT_BGRX8888;
297 break;
298 case DRM_FORMAT_ARGB8888:
299 sprctl |= SP_FORMAT_BGRA8888;
300 break;
301 case DRM_FORMAT_XBGR2101010:
302 sprctl |= SP_FORMAT_RGBX1010102;
303 break;
304 case DRM_FORMAT_ABGR2101010:
305 sprctl |= SP_FORMAT_RGBA1010102;
306 break;
307 case DRM_FORMAT_XRGB2101010:
308 sprctl |= SP_FORMAT_BGRX1010102;
309 break;
310 case DRM_FORMAT_ARGB2101010:
311 sprctl |= SP_FORMAT_BGRA1010102;
312 break;
313 case DRM_FORMAT_XBGR8888:
314 sprctl |= SP_FORMAT_RGBX8888;
315 break;
316 case DRM_FORMAT_ABGR8888:
317 sprctl |= SP_FORMAT_RGBA8888;
318 break;
319 default:
320 MISSING_CASE(fb->format->format);
321 return 0;
322 }
323
324 if (plane_state->hw.color_encoding == DRM_COLOR_YCBCR_BT709)
325 sprctl |= SP_YUV_FORMAT_BT709;
326
327 if (fb->modifier == I915_FORMAT_MOD_X_TILED)
328 sprctl |= SP_TILED;
329
330 if (rotation & DRM_MODE_ROTATE_180)
331 sprctl |= SP_ROTATE_180;
332
333 if (rotation & DRM_MODE_REFLECT_X)
334 sprctl |= SP_MIRROR;
335
336 if (key->flags & I915_SET_COLORKEY_SOURCE)
337 sprctl |= SP_SOURCE_KEY;
338
339 return sprctl;
340}
341
342static void vlv_sprite_update_gamma(const struct intel_plane_state *plane_state)
343{
344 struct intel_display *display = to_intel_display(plane_state);
345 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
346 const struct drm_framebuffer *fb = plane_state->hw.fb;
347 enum pipe pipe = plane->pipe;
348 enum plane_id plane_id = plane->id;
349 u16 gamma[8];
350 int i;
351
352 /* Seems RGB data bypasses the gamma always */
353 if (!fb->format->is_yuv)
354 return;
355
356 i9xx_plane_linear_gamma(gamma);
357
358 /* FIXME these register are single buffered :( */
359 /* The two end points are implicit (0.0 and 1.0) */
360 for (i = 1; i < 8 - 1; i++)
361 intel_de_write_fw(display, SPGAMC(pipe, plane_id, i - 1),
362 val: gamma[i] << 16 | gamma[i] << 8 | gamma[i]);
363}
364
365static void
366vlv_sprite_update_noarm(struct intel_dsb *dsb,
367 struct intel_plane *plane,
368 const struct intel_crtc_state *crtc_state,
369 const struct intel_plane_state *plane_state)
370{
371 struct intel_display *display = to_intel_display(plane);
372 enum pipe pipe = plane->pipe;
373 enum plane_id plane_id = plane->id;
374 int crtc_x = plane_state->uapi.dst.x1;
375 int crtc_y = plane_state->uapi.dst.y1;
376 u32 crtc_w = drm_rect_width(r: &plane_state->uapi.dst);
377 u32 crtc_h = drm_rect_height(r: &plane_state->uapi.dst);
378
379 intel_de_write_fw(display, SPSTRIDE(pipe, plane_id),
380 val: plane_state->view.color_plane[0].mapping_stride);
381 intel_de_write_fw(display, SPPOS(pipe, plane_id),
382 SP_POS_Y(crtc_y) | SP_POS_X(crtc_x));
383 intel_de_write_fw(display, SPSIZE(pipe, plane_id),
384 SP_HEIGHT(crtc_h - 1) | SP_WIDTH(crtc_w - 1));
385}
386
387static void
388vlv_sprite_update_arm(struct intel_dsb *dsb,
389 struct intel_plane *plane,
390 const struct intel_crtc_state *crtc_state,
391 const struct intel_plane_state *plane_state)
392{
393 struct intel_display *display = to_intel_display(plane);
394 enum pipe pipe = plane->pipe;
395 enum plane_id plane_id = plane->id;
396 const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
397 u32 x = plane_state->view.color_plane[0].x;
398 u32 y = plane_state->view.color_plane[0].y;
399 u32 sprctl;
400
401 sprctl = plane_state->ctl | vlv_sprite_ctl_crtc(crtc_state);
402
403 if (display->platform.cherryview && pipe == PIPE_B)
404 chv_sprite_update_csc(plane_state);
405
406 if (key->flags) {
407 intel_de_write_fw(display, SPKEYMINVAL(pipe, plane_id),
408 val: key->min_value);
409 intel_de_write_fw(display, SPKEYMSK(pipe, plane_id),
410 val: key->channel_mask);
411 intel_de_write_fw(display, SPKEYMAXVAL(pipe, plane_id),
412 val: key->max_value);
413 }
414
415 intel_de_write_fw(display, SPCONSTALPHA(pipe, plane_id), val: 0);
416
417 intel_de_write_fw(display, SPLINOFF(pipe, plane_id),
418 val: intel_fb_xy_to_linear(x, y, plane_state, color_plane: 0));
419 intel_de_write_fw(display, SPTILEOFF(pipe, plane_id),
420 SP_OFFSET_Y(y) | SP_OFFSET_X(x));
421
422 /*
423 * The control register self-arms if the plane was previously
424 * disabled. Try to make the plane enable atomic by writing
425 * the control register just before the surface register.
426 */
427 intel_de_write_fw(display, SPCNTR(pipe, plane_id), val: sprctl);
428 intel_de_write_fw(display, SPSURF(pipe, plane_id), val: plane_state->surf);
429
430 vlv_sprite_update_clrc(plane_state);
431 vlv_sprite_update_gamma(plane_state);
432}
433
434static void
435vlv_sprite_disable_arm(struct intel_dsb *dsb,
436 struct intel_plane *plane,
437 const struct intel_crtc_state *crtc_state)
438{
439 struct intel_display *display = to_intel_display(plane);
440 enum pipe pipe = plane->pipe;
441 enum plane_id plane_id = plane->id;
442
443 intel_de_write_fw(display, SPCNTR(pipe, plane_id), val: 0);
444 intel_de_write_fw(display, SPSURF(pipe, plane_id), val: 0);
445}
446
447static void vlv_sprite_capture_error(struct intel_crtc *crtc,
448 struct intel_plane *plane,
449 struct intel_plane_error *error)
450{
451 struct intel_display *display = to_intel_display(plane);
452
453 error->ctl = intel_de_read(display, SPCNTR(crtc->pipe, plane->id));
454 error->surf = intel_de_read(display, SPSURF(crtc->pipe, plane->id));
455 error->surflive = intel_de_read(display, SPSURFLIVE(crtc->pipe, plane->id));
456}
457
458static bool
459vlv_sprite_get_hw_state(struct intel_plane *plane,
460 enum pipe *pipe)
461{
462 struct intel_display *display = to_intel_display(plane);
463 enum intel_display_power_domain power_domain;
464 enum plane_id plane_id = plane->id;
465 intel_wakeref_t wakeref;
466 bool ret;
467
468 power_domain = POWER_DOMAIN_PIPE(plane->pipe);
469 wakeref = intel_display_power_get_if_enabled(display, domain: power_domain);
470 if (!wakeref)
471 return false;
472
473 ret = intel_de_read(display, SPCNTR(plane->pipe, plane_id)) & SP_ENABLE;
474
475 *pipe = plane->pipe;
476
477 intel_display_power_put(display, domain: power_domain, wakeref);
478
479 return ret;
480}
481
482static void ivb_plane_ratio(const struct intel_crtc_state *crtc_state,
483 const struct intel_plane_state *plane_state,
484 unsigned int *num, unsigned int *den)
485{
486 u8 active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR);
487 const struct drm_framebuffer *fb = plane_state->hw.fb;
488 unsigned int cpp = fb->format->cpp[0];
489
490 if (hweight8(active_planes) == 2) {
491 switch (cpp) {
492 case 8:
493 *num = 10;
494 *den = 8;
495 break;
496 case 4:
497 *num = 17;
498 *den = 16;
499 break;
500 default:
501 *num = 1;
502 *den = 1;
503 break;
504 }
505 } else {
506 switch (cpp) {
507 case 8:
508 *num = 9;
509 *den = 8;
510 break;
511 default:
512 *num = 1;
513 *den = 1;
514 break;
515 }
516 }
517}
518
519static void ivb_plane_ratio_scaling(const struct intel_crtc_state *crtc_state,
520 const struct intel_plane_state *plane_state,
521 unsigned int *num, unsigned int *den)
522{
523 const struct drm_framebuffer *fb = plane_state->hw.fb;
524 unsigned int cpp = fb->format->cpp[0];
525
526 switch (cpp) {
527 case 8:
528 *num = 12;
529 *den = 8;
530 break;
531 case 4:
532 *num = 19;
533 *den = 16;
534 break;
535 case 2:
536 *num = 33;
537 *den = 32;
538 break;
539 default:
540 *num = 1;
541 *den = 1;
542 break;
543 }
544}
545
546int ivb_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
547 const struct intel_plane_state *plane_state)
548{
549 unsigned int pixel_rate;
550 unsigned int num, den;
551
552 /*
553 * Note that crtc_state->pixel_rate accounts for both
554 * horizontal and vertical panel fitter downscaling factors.
555 * Pre-HSW bspec tells us to only consider the horizontal
556 * downscaling factor here. We ignore that and just consider
557 * both for simplicity.
558 */
559 pixel_rate = crtc_state->pixel_rate;
560
561 ivb_plane_ratio(crtc_state, plane_state, num: &num, den: &den);
562
563 return DIV_ROUND_UP(pixel_rate * num, den);
564}
565
566static int ivb_sprite_min_cdclk(const struct intel_crtc_state *crtc_state,
567 const struct intel_plane_state *plane_state)
568{
569 unsigned int src_w, dst_w, pixel_rate;
570 unsigned int num, den;
571
572 /*
573 * Note that crtc_state->pixel_rate accounts for both
574 * horizontal and vertical panel fitter downscaling factors.
575 * Pre-HSW bspec tells us to only consider the horizontal
576 * downscaling factor here. We ignore that and just consider
577 * both for simplicity.
578 */
579 pixel_rate = crtc_state->pixel_rate;
580
581 src_w = drm_rect_width(r: &plane_state->uapi.src) >> 16;
582 dst_w = drm_rect_width(r: &plane_state->uapi.dst);
583
584 if (src_w != dst_w)
585 ivb_plane_ratio_scaling(crtc_state, plane_state, num: &num, den: &den);
586 else
587 ivb_plane_ratio(crtc_state, plane_state, num: &num, den: &den);
588
589 /* Horizontal downscaling limits the maximum pixel rate */
590 dst_w = min(src_w, dst_w);
591
592 return DIV_ROUND_UP_ULL(mul_u32_u32(pixel_rate, num * src_w),
593 den * dst_w);
594}
595
596static void hsw_plane_ratio(const struct intel_crtc_state *crtc_state,
597 const struct intel_plane_state *plane_state,
598 unsigned int *num, unsigned int *den)
599{
600 u8 active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR);
601 const struct drm_framebuffer *fb = plane_state->hw.fb;
602 unsigned int cpp = fb->format->cpp[0];
603
604 if (hweight8(active_planes) == 2) {
605 switch (cpp) {
606 case 8:
607 *num = 10;
608 *den = 8;
609 break;
610 default:
611 *num = 1;
612 *den = 1;
613 break;
614 }
615 } else {
616 switch (cpp) {
617 case 8:
618 *num = 9;
619 *den = 8;
620 break;
621 default:
622 *num = 1;
623 *den = 1;
624 break;
625 }
626 }
627}
628
629int hsw_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
630 const struct intel_plane_state *plane_state)
631{
632 unsigned int pixel_rate = crtc_state->pixel_rate;
633 unsigned int num, den;
634
635 hsw_plane_ratio(crtc_state, plane_state, num: &num, den: &den);
636
637 return DIV_ROUND_UP(pixel_rate * num, den);
638}
639
640static u32 ivb_sprite_ctl_crtc(const struct intel_crtc_state *crtc_state)
641{
642 u32 sprctl = 0;
643
644 if (crtc_state->gamma_enable)
645 sprctl |= SPRITE_PIPE_GAMMA_ENABLE;
646
647 if (crtc_state->csc_enable)
648 sprctl |= SPRITE_PIPE_CSC_ENABLE;
649
650 return sprctl;
651}
652
653static bool ivb_need_sprite_gamma(const struct intel_plane_state *plane_state)
654{
655 struct intel_display *display = to_intel_display(plane_state);
656 const struct drm_framebuffer *fb = plane_state->hw.fb;
657
658 return fb->format->cpp[0] == 8 &&
659 (display->platform.ivybridge || display->platform.haswell);
660}
661
662static u32 ivb_sprite_ctl(const struct intel_plane_state *plane_state)
663{
664 struct intel_display *display = to_intel_display(plane_state);
665 const struct drm_framebuffer *fb = plane_state->hw.fb;
666 unsigned int rotation = plane_state->hw.rotation;
667 const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
668 u32 sprctl;
669
670 sprctl = SPRITE_ENABLE;
671
672 if (display->platform.ivybridge)
673 sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
674
675 switch (fb->format->format) {
676 case DRM_FORMAT_XBGR8888:
677 sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
678 break;
679 case DRM_FORMAT_XRGB8888:
680 sprctl |= SPRITE_FORMAT_RGBX888;
681 break;
682 case DRM_FORMAT_XBGR2101010:
683 sprctl |= SPRITE_FORMAT_RGBX101010 | SPRITE_RGB_ORDER_RGBX;
684 break;
685 case DRM_FORMAT_XRGB2101010:
686 sprctl |= SPRITE_FORMAT_RGBX101010;
687 break;
688 case DRM_FORMAT_XBGR16161616F:
689 sprctl |= SPRITE_FORMAT_RGBX161616 | SPRITE_RGB_ORDER_RGBX;
690 break;
691 case DRM_FORMAT_XRGB16161616F:
692 sprctl |= SPRITE_FORMAT_RGBX161616;
693 break;
694 case DRM_FORMAT_YUYV:
695 sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV;
696 break;
697 case DRM_FORMAT_YVYU:
698 sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU;
699 break;
700 case DRM_FORMAT_UYVY:
701 sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY;
702 break;
703 case DRM_FORMAT_VYUY:
704 sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY;
705 break;
706 default:
707 MISSING_CASE(fb->format->format);
708 return 0;
709 }
710
711 if (!ivb_need_sprite_gamma(plane_state))
712 sprctl |= SPRITE_PLANE_GAMMA_DISABLE;
713
714 if (plane_state->hw.color_encoding == DRM_COLOR_YCBCR_BT709)
715 sprctl |= SPRITE_YUV_TO_RGB_CSC_FORMAT_BT709;
716
717 if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
718 sprctl |= SPRITE_YUV_RANGE_CORRECTION_DISABLE;
719
720 if (fb->modifier == I915_FORMAT_MOD_X_TILED)
721 sprctl |= SPRITE_TILED;
722
723 if (rotation & DRM_MODE_ROTATE_180)
724 sprctl |= SPRITE_ROTATE_180;
725
726 if (key->flags & I915_SET_COLORKEY_DESTINATION)
727 sprctl |= SPRITE_DEST_KEY;
728 else if (key->flags & I915_SET_COLORKEY_SOURCE)
729 sprctl |= SPRITE_SOURCE_KEY;
730
731 return sprctl;
732}
733
734static void ivb_sprite_linear_gamma(const struct intel_plane_state *plane_state,
735 u16 gamma[18])
736{
737 int scale, i;
738
739 /*
740 * WaFP16GammaEnabling:ivb,hsw
741 * "Workaround : When using the 64-bit format, the sprite output
742 * on each color channel has one quarter amplitude. It can be
743 * brought up to full amplitude by using sprite internal gamma
744 * correction, pipe gamma correction, or pipe color space
745 * conversion to multiply the sprite output by four."
746 */
747 scale = 4;
748
749 for (i = 0; i < 16; i++)
750 gamma[i] = min((scale * i << 10) / 16, (1 << 10) - 1);
751
752 gamma[i] = min((scale * i << 10) / 16, 1 << 10);
753 i++;
754
755 gamma[i] = 3 << 10;
756 i++;
757}
758
759static void ivb_sprite_update_gamma(const struct intel_plane_state *plane_state)
760{
761 struct intel_display *display = to_intel_display(plane_state);
762 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
763 enum pipe pipe = plane->pipe;
764 u16 gamma[18];
765 int i;
766
767 if (!ivb_need_sprite_gamma(plane_state))
768 return;
769
770 ivb_sprite_linear_gamma(plane_state, gamma);
771
772 /* FIXME these register are single buffered :( */
773 for (i = 0; i < 16; i++)
774 intel_de_write_fw(display, SPRGAMC(pipe, i),
775 val: gamma[i] << 20 | gamma[i] << 10 | gamma[i]);
776
777 intel_de_write_fw(display, SPRGAMC16(pipe, 0), val: gamma[i]);
778 intel_de_write_fw(display, SPRGAMC16(pipe, 1), val: gamma[i]);
779 intel_de_write_fw(display, SPRGAMC16(pipe, 2), val: gamma[i]);
780 i++;
781
782 intel_de_write_fw(display, SPRGAMC17(pipe, 0), val: gamma[i]);
783 intel_de_write_fw(display, SPRGAMC17(pipe, 1), val: gamma[i]);
784 intel_de_write_fw(display, SPRGAMC17(pipe, 2), val: gamma[i]);
785 i++;
786}
787
788static void
789ivb_sprite_update_noarm(struct intel_dsb *dsb,
790 struct intel_plane *plane,
791 const struct intel_crtc_state *crtc_state,
792 const struct intel_plane_state *plane_state)
793{
794 struct intel_display *display = to_intel_display(plane);
795 enum pipe pipe = plane->pipe;
796 int crtc_x = plane_state->uapi.dst.x1;
797 int crtc_y = plane_state->uapi.dst.y1;
798 u32 crtc_w = drm_rect_width(r: &plane_state->uapi.dst);
799 u32 crtc_h = drm_rect_height(r: &plane_state->uapi.dst);
800 u32 src_w = drm_rect_width(r: &plane_state->uapi.src) >> 16;
801 u32 src_h = drm_rect_height(r: &plane_state->uapi.src) >> 16;
802 u32 sprscale = 0;
803
804 if (crtc_w != src_w || crtc_h != src_h)
805 sprscale = SPRITE_SCALE_ENABLE |
806 SPRITE_SRC_WIDTH(src_w - 1) |
807 SPRITE_SRC_HEIGHT(src_h - 1);
808
809 intel_de_write_fw(display, SPRSTRIDE(pipe),
810 val: plane_state->view.color_plane[0].mapping_stride);
811 intel_de_write_fw(display, SPRPOS(pipe),
812 SPRITE_POS_Y(crtc_y) | SPRITE_POS_X(crtc_x));
813 intel_de_write_fw(display, SPRSIZE(pipe),
814 SPRITE_HEIGHT(crtc_h - 1) | SPRITE_WIDTH(crtc_w - 1));
815 if (display->platform.ivybridge)
816 intel_de_write_fw(display, SPRSCALE(pipe), val: sprscale);
817}
818
819static void
820ivb_sprite_update_arm(struct intel_dsb *dsb,
821 struct intel_plane *plane,
822 const struct intel_crtc_state *crtc_state,
823 const struct intel_plane_state *plane_state)
824{
825 struct intel_display *display = to_intel_display(plane);
826 enum pipe pipe = plane->pipe;
827 const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
828 u32 x = plane_state->view.color_plane[0].x;
829 u32 y = plane_state->view.color_plane[0].y;
830 u32 sprctl;
831
832 sprctl = plane_state->ctl | ivb_sprite_ctl_crtc(crtc_state);
833
834 if (key->flags) {
835 intel_de_write_fw(display, SPRKEYVAL(pipe), val: key->min_value);
836 intel_de_write_fw(display, SPRKEYMSK(pipe),
837 val: key->channel_mask);
838 intel_de_write_fw(display, SPRKEYMAX(pipe), val: key->max_value);
839 }
840
841 /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET
842 * register */
843 if (display->platform.haswell || display->platform.broadwell) {
844 intel_de_write_fw(display, SPROFFSET(pipe),
845 SPRITE_OFFSET_Y(y) | SPRITE_OFFSET_X(x));
846 } else {
847 intel_de_write_fw(display, SPRLINOFF(pipe),
848 val: intel_fb_xy_to_linear(x, y, plane_state, color_plane: 0));
849 intel_de_write_fw(display, SPRTILEOFF(pipe),
850 SPRITE_OFFSET_Y(y) | SPRITE_OFFSET_X(x));
851 }
852
853 /*
854 * The control register self-arms if the plane was previously
855 * disabled. Try to make the plane enable atomic by writing
856 * the control register just before the surface register.
857 */
858 intel_de_write_fw(display, SPRCTL(pipe), val: sprctl);
859 intel_de_write_fw(display, SPRSURF(pipe), val: plane_state->surf);
860
861 ivb_sprite_update_gamma(plane_state);
862}
863
864static void
865ivb_sprite_disable_arm(struct intel_dsb *dsb,
866 struct intel_plane *plane,
867 const struct intel_crtc_state *crtc_state)
868{
869 struct intel_display *display = to_intel_display(plane);
870 enum pipe pipe = plane->pipe;
871
872 intel_de_write_fw(display, SPRCTL(pipe), val: 0);
873 /* Disable the scaler */
874 if (display->platform.ivybridge)
875 intel_de_write_fw(display, SPRSCALE(pipe), val: 0);
876 intel_de_write_fw(display, SPRSURF(pipe), val: 0);
877}
878
879static void ivb_sprite_capture_error(struct intel_crtc *crtc,
880 struct intel_plane *plane,
881 struct intel_plane_error *error)
882{
883 struct intel_display *display = to_intel_display(plane);
884
885 error->ctl = intel_de_read(display, SPRCTL(crtc->pipe));
886 error->surf = intel_de_read(display, SPRSURF(crtc->pipe));
887 error->surflive = intel_de_read(display, SPRSURFLIVE(crtc->pipe));
888}
889
890static bool
891ivb_sprite_get_hw_state(struct intel_plane *plane,
892 enum pipe *pipe)
893{
894 struct intel_display *display = to_intel_display(plane);
895 enum intel_display_power_domain power_domain;
896 intel_wakeref_t wakeref;
897 bool ret;
898
899 power_domain = POWER_DOMAIN_PIPE(plane->pipe);
900 wakeref = intel_display_power_get_if_enabled(display, domain: power_domain);
901 if (!wakeref)
902 return false;
903
904 ret = intel_de_read(display, SPRCTL(plane->pipe)) & SPRITE_ENABLE;
905
906 *pipe = plane->pipe;
907
908 intel_display_power_put(display, domain: power_domain, wakeref);
909
910 return ret;
911}
912
913static int g4x_sprite_min_cdclk(const struct intel_crtc_state *crtc_state,
914 const struct intel_plane_state *plane_state)
915{
916 const struct drm_framebuffer *fb = plane_state->hw.fb;
917 unsigned int hscale, pixel_rate;
918 unsigned int limit, decimate;
919
920 /*
921 * Note that crtc_state->pixel_rate accounts for both
922 * horizontal and vertical panel fitter downscaling factors.
923 * Pre-HSW bspec tells us to only consider the horizontal
924 * downscaling factor here. We ignore that and just consider
925 * both for simplicity.
926 */
927 pixel_rate = crtc_state->pixel_rate;
928
929 /* Horizontal downscaling limits the maximum pixel rate */
930 hscale = drm_rect_calc_hscale(src: &plane_state->uapi.src,
931 dst: &plane_state->uapi.dst,
932 min_hscale: 0, INT_MAX);
933 hscale = max(hscale, 0x10000u);
934
935 /* Decimation steps at 2x,4x,8x,16x */
936 decimate = ilog2(hscale >> 16);
937 hscale >>= decimate;
938
939 /* Starting limit is 90% of cdclk */
940 limit = 9;
941
942 /* -10% per decimation step */
943 limit -= decimate;
944
945 /* -10% for RGB */
946 if (!fb->format->is_yuv)
947 limit--;
948
949 /*
950 * We should also do -10% if sprite scaling is enabled
951 * on the other pipe, but we can't really check for that,
952 * so we ignore it.
953 */
954
955 return DIV_ROUND_UP_ULL(mul_u32_u32(pixel_rate, 10 * hscale),
956 limit << 16);
957}
958
959static unsigned int
960g4x_sprite_max_stride(struct intel_plane *plane,
961 u32 pixel_format, u64 modifier,
962 unsigned int rotation)
963{
964 const struct drm_format_info *info = drm_format_info(format: pixel_format);
965 int cpp = info->cpp[0];
966
967 /* Limit to 4k pixels to guarantee TILEOFF.x doesn't get too big. */
968 if (modifier == I915_FORMAT_MOD_X_TILED)
969 return min(4096 * cpp, 16 * 1024);
970 else
971 return 16 * 1024;
972}
973
974static unsigned int
975hsw_sprite_max_stride(struct intel_plane *plane,
976 u32 pixel_format, u64 modifier,
977 unsigned int rotation)
978{
979 const struct drm_format_info *info = drm_format_info(format: pixel_format);
980 int cpp = info->cpp[0];
981
982 /* Limit to 8k pixels to guarantee OFFSET.x doesn't get too big. */
983 return min(8192 * cpp, 16 * 1024);
984}
985
986static unsigned int g4x_sprite_min_alignment(struct intel_plane *plane,
987 const struct drm_framebuffer *fb,
988 int color_plane)
989{
990 struct intel_display *display = to_intel_display(plane);
991
992 if (intel_scanout_needs_vtd_wa(display))
993 return 128 * 1024;
994
995 return 4 * 1024;
996}
997
998static u32 g4x_sprite_ctl_crtc(const struct intel_crtc_state *crtc_state)
999{
1000 u32 dvscntr = 0;
1001
1002 if (crtc_state->gamma_enable)
1003 dvscntr |= DVS_PIPE_GAMMA_ENABLE;
1004
1005 if (crtc_state->csc_enable)
1006 dvscntr |= DVS_PIPE_CSC_ENABLE;
1007
1008 return dvscntr;
1009}
1010
1011static u32 g4x_sprite_ctl(const struct intel_plane_state *plane_state)
1012{
1013 struct intel_display *display = to_intel_display(plane_state);
1014 const struct drm_framebuffer *fb = plane_state->hw.fb;
1015 unsigned int rotation = plane_state->hw.rotation;
1016 const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
1017 u32 dvscntr;
1018
1019 dvscntr = DVS_ENABLE;
1020
1021 if (display->platform.sandybridge)
1022 dvscntr |= DVS_TRICKLE_FEED_DISABLE;
1023
1024 switch (fb->format->format) {
1025 case DRM_FORMAT_XBGR8888:
1026 dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR;
1027 break;
1028 case DRM_FORMAT_XRGB8888:
1029 dvscntr |= DVS_FORMAT_RGBX888;
1030 break;
1031 case DRM_FORMAT_XBGR2101010:
1032 dvscntr |= DVS_FORMAT_RGBX101010 | DVS_RGB_ORDER_XBGR;
1033 break;
1034 case DRM_FORMAT_XRGB2101010:
1035 dvscntr |= DVS_FORMAT_RGBX101010;
1036 break;
1037 case DRM_FORMAT_XBGR16161616F:
1038 dvscntr |= DVS_FORMAT_RGBX161616 | DVS_RGB_ORDER_XBGR;
1039 break;
1040 case DRM_FORMAT_XRGB16161616F:
1041 dvscntr |= DVS_FORMAT_RGBX161616;
1042 break;
1043 case DRM_FORMAT_YUYV:
1044 dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV;
1045 break;
1046 case DRM_FORMAT_YVYU:
1047 dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU;
1048 break;
1049 case DRM_FORMAT_UYVY:
1050 dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY;
1051 break;
1052 case DRM_FORMAT_VYUY:
1053 dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY;
1054 break;
1055 default:
1056 MISSING_CASE(fb->format->format);
1057 return 0;
1058 }
1059
1060 if (plane_state->hw.color_encoding == DRM_COLOR_YCBCR_BT709)
1061 dvscntr |= DVS_YUV_FORMAT_BT709;
1062
1063 if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
1064 dvscntr |= DVS_YUV_RANGE_CORRECTION_DISABLE;
1065
1066 if (fb->modifier == I915_FORMAT_MOD_X_TILED)
1067 dvscntr |= DVS_TILED;
1068
1069 if (rotation & DRM_MODE_ROTATE_180)
1070 dvscntr |= DVS_ROTATE_180;
1071
1072 if (key->flags & I915_SET_COLORKEY_DESTINATION)
1073 dvscntr |= DVS_DEST_KEY;
1074 else if (key->flags & I915_SET_COLORKEY_SOURCE)
1075 dvscntr |= DVS_SOURCE_KEY;
1076
1077 return dvscntr;
1078}
1079
1080static void g4x_sprite_update_gamma(const struct intel_plane_state *plane_state)
1081{
1082 struct intel_display *display = to_intel_display(plane_state);
1083 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1084 const struct drm_framebuffer *fb = plane_state->hw.fb;
1085 enum pipe pipe = plane->pipe;
1086 u16 gamma[8];
1087 int i;
1088
1089 /* Seems RGB data bypasses the gamma always */
1090 if (!fb->format->is_yuv)
1091 return;
1092
1093 i9xx_plane_linear_gamma(gamma);
1094
1095 /* FIXME these register are single buffered :( */
1096 /* The two end points are implicit (0.0 and 1.0) */
1097 for (i = 1; i < 8 - 1; i++)
1098 intel_de_write_fw(display, DVSGAMC_G4X(pipe, i - 1),
1099 val: gamma[i] << 16 | gamma[i] << 8 | gamma[i]);
1100}
1101
1102static void ilk_sprite_linear_gamma(u16 gamma[17])
1103{
1104 int i;
1105
1106 for (i = 0; i < 17; i++)
1107 gamma[i] = (i << 10) / 16;
1108}
1109
1110static void ilk_sprite_update_gamma(const struct intel_plane_state *plane_state)
1111{
1112 struct intel_display *display = to_intel_display(plane_state);
1113 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1114 const struct drm_framebuffer *fb = plane_state->hw.fb;
1115 enum pipe pipe = plane->pipe;
1116 u16 gamma[17];
1117 int i;
1118
1119 /* Seems RGB data bypasses the gamma always */
1120 if (!fb->format->is_yuv)
1121 return;
1122
1123 ilk_sprite_linear_gamma(gamma);
1124
1125 /* FIXME these register are single buffered :( */
1126 for (i = 0; i < 16; i++)
1127 intel_de_write_fw(display, DVSGAMC_ILK(pipe, i),
1128 val: gamma[i] << 20 | gamma[i] << 10 | gamma[i]);
1129
1130 intel_de_write_fw(display, DVSGAMCMAX_ILK(pipe, 0), val: gamma[i]);
1131 intel_de_write_fw(display, DVSGAMCMAX_ILK(pipe, 1), val: gamma[i]);
1132 intel_de_write_fw(display, DVSGAMCMAX_ILK(pipe, 2), val: gamma[i]);
1133 i++;
1134}
1135
1136static void
1137g4x_sprite_update_noarm(struct intel_dsb *dsb,
1138 struct intel_plane *plane,
1139 const struct intel_crtc_state *crtc_state,
1140 const struct intel_plane_state *plane_state)
1141{
1142 struct intel_display *display = to_intel_display(plane);
1143 enum pipe pipe = plane->pipe;
1144 int crtc_x = plane_state->uapi.dst.x1;
1145 int crtc_y = plane_state->uapi.dst.y1;
1146 u32 crtc_w = drm_rect_width(r: &plane_state->uapi.dst);
1147 u32 crtc_h = drm_rect_height(r: &plane_state->uapi.dst);
1148 u32 src_w = drm_rect_width(r: &plane_state->uapi.src) >> 16;
1149 u32 src_h = drm_rect_height(r: &plane_state->uapi.src) >> 16;
1150 u32 dvsscale = 0;
1151
1152 if (crtc_w != src_w || crtc_h != src_h)
1153 dvsscale = DVS_SCALE_ENABLE |
1154 DVS_SRC_WIDTH(src_w - 1) |
1155 DVS_SRC_HEIGHT(src_h - 1);
1156
1157 intel_de_write_fw(display, DVSSTRIDE(pipe),
1158 val: plane_state->view.color_plane[0].mapping_stride);
1159 intel_de_write_fw(display, DVSPOS(pipe),
1160 DVS_POS_Y(crtc_y) | DVS_POS_X(crtc_x));
1161 intel_de_write_fw(display, DVSSIZE(pipe),
1162 DVS_HEIGHT(crtc_h - 1) | DVS_WIDTH(crtc_w - 1));
1163 intel_de_write_fw(display, DVSSCALE(pipe), val: dvsscale);
1164}
1165
1166static void
1167g4x_sprite_update_arm(struct intel_dsb *dsb,
1168 struct intel_plane *plane,
1169 const struct intel_crtc_state *crtc_state,
1170 const struct intel_plane_state *plane_state)
1171{
1172 struct intel_display *display = to_intel_display(plane);
1173 enum pipe pipe = plane->pipe;
1174 const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
1175 u32 x = plane_state->view.color_plane[0].x;
1176 u32 y = plane_state->view.color_plane[0].y;
1177 u32 dvscntr;
1178
1179 dvscntr = plane_state->ctl | g4x_sprite_ctl_crtc(crtc_state);
1180
1181 if (key->flags) {
1182 intel_de_write_fw(display, DVSKEYVAL(pipe), val: key->min_value);
1183 intel_de_write_fw(display, DVSKEYMSK(pipe),
1184 val: key->channel_mask);
1185 intel_de_write_fw(display, DVSKEYMAX(pipe), val: key->max_value);
1186 }
1187
1188 intel_de_write_fw(display, DVSLINOFF(pipe),
1189 val: intel_fb_xy_to_linear(x, y, plane_state, color_plane: 0));
1190 intel_de_write_fw(display, DVSTILEOFF(pipe),
1191 DVS_OFFSET_Y(y) | DVS_OFFSET_X(x));
1192
1193 /*
1194 * The control register self-arms if the plane was previously
1195 * disabled. Try to make the plane enable atomic by writing
1196 * the control register just before the surface register.
1197 */
1198 intel_de_write_fw(display, DVSCNTR(pipe), val: dvscntr);
1199 intel_de_write_fw(display, DVSSURF(pipe), val: plane_state->surf);
1200
1201 if (display->platform.g4x)
1202 g4x_sprite_update_gamma(plane_state);
1203 else
1204 ilk_sprite_update_gamma(plane_state);
1205}
1206
1207static void
1208g4x_sprite_disable_arm(struct intel_dsb *dsb,
1209 struct intel_plane *plane,
1210 const struct intel_crtc_state *crtc_state)
1211{
1212 struct intel_display *display = to_intel_display(plane);
1213 enum pipe pipe = plane->pipe;
1214
1215 intel_de_write_fw(display, DVSCNTR(pipe), val: 0);
1216 /* Disable the scaler */
1217 intel_de_write_fw(display, DVSSCALE(pipe), val: 0);
1218 intel_de_write_fw(display, DVSSURF(pipe), val: 0);
1219}
1220
1221static void g4x_sprite_capture_error(struct intel_crtc *crtc,
1222 struct intel_plane *plane,
1223 struct intel_plane_error *error)
1224{
1225 struct intel_display *display = to_intel_display(plane);
1226
1227 error->ctl = intel_de_read(display, DVSCNTR(crtc->pipe));
1228 error->surf = intel_de_read(display, DVSSURF(crtc->pipe));
1229 error->surflive = intel_de_read(display, DVSSURFLIVE(crtc->pipe));
1230}
1231
1232static bool
1233g4x_sprite_get_hw_state(struct intel_plane *plane,
1234 enum pipe *pipe)
1235{
1236 struct intel_display *display = to_intel_display(plane);
1237 enum intel_display_power_domain power_domain;
1238 intel_wakeref_t wakeref;
1239 bool ret;
1240
1241 power_domain = POWER_DOMAIN_PIPE(plane->pipe);
1242 wakeref = intel_display_power_get_if_enabled(display, domain: power_domain);
1243 if (!wakeref)
1244 return false;
1245
1246 ret = intel_de_read(display, DVSCNTR(plane->pipe)) & DVS_ENABLE;
1247
1248 *pipe = plane->pipe;
1249
1250 intel_display_power_put(display, domain: power_domain, wakeref);
1251
1252 return ret;
1253}
1254
1255static bool g4x_fb_scalable(const struct drm_framebuffer *fb)
1256{
1257 if (!fb)
1258 return false;
1259
1260 switch (fb->format->format) {
1261 case DRM_FORMAT_C8:
1262 case DRM_FORMAT_XRGB16161616F:
1263 case DRM_FORMAT_ARGB16161616F:
1264 case DRM_FORMAT_XBGR16161616F:
1265 case DRM_FORMAT_ABGR16161616F:
1266 return false;
1267 default:
1268 return true;
1269 }
1270}
1271
1272static int
1273g4x_sprite_check_scaling(struct intel_crtc_state *crtc_state,
1274 struct intel_plane_state *plane_state)
1275{
1276 struct intel_display *display = to_intel_display(plane_state);
1277 const struct drm_framebuffer *fb = plane_state->hw.fb;
1278 const struct drm_rect *src = &plane_state->uapi.src;
1279 const struct drm_rect *dst = &plane_state->uapi.dst;
1280 int src_x, src_w, src_h, crtc_w, crtc_h;
1281 const struct drm_display_mode *adjusted_mode =
1282 &crtc_state->hw.adjusted_mode;
1283 unsigned int stride = plane_state->view.color_plane[0].mapping_stride;
1284 unsigned int cpp = fb->format->cpp[0];
1285 unsigned int width_bytes;
1286 int min_width, min_height;
1287
1288 crtc_w = drm_rect_width(r: dst);
1289 crtc_h = drm_rect_height(r: dst);
1290
1291 src_x = src->x1 >> 16;
1292 src_w = drm_rect_width(r: src) >> 16;
1293 src_h = drm_rect_height(r: src) >> 16;
1294
1295 if (src_w == crtc_w && src_h == crtc_h)
1296 return 0;
1297
1298 min_width = 3;
1299
1300 if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
1301 if (src_h & 1) {
1302 drm_dbg_kms(display->drm,
1303 "Source height must be even with interlaced modes\n");
1304 return -EINVAL;
1305 }
1306 min_height = 6;
1307 } else {
1308 min_height = 3;
1309 }
1310
1311 width_bytes = ((src_x * cpp) & 63) + src_w * cpp;
1312
1313 if (src_w < min_width || src_h < min_height ||
1314 src_w > 2048 || src_h > 2048) {
1315 drm_dbg_kms(display->drm,
1316 "Source dimensions (%dx%d) exceed hardware limits (%dx%d - %dx%d)\n",
1317 src_w, src_h, min_width, min_height, 2048, 2048);
1318 return -EINVAL;
1319 }
1320
1321 if (width_bytes > 4096) {
1322 drm_dbg_kms(display->drm,
1323 "Fetch width (%d) exceeds hardware max with scaling (%u)\n",
1324 width_bytes, 4096);
1325 return -EINVAL;
1326 }
1327
1328 if (stride > 4096) {
1329 drm_dbg_kms(display->drm,
1330 "Stride (%u) exceeds hardware max with scaling (%u)\n",
1331 stride, 4096);
1332 return -EINVAL;
1333 }
1334
1335 return 0;
1336}
1337
1338static int
1339g4x_sprite_check(struct intel_crtc_state *crtc_state,
1340 struct intel_plane_state *plane_state)
1341{
1342 struct intel_display *display = to_intel_display(plane_state);
1343 int min_scale = DRM_PLANE_NO_SCALING;
1344 int max_scale = DRM_PLANE_NO_SCALING;
1345 int ret;
1346
1347 if (g4x_fb_scalable(fb: plane_state->hw.fb)) {
1348 if (DISPLAY_VER(display) < 7) {
1349 min_scale = 1;
1350 max_scale = 16 << 16;
1351 } else if (display->platform.ivybridge) {
1352 min_scale = 1;
1353 max_scale = 2 << 16;
1354 }
1355 }
1356
1357 ret = intel_plane_check_clipping(plane_state, crtc_state,
1358 min_scale, max_scale, can_position: true);
1359 if (ret)
1360 return ret;
1361
1362 ret = i9xx_check_plane_surface(plane_state);
1363 if (ret)
1364 return ret;
1365
1366 if (!plane_state->uapi.visible)
1367 return 0;
1368
1369 ret = intel_plane_check_src_coordinates(plane_state);
1370 if (ret)
1371 return ret;
1372
1373 ret = g4x_sprite_check_scaling(crtc_state, plane_state);
1374 if (ret)
1375 return ret;
1376
1377 if (DISPLAY_VER(display) >= 7)
1378 plane_state->ctl = ivb_sprite_ctl(plane_state);
1379 else
1380 plane_state->ctl = g4x_sprite_ctl(plane_state);
1381
1382 return 0;
1383}
1384
1385int chv_plane_check_rotation(const struct intel_plane_state *plane_state)
1386{
1387 struct intel_display *display = to_intel_display(plane_state);
1388 unsigned int rotation = plane_state->hw.rotation;
1389
1390 /* CHV ignores the mirror bit when the rotate bit is set :( */
1391 if (display->platform.cherryview &&
1392 rotation & DRM_MODE_ROTATE_180 &&
1393 rotation & DRM_MODE_REFLECT_X) {
1394 drm_dbg_kms(display->drm,
1395 "Cannot rotate and reflect at the same time\n");
1396 return -EINVAL;
1397 }
1398
1399 return 0;
1400}
1401
1402static int
1403vlv_sprite_check(struct intel_crtc_state *crtc_state,
1404 struct intel_plane_state *plane_state)
1405{
1406 int ret;
1407
1408 ret = chv_plane_check_rotation(plane_state);
1409 if (ret)
1410 return ret;
1411
1412 ret = intel_plane_check_clipping(plane_state, crtc_state,
1413 DRM_PLANE_NO_SCALING,
1414 DRM_PLANE_NO_SCALING,
1415 can_position: true);
1416 if (ret)
1417 return ret;
1418
1419 ret = i9xx_check_plane_surface(plane_state);
1420 if (ret)
1421 return ret;
1422
1423 if (!plane_state->uapi.visible)
1424 return 0;
1425
1426 ret = intel_plane_check_src_coordinates(plane_state);
1427 if (ret)
1428 return ret;
1429
1430 plane_state->ctl = vlv_sprite_ctl(plane_state);
1431
1432 return 0;
1433}
1434
1435static const u32 g4x_sprite_formats[] = {
1436 DRM_FORMAT_XRGB8888,
1437 DRM_FORMAT_YUYV,
1438 DRM_FORMAT_YVYU,
1439 DRM_FORMAT_UYVY,
1440 DRM_FORMAT_VYUY,
1441};
1442
1443static const u32 snb_sprite_formats[] = {
1444 DRM_FORMAT_XRGB8888,
1445 DRM_FORMAT_XBGR8888,
1446 DRM_FORMAT_XRGB2101010,
1447 DRM_FORMAT_XBGR2101010,
1448 DRM_FORMAT_XRGB16161616F,
1449 DRM_FORMAT_XBGR16161616F,
1450 DRM_FORMAT_YUYV,
1451 DRM_FORMAT_YVYU,
1452 DRM_FORMAT_UYVY,
1453 DRM_FORMAT_VYUY,
1454};
1455
1456static const u32 vlv_sprite_formats[] = {
1457 DRM_FORMAT_C8,
1458 DRM_FORMAT_RGB565,
1459 DRM_FORMAT_XRGB8888,
1460 DRM_FORMAT_XBGR8888,
1461 DRM_FORMAT_ARGB8888,
1462 DRM_FORMAT_ABGR8888,
1463 DRM_FORMAT_XBGR2101010,
1464 DRM_FORMAT_ABGR2101010,
1465 DRM_FORMAT_YUYV,
1466 DRM_FORMAT_YVYU,
1467 DRM_FORMAT_UYVY,
1468 DRM_FORMAT_VYUY,
1469};
1470
1471static const u32 chv_pipe_b_sprite_formats[] = {
1472 DRM_FORMAT_C8,
1473 DRM_FORMAT_RGB565,
1474 DRM_FORMAT_XRGB8888,
1475 DRM_FORMAT_XBGR8888,
1476 DRM_FORMAT_ARGB8888,
1477 DRM_FORMAT_ABGR8888,
1478 DRM_FORMAT_XRGB2101010,
1479 DRM_FORMAT_XBGR2101010,
1480 DRM_FORMAT_ARGB2101010,
1481 DRM_FORMAT_ABGR2101010,
1482 DRM_FORMAT_YUYV,
1483 DRM_FORMAT_YVYU,
1484 DRM_FORMAT_UYVY,
1485 DRM_FORMAT_VYUY,
1486};
1487
1488static bool g4x_sprite_format_mod_supported(struct drm_plane *_plane,
1489 u32 format, u64 modifier)
1490{
1491 if (!intel_fb_plane_supports_modifier(to_intel_plane(_plane), modifier))
1492 return false;
1493
1494 switch (format) {
1495 case DRM_FORMAT_XRGB8888:
1496 case DRM_FORMAT_YUYV:
1497 case DRM_FORMAT_YVYU:
1498 case DRM_FORMAT_UYVY:
1499 case DRM_FORMAT_VYUY:
1500 if (modifier == DRM_FORMAT_MOD_LINEAR ||
1501 modifier == I915_FORMAT_MOD_X_TILED)
1502 return true;
1503 fallthrough;
1504 default:
1505 return false;
1506 }
1507}
1508
1509static bool snb_sprite_format_mod_supported(struct drm_plane *_plane,
1510 u32 format, u64 modifier)
1511{
1512 if (!intel_fb_plane_supports_modifier(to_intel_plane(_plane), modifier))
1513 return false;
1514
1515 switch (format) {
1516 case DRM_FORMAT_XRGB8888:
1517 case DRM_FORMAT_XBGR8888:
1518 case DRM_FORMAT_XRGB2101010:
1519 case DRM_FORMAT_XBGR2101010:
1520 case DRM_FORMAT_XRGB16161616F:
1521 case DRM_FORMAT_XBGR16161616F:
1522 case DRM_FORMAT_YUYV:
1523 case DRM_FORMAT_YVYU:
1524 case DRM_FORMAT_UYVY:
1525 case DRM_FORMAT_VYUY:
1526 if (modifier == DRM_FORMAT_MOD_LINEAR ||
1527 modifier == I915_FORMAT_MOD_X_TILED)
1528 return true;
1529 fallthrough;
1530 default:
1531 return false;
1532 }
1533}
1534
1535static bool vlv_sprite_format_mod_supported(struct drm_plane *_plane,
1536 u32 format, u64 modifier)
1537{
1538 if (!intel_fb_plane_supports_modifier(to_intel_plane(_plane), modifier))
1539 return false;
1540
1541 switch (format) {
1542 case DRM_FORMAT_C8:
1543 case DRM_FORMAT_RGB565:
1544 case DRM_FORMAT_ABGR8888:
1545 case DRM_FORMAT_ARGB8888:
1546 case DRM_FORMAT_XBGR8888:
1547 case DRM_FORMAT_XRGB8888:
1548 case DRM_FORMAT_XBGR2101010:
1549 case DRM_FORMAT_ABGR2101010:
1550 case DRM_FORMAT_XRGB2101010:
1551 case DRM_FORMAT_ARGB2101010:
1552 case DRM_FORMAT_YUYV:
1553 case DRM_FORMAT_YVYU:
1554 case DRM_FORMAT_UYVY:
1555 case DRM_FORMAT_VYUY:
1556 if (modifier == DRM_FORMAT_MOD_LINEAR ||
1557 modifier == I915_FORMAT_MOD_X_TILED)
1558 return true;
1559 fallthrough;
1560 default:
1561 return false;
1562 }
1563}
1564
1565static const struct drm_plane_funcs g4x_sprite_funcs = {
1566 .update_plane = drm_atomic_helper_update_plane,
1567 .disable_plane = drm_atomic_helper_disable_plane,
1568 .destroy = intel_plane_destroy,
1569 .atomic_duplicate_state = intel_plane_duplicate_state,
1570 .atomic_destroy_state = intel_plane_destroy_state,
1571 .format_mod_supported = g4x_sprite_format_mod_supported,
1572};
1573
1574static const struct drm_plane_funcs snb_sprite_funcs = {
1575 .update_plane = drm_atomic_helper_update_plane,
1576 .disable_plane = drm_atomic_helper_disable_plane,
1577 .destroy = intel_plane_destroy,
1578 .atomic_duplicate_state = intel_plane_duplicate_state,
1579 .atomic_destroy_state = intel_plane_destroy_state,
1580 .format_mod_supported = snb_sprite_format_mod_supported,
1581};
1582
1583static const struct drm_plane_funcs vlv_sprite_funcs = {
1584 .update_plane = drm_atomic_helper_update_plane,
1585 .disable_plane = drm_atomic_helper_disable_plane,
1586 .destroy = intel_plane_destroy,
1587 .atomic_duplicate_state = intel_plane_duplicate_state,
1588 .atomic_destroy_state = intel_plane_destroy_state,
1589 .format_mod_supported = vlv_sprite_format_mod_supported,
1590};
1591
1592struct intel_plane *
1593intel_sprite_plane_create(struct intel_display *display,
1594 enum pipe pipe, int sprite)
1595{
1596 struct intel_plane *plane;
1597 const struct drm_plane_funcs *plane_funcs;
1598 unsigned int supported_rotations;
1599 const u64 *modifiers;
1600 const u32 *formats;
1601 int num_formats;
1602 int ret, zpos;
1603
1604 plane = intel_plane_alloc();
1605 if (IS_ERR(ptr: plane))
1606 return plane;
1607
1608 if (display->platform.valleyview || display->platform.cherryview) {
1609 plane->update_noarm = vlv_sprite_update_noarm;
1610 plane->update_arm = vlv_sprite_update_arm;
1611 plane->disable_arm = vlv_sprite_disable_arm;
1612 plane->capture_error = vlv_sprite_capture_error;
1613 plane->get_hw_state = vlv_sprite_get_hw_state;
1614 plane->check_plane = vlv_sprite_check;
1615 plane->surf_offset = i965_plane_surf_offset;
1616 plane->max_stride = i965_plane_max_stride;
1617 plane->min_alignment = vlv_plane_min_alignment;
1618 plane->min_cdclk = vlv_plane_min_cdclk;
1619
1620 /* FIXME undocumented for VLV/CHV so not sure what's actually needed */
1621 if (intel_scanout_needs_vtd_wa(display))
1622 plane->vtd_guard = 128;
1623
1624 if (display->platform.cherryview && pipe == PIPE_B) {
1625 formats = chv_pipe_b_sprite_formats;
1626 num_formats = ARRAY_SIZE(chv_pipe_b_sprite_formats);
1627 } else {
1628 formats = vlv_sprite_formats;
1629 num_formats = ARRAY_SIZE(vlv_sprite_formats);
1630 }
1631
1632 plane_funcs = &vlv_sprite_funcs;
1633 } else if (DISPLAY_VER(display) >= 7) {
1634 plane->update_noarm = ivb_sprite_update_noarm;
1635 plane->update_arm = ivb_sprite_update_arm;
1636 plane->disable_arm = ivb_sprite_disable_arm;
1637 plane->capture_error = ivb_sprite_capture_error;
1638 plane->get_hw_state = ivb_sprite_get_hw_state;
1639 plane->check_plane = g4x_sprite_check;
1640 plane->surf_offset = i965_plane_surf_offset;
1641
1642 if (display->platform.broadwell || display->platform.haswell) {
1643 plane->max_stride = hsw_sprite_max_stride;
1644 plane->min_cdclk = hsw_plane_min_cdclk;
1645 } else {
1646 plane->max_stride = g4x_sprite_max_stride;
1647 plane->min_cdclk = ivb_sprite_min_cdclk;
1648 }
1649
1650 plane->min_alignment = g4x_sprite_min_alignment;
1651
1652 if (intel_scanout_needs_vtd_wa(display))
1653 plane->vtd_guard = 64;
1654
1655 formats = snb_sprite_formats;
1656 num_formats = ARRAY_SIZE(snb_sprite_formats);
1657
1658 plane_funcs = &snb_sprite_funcs;
1659 } else {
1660 plane->update_noarm = g4x_sprite_update_noarm;
1661 plane->update_arm = g4x_sprite_update_arm;
1662 plane->disable_arm = g4x_sprite_disable_arm;
1663 plane->capture_error = g4x_sprite_capture_error;
1664 plane->get_hw_state = g4x_sprite_get_hw_state;
1665 plane->check_plane = g4x_sprite_check;
1666 plane->surf_offset = i965_plane_surf_offset;
1667 plane->max_stride = g4x_sprite_max_stride;
1668 plane->min_alignment = g4x_sprite_min_alignment;
1669 plane->min_cdclk = g4x_sprite_min_cdclk;
1670
1671 if (intel_scanout_needs_vtd_wa(display))
1672 plane->vtd_guard = 64;
1673
1674 if (display->platform.sandybridge) {
1675 formats = snb_sprite_formats;
1676 num_formats = ARRAY_SIZE(snb_sprite_formats);
1677
1678 plane_funcs = &snb_sprite_funcs;
1679 } else {
1680 formats = g4x_sprite_formats;
1681 num_formats = ARRAY_SIZE(g4x_sprite_formats);
1682
1683 plane_funcs = &g4x_sprite_funcs;
1684 }
1685 }
1686
1687 if (display->platform.cherryview && pipe == PIPE_B) {
1688 supported_rotations =
1689 DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
1690 DRM_MODE_REFLECT_X;
1691 } else {
1692 supported_rotations =
1693 DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
1694 }
1695
1696 plane->pipe = pipe;
1697 plane->id = PLANE_SPRITE0 + sprite;
1698 plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);
1699
1700 modifiers = intel_fb_plane_get_modifiers(display, INTEL_PLANE_CAP_TILING_X);
1701
1702 ret = drm_universal_plane_init(dev: display->drm, plane: &plane->base,
1703 possible_crtcs: 0, funcs: plane_funcs,
1704 formats, format_count: num_formats, format_modifiers: modifiers,
1705 type: DRM_PLANE_TYPE_OVERLAY,
1706 name: "sprite %c", sprite_name(display, pipe, sprite));
1707 kfree(objp: modifiers);
1708
1709 if (ret)
1710 goto fail;
1711
1712 drm_plane_create_rotation_property(plane: &plane->base,
1713 DRM_MODE_ROTATE_0,
1714 supported_rotations);
1715
1716 drm_plane_create_color_properties(plane: &plane->base,
1717 BIT(DRM_COLOR_YCBCR_BT601) |
1718 BIT(DRM_COLOR_YCBCR_BT709),
1719 BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
1720 BIT(DRM_COLOR_YCBCR_FULL_RANGE),
1721 default_encoding: DRM_COLOR_YCBCR_BT709,
1722 default_range: DRM_COLOR_YCBCR_LIMITED_RANGE);
1723
1724 zpos = sprite + 1;
1725 drm_plane_create_zpos_immutable_property(plane: &plane->base, zpos);
1726
1727 intel_plane_helper_add(plane);
1728
1729 return plane;
1730
1731fail:
1732 intel_plane_free(plane);
1733
1734 return ERR_PTR(error: ret);
1735}
1736