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 "i9xx_plane.h"
43#include "intel_de.h"
44#include "intel_display_types.h"
45#include "intel_display_utils.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 const struct drm_format_info *info,
962 u64 modifier, unsigned int rotation)
963{
964 int cpp = info->cpp[0];
965
966 /* Limit to 4k pixels to guarantee TILEOFF.x doesn't get too big. */
967 if (modifier == I915_FORMAT_MOD_X_TILED)
968 return min(4096 * cpp, 16 * 1024);
969 else
970 return 16 * 1024;
971}
972
973static unsigned int
974hsw_sprite_max_stride(struct intel_plane *plane,
975 const struct drm_format_info *info,
976 u64 modifier, unsigned int rotation)
977{
978 int cpp = info->cpp[0];
979
980 /* Limit to 8k pixels to guarantee OFFSET.x doesn't get too big. */
981 return min(8192 * cpp, 16 * 1024);
982}
983
984static unsigned int g4x_sprite_min_alignment(struct intel_plane *plane,
985 const struct drm_framebuffer *fb,
986 int color_plane)
987{
988 struct intel_display *display = to_intel_display(plane);
989
990 if (intel_scanout_needs_vtd_wa(display))
991 return 128 * 1024;
992
993 return 4 * 1024;
994}
995
996static u32 g4x_sprite_ctl_crtc(const struct intel_crtc_state *crtc_state)
997{
998 u32 dvscntr = 0;
999
1000 if (crtc_state->gamma_enable)
1001 dvscntr |= DVS_PIPE_GAMMA_ENABLE;
1002
1003 if (crtc_state->csc_enable)
1004 dvscntr |= DVS_PIPE_CSC_ENABLE;
1005
1006 return dvscntr;
1007}
1008
1009static u32 g4x_sprite_ctl(const struct intel_plane_state *plane_state)
1010{
1011 struct intel_display *display = to_intel_display(plane_state);
1012 const struct drm_framebuffer *fb = plane_state->hw.fb;
1013 unsigned int rotation = plane_state->hw.rotation;
1014 const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
1015 u32 dvscntr;
1016
1017 dvscntr = DVS_ENABLE;
1018
1019 if (display->platform.sandybridge)
1020 dvscntr |= DVS_TRICKLE_FEED_DISABLE;
1021
1022 switch (fb->format->format) {
1023 case DRM_FORMAT_XBGR8888:
1024 dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR;
1025 break;
1026 case DRM_FORMAT_XRGB8888:
1027 dvscntr |= DVS_FORMAT_RGBX888;
1028 break;
1029 case DRM_FORMAT_XBGR2101010:
1030 dvscntr |= DVS_FORMAT_RGBX101010 | DVS_RGB_ORDER_XBGR;
1031 break;
1032 case DRM_FORMAT_XRGB2101010:
1033 dvscntr |= DVS_FORMAT_RGBX101010;
1034 break;
1035 case DRM_FORMAT_XBGR16161616F:
1036 dvscntr |= DVS_FORMAT_RGBX161616 | DVS_RGB_ORDER_XBGR;
1037 break;
1038 case DRM_FORMAT_XRGB16161616F:
1039 dvscntr |= DVS_FORMAT_RGBX161616;
1040 break;
1041 case DRM_FORMAT_YUYV:
1042 dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV;
1043 break;
1044 case DRM_FORMAT_YVYU:
1045 dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU;
1046 break;
1047 case DRM_FORMAT_UYVY:
1048 dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY;
1049 break;
1050 case DRM_FORMAT_VYUY:
1051 dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY;
1052 break;
1053 default:
1054 MISSING_CASE(fb->format->format);
1055 return 0;
1056 }
1057
1058 if (plane_state->hw.color_encoding == DRM_COLOR_YCBCR_BT709)
1059 dvscntr |= DVS_YUV_FORMAT_BT709;
1060
1061 if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
1062 dvscntr |= DVS_YUV_RANGE_CORRECTION_DISABLE;
1063
1064 if (fb->modifier == I915_FORMAT_MOD_X_TILED)
1065 dvscntr |= DVS_TILED;
1066
1067 if (rotation & DRM_MODE_ROTATE_180)
1068 dvscntr |= DVS_ROTATE_180;
1069
1070 if (key->flags & I915_SET_COLORKEY_DESTINATION)
1071 dvscntr |= DVS_DEST_KEY;
1072 else if (key->flags & I915_SET_COLORKEY_SOURCE)
1073 dvscntr |= DVS_SOURCE_KEY;
1074
1075 return dvscntr;
1076}
1077
1078static void g4x_sprite_update_gamma(const struct intel_plane_state *plane_state)
1079{
1080 struct intel_display *display = to_intel_display(plane_state);
1081 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1082 const struct drm_framebuffer *fb = plane_state->hw.fb;
1083 enum pipe pipe = plane->pipe;
1084 u16 gamma[8];
1085 int i;
1086
1087 /* Seems RGB data bypasses the gamma always */
1088 if (!fb->format->is_yuv)
1089 return;
1090
1091 i9xx_plane_linear_gamma(gamma);
1092
1093 /* FIXME these register are single buffered :( */
1094 /* The two end points are implicit (0.0 and 1.0) */
1095 for (i = 1; i < 8 - 1; i++)
1096 intel_de_write_fw(display, DVSGAMC_G4X(pipe, i - 1),
1097 val: gamma[i] << 16 | gamma[i] << 8 | gamma[i]);
1098}
1099
1100static void ilk_sprite_linear_gamma(u16 gamma[17])
1101{
1102 int i;
1103
1104 for (i = 0; i < 17; i++)
1105 gamma[i] = (i << 10) / 16;
1106}
1107
1108static void ilk_sprite_update_gamma(const struct intel_plane_state *plane_state)
1109{
1110 struct intel_display *display = to_intel_display(plane_state);
1111 struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1112 const struct drm_framebuffer *fb = plane_state->hw.fb;
1113 enum pipe pipe = plane->pipe;
1114 u16 gamma[17];
1115 int i;
1116
1117 /* Seems RGB data bypasses the gamma always */
1118 if (!fb->format->is_yuv)
1119 return;
1120
1121 ilk_sprite_linear_gamma(gamma);
1122
1123 /* FIXME these register are single buffered :( */
1124 for (i = 0; i < 16; i++)
1125 intel_de_write_fw(display, DVSGAMC_ILK(pipe, i),
1126 val: gamma[i] << 20 | gamma[i] << 10 | gamma[i]);
1127
1128 intel_de_write_fw(display, DVSGAMCMAX_ILK(pipe, 0), val: gamma[i]);
1129 intel_de_write_fw(display, DVSGAMCMAX_ILK(pipe, 1), val: gamma[i]);
1130 intel_de_write_fw(display, DVSGAMCMAX_ILK(pipe, 2), val: gamma[i]);
1131 i++;
1132}
1133
1134static void
1135g4x_sprite_update_noarm(struct intel_dsb *dsb,
1136 struct intel_plane *plane,
1137 const struct intel_crtc_state *crtc_state,
1138 const struct intel_plane_state *plane_state)
1139{
1140 struct intel_display *display = to_intel_display(plane);
1141 enum pipe pipe = plane->pipe;
1142 int crtc_x = plane_state->uapi.dst.x1;
1143 int crtc_y = plane_state->uapi.dst.y1;
1144 u32 crtc_w = drm_rect_width(r: &plane_state->uapi.dst);
1145 u32 crtc_h = drm_rect_height(r: &plane_state->uapi.dst);
1146 u32 src_w = drm_rect_width(r: &plane_state->uapi.src) >> 16;
1147 u32 src_h = drm_rect_height(r: &plane_state->uapi.src) >> 16;
1148 u32 dvsscale = 0;
1149
1150 if (crtc_w != src_w || crtc_h != src_h)
1151 dvsscale = DVS_SCALE_ENABLE |
1152 DVS_SRC_WIDTH(src_w - 1) |
1153 DVS_SRC_HEIGHT(src_h - 1);
1154
1155 intel_de_write_fw(display, DVSSTRIDE(pipe),
1156 val: plane_state->view.color_plane[0].mapping_stride);
1157 intel_de_write_fw(display, DVSPOS(pipe),
1158 DVS_POS_Y(crtc_y) | DVS_POS_X(crtc_x));
1159 intel_de_write_fw(display, DVSSIZE(pipe),
1160 DVS_HEIGHT(crtc_h - 1) | DVS_WIDTH(crtc_w - 1));
1161 intel_de_write_fw(display, DVSSCALE(pipe), val: dvsscale);
1162}
1163
1164static void
1165g4x_sprite_update_arm(struct intel_dsb *dsb,
1166 struct intel_plane *plane,
1167 const struct intel_crtc_state *crtc_state,
1168 const struct intel_plane_state *plane_state)
1169{
1170 struct intel_display *display = to_intel_display(plane);
1171 enum pipe pipe = plane->pipe;
1172 const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
1173 u32 x = plane_state->view.color_plane[0].x;
1174 u32 y = plane_state->view.color_plane[0].y;
1175 u32 dvscntr;
1176
1177 dvscntr = plane_state->ctl | g4x_sprite_ctl_crtc(crtc_state);
1178
1179 if (key->flags) {
1180 intel_de_write_fw(display, DVSKEYVAL(pipe), val: key->min_value);
1181 intel_de_write_fw(display, DVSKEYMSK(pipe),
1182 val: key->channel_mask);
1183 intel_de_write_fw(display, DVSKEYMAX(pipe), val: key->max_value);
1184 }
1185
1186 intel_de_write_fw(display, DVSLINOFF(pipe),
1187 val: intel_fb_xy_to_linear(x, y, plane_state, color_plane: 0));
1188 intel_de_write_fw(display, DVSTILEOFF(pipe),
1189 DVS_OFFSET_Y(y) | DVS_OFFSET_X(x));
1190
1191 /*
1192 * The control register self-arms if the plane was previously
1193 * disabled. Try to make the plane enable atomic by writing
1194 * the control register just before the surface register.
1195 */
1196 intel_de_write_fw(display, DVSCNTR(pipe), val: dvscntr);
1197 intel_de_write_fw(display, DVSSURF(pipe), val: plane_state->surf);
1198
1199 if (display->platform.g4x)
1200 g4x_sprite_update_gamma(plane_state);
1201 else
1202 ilk_sprite_update_gamma(plane_state);
1203}
1204
1205static void
1206g4x_sprite_disable_arm(struct intel_dsb *dsb,
1207 struct intel_plane *plane,
1208 const struct intel_crtc_state *crtc_state)
1209{
1210 struct intel_display *display = to_intel_display(plane);
1211 enum pipe pipe = plane->pipe;
1212
1213 intel_de_write_fw(display, DVSCNTR(pipe), val: 0);
1214 /* Disable the scaler */
1215 intel_de_write_fw(display, DVSSCALE(pipe), val: 0);
1216 intel_de_write_fw(display, DVSSURF(pipe), val: 0);
1217}
1218
1219static void g4x_sprite_capture_error(struct intel_crtc *crtc,
1220 struct intel_plane *plane,
1221 struct intel_plane_error *error)
1222{
1223 struct intel_display *display = to_intel_display(plane);
1224
1225 error->ctl = intel_de_read(display, DVSCNTR(crtc->pipe));
1226 error->surf = intel_de_read(display, DVSSURF(crtc->pipe));
1227 error->surflive = intel_de_read(display, DVSSURFLIVE(crtc->pipe));
1228}
1229
1230static bool
1231g4x_sprite_get_hw_state(struct intel_plane *plane,
1232 enum pipe *pipe)
1233{
1234 struct intel_display *display = to_intel_display(plane);
1235 enum intel_display_power_domain power_domain;
1236 intel_wakeref_t wakeref;
1237 bool ret;
1238
1239 power_domain = POWER_DOMAIN_PIPE(plane->pipe);
1240 wakeref = intel_display_power_get_if_enabled(display, domain: power_domain);
1241 if (!wakeref)
1242 return false;
1243
1244 ret = intel_de_read(display, DVSCNTR(plane->pipe)) & DVS_ENABLE;
1245
1246 *pipe = plane->pipe;
1247
1248 intel_display_power_put(display, domain: power_domain, wakeref);
1249
1250 return ret;
1251}
1252
1253static bool g4x_fb_scalable(const struct drm_framebuffer *fb)
1254{
1255 if (!fb)
1256 return false;
1257
1258 switch (fb->format->format) {
1259 case DRM_FORMAT_C8:
1260 case DRM_FORMAT_XRGB16161616F:
1261 case DRM_FORMAT_ARGB16161616F:
1262 case DRM_FORMAT_XBGR16161616F:
1263 case DRM_FORMAT_ABGR16161616F:
1264 return false;
1265 default:
1266 return true;
1267 }
1268}
1269
1270static int
1271g4x_sprite_check_scaling(struct intel_crtc_state *crtc_state,
1272 struct intel_plane_state *plane_state)
1273{
1274 struct intel_display *display = to_intel_display(plane_state);
1275 const struct drm_framebuffer *fb = plane_state->hw.fb;
1276 const struct drm_rect *src = &plane_state->uapi.src;
1277 const struct drm_rect *dst = &plane_state->uapi.dst;
1278 int src_x, src_w, src_h, crtc_w, crtc_h;
1279 const struct drm_display_mode *adjusted_mode =
1280 &crtc_state->hw.adjusted_mode;
1281 unsigned int stride = plane_state->view.color_plane[0].mapping_stride;
1282 unsigned int cpp = fb->format->cpp[0];
1283 unsigned int width_bytes;
1284 int min_width, min_height;
1285
1286 crtc_w = drm_rect_width(r: dst);
1287 crtc_h = drm_rect_height(r: dst);
1288
1289 src_x = src->x1 >> 16;
1290 src_w = drm_rect_width(r: src) >> 16;
1291 src_h = drm_rect_height(r: src) >> 16;
1292
1293 if (src_w == crtc_w && src_h == crtc_h)
1294 return 0;
1295
1296 min_width = 3;
1297
1298 if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
1299 if (src_h & 1) {
1300 drm_dbg_kms(display->drm,
1301 "Source height must be even with interlaced modes\n");
1302 return -EINVAL;
1303 }
1304 min_height = 6;
1305 } else {
1306 min_height = 3;
1307 }
1308
1309 width_bytes = ((src_x * cpp) & 63) + src_w * cpp;
1310
1311 if (src_w < min_width || src_h < min_height ||
1312 src_w > 2048 || src_h > 2048) {
1313 drm_dbg_kms(display->drm,
1314 "Source dimensions (%dx%d) exceed hardware limits (%dx%d - %dx%d)\n",
1315 src_w, src_h, min_width, min_height, 2048, 2048);
1316 return -EINVAL;
1317 }
1318
1319 if (width_bytes > 4096) {
1320 drm_dbg_kms(display->drm,
1321 "Fetch width (%d) exceeds hardware max with scaling (%u)\n",
1322 width_bytes, 4096);
1323 return -EINVAL;
1324 }
1325
1326 if (stride > 4096) {
1327 drm_dbg_kms(display->drm,
1328 "Stride (%u) exceeds hardware max with scaling (%u)\n",
1329 stride, 4096);
1330 return -EINVAL;
1331 }
1332
1333 return 0;
1334}
1335
1336static int
1337g4x_sprite_check(struct intel_crtc_state *crtc_state,
1338 struct intel_plane_state *plane_state)
1339{
1340 struct intel_display *display = to_intel_display(plane_state);
1341 int min_scale = DRM_PLANE_NO_SCALING;
1342 int max_scale = DRM_PLANE_NO_SCALING;
1343 int ret;
1344
1345 if (g4x_fb_scalable(fb: plane_state->hw.fb)) {
1346 if (DISPLAY_VER(display) < 7) {
1347 min_scale = 1;
1348 max_scale = 16 << 16;
1349 } else if (display->platform.ivybridge) {
1350 min_scale = 1;
1351 max_scale = 2 << 16;
1352 }
1353 }
1354
1355 ret = intel_plane_check_clipping(plane_state, crtc_state,
1356 min_scale, max_scale, can_position: true);
1357 if (ret)
1358 return ret;
1359
1360 ret = i9xx_check_plane_surface(plane_state);
1361 if (ret)
1362 return ret;
1363
1364 if (!plane_state->uapi.visible)
1365 return 0;
1366
1367 ret = intel_plane_check_src_coordinates(plane_state);
1368 if (ret)
1369 return ret;
1370
1371 ret = g4x_sprite_check_scaling(crtc_state, plane_state);
1372 if (ret)
1373 return ret;
1374
1375 if (DISPLAY_VER(display) >= 7)
1376 plane_state->ctl = ivb_sprite_ctl(plane_state);
1377 else
1378 plane_state->ctl = g4x_sprite_ctl(plane_state);
1379
1380 return 0;
1381}
1382
1383int chv_plane_check_rotation(const struct intel_plane_state *plane_state)
1384{
1385 struct intel_display *display = to_intel_display(plane_state);
1386 unsigned int rotation = plane_state->hw.rotation;
1387
1388 /* CHV ignores the mirror bit when the rotate bit is set :( */
1389 if (display->platform.cherryview &&
1390 rotation & DRM_MODE_ROTATE_180 &&
1391 rotation & DRM_MODE_REFLECT_X) {
1392 drm_dbg_kms(display->drm,
1393 "Cannot rotate and reflect at the same time\n");
1394 return -EINVAL;
1395 }
1396
1397 return 0;
1398}
1399
1400static int
1401vlv_sprite_check(struct intel_crtc_state *crtc_state,
1402 struct intel_plane_state *plane_state)
1403{
1404 int ret;
1405
1406 ret = chv_plane_check_rotation(plane_state);
1407 if (ret)
1408 return ret;
1409
1410 ret = intel_plane_check_clipping(plane_state, crtc_state,
1411 DRM_PLANE_NO_SCALING,
1412 DRM_PLANE_NO_SCALING,
1413 can_position: true);
1414 if (ret)
1415 return ret;
1416
1417 ret = i9xx_check_plane_surface(plane_state);
1418 if (ret)
1419 return ret;
1420
1421 if (!plane_state->uapi.visible)
1422 return 0;
1423
1424 ret = intel_plane_check_src_coordinates(plane_state);
1425 if (ret)
1426 return ret;
1427
1428 plane_state->ctl = vlv_sprite_ctl(plane_state);
1429
1430 return 0;
1431}
1432
1433static const u32 g4x_sprite_formats[] = {
1434 DRM_FORMAT_XRGB8888,
1435 DRM_FORMAT_YUYV,
1436 DRM_FORMAT_YVYU,
1437 DRM_FORMAT_UYVY,
1438 DRM_FORMAT_VYUY,
1439};
1440
1441static const u32 snb_sprite_formats[] = {
1442 DRM_FORMAT_XRGB8888,
1443 DRM_FORMAT_XBGR8888,
1444 DRM_FORMAT_XRGB2101010,
1445 DRM_FORMAT_XBGR2101010,
1446 DRM_FORMAT_XRGB16161616F,
1447 DRM_FORMAT_XBGR16161616F,
1448 DRM_FORMAT_YUYV,
1449 DRM_FORMAT_YVYU,
1450 DRM_FORMAT_UYVY,
1451 DRM_FORMAT_VYUY,
1452};
1453
1454static const u32 vlv_sprite_formats[] = {
1455 DRM_FORMAT_C8,
1456 DRM_FORMAT_RGB565,
1457 DRM_FORMAT_XRGB8888,
1458 DRM_FORMAT_XBGR8888,
1459 DRM_FORMAT_ARGB8888,
1460 DRM_FORMAT_ABGR8888,
1461 DRM_FORMAT_XBGR2101010,
1462 DRM_FORMAT_ABGR2101010,
1463 DRM_FORMAT_YUYV,
1464 DRM_FORMAT_YVYU,
1465 DRM_FORMAT_UYVY,
1466 DRM_FORMAT_VYUY,
1467};
1468
1469static const u32 chv_pipe_b_sprite_formats[] = {
1470 DRM_FORMAT_C8,
1471 DRM_FORMAT_RGB565,
1472 DRM_FORMAT_XRGB8888,
1473 DRM_FORMAT_XBGR8888,
1474 DRM_FORMAT_ARGB8888,
1475 DRM_FORMAT_ABGR8888,
1476 DRM_FORMAT_XRGB2101010,
1477 DRM_FORMAT_XBGR2101010,
1478 DRM_FORMAT_ARGB2101010,
1479 DRM_FORMAT_ABGR2101010,
1480 DRM_FORMAT_YUYV,
1481 DRM_FORMAT_YVYU,
1482 DRM_FORMAT_UYVY,
1483 DRM_FORMAT_VYUY,
1484};
1485
1486static bool g4x_sprite_format_mod_supported(struct drm_plane *_plane,
1487 u32 format, u64 modifier)
1488{
1489 if (!intel_fb_plane_supports_modifier(to_intel_plane(_plane), modifier))
1490 return false;
1491
1492 switch (format) {
1493 case DRM_FORMAT_XRGB8888:
1494 case DRM_FORMAT_YUYV:
1495 case DRM_FORMAT_YVYU:
1496 case DRM_FORMAT_UYVY:
1497 case DRM_FORMAT_VYUY:
1498 if (modifier == DRM_FORMAT_MOD_LINEAR ||
1499 modifier == I915_FORMAT_MOD_X_TILED)
1500 return true;
1501 fallthrough;
1502 default:
1503 return false;
1504 }
1505}
1506
1507static bool snb_sprite_format_mod_supported(struct drm_plane *_plane,
1508 u32 format, u64 modifier)
1509{
1510 if (!intel_fb_plane_supports_modifier(to_intel_plane(_plane), modifier))
1511 return false;
1512
1513 switch (format) {
1514 case DRM_FORMAT_XRGB8888:
1515 case DRM_FORMAT_XBGR8888:
1516 case DRM_FORMAT_XRGB2101010:
1517 case DRM_FORMAT_XBGR2101010:
1518 case DRM_FORMAT_XRGB16161616F:
1519 case DRM_FORMAT_XBGR16161616F:
1520 case DRM_FORMAT_YUYV:
1521 case DRM_FORMAT_YVYU:
1522 case DRM_FORMAT_UYVY:
1523 case DRM_FORMAT_VYUY:
1524 if (modifier == DRM_FORMAT_MOD_LINEAR ||
1525 modifier == I915_FORMAT_MOD_X_TILED)
1526 return true;
1527 fallthrough;
1528 default:
1529 return false;
1530 }
1531}
1532
1533static bool vlv_sprite_format_mod_supported(struct drm_plane *_plane,
1534 u32 format, u64 modifier)
1535{
1536 if (!intel_fb_plane_supports_modifier(to_intel_plane(_plane), modifier))
1537 return false;
1538
1539 switch (format) {
1540 case DRM_FORMAT_C8:
1541 case DRM_FORMAT_RGB565:
1542 case DRM_FORMAT_ABGR8888:
1543 case DRM_FORMAT_ARGB8888:
1544 case DRM_FORMAT_XBGR8888:
1545 case DRM_FORMAT_XRGB8888:
1546 case DRM_FORMAT_XBGR2101010:
1547 case DRM_FORMAT_ABGR2101010:
1548 case DRM_FORMAT_XRGB2101010:
1549 case DRM_FORMAT_ARGB2101010:
1550 case DRM_FORMAT_YUYV:
1551 case DRM_FORMAT_YVYU:
1552 case DRM_FORMAT_UYVY:
1553 case DRM_FORMAT_VYUY:
1554 if (modifier == DRM_FORMAT_MOD_LINEAR ||
1555 modifier == I915_FORMAT_MOD_X_TILED)
1556 return true;
1557 fallthrough;
1558 default:
1559 return false;
1560 }
1561}
1562
1563static const struct drm_plane_funcs g4x_sprite_funcs = {
1564 .update_plane = drm_atomic_helper_update_plane,
1565 .disable_plane = drm_atomic_helper_disable_plane,
1566 .destroy = intel_plane_destroy,
1567 .atomic_duplicate_state = intel_plane_duplicate_state,
1568 .atomic_destroy_state = intel_plane_destroy_state,
1569 .format_mod_supported = g4x_sprite_format_mod_supported,
1570};
1571
1572static const struct drm_plane_funcs snb_sprite_funcs = {
1573 .update_plane = drm_atomic_helper_update_plane,
1574 .disable_plane = drm_atomic_helper_disable_plane,
1575 .destroy = intel_plane_destroy,
1576 .atomic_duplicate_state = intel_plane_duplicate_state,
1577 .atomic_destroy_state = intel_plane_destroy_state,
1578 .format_mod_supported = snb_sprite_format_mod_supported,
1579};
1580
1581static const struct drm_plane_funcs vlv_sprite_funcs = {
1582 .update_plane = drm_atomic_helper_update_plane,
1583 .disable_plane = drm_atomic_helper_disable_plane,
1584 .destroy = intel_plane_destroy,
1585 .atomic_duplicate_state = intel_plane_duplicate_state,
1586 .atomic_destroy_state = intel_plane_destroy_state,
1587 .format_mod_supported = vlv_sprite_format_mod_supported,
1588};
1589
1590struct intel_plane *
1591intel_sprite_plane_create(struct intel_display *display,
1592 enum pipe pipe, int sprite)
1593{
1594 struct intel_plane *plane;
1595 const struct drm_plane_funcs *plane_funcs;
1596 unsigned int supported_rotations;
1597 const u64 *modifiers;
1598 const u32 *formats;
1599 int num_formats;
1600 int ret, zpos;
1601
1602 plane = intel_plane_alloc();
1603 if (IS_ERR(ptr: plane))
1604 return plane;
1605
1606 if (display->platform.valleyview || display->platform.cherryview) {
1607 plane->update_noarm = vlv_sprite_update_noarm;
1608 plane->update_arm = vlv_sprite_update_arm;
1609 plane->disable_arm = vlv_sprite_disable_arm;
1610 plane->capture_error = vlv_sprite_capture_error;
1611 plane->get_hw_state = vlv_sprite_get_hw_state;
1612 plane->check_plane = vlv_sprite_check;
1613 plane->surf_offset = i965_plane_surf_offset;
1614 plane->max_stride = i965_plane_max_stride;
1615 plane->min_alignment = vlv_plane_min_alignment;
1616 plane->min_cdclk = vlv_plane_min_cdclk;
1617
1618 /* FIXME undocumented for VLV/CHV so not sure what's actually needed */
1619 if (intel_scanout_needs_vtd_wa(display))
1620 plane->vtd_guard = 128;
1621
1622 if (display->platform.cherryview && pipe == PIPE_B) {
1623 formats = chv_pipe_b_sprite_formats;
1624 num_formats = ARRAY_SIZE(chv_pipe_b_sprite_formats);
1625 } else {
1626 formats = vlv_sprite_formats;
1627 num_formats = ARRAY_SIZE(vlv_sprite_formats);
1628 }
1629
1630 plane_funcs = &vlv_sprite_funcs;
1631 } else if (DISPLAY_VER(display) >= 7) {
1632 plane->update_noarm = ivb_sprite_update_noarm;
1633 plane->update_arm = ivb_sprite_update_arm;
1634 plane->disable_arm = ivb_sprite_disable_arm;
1635 plane->capture_error = ivb_sprite_capture_error;
1636 plane->get_hw_state = ivb_sprite_get_hw_state;
1637 plane->check_plane = g4x_sprite_check;
1638 plane->surf_offset = i965_plane_surf_offset;
1639
1640 if (display->platform.broadwell || display->platform.haswell) {
1641 plane->max_stride = hsw_sprite_max_stride;
1642 plane->min_cdclk = hsw_plane_min_cdclk;
1643 } else {
1644 plane->max_stride = g4x_sprite_max_stride;
1645 plane->min_cdclk = ivb_sprite_min_cdclk;
1646 }
1647
1648 plane->min_alignment = g4x_sprite_min_alignment;
1649
1650 if (intel_scanout_needs_vtd_wa(display))
1651 plane->vtd_guard = 64;
1652
1653 formats = snb_sprite_formats;
1654 num_formats = ARRAY_SIZE(snb_sprite_formats);
1655
1656 plane_funcs = &snb_sprite_funcs;
1657 } else {
1658 plane->update_noarm = g4x_sprite_update_noarm;
1659 plane->update_arm = g4x_sprite_update_arm;
1660 plane->disable_arm = g4x_sprite_disable_arm;
1661 plane->capture_error = g4x_sprite_capture_error;
1662 plane->get_hw_state = g4x_sprite_get_hw_state;
1663 plane->check_plane = g4x_sprite_check;
1664 plane->surf_offset = i965_plane_surf_offset;
1665 plane->max_stride = g4x_sprite_max_stride;
1666 plane->min_alignment = g4x_sprite_min_alignment;
1667 plane->min_cdclk = g4x_sprite_min_cdclk;
1668
1669 if (intel_scanout_needs_vtd_wa(display))
1670 plane->vtd_guard = 64;
1671
1672 if (display->platform.sandybridge) {
1673 formats = snb_sprite_formats;
1674 num_formats = ARRAY_SIZE(snb_sprite_formats);
1675
1676 plane_funcs = &snb_sprite_funcs;
1677 } else {
1678 formats = g4x_sprite_formats;
1679 num_formats = ARRAY_SIZE(g4x_sprite_formats);
1680
1681 plane_funcs = &g4x_sprite_funcs;
1682 }
1683 }
1684
1685 if (display->platform.cherryview && pipe == PIPE_B) {
1686 supported_rotations =
1687 DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
1688 DRM_MODE_REFLECT_X;
1689 } else {
1690 supported_rotations =
1691 DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
1692 }
1693
1694 plane->pipe = pipe;
1695 plane->id = PLANE_SPRITE0 + sprite;
1696 plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);
1697
1698 modifiers = intel_fb_plane_get_modifiers(display, INTEL_PLANE_CAP_TILING_X);
1699
1700 ret = drm_universal_plane_init(dev: display->drm, plane: &plane->base,
1701 possible_crtcs: 0, funcs: plane_funcs,
1702 formats, format_count: num_formats, format_modifiers: modifiers,
1703 type: DRM_PLANE_TYPE_OVERLAY,
1704 name: "sprite %c", sprite_name(display, pipe, sprite));
1705 kfree(objp: modifiers);
1706
1707 if (ret)
1708 goto fail;
1709
1710 drm_plane_create_rotation_property(plane: &plane->base,
1711 DRM_MODE_ROTATE_0,
1712 supported_rotations);
1713
1714 drm_plane_create_color_properties(plane: &plane->base,
1715 BIT(DRM_COLOR_YCBCR_BT601) |
1716 BIT(DRM_COLOR_YCBCR_BT709),
1717 BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
1718 BIT(DRM_COLOR_YCBCR_FULL_RANGE),
1719 default_encoding: DRM_COLOR_YCBCR_BT709,
1720 default_range: DRM_COLOR_YCBCR_LIMITED_RANGE);
1721
1722 zpos = sprite + 1;
1723 drm_plane_create_zpos_immutable_property(plane: &plane->base, zpos);
1724
1725 intel_plane_helper_add(plane);
1726
1727 return plane;
1728
1729fail:
1730 intel_plane_free(plane);
1731
1732 return ERR_PTR(error: ret);
1733}
1734

source code of linux/drivers/gpu/drm/i915/display/intel_sprite.c