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