Branch data Line data Source code
1 : : /*
2 : : * Copyright © 2009
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 : : * Daniel Vetter <daniel@ffwll.ch>
25 : : *
26 : : * Derived from Xorg ddx, xf86-video-intel, src/i830_video.c
27 : : */
28 : :
29 : : #include <drm/drm_fourcc.h>
30 : : #include <drm/i915_drm.h>
31 : :
32 : : #include "gem/i915_gem_pm.h"
33 : : #include "gt/intel_ring.h"
34 : :
35 : : #include "i915_drv.h"
36 : : #include "i915_reg.h"
37 : : #include "intel_display_types.h"
38 : : #include "intel_frontbuffer.h"
39 : : #include "intel_overlay.h"
40 : :
41 : : /* Limits for overlay size. According to intel doc, the real limits are:
42 : : * Y width: 4095, UV width (planar): 2047, Y height: 2047,
43 : : * UV width (planar): * 1023. But the xorg thinks 2048 for height and width. Use
44 : : * the mininum of both. */
45 : : #define IMAGE_MAX_WIDTH 2048
46 : : #define IMAGE_MAX_HEIGHT 2046 /* 2 * 1023 */
47 : : /* on 830 and 845 these large limits result in the card hanging */
48 : : #define IMAGE_MAX_WIDTH_LEGACY 1024
49 : : #define IMAGE_MAX_HEIGHT_LEGACY 1088
50 : :
51 : : /* overlay register definitions */
52 : : /* OCMD register */
53 : : #define OCMD_TILED_SURFACE (0x1<<19)
54 : : #define OCMD_MIRROR_MASK (0x3<<17)
55 : : #define OCMD_MIRROR_MODE (0x3<<17)
56 : : #define OCMD_MIRROR_HORIZONTAL (0x1<<17)
57 : : #define OCMD_MIRROR_VERTICAL (0x2<<17)
58 : : #define OCMD_MIRROR_BOTH (0x3<<17)
59 : : #define OCMD_BYTEORDER_MASK (0x3<<14) /* zero for YUYV or FOURCC YUY2 */
60 : : #define OCMD_UV_SWAP (0x1<<14) /* YVYU */
61 : : #define OCMD_Y_SWAP (0x2<<14) /* UYVY or FOURCC UYVY */
62 : : #define OCMD_Y_AND_UV_SWAP (0x3<<14) /* VYUY */
63 : : #define OCMD_SOURCE_FORMAT_MASK (0xf<<10)
64 : : #define OCMD_RGB_888 (0x1<<10) /* not in i965 Intel docs */
65 : : #define OCMD_RGB_555 (0x2<<10) /* not in i965 Intel docs */
66 : : #define OCMD_RGB_565 (0x3<<10) /* not in i965 Intel docs */
67 : : #define OCMD_YUV_422_PACKED (0x8<<10)
68 : : #define OCMD_YUV_411_PACKED (0x9<<10) /* not in i965 Intel docs */
69 : : #define OCMD_YUV_420_PLANAR (0xc<<10)
70 : : #define OCMD_YUV_422_PLANAR (0xd<<10)
71 : : #define OCMD_YUV_410_PLANAR (0xe<<10) /* also 411 */
72 : : #define OCMD_TVSYNCFLIP_PARITY (0x1<<9)
73 : : #define OCMD_TVSYNCFLIP_ENABLE (0x1<<7)
74 : : #define OCMD_BUF_TYPE_MASK (0x1<<5)
75 : : #define OCMD_BUF_TYPE_FRAME (0x0<<5)
76 : : #define OCMD_BUF_TYPE_FIELD (0x1<<5)
77 : : #define OCMD_TEST_MODE (0x1<<4)
78 : : #define OCMD_BUFFER_SELECT (0x3<<2)
79 : : #define OCMD_BUFFER0 (0x0<<2)
80 : : #define OCMD_BUFFER1 (0x1<<2)
81 : : #define OCMD_FIELD_SELECT (0x1<<2)
82 : : #define OCMD_FIELD0 (0x0<<1)
83 : : #define OCMD_FIELD1 (0x1<<1)
84 : : #define OCMD_ENABLE (0x1<<0)
85 : :
86 : : /* OCONFIG register */
87 : : #define OCONF_PIPE_MASK (0x1<<18)
88 : : #define OCONF_PIPE_A (0x0<<18)
89 : : #define OCONF_PIPE_B (0x1<<18)
90 : : #define OCONF_GAMMA2_ENABLE (0x1<<16)
91 : : #define OCONF_CSC_MODE_BT601 (0x0<<5)
92 : : #define OCONF_CSC_MODE_BT709 (0x1<<5)
93 : : #define OCONF_CSC_BYPASS (0x1<<4)
94 : : #define OCONF_CC_OUT_8BIT (0x1<<3)
95 : : #define OCONF_TEST_MODE (0x1<<2)
96 : : #define OCONF_THREE_LINE_BUFFER (0x1<<0)
97 : : #define OCONF_TWO_LINE_BUFFER (0x0<<0)
98 : :
99 : : /* DCLRKM (dst-key) register */
100 : : #define DST_KEY_ENABLE (0x1<<31)
101 : : #define CLK_RGB24_MASK 0x0
102 : : #define CLK_RGB16_MASK 0x070307
103 : : #define CLK_RGB15_MASK 0x070707
104 : : #define CLK_RGB8I_MASK 0xffffff
105 : :
106 : : #define RGB16_TO_COLORKEY(c) \
107 : : (((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3))
108 : : #define RGB15_TO_COLORKEY(c) \
109 : : (((c & 0x7c00) << 9) | ((c & 0x03E0) << 6) | ((c & 0x001F) << 3))
110 : :
111 : : /* overlay flip addr flag */
112 : : #define OFC_UPDATE 0x1
113 : :
114 : : /* polyphase filter coefficients */
115 : : #define N_HORIZ_Y_TAPS 5
116 : : #define N_VERT_Y_TAPS 3
117 : : #define N_HORIZ_UV_TAPS 3
118 : : #define N_VERT_UV_TAPS 3
119 : : #define N_PHASES 17
120 : : #define MAX_TAPS 5
121 : :
122 : : /* memory bufferd overlay registers */
123 : : struct overlay_registers {
124 : : u32 OBUF_0Y;
125 : : u32 OBUF_1Y;
126 : : u32 OBUF_0U;
127 : : u32 OBUF_0V;
128 : : u32 OBUF_1U;
129 : : u32 OBUF_1V;
130 : : u32 OSTRIDE;
131 : : u32 YRGB_VPH;
132 : : u32 UV_VPH;
133 : : u32 HORZ_PH;
134 : : u32 INIT_PHS;
135 : : u32 DWINPOS;
136 : : u32 DWINSZ;
137 : : u32 SWIDTH;
138 : : u32 SWIDTHSW;
139 : : u32 SHEIGHT;
140 : : u32 YRGBSCALE;
141 : : u32 UVSCALE;
142 : : u32 OCLRC0;
143 : : u32 OCLRC1;
144 : : u32 DCLRKV;
145 : : u32 DCLRKM;
146 : : u32 SCLRKVH;
147 : : u32 SCLRKVL;
148 : : u32 SCLRKEN;
149 : : u32 OCONFIG;
150 : : u32 OCMD;
151 : : u32 RESERVED1; /* 0x6C */
152 : : u32 OSTART_0Y;
153 : : u32 OSTART_1Y;
154 : : u32 OSTART_0U;
155 : : u32 OSTART_0V;
156 : : u32 OSTART_1U;
157 : : u32 OSTART_1V;
158 : : u32 OTILEOFF_0Y;
159 : : u32 OTILEOFF_1Y;
160 : : u32 OTILEOFF_0U;
161 : : u32 OTILEOFF_0V;
162 : : u32 OTILEOFF_1U;
163 : : u32 OTILEOFF_1V;
164 : : u32 FASTHSCALE; /* 0xA0 */
165 : : u32 UVSCALEV; /* 0xA4 */
166 : : u32 RESERVEDC[(0x200 - 0xA8) / 4]; /* 0xA8 - 0x1FC */
167 : : u16 Y_VCOEFS[N_VERT_Y_TAPS * N_PHASES]; /* 0x200 */
168 : : u16 RESERVEDD[0x100 / 2 - N_VERT_Y_TAPS * N_PHASES];
169 : : u16 Y_HCOEFS[N_HORIZ_Y_TAPS * N_PHASES]; /* 0x300 */
170 : : u16 RESERVEDE[0x200 / 2 - N_HORIZ_Y_TAPS * N_PHASES];
171 : : u16 UV_VCOEFS[N_VERT_UV_TAPS * N_PHASES]; /* 0x500 */
172 : : u16 RESERVEDF[0x100 / 2 - N_VERT_UV_TAPS * N_PHASES];
173 : : u16 UV_HCOEFS[N_HORIZ_UV_TAPS * N_PHASES]; /* 0x600 */
174 : : u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES];
175 : : };
176 : :
177 : : struct intel_overlay {
178 : : struct drm_i915_private *i915;
179 : : struct intel_context *context;
180 : : struct intel_crtc *crtc;
181 : : struct i915_vma *vma;
182 : : struct i915_vma *old_vma;
183 : : bool active;
184 : : bool pfit_active;
185 : : u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
186 : : u32 color_key:24;
187 : : u32 color_key_enabled:1;
188 : : u32 brightness, contrast, saturation;
189 : : u32 old_xscale, old_yscale;
190 : : /* register access */
191 : : struct drm_i915_gem_object *reg_bo;
192 : : struct overlay_registers __iomem *regs;
193 : : u32 flip_addr;
194 : : /* flip handling */
195 : : struct i915_active last_flip;
196 : : void (*flip_complete)(struct intel_overlay *ovl);
197 : : };
198 : :
199 : 0 : static void i830_overlay_clock_gating(struct drm_i915_private *dev_priv,
200 : : bool enable)
201 : : {
202 : 0 : struct pci_dev *pdev = dev_priv->drm.pdev;
203 : 0 : u8 val;
204 : :
205 : : /* WA_OVERLAY_CLKGATE:alm */
206 [ # # ]: 0 : if (enable)
207 : 0 : I915_WRITE(DSPCLK_GATE_D, 0);
208 : : else
209 : 0 : I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
210 : :
211 : : /* WA_DISABLE_L2CACHE_CLOCK_GATING:alm */
212 : 0 : pci_bus_read_config_byte(pdev->bus,
213 : : PCI_DEVFN(0, 0), I830_CLOCK_GATE, &val);
214 [ # # ]: 0 : if (enable)
215 : 0 : val &= ~I830_L2_CACHE_CLOCK_GATE_DISABLE;
216 : : else
217 : 0 : val |= I830_L2_CACHE_CLOCK_GATE_DISABLE;
218 : 0 : pci_bus_write_config_byte(pdev->bus,
219 : : PCI_DEVFN(0, 0), I830_CLOCK_GATE, val);
220 : 0 : }
221 : :
222 : : static struct i915_request *
223 : 0 : alloc_request(struct intel_overlay *overlay, void (*fn)(struct intel_overlay *))
224 : : {
225 : 0 : struct i915_request *rq;
226 : 0 : int err;
227 : :
228 : 0 : overlay->flip_complete = fn;
229 : :
230 : 0 : rq = i915_request_create(overlay->context);
231 [ # # ]: 0 : if (IS_ERR(rq))
232 : : return rq;
233 : :
234 : 0 : err = i915_active_add_request(&overlay->last_flip, rq);
235 [ # # ]: 0 : if (err) {
236 : 0 : i915_request_add(rq);
237 : 0 : return ERR_PTR(err);
238 : : }
239 : :
240 : : return rq;
241 : : }
242 : :
243 : : /* overlay needs to be disable in OCMD reg */
244 : 0 : static int intel_overlay_on(struct intel_overlay *overlay)
245 : : {
246 : 0 : struct drm_i915_private *dev_priv = overlay->i915;
247 : 0 : struct i915_request *rq;
248 : 0 : u32 *cs;
249 : :
250 [ # # ]: 0 : WARN_ON(overlay->active);
251 : :
252 : 0 : rq = alloc_request(overlay, NULL);
253 [ # # ]: 0 : if (IS_ERR(rq))
254 : 0 : return PTR_ERR(rq);
255 : :
256 : 0 : cs = intel_ring_begin(rq, 4);
257 [ # # ]: 0 : if (IS_ERR(cs)) {
258 : 0 : i915_request_add(rq);
259 : 0 : return PTR_ERR(cs);
260 : : }
261 : :
262 : 0 : overlay->active = true;
263 : :
264 [ # # ]: 0 : if (IS_I830(dev_priv))
265 : 0 : i830_overlay_clock_gating(dev_priv, false);
266 : :
267 : 0 : *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_ON;
268 : 0 : *cs++ = overlay->flip_addr | OFC_UPDATE;
269 : 0 : *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP;
270 : 0 : *cs++ = MI_NOOP;
271 : 0 : intel_ring_advance(rq, cs);
272 : :
273 : 0 : i915_request_add(rq);
274 : :
275 : 0 : return i915_active_wait(&overlay->last_flip);
276 : : }
277 : :
278 : 0 : static void intel_overlay_flip_prepare(struct intel_overlay *overlay,
279 : : struct i915_vma *vma)
280 : : {
281 : 0 : enum pipe pipe = overlay->crtc->pipe;
282 : 0 : struct intel_frontbuffer *from = NULL, *to = NULL;
283 : :
284 [ # # ]: 0 : WARN_ON(overlay->old_vma);
285 : :
286 [ # # ]: 0 : if (overlay->vma)
287 : 0 : from = intel_frontbuffer_get(overlay->vma->obj);
288 [ # # ]: 0 : if (vma)
289 : 0 : to = intel_frontbuffer_get(vma->obj);
290 : :
291 : 0 : intel_frontbuffer_track(from, to, INTEL_FRONTBUFFER_OVERLAY(pipe));
292 : :
293 [ # # ]: 0 : if (to)
294 : 0 : intel_frontbuffer_put(to);
295 [ # # ]: 0 : if (from)
296 : 0 : intel_frontbuffer_put(from);
297 : :
298 : 0 : intel_frontbuffer_flip_prepare(overlay->i915,
299 : : INTEL_FRONTBUFFER_OVERLAY(pipe));
300 : :
301 : 0 : overlay->old_vma = overlay->vma;
302 [ # # ]: 0 : if (vma)
303 : 0 : overlay->vma = i915_vma_get(vma);
304 : : else
305 : 0 : overlay->vma = NULL;
306 : 0 : }
307 : :
308 : : /* overlay needs to be enabled in OCMD reg */
309 : 0 : static int intel_overlay_continue(struct intel_overlay *overlay,
310 : : struct i915_vma *vma,
311 : : bool load_polyphase_filter)
312 : : {
313 : 0 : struct drm_i915_private *dev_priv = overlay->i915;
314 : 0 : struct i915_request *rq;
315 : 0 : u32 flip_addr = overlay->flip_addr;
316 : 0 : u32 tmp, *cs;
317 : :
318 [ # # ]: 0 : WARN_ON(!overlay->active);
319 : :
320 [ # # ]: 0 : if (load_polyphase_filter)
321 : 0 : flip_addr |= OFC_UPDATE;
322 : :
323 : : /* check for underruns */
324 : 0 : tmp = I915_READ(DOVSTA);
325 [ # # ]: 0 : if (tmp & (1 << 17))
326 : 0 : DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
327 : :
328 : 0 : rq = alloc_request(overlay, NULL);
329 [ # # ]: 0 : if (IS_ERR(rq))
330 : 0 : return PTR_ERR(rq);
331 : :
332 : 0 : cs = intel_ring_begin(rq, 2);
333 [ # # ]: 0 : if (IS_ERR(cs)) {
334 : 0 : i915_request_add(rq);
335 : 0 : return PTR_ERR(cs);
336 : : }
337 : :
338 : 0 : *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE;
339 : 0 : *cs++ = flip_addr;
340 : 0 : intel_ring_advance(rq, cs);
341 : :
342 : 0 : intel_overlay_flip_prepare(overlay, vma);
343 : 0 : i915_request_add(rq);
344 : :
345 : 0 : return 0;
346 : : }
347 : :
348 : 0 : static void intel_overlay_release_old_vma(struct intel_overlay *overlay)
349 : : {
350 : 0 : struct i915_vma *vma;
351 : :
352 : 0 : vma = fetch_and_zero(&overlay->old_vma);
353 [ # # # # ]: 0 : if (WARN_ON(!vma))
354 : : return;
355 : :
356 : 0 : intel_frontbuffer_flip_complete(overlay->i915,
357 : 0 : INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe));
358 : :
359 : 0 : i915_gem_object_unpin_from_display_plane(vma);
360 : 0 : i915_vma_put(vma);
361 : : }
362 : :
363 : : static void
364 : 0 : intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
365 : : {
366 : 0 : intel_overlay_release_old_vma(overlay);
367 : 0 : }
368 : :
369 : 0 : static void intel_overlay_off_tail(struct intel_overlay *overlay)
370 : : {
371 : 0 : struct drm_i915_private *dev_priv = overlay->i915;
372 : :
373 : 0 : intel_overlay_release_old_vma(overlay);
374 : :
375 : 0 : overlay->crtc->overlay = NULL;
376 : 0 : overlay->crtc = NULL;
377 : 0 : overlay->active = false;
378 : :
379 [ # # ]: 0 : if (IS_I830(dev_priv))
380 : 0 : i830_overlay_clock_gating(dev_priv, true);
381 : 0 : }
382 : :
383 : : static void
384 : 0 : intel_overlay_last_flip_retire(struct i915_active *active)
385 : : {
386 : 0 : struct intel_overlay *overlay =
387 : 0 : container_of(active, typeof(*overlay), last_flip);
388 : :
389 [ # # ]: 0 : if (overlay->flip_complete)
390 : 0 : overlay->flip_complete(overlay);
391 : 0 : }
392 : :
393 : : /* overlay needs to be disabled in OCMD reg */
394 : 0 : static int intel_overlay_off(struct intel_overlay *overlay)
395 : : {
396 : 0 : struct i915_request *rq;
397 : 0 : u32 *cs, flip_addr = overlay->flip_addr;
398 : :
399 [ # # ]: 0 : WARN_ON(!overlay->active);
400 : :
401 : : /* According to intel docs the overlay hw may hang (when switching
402 : : * off) without loading the filter coeffs. It is however unclear whether
403 : : * this applies to the disabling of the overlay or to the switching off
404 : : * of the hw. Do it in both cases */
405 : 0 : flip_addr |= OFC_UPDATE;
406 : :
407 : 0 : rq = alloc_request(overlay, intel_overlay_off_tail);
408 [ # # ]: 0 : if (IS_ERR(rq))
409 : 0 : return PTR_ERR(rq);
410 : :
411 : 0 : cs = intel_ring_begin(rq, 6);
412 [ # # ]: 0 : if (IS_ERR(cs)) {
413 : 0 : i915_request_add(rq);
414 : 0 : return PTR_ERR(cs);
415 : : }
416 : :
417 : : /* wait for overlay to go idle */
418 : 0 : *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE;
419 : 0 : *cs++ = flip_addr;
420 : 0 : *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP;
421 : :
422 : : /* turn overlay off */
423 : 0 : *cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_OFF;
424 : 0 : *cs++ = flip_addr;
425 : 0 : *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP;
426 : :
427 : 0 : intel_ring_advance(rq, cs);
428 : :
429 : 0 : intel_overlay_flip_prepare(overlay, NULL);
430 : 0 : i915_request_add(rq);
431 : :
432 : 0 : return i915_active_wait(&overlay->last_flip);
433 : : }
434 : :
435 : : /* recover from an interruption due to a signal
436 : : * We have to be careful not to repeat work forever an make forward progess. */
437 : 0 : static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
438 : : {
439 : 0 : return i915_active_wait(&overlay->last_flip);
440 : : }
441 : :
442 : : /* Wait for pending overlay flip and release old frame.
443 : : * Needs to be called before the overlay register are changed
444 : : * via intel_overlay_(un)map_regs
445 : : */
446 : 0 : static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
447 : : {
448 : 0 : struct drm_i915_private *dev_priv = overlay->i915;
449 : 0 : struct i915_request *rq;
450 : 0 : u32 *cs;
451 : :
452 : : /*
453 : : * Only wait if there is actually an old frame to release to
454 : : * guarantee forward progress.
455 : : */
456 [ # # ]: 0 : if (!overlay->old_vma)
457 : : return 0;
458 : :
459 [ # # ]: 0 : if (!(I915_READ(GEN2_ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT)) {
460 : 0 : intel_overlay_release_old_vid_tail(overlay);
461 : 0 : return 0;
462 : : }
463 : :
464 : 0 : rq = alloc_request(overlay, intel_overlay_release_old_vid_tail);
465 [ # # ]: 0 : if (IS_ERR(rq))
466 : 0 : return PTR_ERR(rq);
467 : :
468 : 0 : cs = intel_ring_begin(rq, 2);
469 [ # # ]: 0 : if (IS_ERR(cs)) {
470 : 0 : i915_request_add(rq);
471 : 0 : return PTR_ERR(cs);
472 : : }
473 : :
474 : 0 : *cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP;
475 : 0 : *cs++ = MI_NOOP;
476 : 0 : intel_ring_advance(rq, cs);
477 : :
478 : 0 : i915_request_add(rq);
479 : :
480 : 0 : return i915_active_wait(&overlay->last_flip);
481 : : }
482 : :
483 : 0 : void intel_overlay_reset(struct drm_i915_private *dev_priv)
484 : : {
485 : 0 : struct intel_overlay *overlay = dev_priv->overlay;
486 : :
487 [ # # ]: 0 : if (!overlay)
488 : : return;
489 : :
490 : 0 : overlay->old_xscale = 0;
491 : 0 : overlay->old_yscale = 0;
492 : 0 : overlay->crtc = NULL;
493 : 0 : overlay->active = false;
494 : : }
495 : :
496 : : static int packed_depth_bytes(u32 format)
497 : : {
498 : : switch (format & I915_OVERLAY_DEPTH_MASK) {
499 : : case I915_OVERLAY_YUV422:
500 : : return 4;
501 : : case I915_OVERLAY_YUV411:
502 : : /* return 6; not implemented */
503 : : default:
504 : : return -EINVAL;
505 : : }
506 : : }
507 : :
508 : 0 : static int packed_width_bytes(u32 format, short width)
509 : : {
510 : 0 : switch (format & I915_OVERLAY_DEPTH_MASK) {
511 : 0 : case I915_OVERLAY_YUV422:
512 : 0 : return width << 1;
513 : : default:
514 : : return -EINVAL;
515 : : }
516 : : }
517 : :
518 : 0 : static int uv_hsubsampling(u32 format)
519 : : {
520 : 0 : switch (format & I915_OVERLAY_DEPTH_MASK) {
521 : : case I915_OVERLAY_YUV422:
522 : : case I915_OVERLAY_YUV420:
523 : : return 2;
524 : 0 : case I915_OVERLAY_YUV411:
525 : : case I915_OVERLAY_YUV410:
526 : 0 : return 4;
527 : 0 : default:
528 : 0 : return -EINVAL;
529 : : }
530 : : }
531 : :
532 : 0 : static int uv_vsubsampling(u32 format)
533 : : {
534 : 0 : switch (format & I915_OVERLAY_DEPTH_MASK) {
535 : : case I915_OVERLAY_YUV420:
536 : : case I915_OVERLAY_YUV410:
537 : : return 2;
538 : 0 : case I915_OVERLAY_YUV422:
539 : : case I915_OVERLAY_YUV411:
540 : 0 : return 1;
541 : 0 : default:
542 : 0 : return -EINVAL;
543 : : }
544 : : }
545 : :
546 : 0 : static u32 calc_swidthsw(struct drm_i915_private *dev_priv, u32 offset, u32 width)
547 : : {
548 : 0 : u32 sw;
549 : :
550 : 0 : if (IS_GEN(dev_priv, 2))
551 : 0 : sw = ALIGN((offset & 31) + width, 32);
552 : : else
553 : 0 : sw = ALIGN((offset & 63) + width, 64);
554 : :
555 [ # # # # : 0 : if (sw == 0)
# # ]
556 : : return 0;
557 : :
558 : 0 : return (sw - 32) >> 3;
559 : : }
560 : :
561 : : static const u16 y_static_hcoeffs[N_PHASES][N_HORIZ_Y_TAPS] = {
562 : : [ 0] = { 0x3000, 0xb4a0, 0x1930, 0x1920, 0xb4a0, },
563 : : [ 1] = { 0x3000, 0xb500, 0x19d0, 0x1880, 0xb440, },
564 : : [ 2] = { 0x3000, 0xb540, 0x1a88, 0x2f80, 0xb3e0, },
565 : : [ 3] = { 0x3000, 0xb580, 0x1b30, 0x2e20, 0xb380, },
566 : : [ 4] = { 0x3000, 0xb5c0, 0x1bd8, 0x2cc0, 0xb320, },
567 : : [ 5] = { 0x3020, 0xb5e0, 0x1c60, 0x2b80, 0xb2c0, },
568 : : [ 6] = { 0x3020, 0xb5e0, 0x1cf8, 0x2a20, 0xb260, },
569 : : [ 7] = { 0x3020, 0xb5e0, 0x1d80, 0x28e0, 0xb200, },
570 : : [ 8] = { 0x3020, 0xb5c0, 0x1e08, 0x3f40, 0xb1c0, },
571 : : [ 9] = { 0x3020, 0xb580, 0x1e78, 0x3ce0, 0xb160, },
572 : : [10] = { 0x3040, 0xb520, 0x1ed8, 0x3aa0, 0xb120, },
573 : : [11] = { 0x3040, 0xb4a0, 0x1f30, 0x3880, 0xb0e0, },
574 : : [12] = { 0x3040, 0xb400, 0x1f78, 0x3680, 0xb0a0, },
575 : : [13] = { 0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060, },
576 : : [14] = { 0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040, },
577 : : [15] = { 0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020, },
578 : : [16] = { 0xb000, 0x3000, 0x0800, 0x3000, 0xb000, },
579 : : };
580 : :
581 : : static const u16 uv_static_hcoeffs[N_PHASES][N_HORIZ_UV_TAPS] = {
582 : : [ 0] = { 0x3000, 0x1800, 0x1800, },
583 : : [ 1] = { 0xb000, 0x18d0, 0x2e60, },
584 : : [ 2] = { 0xb000, 0x1990, 0x2ce0, },
585 : : [ 3] = { 0xb020, 0x1a68, 0x2b40, },
586 : : [ 4] = { 0xb040, 0x1b20, 0x29e0, },
587 : : [ 5] = { 0xb060, 0x1bd8, 0x2880, },
588 : : [ 6] = { 0xb080, 0x1c88, 0x3e60, },
589 : : [ 7] = { 0xb0a0, 0x1d28, 0x3c00, },
590 : : [ 8] = { 0xb0c0, 0x1db8, 0x39e0, },
591 : : [ 9] = { 0xb0e0, 0x1e40, 0x37e0, },
592 : : [10] = { 0xb100, 0x1eb8, 0x3620, },
593 : : [11] = { 0xb100, 0x1f18, 0x34a0, },
594 : : [12] = { 0xb100, 0x1f68, 0x3360, },
595 : : [13] = { 0xb0e0, 0x1fa8, 0x3240, },
596 : : [14] = { 0xb0c0, 0x1fe0, 0x3140, },
597 : : [15] = { 0xb060, 0x1ff0, 0x30a0, },
598 : : [16] = { 0x3000, 0x0800, 0x3000, },
599 : : };
600 : :
601 : 0 : static void update_polyphase_filter(struct overlay_registers __iomem *regs)
602 : : {
603 : 0 : memcpy_toio(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs));
604 : 0 : memcpy_toio(regs->UV_HCOEFS, uv_static_hcoeffs,
605 : : sizeof(uv_static_hcoeffs));
606 : 0 : }
607 : :
608 : : static bool update_scaling_factors(struct intel_overlay *overlay,
609 : : struct overlay_registers __iomem *regs,
610 : : struct drm_intel_overlay_put_image *params)
611 : : {
612 : : /* fixed point with a 12 bit shift */
613 : : u32 xscale, yscale, xscale_UV, yscale_UV;
614 : : #define FP_SHIFT 12
615 : : #define FRACT_MASK 0xfff
616 : : bool scale_changed = false;
617 : : int uv_hscale = uv_hsubsampling(params->flags);
618 : : int uv_vscale = uv_vsubsampling(params->flags);
619 : :
620 : : if (params->dst_width > 1)
621 : : xscale = ((params->src_scan_width - 1) << FP_SHIFT) /
622 : : params->dst_width;
623 : : else
624 : : xscale = 1 << FP_SHIFT;
625 : :
626 : : if (params->dst_height > 1)
627 : : yscale = ((params->src_scan_height - 1) << FP_SHIFT) /
628 : : params->dst_height;
629 : : else
630 : : yscale = 1 << FP_SHIFT;
631 : :
632 : : /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
633 : : xscale_UV = xscale/uv_hscale;
634 : : yscale_UV = yscale/uv_vscale;
635 : : /* make the Y scale to UV scale ratio an exact multiply */
636 : : xscale = xscale_UV * uv_hscale;
637 : : yscale = yscale_UV * uv_vscale;
638 : : /*} else {
639 : : xscale_UV = 0;
640 : : yscale_UV = 0;
641 : : }*/
642 : :
643 : : if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)
644 : : scale_changed = true;
645 : : overlay->old_xscale = xscale;
646 : : overlay->old_yscale = yscale;
647 : :
648 : : iowrite32(((yscale & FRACT_MASK) << 20) |
649 : : ((xscale >> FP_SHIFT) << 16) |
650 : : ((xscale & FRACT_MASK) << 3),
651 : : ®s->YRGBSCALE);
652 : :
653 : : iowrite32(((yscale_UV & FRACT_MASK) << 20) |
654 : : ((xscale_UV >> FP_SHIFT) << 16) |
655 : : ((xscale_UV & FRACT_MASK) << 3),
656 : : ®s->UVSCALE);
657 : :
658 : : iowrite32((((yscale >> FP_SHIFT) << 16) |
659 : : ((yscale_UV >> FP_SHIFT) << 0)),
660 : : ®s->UVSCALEV);
661 : :
662 : : if (scale_changed)
663 : : update_polyphase_filter(regs);
664 : :
665 : : return scale_changed;
666 : : }
667 : :
668 : 0 : static void update_colorkey(struct intel_overlay *overlay,
669 : : struct overlay_registers __iomem *regs)
670 : : {
671 : 0 : const struct intel_plane_state *state =
672 : 0 : to_intel_plane_state(overlay->crtc->base.primary->state);
673 : 0 : u32 key = overlay->color_key;
674 : 0 : u32 format = 0;
675 : 0 : u32 flags = 0;
676 : :
677 [ # # ]: 0 : if (overlay->color_key_enabled)
678 : 0 : flags |= DST_KEY_ENABLE;
679 : :
680 [ # # ]: 0 : if (state->uapi.visible)
681 : 0 : format = state->hw.fb->format->format;
682 : :
683 [ # # # # ]: 0 : switch (format) {
684 : 0 : case DRM_FORMAT_C8:
685 : 0 : key = 0;
686 : 0 : flags |= CLK_RGB8I_MASK;
687 : 0 : break;
688 : 0 : case DRM_FORMAT_XRGB1555:
689 : 0 : key = RGB15_TO_COLORKEY(key);
690 : 0 : flags |= CLK_RGB15_MASK;
691 : 0 : break;
692 : 0 : case DRM_FORMAT_RGB565:
693 : 0 : key = RGB16_TO_COLORKEY(key);
694 : 0 : flags |= CLK_RGB16_MASK;
695 : 0 : break;
696 : : default:
697 : : flags |= CLK_RGB24_MASK;
698 : : break;
699 : : }
700 : :
701 : 0 : iowrite32(key, ®s->DCLRKV);
702 : 0 : iowrite32(flags, ®s->DCLRKM);
703 : 0 : }
704 : :
705 : : static u32 overlay_cmd_reg(struct drm_intel_overlay_put_image *params)
706 : : {
707 : : u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0;
708 : :
709 : : if (params->flags & I915_OVERLAY_YUV_PLANAR) {
710 : : switch (params->flags & I915_OVERLAY_DEPTH_MASK) {
711 : : case I915_OVERLAY_YUV422:
712 : : cmd |= OCMD_YUV_422_PLANAR;
713 : : break;
714 : : case I915_OVERLAY_YUV420:
715 : : cmd |= OCMD_YUV_420_PLANAR;
716 : : break;
717 : : case I915_OVERLAY_YUV411:
718 : : case I915_OVERLAY_YUV410:
719 : : cmd |= OCMD_YUV_410_PLANAR;
720 : : break;
721 : : }
722 : : } else { /* YUV packed */
723 : : switch (params->flags & I915_OVERLAY_DEPTH_MASK) {
724 : : case I915_OVERLAY_YUV422:
725 : : cmd |= OCMD_YUV_422_PACKED;
726 : : break;
727 : : case I915_OVERLAY_YUV411:
728 : : cmd |= OCMD_YUV_411_PACKED;
729 : : break;
730 : : }
731 : :
732 : : switch (params->flags & I915_OVERLAY_SWAP_MASK) {
733 : : case I915_OVERLAY_NO_SWAP:
734 : : break;
735 : : case I915_OVERLAY_UV_SWAP:
736 : : cmd |= OCMD_UV_SWAP;
737 : : break;
738 : : case I915_OVERLAY_Y_SWAP:
739 : : cmd |= OCMD_Y_SWAP;
740 : : break;
741 : : case I915_OVERLAY_Y_AND_UV_SWAP:
742 : : cmd |= OCMD_Y_AND_UV_SWAP;
743 : : break;
744 : : }
745 : : }
746 : :
747 : : return cmd;
748 : : }
749 : :
750 : 0 : static int intel_overlay_do_put_image(struct intel_overlay *overlay,
751 : : struct drm_i915_gem_object *new_bo,
752 : : struct drm_intel_overlay_put_image *params)
753 : : {
754 : 0 : struct overlay_registers __iomem *regs = overlay->regs;
755 : 0 : struct drm_i915_private *dev_priv = overlay->i915;
756 : 0 : u32 swidth, swidthsw, sheight, ostride;
757 : 0 : enum pipe pipe = overlay->crtc->pipe;
758 : 0 : bool scale_changed = false;
759 : 0 : struct i915_vma *vma;
760 : 0 : int ret, tmp_width;
761 : :
762 [ # # ]: 0 : WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex));
763 : :
764 : 0 : ret = intel_overlay_release_old_vid(overlay);
765 [ # # ]: 0 : if (ret != 0)
766 : : return ret;
767 : :
768 : 0 : atomic_inc(&dev_priv->gpu_error.pending_fb_pin);
769 : :
770 : 0 : vma = i915_gem_object_pin_to_display_plane(new_bo,
771 : : 0, NULL, PIN_MAPPABLE);
772 [ # # ]: 0 : if (IS_ERR(vma)) {
773 : 0 : ret = PTR_ERR(vma);
774 : 0 : goto out_pin_section;
775 : : }
776 [ # # ]: 0 : i915_gem_object_flush_frontbuffer(new_bo, ORIGIN_DIRTYFB);
777 : :
778 [ # # ]: 0 : if (!overlay->active) {
779 : 0 : u32 oconfig;
780 : :
781 : 0 : oconfig = OCONF_CC_OUT_8BIT;
782 [ # # ]: 0 : if (IS_GEN(dev_priv, 4))
783 : 0 : oconfig |= OCONF_CSC_MODE_BT709;
784 : 0 : oconfig |= pipe == 0 ?
785 [ # # ]: 0 : OCONF_PIPE_A : OCONF_PIPE_B;
786 : 0 : iowrite32(oconfig, ®s->OCONFIG);
787 : :
788 : 0 : ret = intel_overlay_on(overlay);
789 [ # # ]: 0 : if (ret != 0)
790 : 0 : goto out_unpin;
791 : : }
792 : :
793 : 0 : iowrite32(params->dst_y << 16 | params->dst_x, ®s->DWINPOS);
794 : 0 : iowrite32(params->dst_height << 16 | params->dst_width, ®s->DWINSZ);
795 : :
796 [ # # ]: 0 : if (params->flags & I915_OVERLAY_YUV_PACKED)
797 : 0 : tmp_width = packed_width_bytes(params->flags,
798 [ # # ]: 0 : params->src_width);
799 : : else
800 : 0 : tmp_width = params->src_width;
801 : :
802 : 0 : swidth = params->src_width;
803 [ # # ]: 0 : swidthsw = calc_swidthsw(dev_priv, params->offset_Y, tmp_width);
804 : 0 : sheight = params->src_height;
805 : 0 : iowrite32(i915_ggtt_offset(vma) + params->offset_Y, ®s->OBUF_0Y);
806 : 0 : ostride = params->stride_Y;
807 : :
808 [ # # ]: 0 : if (params->flags & I915_OVERLAY_YUV_PLANAR) {
809 [ # # # ]: 0 : int uv_hscale = uv_hsubsampling(params->flags);
810 [ # # # ]: 0 : int uv_vscale = uv_vsubsampling(params->flags);
811 : 0 : u32 tmp_U, tmp_V;
812 : :
813 : 0 : swidth |= (params->src_width / uv_hscale) << 16;
814 : 0 : sheight |= (params->src_height / uv_vscale) << 16;
815 : :
816 [ # # ]: 0 : tmp_U = calc_swidthsw(dev_priv, params->offset_U,
817 : : params->src_width / uv_hscale);
818 [ # # ]: 0 : tmp_V = calc_swidthsw(dev_priv, params->offset_V,
819 : : params->src_width / uv_hscale);
820 : 0 : swidthsw |= max(tmp_U, tmp_V) << 16;
821 : :
822 : 0 : iowrite32(i915_ggtt_offset(vma) + params->offset_U,
823 : 0 : ®s->OBUF_0U);
824 : 0 : iowrite32(i915_ggtt_offset(vma) + params->offset_V,
825 : 0 : ®s->OBUF_0V);
826 : :
827 : 0 : ostride |= params->stride_UV << 16;
828 : : }
829 : :
830 : 0 : iowrite32(swidth, ®s->SWIDTH);
831 : 0 : iowrite32(swidthsw, ®s->SWIDTHSW);
832 : 0 : iowrite32(sheight, ®s->SHEIGHT);
833 : 0 : iowrite32(ostride, ®s->OSTRIDE);
834 : :
835 : 0 : scale_changed = update_scaling_factors(overlay, regs, params);
836 : :
837 : 0 : update_colorkey(overlay, regs);
838 : :
839 : 0 : iowrite32(overlay_cmd_reg(params), ®s->OCMD);
840 : :
841 : 0 : ret = intel_overlay_continue(overlay, vma, scale_changed);
842 [ # # ]: 0 : if (ret)
843 : 0 : goto out_unpin;
844 : :
845 : : return 0;
846 : :
847 : 0 : out_unpin:
848 : 0 : i915_gem_object_unpin_from_display_plane(vma);
849 : 0 : out_pin_section:
850 : 0 : atomic_dec(&dev_priv->gpu_error.pending_fb_pin);
851 : :
852 : 0 : return ret;
853 : : }
854 : :
855 : 0 : int intel_overlay_switch_off(struct intel_overlay *overlay)
856 : : {
857 : 0 : struct drm_i915_private *dev_priv = overlay->i915;
858 : 0 : int ret;
859 : :
860 [ # # ]: 0 : WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex));
861 : :
862 : 0 : ret = intel_overlay_recover_from_interrupt(overlay);
863 [ # # ]: 0 : if (ret != 0)
864 : : return ret;
865 : :
866 [ # # ]: 0 : if (!overlay->active)
867 : : return 0;
868 : :
869 : 0 : ret = intel_overlay_release_old_vid(overlay);
870 [ # # ]: 0 : if (ret != 0)
871 : : return ret;
872 : :
873 : 0 : iowrite32(0, &overlay->regs->OCMD);
874 : :
875 : 0 : return intel_overlay_off(overlay);
876 : : }
877 : :
878 : 0 : static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
879 : : struct intel_crtc *crtc)
880 : : {
881 : 0 : if (!crtc->active)
882 : : return -EINVAL;
883 : :
884 : : /* can't use the overlay with double wide pipe */
885 [ # # ]: 0 : if (crtc->config->double_wide)
886 : : return -EINVAL;
887 : :
888 : : return 0;
889 : : }
890 : :
891 : : static void update_pfit_vscale_ratio(struct intel_overlay *overlay)
892 : : {
893 : : struct drm_i915_private *dev_priv = overlay->i915;
894 : : u32 pfit_control = I915_READ(PFIT_CONTROL);
895 : : u32 ratio;
896 : :
897 : : /* XXX: This is not the same logic as in the xorg driver, but more in
898 : : * line with the intel documentation for the i965
899 : : */
900 : : if (INTEL_GEN(dev_priv) >= 4) {
901 : : /* on i965 use the PGM reg to read out the autoscaler values */
902 : : ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965;
903 : : } else {
904 : : if (pfit_control & VERT_AUTO_SCALE)
905 : : ratio = I915_READ(PFIT_AUTO_RATIOS);
906 : : else
907 : : ratio = I915_READ(PFIT_PGM_RATIOS);
908 : : ratio >>= PFIT_VERT_SCALE_SHIFT;
909 : : }
910 : :
911 : : overlay->pfit_vscale_ratio = ratio;
912 : : }
913 : :
914 : 0 : static int check_overlay_dst(struct intel_overlay *overlay,
915 : : struct drm_intel_overlay_put_image *rec)
916 : : {
917 : 0 : const struct intel_crtc_state *pipe_config =
918 : : overlay->crtc->config;
919 : :
920 : 0 : if (rec->dst_x < pipe_config->pipe_src_w &&
921 [ # # ]: 0 : rec->dst_x + rec->dst_width <= pipe_config->pipe_src_w &&
922 [ # # ]: 0 : rec->dst_y < pipe_config->pipe_src_h &&
923 [ # # ]: 0 : rec->dst_y + rec->dst_height <= pipe_config->pipe_src_h)
924 : : return 0;
925 : : else
926 : 0 : return -EINVAL;
927 : : }
928 : :
929 : 0 : static int check_overlay_scaling(struct drm_intel_overlay_put_image *rec)
930 : : {
931 : 0 : u32 tmp;
932 : :
933 : : /* downscaling limit is 8.0 */
934 : 0 : tmp = ((rec->src_scan_height << 16) / rec->dst_height) >> 16;
935 : 0 : if (tmp > 7)
936 : : return -EINVAL;
937 : :
938 : 0 : tmp = ((rec->src_scan_width << 16) / rec->dst_width) >> 16;
939 [ # # ]: 0 : if (tmp > 7)
940 : : return -EINVAL;
941 : :
942 : : return 0;
943 : : }
944 : :
945 : : static int check_overlay_src(struct drm_i915_private *dev_priv,
946 : : struct drm_intel_overlay_put_image *rec,
947 : : struct drm_i915_gem_object *new_bo)
948 : : {
949 : : int uv_hscale = uv_hsubsampling(rec->flags);
950 : : int uv_vscale = uv_vsubsampling(rec->flags);
951 : : u32 stride_mask;
952 : : int depth;
953 : : u32 tmp;
954 : :
955 : : /* check src dimensions */
956 : : if (IS_I845G(dev_priv) || IS_I830(dev_priv)) {
957 : : if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY ||
958 : : rec->src_width > IMAGE_MAX_WIDTH_LEGACY)
959 : : return -EINVAL;
960 : : } else {
961 : : if (rec->src_height > IMAGE_MAX_HEIGHT ||
962 : : rec->src_width > IMAGE_MAX_WIDTH)
963 : : return -EINVAL;
964 : : }
965 : :
966 : : /* better safe than sorry, use 4 as the maximal subsampling ratio */
967 : : if (rec->src_height < N_VERT_Y_TAPS*4 ||
968 : : rec->src_width < N_HORIZ_Y_TAPS*4)
969 : : return -EINVAL;
970 : :
971 : : /* check alignment constraints */
972 : : switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
973 : : case I915_OVERLAY_RGB:
974 : : /* not implemented */
975 : : return -EINVAL;
976 : :
977 : : case I915_OVERLAY_YUV_PACKED:
978 : : if (uv_vscale != 1)
979 : : return -EINVAL;
980 : :
981 : : depth = packed_depth_bytes(rec->flags);
982 : : if (depth < 0)
983 : : return depth;
984 : :
985 : : /* ignore UV planes */
986 : : rec->stride_UV = 0;
987 : : rec->offset_U = 0;
988 : : rec->offset_V = 0;
989 : : /* check pixel alignment */
990 : : if (rec->offset_Y % depth)
991 : : return -EINVAL;
992 : : break;
993 : :
994 : : case I915_OVERLAY_YUV_PLANAR:
995 : : if (uv_vscale < 0 || uv_hscale < 0)
996 : : return -EINVAL;
997 : : /* no offset restrictions for planar formats */
998 : : break;
999 : :
1000 : : default:
1001 : : return -EINVAL;
1002 : : }
1003 : :
1004 : : if (rec->src_width % uv_hscale)
1005 : : return -EINVAL;
1006 : :
1007 : : /* stride checking */
1008 : : if (IS_I830(dev_priv) || IS_I845G(dev_priv))
1009 : : stride_mask = 255;
1010 : : else
1011 : : stride_mask = 63;
1012 : :
1013 : : if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
1014 : : return -EINVAL;
1015 : : if (IS_GEN(dev_priv, 4) && rec->stride_Y < 512)
1016 : : return -EINVAL;
1017 : :
1018 : : tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ?
1019 : : 4096 : 8192;
1020 : : if (rec->stride_Y > tmp || rec->stride_UV > 2*1024)
1021 : : return -EINVAL;
1022 : :
1023 : : /* check buffer dimensions */
1024 : : switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
1025 : : case I915_OVERLAY_RGB:
1026 : : case I915_OVERLAY_YUV_PACKED:
1027 : : /* always 4 Y values per depth pixels */
1028 : : if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y)
1029 : : return -EINVAL;
1030 : :
1031 : : tmp = rec->stride_Y*rec->src_height;
1032 : : if (rec->offset_Y + tmp > new_bo->base.size)
1033 : : return -EINVAL;
1034 : : break;
1035 : :
1036 : : case I915_OVERLAY_YUV_PLANAR:
1037 : : if (rec->src_width > rec->stride_Y)
1038 : : return -EINVAL;
1039 : : if (rec->src_width/uv_hscale > rec->stride_UV)
1040 : : return -EINVAL;
1041 : :
1042 : : tmp = rec->stride_Y * rec->src_height;
1043 : : if (rec->offset_Y + tmp > new_bo->base.size)
1044 : : return -EINVAL;
1045 : :
1046 : : tmp = rec->stride_UV * (rec->src_height / uv_vscale);
1047 : : if (rec->offset_U + tmp > new_bo->base.size ||
1048 : : rec->offset_V + tmp > new_bo->base.size)
1049 : : return -EINVAL;
1050 : : break;
1051 : : }
1052 : :
1053 : : return 0;
1054 : : }
1055 : :
1056 : 0 : int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data,
1057 : : struct drm_file *file_priv)
1058 : : {
1059 : 0 : struct drm_intel_overlay_put_image *params = data;
1060 [ # # ]: 0 : struct drm_i915_private *dev_priv = to_i915(dev);
1061 : 0 : struct intel_overlay *overlay;
1062 : 0 : struct drm_crtc *drmmode_crtc;
1063 : 0 : struct intel_crtc *crtc;
1064 : 0 : struct drm_i915_gem_object *new_bo;
1065 : 0 : int ret;
1066 : :
1067 : 0 : overlay = dev_priv->overlay;
1068 [ # # ]: 0 : if (!overlay) {
1069 : 0 : DRM_DEBUG("userspace bug: no overlay\n");
1070 : 0 : return -ENODEV;
1071 : : }
1072 : :
1073 [ # # ]: 0 : if (!(params->flags & I915_OVERLAY_ENABLE)) {
1074 : 0 : drm_modeset_lock_all(dev);
1075 : 0 : ret = intel_overlay_switch_off(overlay);
1076 : 0 : drm_modeset_unlock_all(dev);
1077 : :
1078 : 0 : return ret;
1079 : : }
1080 : :
1081 : 0 : drmmode_crtc = drm_crtc_find(dev, file_priv, params->crtc_id);
1082 [ # # ]: 0 : if (!drmmode_crtc)
1083 : : return -ENOENT;
1084 : 0 : crtc = to_intel_crtc(drmmode_crtc);
1085 : :
1086 : 0 : new_bo = i915_gem_object_lookup(file_priv, params->bo_handle);
1087 [ # # ]: 0 : if (!new_bo)
1088 : : return -ENOENT;
1089 : :
1090 : 0 : drm_modeset_lock_all(dev);
1091 : :
1092 [ # # ]: 0 : if (i915_gem_object_is_tiled(new_bo)) {
1093 : 0 : DRM_DEBUG_KMS("buffer used for overlay image can not be tiled\n");
1094 : 0 : ret = -EINVAL;
1095 : 0 : goto out_unlock;
1096 : : }
1097 : :
1098 : 0 : ret = intel_overlay_recover_from_interrupt(overlay);
1099 [ # # ]: 0 : if (ret != 0)
1100 : 0 : goto out_unlock;
1101 : :
1102 [ # # ]: 0 : if (overlay->crtc != crtc) {
1103 : 0 : ret = intel_overlay_switch_off(overlay);
1104 [ # # ]: 0 : if (ret != 0)
1105 : 0 : goto out_unlock;
1106 : :
1107 [ # # ]: 0 : ret = check_overlay_possible_on_crtc(overlay, crtc);
1108 : 0 : if (ret != 0)
1109 : 0 : goto out_unlock;
1110 : :
1111 : 0 : overlay->crtc = crtc;
1112 : 0 : crtc->overlay = overlay;
1113 : :
1114 : : /* line too wide, i.e. one-line-mode */
1115 [ # # ]: 0 : if (crtc->config->pipe_src_w > 1024 &&
1116 [ # # ]: 0 : crtc->config->gmch_pfit.control & PFIT_ENABLE) {
1117 : 0 : overlay->pfit_active = true;
1118 : 0 : update_pfit_vscale_ratio(overlay);
1119 : : } else
1120 : 0 : overlay->pfit_active = false;
1121 : : }
1122 : :
1123 [ # # ]: 0 : ret = check_overlay_dst(overlay, params);
1124 : 0 : if (ret != 0)
1125 : 0 : goto out_unlock;
1126 : :
1127 [ # # ]: 0 : if (overlay->pfit_active) {
1128 : 0 : params->dst_y = (((u32)params->dst_y << 12) /
1129 : 0 : overlay->pfit_vscale_ratio);
1130 : : /* shifting right rounds downwards, so add 1 */
1131 : 0 : params->dst_height = (((u32)params->dst_height << 12) /
1132 : 0 : overlay->pfit_vscale_ratio) + 1;
1133 : : }
1134 : :
1135 [ # # ]: 0 : if (params->src_scan_height > params->src_height ||
1136 [ # # ]: 0 : params->src_scan_width > params->src_width) {
1137 : 0 : ret = -EINVAL;
1138 : 0 : goto out_unlock;
1139 : : }
1140 : :
1141 : 0 : ret = check_overlay_src(dev_priv, params, new_bo);
1142 [ # # ]: 0 : if (ret != 0)
1143 : 0 : goto out_unlock;
1144 : :
1145 : : /* Check scaling after src size to prevent a divide-by-zero. */
1146 [ # # ]: 0 : ret = check_overlay_scaling(params);
1147 : 0 : if (ret != 0)
1148 : 0 : goto out_unlock;
1149 : :
1150 : 0 : ret = intel_overlay_do_put_image(overlay, new_bo, params);
1151 [ # # ]: 0 : if (ret != 0)
1152 : 0 : goto out_unlock;
1153 : :
1154 : 0 : drm_modeset_unlock_all(dev);
1155 : 0 : i915_gem_object_put(new_bo);
1156 : :
1157 : 0 : return 0;
1158 : :
1159 : 0 : out_unlock:
1160 : 0 : drm_modeset_unlock_all(dev);
1161 : 0 : i915_gem_object_put(new_bo);
1162 : :
1163 : 0 : return ret;
1164 : : }
1165 : :
1166 : 0 : static void update_reg_attrs(struct intel_overlay *overlay,
1167 : : struct overlay_registers __iomem *regs)
1168 : : {
1169 : 0 : iowrite32((overlay->contrast << 18) | (overlay->brightness & 0xff),
1170 : 0 : ®s->OCLRC0);
1171 : 0 : iowrite32(overlay->saturation, ®s->OCLRC1);
1172 : 0 : }
1173 : :
1174 : 0 : static bool check_gamma_bounds(u32 gamma1, u32 gamma2)
1175 : : {
1176 : 0 : int i;
1177 : :
1178 : 0 : if (gamma1 & 0xff000000 || gamma2 & 0xff000000)
1179 : : return false;
1180 : :
1181 [ # # # # : 0 : for (i = 0; i < 3; i++) {
# # # # #
# # # #
# ]
1182 [ # # # # : 0 : if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
# # # # #
# # # #
# ]
1183 : : return false;
1184 : : }
1185 : :
1186 : : return true;
1187 : : }
1188 : :
1189 : : static bool check_gamma5_errata(u32 gamma5)
1190 : : {
1191 : : int i;
1192 : :
1193 [ # # ]: 0 : for (i = 0; i < 3; i++) {
1194 [ # # ]: 0 : if (((gamma5 >> i*8) & 0xff) == 0x80)
1195 : : return false;
1196 : : }
1197 : :
1198 : : return true;
1199 : : }
1200 : :
1201 : 0 : static int check_gamma(struct drm_intel_overlay_attrs *attrs)
1202 : : {
1203 [ # # # # : 0 : if (!check_gamma_bounds(0, attrs->gamma0) ||
# # ]
1204 [ # # # # ]: 0 : !check_gamma_bounds(attrs->gamma0, attrs->gamma1) ||
1205 [ # # # # ]: 0 : !check_gamma_bounds(attrs->gamma1, attrs->gamma2) ||
1206 [ # # # # ]: 0 : !check_gamma_bounds(attrs->gamma2, attrs->gamma3) ||
1207 [ # # # # ]: 0 : !check_gamma_bounds(attrs->gamma3, attrs->gamma4) ||
1208 [ # # # # ]: 0 : !check_gamma_bounds(attrs->gamma4, attrs->gamma5) ||
1209 : : !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
1210 : : return -EINVAL;
1211 : :
1212 [ # # ]: 0 : if (!check_gamma5_errata(attrs->gamma5))
1213 : 0 : return -EINVAL;
1214 : :
1215 : : return 0;
1216 : : }
1217 : :
1218 : 0 : int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data,
1219 : : struct drm_file *file_priv)
1220 : : {
1221 : 0 : struct drm_intel_overlay_attrs *attrs = data;
1222 [ # # ]: 0 : struct drm_i915_private *dev_priv = to_i915(dev);
1223 : 0 : struct intel_overlay *overlay;
1224 : 0 : int ret;
1225 : :
1226 : 0 : overlay = dev_priv->overlay;
1227 [ # # ]: 0 : if (!overlay) {
1228 : 0 : DRM_DEBUG("userspace bug: no overlay\n");
1229 : 0 : return -ENODEV;
1230 : : }
1231 : :
1232 : 0 : drm_modeset_lock_all(dev);
1233 : :
1234 : 0 : ret = -EINVAL;
1235 [ # # ]: 0 : if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) {
1236 : 0 : attrs->color_key = overlay->color_key;
1237 : 0 : attrs->brightness = overlay->brightness;
1238 : 0 : attrs->contrast = overlay->contrast;
1239 : 0 : attrs->saturation = overlay->saturation;
1240 : :
1241 [ # # ]: 0 : if (!IS_GEN(dev_priv, 2)) {
1242 : 0 : attrs->gamma0 = I915_READ(OGAMC0);
1243 : 0 : attrs->gamma1 = I915_READ(OGAMC1);
1244 : 0 : attrs->gamma2 = I915_READ(OGAMC2);
1245 : 0 : attrs->gamma3 = I915_READ(OGAMC3);
1246 : 0 : attrs->gamma4 = I915_READ(OGAMC4);
1247 : 0 : attrs->gamma5 = I915_READ(OGAMC5);
1248 : : }
1249 : : } else {
1250 [ # # ]: 0 : if (attrs->brightness < -128 || attrs->brightness > 127)
1251 : 0 : goto out_unlock;
1252 [ # # ]: 0 : if (attrs->contrast > 255)
1253 : 0 : goto out_unlock;
1254 [ # # ]: 0 : if (attrs->saturation > 1023)
1255 : 0 : goto out_unlock;
1256 : :
1257 : 0 : overlay->color_key = attrs->color_key;
1258 : 0 : overlay->brightness = attrs->brightness;
1259 : 0 : overlay->contrast = attrs->contrast;
1260 : 0 : overlay->saturation = attrs->saturation;
1261 : :
1262 : 0 : update_reg_attrs(overlay, overlay->regs);
1263 : :
1264 [ # # ]: 0 : if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) {
1265 [ # # ]: 0 : if (IS_GEN(dev_priv, 2))
1266 : 0 : goto out_unlock;
1267 : :
1268 [ # # ]: 0 : if (overlay->active) {
1269 : 0 : ret = -EBUSY;
1270 : 0 : goto out_unlock;
1271 : : }
1272 : :
1273 : 0 : ret = check_gamma(attrs);
1274 [ # # ]: 0 : if (ret)
1275 : 0 : goto out_unlock;
1276 : :
1277 : 0 : I915_WRITE(OGAMC0, attrs->gamma0);
1278 : 0 : I915_WRITE(OGAMC1, attrs->gamma1);
1279 : 0 : I915_WRITE(OGAMC2, attrs->gamma2);
1280 : 0 : I915_WRITE(OGAMC3, attrs->gamma3);
1281 : 0 : I915_WRITE(OGAMC4, attrs->gamma4);
1282 : 0 : I915_WRITE(OGAMC5, attrs->gamma5);
1283 : : }
1284 : : }
1285 : 0 : overlay->color_key_enabled = (attrs->flags & I915_OVERLAY_DISABLE_DEST_COLORKEY) == 0;
1286 : :
1287 : 0 : ret = 0;
1288 : 0 : out_unlock:
1289 : 0 : drm_modeset_unlock_all(dev);
1290 : :
1291 : 0 : return ret;
1292 : : }
1293 : :
1294 : 0 : static int get_registers(struct intel_overlay *overlay, bool use_phys)
1295 : : {
1296 : 0 : struct drm_i915_private *i915 = overlay->i915;
1297 : 0 : struct drm_i915_gem_object *obj;
1298 : 0 : struct i915_vma *vma;
1299 : 0 : int err;
1300 : :
1301 : 0 : obj = i915_gem_object_create_stolen(i915, PAGE_SIZE);
1302 [ # # ]: 0 : if (IS_ERR(obj))
1303 : 0 : obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
1304 [ # # ]: 0 : if (IS_ERR(obj))
1305 : 0 : return PTR_ERR(obj);
1306 : :
1307 : 0 : vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, PIN_MAPPABLE);
1308 [ # # ]: 0 : if (IS_ERR(vma)) {
1309 : 0 : err = PTR_ERR(vma);
1310 : 0 : goto err_put_bo;
1311 : : }
1312 : :
1313 [ # # ]: 0 : if (use_phys)
1314 : 0 : overlay->flip_addr = sg_dma_address(obj->mm.pages->sgl);
1315 : : else
1316 : 0 : overlay->flip_addr = i915_ggtt_offset(vma);
1317 : 0 : overlay->regs = i915_vma_pin_iomap(vma);
1318 : 0 : i915_vma_unpin(vma);
1319 : :
1320 [ # # ]: 0 : if (IS_ERR(overlay->regs)) {
1321 : 0 : err = PTR_ERR(overlay->regs);
1322 : 0 : goto err_put_bo;
1323 : : }
1324 : :
1325 : 0 : overlay->reg_bo = obj;
1326 : 0 : return 0;
1327 : :
1328 : 0 : err_put_bo:
1329 : 0 : i915_gem_object_put(obj);
1330 : 0 : return err;
1331 : : }
1332 : :
1333 : 0 : void intel_overlay_setup(struct drm_i915_private *dev_priv)
1334 : : {
1335 : 0 : struct intel_overlay *overlay;
1336 : 0 : struct intel_engine_cs *engine;
1337 : 0 : int ret;
1338 : :
1339 [ # # ]: 0 : if (!HAS_OVERLAY(dev_priv))
1340 : : return;
1341 : :
1342 : 0 : engine = dev_priv->engine[RCS0];
1343 [ # # # # ]: 0 : if (!engine || !engine->kernel_context)
1344 : : return;
1345 : :
1346 : 0 : overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
1347 [ # # ]: 0 : if (!overlay)
1348 : : return;
1349 : :
1350 : 0 : overlay->i915 = dev_priv;
1351 : 0 : overlay->context = engine->kernel_context;
1352 : 0 : GEM_BUG_ON(!overlay->context);
1353 : :
1354 : 0 : overlay->color_key = 0x0101fe;
1355 : 0 : overlay->color_key_enabled = true;
1356 : 0 : overlay->brightness = -19;
1357 : 0 : overlay->contrast = 75;
1358 : 0 : overlay->saturation = 146;
1359 : :
1360 : 0 : i915_active_init(&overlay->last_flip,
1361 : : NULL, intel_overlay_last_flip_retire);
1362 : :
1363 : 0 : ret = get_registers(overlay, OVERLAY_NEEDS_PHYSICAL(dev_priv));
1364 [ # # ]: 0 : if (ret)
1365 : 0 : goto out_free;
1366 : :
1367 : 0 : memset_io(overlay->regs, 0, sizeof(struct overlay_registers));
1368 : 0 : update_polyphase_filter(overlay->regs);
1369 : 0 : update_reg_attrs(overlay, overlay->regs);
1370 : :
1371 : 0 : dev_priv->overlay = overlay;
1372 : 0 : DRM_INFO("Initialized overlay support.\n");
1373 : 0 : return;
1374 : :
1375 : : out_free:
1376 : 0 : kfree(overlay);
1377 : : }
1378 : :
1379 : 0 : void intel_overlay_cleanup(struct drm_i915_private *dev_priv)
1380 : : {
1381 : 0 : struct intel_overlay *overlay;
1382 : :
1383 : 0 : overlay = fetch_and_zero(&dev_priv->overlay);
1384 [ # # ]: 0 : if (!overlay)
1385 : : return;
1386 : :
1387 : : /*
1388 : : * The bo's should be free'd by the generic code already.
1389 : : * Furthermore modesetting teardown happens beforehand so the
1390 : : * hardware should be off already.
1391 : : */
1392 [ # # ]: 0 : WARN_ON(overlay->active);
1393 : :
1394 : 0 : i915_gem_object_put(overlay->reg_bo);
1395 : 0 : i915_active_fini(&overlay->last_flip);
1396 : :
1397 : 0 : kfree(overlay);
1398 : : }
1399 : :
1400 : : #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
1401 : :
1402 : : struct intel_overlay_error_state {
1403 : : struct overlay_registers regs;
1404 : : unsigned long base;
1405 : : u32 dovsta;
1406 : : u32 isr;
1407 : : };
1408 : :
1409 : : struct intel_overlay_error_state *
1410 : 0 : intel_overlay_capture_error_state(struct drm_i915_private *dev_priv)
1411 : : {
1412 : 0 : struct intel_overlay *overlay = dev_priv->overlay;
1413 : 0 : struct intel_overlay_error_state *error;
1414 : :
1415 [ # # # # ]: 0 : if (!overlay || !overlay->active)
1416 : : return NULL;
1417 : :
1418 : 0 : error = kmalloc(sizeof(*error), GFP_ATOMIC);
1419 [ # # ]: 0 : if (error == NULL)
1420 : : return NULL;
1421 : :
1422 : 0 : error->dovsta = I915_READ(DOVSTA);
1423 : 0 : error->isr = I915_READ(GEN2_ISR);
1424 : 0 : error->base = overlay->flip_addr;
1425 : :
1426 : 0 : memcpy_fromio(&error->regs, overlay->regs, sizeof(error->regs));
1427 : :
1428 : 0 : return error;
1429 : : }
1430 : :
1431 : : void
1432 : 0 : intel_overlay_print_error_state(struct drm_i915_error_state_buf *m,
1433 : : struct intel_overlay_error_state *error)
1434 : : {
1435 : 0 : i915_error_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",
1436 : : error->dovsta, error->isr);
1437 : 0 : i915_error_printf(m, " Register file at 0x%08lx:\n",
1438 : : error->base);
1439 : :
1440 : : #define P(x) i915_error_printf(m, " " #x ": 0x%08x\n", error->regs.x)
1441 : 0 : P(OBUF_0Y);
1442 : 0 : P(OBUF_1Y);
1443 : 0 : P(OBUF_0U);
1444 : 0 : P(OBUF_0V);
1445 : 0 : P(OBUF_1U);
1446 : 0 : P(OBUF_1V);
1447 : 0 : P(OSTRIDE);
1448 : 0 : P(YRGB_VPH);
1449 : 0 : P(UV_VPH);
1450 : 0 : P(HORZ_PH);
1451 : 0 : P(INIT_PHS);
1452 : 0 : P(DWINPOS);
1453 : 0 : P(DWINSZ);
1454 : 0 : P(SWIDTH);
1455 : 0 : P(SWIDTHSW);
1456 : 0 : P(SHEIGHT);
1457 : 0 : P(YRGBSCALE);
1458 : 0 : P(UVSCALE);
1459 : 0 : P(OCLRC0);
1460 : 0 : P(OCLRC1);
1461 : 0 : P(DCLRKV);
1462 : 0 : P(DCLRKM);
1463 : 0 : P(SCLRKVH);
1464 : 0 : P(SCLRKVL);
1465 : 0 : P(SCLRKEN);
1466 : 0 : P(OCONFIG);
1467 : 0 : P(OCMD);
1468 : 0 : P(OSTART_0Y);
1469 : 0 : P(OSTART_1Y);
1470 : 0 : P(OSTART_0U);
1471 : 0 : P(OSTART_0V);
1472 : 0 : P(OSTART_1U);
1473 : 0 : P(OSTART_1V);
1474 : 0 : P(OTILEOFF_0Y);
1475 : 0 : P(OTILEOFF_1Y);
1476 : 0 : P(OTILEOFF_0U);
1477 : 0 : P(OTILEOFF_0V);
1478 : 0 : P(OTILEOFF_1U);
1479 : 0 : P(OTILEOFF_1V);
1480 : 0 : P(FASTHSCALE);
1481 : 0 : P(UVSCALEV);
1482 : : #undef P
1483 : 0 : }
1484 : :
1485 : : #endif
|