]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/gpu/drm/i915/intel_overlay.c
drm/i915: fully switch off overlay when not in use
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / drm / i915 / intel_overlay.c
CommitLineData
02e792fb
DV
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#include "drmP.h"
29#include "drm.h"
30#include "i915_drm.h"
31#include "i915_drv.h"
32#include "i915_reg.h"
33#include "intel_drv.h"
34
35/* Limits for overlay size. According to intel doc, the real limits are:
36 * Y width: 4095, UV width (planar): 2047, Y height: 2047,
37 * UV width (planar): * 1023. But the xorg thinks 2048 for height and width. Use
38 * the mininum of both. */
39#define IMAGE_MAX_WIDTH 2048
40#define IMAGE_MAX_HEIGHT 2046 /* 2 * 1023 */
41/* on 830 and 845 these large limits result in the card hanging */
42#define IMAGE_MAX_WIDTH_LEGACY 1024
43#define IMAGE_MAX_HEIGHT_LEGACY 1088
44
45/* overlay register definitions */
46/* OCMD register */
47#define OCMD_TILED_SURFACE (0x1<<19)
48#define OCMD_MIRROR_MASK (0x3<<17)
49#define OCMD_MIRROR_MODE (0x3<<17)
50#define OCMD_MIRROR_HORIZONTAL (0x1<<17)
51#define OCMD_MIRROR_VERTICAL (0x2<<17)
52#define OCMD_MIRROR_BOTH (0x3<<17)
53#define OCMD_BYTEORDER_MASK (0x3<<14) /* zero for YUYV or FOURCC YUY2 */
54#define OCMD_UV_SWAP (0x1<<14) /* YVYU */
55#define OCMD_Y_SWAP (0x2<<14) /* UYVY or FOURCC UYVY */
56#define OCMD_Y_AND_UV_SWAP (0x3<<14) /* VYUY */
57#define OCMD_SOURCE_FORMAT_MASK (0xf<<10)
58#define OCMD_RGB_888 (0x1<<10) /* not in i965 Intel docs */
59#define OCMD_RGB_555 (0x2<<10) /* not in i965 Intel docs */
60#define OCMD_RGB_565 (0x3<<10) /* not in i965 Intel docs */
61#define OCMD_YUV_422_PACKED (0x8<<10)
62#define OCMD_YUV_411_PACKED (0x9<<10) /* not in i965 Intel docs */
63#define OCMD_YUV_420_PLANAR (0xc<<10)
64#define OCMD_YUV_422_PLANAR (0xd<<10)
65#define OCMD_YUV_410_PLANAR (0xe<<10) /* also 411 */
66#define OCMD_TVSYNCFLIP_PARITY (0x1<<9)
67#define OCMD_TVSYNCFLIP_ENABLE (0x1<<7)
68#define OCMD_BUF_TYPE_MASK (Ox1<<5)
69#define OCMD_BUF_TYPE_FRAME (0x0<<5)
70#define OCMD_BUF_TYPE_FIELD (0x1<<5)
71#define OCMD_TEST_MODE (0x1<<4)
72#define OCMD_BUFFER_SELECT (0x3<<2)
73#define OCMD_BUFFER0 (0x0<<2)
74#define OCMD_BUFFER1 (0x1<<2)
75#define OCMD_FIELD_SELECT (0x1<<2)
76#define OCMD_FIELD0 (0x0<<1)
77#define OCMD_FIELD1 (0x1<<1)
78#define OCMD_ENABLE (0x1<<0)
79
80/* OCONFIG register */
81#define OCONF_PIPE_MASK (0x1<<18)
82#define OCONF_PIPE_A (0x0<<18)
83#define OCONF_PIPE_B (0x1<<18)
84#define OCONF_GAMMA2_ENABLE (0x1<<16)
85#define OCONF_CSC_MODE_BT601 (0x0<<5)
86#define OCONF_CSC_MODE_BT709 (0x1<<5)
87#define OCONF_CSC_BYPASS (0x1<<4)
88#define OCONF_CC_OUT_8BIT (0x1<<3)
89#define OCONF_TEST_MODE (0x1<<2)
90#define OCONF_THREE_LINE_BUFFER (0x1<<0)
91#define OCONF_TWO_LINE_BUFFER (0x0<<0)
92
93/* DCLRKM (dst-key) register */
94#define DST_KEY_ENABLE (0x1<<31)
95#define CLK_RGB24_MASK 0x0
96#define CLK_RGB16_MASK 0x070307
97#define CLK_RGB15_MASK 0x070707
98#define CLK_RGB8I_MASK 0xffffff
99
100#define RGB16_TO_COLORKEY(c) \
101 (((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3))
102#define RGB15_TO_COLORKEY(c) \
103 (((c & 0x7c00) << 9) | ((c & 0x03E0) << 6) | ((c & 0x001F) << 3))
104
105/* overlay flip addr flag */
106#define OFC_UPDATE 0x1
107
108/* polyphase filter coefficients */
109#define N_HORIZ_Y_TAPS 5
110#define N_VERT_Y_TAPS 3
111#define N_HORIZ_UV_TAPS 3
112#define N_VERT_UV_TAPS 3
113#define N_PHASES 17
114#define MAX_TAPS 5
115
116/* memory bufferd overlay registers */
117struct overlay_registers {
118 u32 OBUF_0Y;
119 u32 OBUF_1Y;
120 u32 OBUF_0U;
121 u32 OBUF_0V;
122 u32 OBUF_1U;
123 u32 OBUF_1V;
124 u32 OSTRIDE;
125 u32 YRGB_VPH;
126 u32 UV_VPH;
127 u32 HORZ_PH;
128 u32 INIT_PHS;
129 u32 DWINPOS;
130 u32 DWINSZ;
131 u32 SWIDTH;
132 u32 SWIDTHSW;
133 u32 SHEIGHT;
134 u32 YRGBSCALE;
135 u32 UVSCALE;
136 u32 OCLRC0;
137 u32 OCLRC1;
138 u32 DCLRKV;
139 u32 DCLRKM;
140 u32 SCLRKVH;
141 u32 SCLRKVL;
142 u32 SCLRKEN;
143 u32 OCONFIG;
144 u32 OCMD;
145 u32 RESERVED1; /* 0x6C */
146 u32 OSTART_0Y;
147 u32 OSTART_1Y;
148 u32 OSTART_0U;
149 u32 OSTART_0V;
150 u32 OSTART_1U;
151 u32 OSTART_1V;
152 u32 OTILEOFF_0Y;
153 u32 OTILEOFF_1Y;
154 u32 OTILEOFF_0U;
155 u32 OTILEOFF_0V;
156 u32 OTILEOFF_1U;
157 u32 OTILEOFF_1V;
158 u32 FASTHSCALE; /* 0xA0 */
159 u32 UVSCALEV; /* 0xA4 */
160 u32 RESERVEDC[(0x200 - 0xA8) / 4]; /* 0xA8 - 0x1FC */
161 u16 Y_VCOEFS[N_VERT_Y_TAPS * N_PHASES]; /* 0x200 */
162 u16 RESERVEDD[0x100 / 2 - N_VERT_Y_TAPS * N_PHASES];
163 u16 Y_HCOEFS[N_HORIZ_Y_TAPS * N_PHASES]; /* 0x300 */
164 u16 RESERVEDE[0x200 / 2 - N_HORIZ_Y_TAPS * N_PHASES];
165 u16 UV_VCOEFS[N_VERT_UV_TAPS * N_PHASES]; /* 0x500 */
166 u16 RESERVEDF[0x100 / 2 - N_VERT_UV_TAPS * N_PHASES];
167 u16 UV_HCOEFS[N_HORIZ_UV_TAPS * N_PHASES]; /* 0x600 */
168 u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES];
169};
170
171/* overlay flip addr flag */
172#define OFC_UPDATE 0x1
173
174#define OVERLAY_NONPHYSICAL(dev) (IS_G33(dev) || IS_I965G(dev))
175#define OVERLAY_EXISTS(dev) (!IS_G4X(dev) && !IS_IGDNG(dev))
176
177
178static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
179{
180 drm_i915_private_t *dev_priv = overlay->dev->dev_private;
181 struct overlay_registers *regs;
182
183 /* no recursive mappings */
184 BUG_ON(overlay->virt_addr);
185
186 if (OVERLAY_NONPHYSICAL(overlay->dev)) {
187 regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
188 overlay->reg_bo->gtt_offset);
189
190 if (!regs) {
191 DRM_ERROR("failed to map overlay regs in GTT\n");
192 return NULL;
193 }
194 } else
195 regs = overlay->reg_bo->phys_obj->handle->vaddr;
196
197 return overlay->virt_addr = regs;
198}
199
200static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay)
201{
202 struct drm_device *dev = overlay->dev;
203 drm_i915_private_t *dev_priv = dev->dev_private;
204
205 if (OVERLAY_NONPHYSICAL(overlay->dev))
206 io_mapping_unmap_atomic(overlay->virt_addr);
207
208 overlay->virt_addr = NULL;
209
210 I915_READ(OVADD); /* flush wc cashes */
211
212 return;
213}
214
215/* overlay needs to be disable in OCMD reg */
216static int intel_overlay_on(struct intel_overlay *overlay)
217{
218 struct drm_device *dev = overlay->dev;
219 drm_i915_private_t *dev_priv = dev->dev_private;
220 int ret;
221 RING_LOCALS;
222
223 BUG_ON(overlay->active);
224
225 BEGIN_LP_RING(6);
226 OUT_RING(MI_FLUSH);
227 OUT_RING(MI_NOOP);
228 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON);
229 OUT_RING(overlay->flip_addr | OFC_UPDATE);
230 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
231 OUT_RING(MI_NOOP);
232 ADVANCE_LP_RING();
233
234 ret = i915_lp_ring_sync(dev);
235 if (ret != 0) {
236 DRM_ERROR("intel overlay: ring sync failed, hw likely wedged\n");
237 overlay->hw_wedged = 1;
238 return 0;
239 }
240
241 overlay->active = 1;
242
243 return 0;
244}
245
246/* overlay needs to be enabled in OCMD reg */
247static void intel_overlay_continue(struct intel_overlay *overlay,
248 bool load_polyphase_filter)
249{
250 struct drm_device *dev = overlay->dev;
251 drm_i915_private_t *dev_priv = dev->dev_private;
252 u32 flip_addr = overlay->flip_addr;
253 u32 tmp;
254 int ret;
255 RING_LOCALS;
256
257 BUG_ON(!overlay->active);
258
259 if (load_polyphase_filter)
260 flip_addr |= OFC_UPDATE;
261
262 /* check for underruns */
263 tmp = I915_READ(DOVSTA);
264 if (tmp & (1 << 17))
265 DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
266
267 BEGIN_LP_RING(6);
268 OUT_RING(MI_FLUSH);
269 OUT_RING(MI_NOOP);
270 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
271 OUT_RING(flip_addr);
272 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
273 OUT_RING(MI_NOOP);
274 ADVANCE_LP_RING();
275
276 /* run in lockstep with the hw for easier testing */
277 ret = i915_lp_ring_sync(dev);
278 if (ret != 0) {
279 DRM_ERROR("intel overlay: ring sync failed, hw likely wedged\n");
280 overlay->hw_wedged = 1;
281 }
282}
283
284static int intel_overlay_wait_flip(struct intel_overlay *overlay)
285{
286 /* don't overcomplicate things for now with asynchronous operations
287 * see comment above */
288 return 0;
289}
290
291/* overlay needs to be disabled in OCMD reg */
292static int intel_overlay_off(struct intel_overlay *overlay)
293{
294 u32 flip_addr = overlay->flip_addr;
295 struct drm_device *dev = overlay->dev;
296 drm_i915_private_t *dev_priv = dev->dev_private;
297 int ret;
298 RING_LOCALS;
299
300 BUG_ON(!overlay->active);
301
302 /* According to intel docs the overlay hw may hang (when switching
303 * off) without loading the filter coeffs. It is however unclear whether
304 * this applies to the disabling of the overlay or to the switching off
305 * of the hw. Do it in both cases */
306 flip_addr |= OFC_UPDATE;
307
308 /* wait for overlay to go idle */
309 BEGIN_LP_RING(6);
310 OUT_RING(MI_FLUSH);
311 OUT_RING(MI_NOOP);
312 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
313 OUT_RING(flip_addr);
314 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
315 OUT_RING(MI_NOOP);
316 ADVANCE_LP_RING();
317
318 ret = i915_lp_ring_sync(dev);
319 if (ret != 0) {
320 DRM_ERROR("intel overlay: ring sync failed, hw likely wedged\n");
321 overlay->hw_wedged = 1;
322 return ret;
323 }
324
325 /* turn overlay off */
02e792fb
DV
326 BEGIN_LP_RING(6);
327 OUT_RING(MI_FLUSH);
328 OUT_RING(MI_NOOP);
329 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
330 OUT_RING(flip_addr);
331 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
332 OUT_RING(MI_NOOP);
333 ADVANCE_LP_RING();
334
335 ret = i915_lp_ring_sync(dev);
336 if (ret != 0) {
337 DRM_ERROR("intel overlay: ring sync failed, hw likely wedged\n");
338 overlay->hw_wedged = 1;
339 return ret;
240a2d12 340 }
02e792fb
DV
341
342 overlay->active = 0;
343
344 return ret;
345}
346
347/* wait for pending overlay flip and release old frame */
348static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
349{
350 int ret;
351 struct drm_gem_object *obj;
352
353 ret = intel_overlay_wait_flip(overlay);
354 if (ret != 0)
355 return ret;
356
357 if (!overlay->old_vid_bo)
358 return 0;
359
360 obj = overlay->old_vid_bo->obj;
361 i915_gem_object_unpin(obj);
362 drm_gem_object_unreference(obj);
363 overlay->old_vid_bo = NULL;
364
365 return 0;
366}
367
368struct put_image_params {
369 int format;
370 short dst_x;
371 short dst_y;
372 short dst_w;
373 short dst_h;
374 short src_w;
375 short src_scan_h;
376 short src_scan_w;
377 short src_h;
378 short stride_Y;
379 short stride_UV;
380 int offset_Y;
381 int offset_U;
382 int offset_V;
383};
384
385static int packed_depth_bytes(u32 format)
386{
387 switch (format & I915_OVERLAY_DEPTH_MASK) {
388 case I915_OVERLAY_YUV422:
389 return 4;
390 case I915_OVERLAY_YUV411:
391 /* return 6; not implemented */
392 default:
393 return -EINVAL;
394 }
395}
396
397static int packed_width_bytes(u32 format, short width)
398{
399 switch (format & I915_OVERLAY_DEPTH_MASK) {
400 case I915_OVERLAY_YUV422:
401 return width << 1;
402 default:
403 return -EINVAL;
404 }
405}
406
407static int uv_hsubsampling(u32 format)
408{
409 switch (format & I915_OVERLAY_DEPTH_MASK) {
410 case I915_OVERLAY_YUV422:
411 case I915_OVERLAY_YUV420:
412 return 2;
413 case I915_OVERLAY_YUV411:
414 case I915_OVERLAY_YUV410:
415 return 4;
416 default:
417 return -EINVAL;
418 }
419}
420
421static int uv_vsubsampling(u32 format)
422{
423 switch (format & I915_OVERLAY_DEPTH_MASK) {
424 case I915_OVERLAY_YUV420:
425 case I915_OVERLAY_YUV410:
426 return 2;
427 case I915_OVERLAY_YUV422:
428 case I915_OVERLAY_YUV411:
429 return 1;
430 default:
431 return -EINVAL;
432 }
433}
434
435static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width)
436{
437 u32 mask, shift, ret;
438 if (IS_I9XX(dev)) {
439 mask = 0x3f;
440 shift = 6;
441 } else {
442 mask = 0x1f;
443 shift = 5;
444 }
445 ret = ((offset + width + mask) >> shift) - (offset >> shift);
446 if (IS_I9XX(dev))
447 ret <<= 1;
448 ret -=1;
449 return ret << 2;
450}
451
452static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = {
453 0x3000, 0xb4a0, 0x1930, 0x1920, 0xb4a0,
454 0x3000, 0xb500, 0x19d0, 0x1880, 0xb440,
455 0x3000, 0xb540, 0x1a88, 0x2f80, 0xb3e0,
456 0x3000, 0xb580, 0x1b30, 0x2e20, 0xb380,
457 0x3000, 0xb5c0, 0x1bd8, 0x2cc0, 0xb320,
458 0x3020, 0xb5e0, 0x1c60, 0x2b80, 0xb2c0,
459 0x3020, 0xb5e0, 0x1cf8, 0x2a20, 0xb260,
460 0x3020, 0xb5e0, 0x1d80, 0x28e0, 0xb200,
461 0x3020, 0xb5c0, 0x1e08, 0x3f40, 0xb1c0,
462 0x3020, 0xb580, 0x1e78, 0x3ce0, 0xb160,
463 0x3040, 0xb520, 0x1ed8, 0x3aa0, 0xb120,
464 0x3040, 0xb4a0, 0x1f30, 0x3880, 0xb0e0,
465 0x3040, 0xb400, 0x1f78, 0x3680, 0xb0a0,
466 0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060,
467 0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040,
468 0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020,
469 0xb000, 0x3000, 0x0800, 0x3000, 0xb000};
470static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
471 0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60,
472 0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40,
473 0xb040, 0x1b20, 0x29e0, 0xb060, 0x1bd8, 0x2880,
474 0xb080, 0x1c88, 0x3e60, 0xb0a0, 0x1d28, 0x3c00,
475 0xb0c0, 0x1db8, 0x39e0, 0xb0e0, 0x1e40, 0x37e0,
476 0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0,
477 0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240,
478 0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0,
479 0x3000, 0x0800, 0x3000};
480
481static void update_polyphase_filter(struct overlay_registers *regs)
482{
483 memcpy(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs));
484 memcpy(regs->UV_HCOEFS, uv_static_hcoeffs, sizeof(uv_static_hcoeffs));
485}
486
487static bool update_scaling_factors(struct intel_overlay *overlay,
488 struct overlay_registers *regs,
489 struct put_image_params *params)
490{
491 /* fixed point with a 12 bit shift */
492 u32 xscale, yscale, xscale_UV, yscale_UV;
493#define FP_SHIFT 12
494#define FRACT_MASK 0xfff
495 bool scale_changed = false;
496 int uv_hscale = uv_hsubsampling(params->format);
497 int uv_vscale = uv_vsubsampling(params->format);
498
499 if (params->dst_w > 1)
500 xscale = ((params->src_scan_w - 1) << FP_SHIFT)
501 /(params->dst_w);
502 else
503 xscale = 1 << FP_SHIFT;
504
505 if (params->dst_h > 1)
506 yscale = ((params->src_scan_h - 1) << FP_SHIFT)
507 /(params->dst_h);
508 else
509 yscale = 1 << FP_SHIFT;
510
511 /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
512 xscale_UV = xscale/uv_hscale;
513 yscale_UV = yscale/uv_vscale;
514 /* make the Y scale to UV scale ratio an exact multiply */
515 xscale = xscale_UV * uv_hscale;
516 yscale = yscale_UV * uv_vscale;
517 /*} else {
518 xscale_UV = 0;
519 yscale_UV = 0;
520 }*/
521
522 if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)
523 scale_changed = true;
524 overlay->old_xscale = xscale;
525 overlay->old_yscale = yscale;
526
527 regs->YRGBSCALE = ((yscale & FRACT_MASK) << 20)
528 | ((xscale >> FP_SHIFT) << 16)
529 | ((xscale & FRACT_MASK) << 3);
530 regs->UVSCALE = ((yscale_UV & FRACT_MASK) << 20)
531 | ((xscale_UV >> FP_SHIFT) << 16)
532 | ((xscale_UV & FRACT_MASK) << 3);
533 regs->UVSCALEV = ((yscale >> FP_SHIFT) << 16)
534 | ((yscale_UV >> FP_SHIFT) << 0);
535
536 if (scale_changed)
537 update_polyphase_filter(regs);
538
539 return scale_changed;
540}
541
542static void update_colorkey(struct intel_overlay *overlay,
543 struct overlay_registers *regs)
544{
545 u32 key = overlay->color_key;
546 switch (overlay->crtc->base.fb->bits_per_pixel) {
547 case 8:
548 regs->DCLRKV = 0;
549 regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;
550 case 16:
551 if (overlay->crtc->base.fb->depth == 15) {
552 regs->DCLRKV = RGB15_TO_COLORKEY(key);
553 regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;
554 } else {
555 regs->DCLRKV = RGB16_TO_COLORKEY(key);
556 regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;
557 }
558 case 24:
559 case 32:
560 regs->DCLRKV = key;
561 regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;
562 }
563}
564
565static u32 overlay_cmd_reg(struct put_image_params *params)
566{
567 u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0;
568
569 if (params->format & I915_OVERLAY_YUV_PLANAR) {
570 switch (params->format & I915_OVERLAY_DEPTH_MASK) {
571 case I915_OVERLAY_YUV422:
572 cmd |= OCMD_YUV_422_PLANAR;
573 break;
574 case I915_OVERLAY_YUV420:
575 cmd |= OCMD_YUV_420_PLANAR;
576 break;
577 case I915_OVERLAY_YUV411:
578 case I915_OVERLAY_YUV410:
579 cmd |= OCMD_YUV_410_PLANAR;
580 break;
581 }
582 } else { /* YUV packed */
583 switch (params->format & I915_OVERLAY_DEPTH_MASK) {
584 case I915_OVERLAY_YUV422:
585 cmd |= OCMD_YUV_422_PACKED;
586 break;
587 case I915_OVERLAY_YUV411:
588 cmd |= OCMD_YUV_411_PACKED;
589 break;
590 }
591
592 switch (params->format & I915_OVERLAY_SWAP_MASK) {
593 case I915_OVERLAY_NO_SWAP:
594 break;
595 case I915_OVERLAY_UV_SWAP:
596 cmd |= OCMD_UV_SWAP;
597 break;
598 case I915_OVERLAY_Y_SWAP:
599 cmd |= OCMD_Y_SWAP;
600 break;
601 case I915_OVERLAY_Y_AND_UV_SWAP:
602 cmd |= OCMD_Y_AND_UV_SWAP;
603 break;
604 }
605 }
606
607 return cmd;
608}
609
610int intel_overlay_do_put_image(struct intel_overlay *overlay,
611 struct drm_gem_object *new_bo,
612 struct put_image_params *params)
613{
614 int ret, tmp_width;
615 struct overlay_registers *regs;
616 bool scale_changed = false;
617 struct drm_i915_gem_object *bo_priv = new_bo->driver_private;
618 struct drm_device *dev = overlay->dev;
619
620 BUG_ON(!mutex_is_locked(&dev->struct_mutex));
621 BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
622 BUG_ON(!overlay);
623
624 if (overlay->hw_wedged)
625 return -EBUSY;
626
627 ret = intel_overlay_release_old_vid(overlay);
628 if (ret != 0)
629 return ret;
630
631 ret = i915_gem_object_pin(new_bo, PAGE_SIZE);
632 if (ret != 0)
633 return ret;
634
635 ret = i915_gem_object_set_to_gtt_domain(new_bo, 0);
636 if (ret != 0)
637 goto out_unpin;
638
639 if (!overlay->active) {
640 regs = intel_overlay_map_regs_atomic(overlay);
641 if (!regs) {
642 ret = -ENOMEM;
643 goto out_unpin;
644 }
645 regs->OCONFIG = OCONF_CC_OUT_8BIT;
646 if (IS_I965GM(overlay->dev))
647 regs->OCONFIG |= OCONF_CSC_MODE_BT709;
648 regs->OCONFIG |= overlay->crtc->pipe == 0 ?
649 OCONF_PIPE_A : OCONF_PIPE_B;
650 intel_overlay_unmap_regs_atomic(overlay);
651
652 ret = intel_overlay_on(overlay);
653 if (ret != 0)
654 goto out_unpin;
655 }
656
657 regs = intel_overlay_map_regs_atomic(overlay);
658 if (!regs) {
659 ret = -ENOMEM;
660 goto out_unpin;
661 }
662
663 regs->DWINPOS = (params->dst_y << 16) | params->dst_x;
664 regs->DWINSZ = (params->dst_h << 16) | params->dst_w;
665
666 if (params->format & I915_OVERLAY_YUV_PACKED)
667 tmp_width = packed_width_bytes(params->format, params->src_w);
668 else
669 tmp_width = params->src_w;
670
671 regs->SWIDTH = params->src_w;
672 regs->SWIDTHSW = calc_swidthsw(overlay->dev,
673 params->offset_Y, tmp_width);
674 regs->SHEIGHT = params->src_h;
675 regs->OBUF_0Y = bo_priv->gtt_offset + params-> offset_Y;
676 regs->OSTRIDE = params->stride_Y;
677
678 if (params->format & I915_OVERLAY_YUV_PLANAR) {
679 int uv_hscale = uv_hsubsampling(params->format);
680 int uv_vscale = uv_vsubsampling(params->format);
681 u32 tmp_U, tmp_V;
682 regs->SWIDTH |= (params->src_w/uv_hscale) << 16;
683 tmp_U = calc_swidthsw(overlay->dev, params->offset_U,
684 params->src_w/uv_hscale);
685 tmp_V = calc_swidthsw(overlay->dev, params->offset_V,
686 params->src_w/uv_hscale);
687 regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16;
688 regs->SHEIGHT |= (params->src_h/uv_vscale) << 16;
689 regs->OBUF_0U = bo_priv->gtt_offset + params->offset_U;
690 regs->OBUF_0V = bo_priv->gtt_offset + params->offset_V;
691 regs->OSTRIDE |= params->stride_UV << 16;
692 }
693
694 scale_changed = update_scaling_factors(overlay, regs, params);
695
696 update_colorkey(overlay, regs);
697
698 regs->OCMD = overlay_cmd_reg(params);
699
700 intel_overlay_unmap_regs_atomic(overlay);
701
702 intel_overlay_continue(overlay, scale_changed);
703
704 overlay->old_vid_bo = overlay->vid_bo;
705 overlay->vid_bo = new_bo->driver_private;
706
707 return 0;
708
709out_unpin:
710 i915_gem_object_unpin(new_bo);
711 return ret;
712}
713
714int intel_overlay_switch_off(struct intel_overlay *overlay)
715{
716 int ret;
717 struct overlay_registers *regs;
718 struct drm_gem_object *obj;
719 struct drm_device *dev = overlay->dev;
720
721 BUG_ON(!mutex_is_locked(&dev->struct_mutex));
722 BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
723
724 if (!overlay->active)
725 return 0;
726
727 if (overlay->hw_wedged)
728 return -EBUSY;
729
730 ret = intel_overlay_release_old_vid(overlay);
731 if (ret != 0)
732 return ret;
733
734 regs = intel_overlay_map_regs_atomic(overlay);
735 regs->OCMD = 0;
736 intel_overlay_unmap_regs_atomic(overlay);
737
738 ret = intel_overlay_off(overlay);
739 /* never have the overlay hw on without showing a frame */
740 BUG_ON(!overlay->vid_bo);
741 obj = overlay->vid_bo->obj;
742
743 i915_gem_object_unpin(obj);
744 drm_gem_object_unreference(obj);
745 overlay->vid_bo = NULL;
746
747 overlay->crtc->overlay = NULL;
748 overlay->crtc = NULL;
749
750 return 0;
751}
752
753static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
754 struct intel_crtc *crtc)
755{
756 drm_i915_private_t *dev_priv = overlay->dev->dev_private;
757 u32 pipeconf;
758 int pipeconf_reg = (crtc->pipe == 0) ? PIPEACONF : PIPEBCONF;
759
760 if (!crtc->base.enabled || crtc->dpms_mode != DRM_MODE_DPMS_ON)
761 return -EINVAL;
762
763 pipeconf = I915_READ(pipeconf_reg);
764
765 /* can't use the overlay with double wide pipe */
766 if (!IS_I965G(overlay->dev) && pipeconf & PIPEACONF_DOUBLE_WIDE)
767 return -EINVAL;
768
769 return 0;
770}
771
772static void update_pfit_vscale_ratio(struct intel_overlay *overlay)
773{
774 struct drm_device *dev = overlay->dev;
775 drm_i915_private_t *dev_priv = dev->dev_private;
776 u32 ratio;
777 u32 pfit_control = I915_READ(PFIT_CONTROL);
778
779 /* XXX: This is not the same logic as in the xorg driver, but more in
780 * line with the intel documentation for the i965 */
781 if (!IS_I965G(dev) && (pfit_control & VERT_AUTO_SCALE)) {
782 ratio = I915_READ(PFIT_AUTO_RATIOS) >> PFIT_VERT_SCALE_SHIFT;
783 } else { /* on i965 use the PGM reg to read out the autoscaler values */
784 ratio = I915_READ(PFIT_PGM_RATIOS);
785 if (IS_I965G(dev))
786 ratio >>= PFIT_VERT_SCALE_SHIFT_965;
787 else
788 ratio >>= PFIT_VERT_SCALE_SHIFT;
789 }
790
791 overlay->pfit_vscale_ratio = ratio;
792}
793
794static int check_overlay_dst(struct intel_overlay *overlay,
795 struct drm_intel_overlay_put_image *rec)
796{
797 struct drm_display_mode *mode = &overlay->crtc->base.mode;
798
799 if ((rec->dst_x < mode->crtc_hdisplay)
800 && (rec->dst_x + rec->dst_width
801 <= mode->crtc_hdisplay)
802 && (rec->dst_y < mode->crtc_vdisplay)
803 && (rec->dst_y + rec->dst_height
804 <= mode->crtc_vdisplay))
805 return 0;
806 else
807 return -EINVAL;
808}
809
810static int check_overlay_scaling(struct put_image_params *rec)
811{
812 u32 tmp;
813
814 /* downscaling limit is 8.0 */
815 tmp = ((rec->src_scan_h << 16) / rec->dst_h) >> 16;
816 if (tmp > 7)
817 return -EINVAL;
818 tmp = ((rec->src_scan_w << 16) / rec->dst_w) >> 16;
819 if (tmp > 7)
820 return -EINVAL;
821
822 return 0;
823}
824
825static int check_overlay_src(struct drm_device *dev,
826 struct drm_intel_overlay_put_image *rec,
827 struct drm_gem_object *new_bo)
828{
829 u32 stride_mask;
830 int depth;
831 int uv_hscale = uv_hsubsampling(rec->flags);
832 int uv_vscale = uv_vsubsampling(rec->flags);
833 size_t tmp;
834
835 /* check src dimensions */
836 if (IS_845G(dev) || IS_I830(dev)) {
837 if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY
838 || rec->src_width > IMAGE_MAX_WIDTH_LEGACY)
839 return -EINVAL;
840 } else {
841 if (rec->src_height > IMAGE_MAX_HEIGHT
842 || rec->src_width > IMAGE_MAX_WIDTH)
843 return -EINVAL;
844 }
845 /* better safe than sorry, use 4 as the maximal subsampling ratio */
846 if (rec->src_height < N_VERT_Y_TAPS*4
847 || rec->src_width < N_HORIZ_Y_TAPS*4)
848 return -EINVAL;
849
850 /* check alingment constrains */
851 switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
852 case I915_OVERLAY_RGB:
853 /* not implemented */
854 return -EINVAL;
855 case I915_OVERLAY_YUV_PACKED:
856 depth = packed_depth_bytes(rec->flags);
857 if (uv_vscale != 1)
858 return -EINVAL;
859 if (depth < 0)
860 return depth;
861 /* ignore UV planes */
862 rec->stride_UV = 0;
863 rec->offset_U = 0;
864 rec->offset_V = 0;
865 /* check pixel alignment */
866 if (rec->offset_Y % depth)
867 return -EINVAL;
868 break;
869 case I915_OVERLAY_YUV_PLANAR:
870 if (uv_vscale < 0 || uv_hscale < 0)
871 return -EINVAL;
872 /* no offset restrictions for planar formats */
873 break;
874 default:
875 return -EINVAL;
876 }
877
878 if (rec->src_width % uv_hscale)
879 return -EINVAL;
880
881 /* stride checking */
882 stride_mask = 63;
883
884 if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
885 return -EINVAL;
886 if (IS_I965G(dev) && rec->stride_Y < 512)
887 return -EINVAL;
888
889 tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ?
890 4 : 8;
891 if (rec->stride_Y > tmp*1024 || rec->stride_UV > 2*1024)
892 return -EINVAL;
893
894 /* check buffer dimensions */
895 switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
896 case I915_OVERLAY_RGB:
897 case I915_OVERLAY_YUV_PACKED:
898 /* always 4 Y values per depth pixels */
899 if (packed_width_bytes(rec->flags, rec->src_width)
900 > rec->stride_Y)
901 return -EINVAL;
902
903 tmp = rec->stride_Y*rec->src_height;
904 if (rec->offset_Y + tmp > new_bo->size)
905 return -EINVAL;
906 break;
907 case I915_OVERLAY_YUV_PLANAR:
908 if (rec->src_width > rec->stride_Y)
909 return -EINVAL;
910 if (rec->src_width/uv_hscale > rec->stride_UV)
911 return -EINVAL;
912
913 tmp = rec->stride_Y*rec->src_height;
914 if (rec->offset_Y + tmp > new_bo->size)
915 return -EINVAL;
916 tmp = rec->stride_UV*rec->src_height;
917 tmp /= uv_vscale;
918 if (rec->offset_U + tmp > new_bo->size
919 || rec->offset_V + tmp > new_bo->size)
920 return -EINVAL;
921 break;
922 }
923
924 return 0;
925}
926
927int intel_overlay_put_image(struct drm_device *dev, void *data,
928 struct drm_file *file_priv)
929{
930 struct drm_intel_overlay_put_image *put_image_rec = data;
931 drm_i915_private_t *dev_priv = dev->dev_private;
932 struct intel_overlay *overlay;
933 struct drm_mode_object *drmmode_obj;
934 struct intel_crtc *crtc;
935 struct drm_gem_object *new_bo;
936 struct put_image_params *params;
937 int ret;
938
939 if (!dev_priv) {
940 DRM_ERROR("called with no initialization\n");
941 return -EINVAL;
942 }
943
944 overlay = dev_priv->overlay;
945 if (!overlay) {
946 DRM_DEBUG("userspace bug: no overlay\n");
947 return -ENODEV;
948 }
949
950 if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) {
951 mutex_lock(&dev->mode_config.mutex);
952 mutex_lock(&dev->struct_mutex);
953
954 ret = intel_overlay_switch_off(overlay);
955
956 mutex_unlock(&dev->struct_mutex);
957 mutex_unlock(&dev->mode_config.mutex);
958
959 return ret;
960 }
961
962 params = kmalloc(sizeof(struct put_image_params), GFP_KERNEL);
963 if (!params)
964 return -ENOMEM;
965
966 drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id,
967 DRM_MODE_OBJECT_CRTC);
968 if (!drmmode_obj)
969 return -ENOENT;
970 crtc = to_intel_crtc(obj_to_crtc(drmmode_obj));
971
972 new_bo = drm_gem_object_lookup(dev, file_priv,
973 put_image_rec->bo_handle);
974 if (!new_bo)
975 return -ENOENT;
976
977 mutex_lock(&dev->mode_config.mutex);
978 mutex_lock(&dev->struct_mutex);
979
980 if (overlay->crtc != crtc) {
981 struct drm_display_mode *mode = &crtc->base.mode;
982 ret = intel_overlay_switch_off(overlay);
983 if (ret != 0)
984 goto out_unlock;
985
986 ret = check_overlay_possible_on_crtc(overlay, crtc);
987 if (ret != 0)
988 goto out_unlock;
989
990 overlay->crtc = crtc;
991 crtc->overlay = overlay;
992
993 if (intel_panel_fitter_pipe(dev) == crtc->pipe
994 /* and line to wide, i.e. one-line-mode */
995 && mode->hdisplay > 1024) {
996 overlay->pfit_active = 1;
997 update_pfit_vscale_ratio(overlay);
998 } else
999 overlay->pfit_active = 0;
1000 }
1001
1002 ret = check_overlay_dst(overlay, put_image_rec);
1003 if (ret != 0)
1004 goto out_unlock;
1005
1006 if (overlay->pfit_active) {
1007 params->dst_y = ((((u32)put_image_rec->dst_y) << 12) /
1008 overlay->pfit_vscale_ratio);
1009 /* shifting right rounds downwards, so add 1 */
1010 params->dst_h = ((((u32)put_image_rec->dst_height) << 12) /
1011 overlay->pfit_vscale_ratio) + 1;
1012 } else {
1013 params->dst_y = put_image_rec->dst_y;
1014 params->dst_h = put_image_rec->dst_height;
1015 }
1016 params->dst_x = put_image_rec->dst_x;
1017 params->dst_w = put_image_rec->dst_width;
1018
1019 params->src_w = put_image_rec->src_width;
1020 params->src_h = put_image_rec->src_height;
1021 params->src_scan_w = put_image_rec->src_scan_width;
1022 params->src_scan_h = put_image_rec->src_scan_height;
1023 if (params->src_scan_h > params->src_h
1024 || params->src_scan_w > params->src_w) {
1025 ret = -EINVAL;
1026 goto out_unlock;
1027 }
1028
1029 ret = check_overlay_src(dev, put_image_rec, new_bo);
1030 if (ret != 0)
1031 goto out_unlock;
1032 params->format = put_image_rec->flags & ~I915_OVERLAY_FLAGS_MASK;
1033 params->stride_Y = put_image_rec->stride_Y;
1034 params->stride_UV = put_image_rec->stride_UV;
1035 params->offset_Y = put_image_rec->offset_Y;
1036 params->offset_U = put_image_rec->offset_U;
1037 params->offset_V = put_image_rec->offset_V;
1038
1039 /* Check scaling after src size to prevent a divide-by-zero. */
1040 ret = check_overlay_scaling(params);
1041 if (ret != 0)
1042 goto out_unlock;
1043
1044 ret = intel_overlay_do_put_image(overlay, new_bo, params);
1045 if (ret != 0)
1046 goto out_unlock;
1047
1048 mutex_unlock(&dev->struct_mutex);
1049 mutex_unlock(&dev->mode_config.mutex);
1050
1051 kfree(params);
1052
1053 return 0;
1054
1055out_unlock:
1056 mutex_unlock(&dev->struct_mutex);
1057 mutex_unlock(&dev->mode_config.mutex);
1058 drm_gem_object_unreference(new_bo);
1059 kfree(params);
1060
1061 return ret;
1062}
1063
1064static void update_reg_attrs(struct intel_overlay *overlay,
1065 struct overlay_registers *regs)
1066{
1067 regs->OCLRC0 = (overlay->contrast << 18) | (overlay->brightness & 0xff);
1068 regs->OCLRC1 = overlay->saturation;
1069}
1070
1071static bool check_gamma_bounds(u32 gamma1, u32 gamma2)
1072{
1073 int i;
1074
1075 if (gamma1 & 0xff000000 || gamma2 & 0xff000000)
1076 return false;
1077
1078 for (i = 0; i < 3; i++) {
1079 if (((gamma1 >> i * 8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
1080 return false;
1081 }
1082
1083 return true;
1084}
1085
1086static bool check_gamma5_errata(u32 gamma5)
1087{
1088 int i;
1089
1090 for (i = 0; i < 3; i++) {
1091 if (((gamma5 >> i*8) & 0xff) == 0x80)
1092 return false;
1093 }
1094
1095 return true;
1096}
1097
1098static int check_gamma(struct drm_intel_overlay_attrs *attrs)
1099{
1100 if (!check_gamma_bounds(0, attrs->gamma0)
1101 || !check_gamma_bounds(attrs->gamma0, attrs->gamma1)
1102 || !check_gamma_bounds(attrs->gamma1, attrs->gamma2)
1103 || !check_gamma_bounds(attrs->gamma2, attrs->gamma3)
1104 || !check_gamma_bounds(attrs->gamma3, attrs->gamma4)
1105 || !check_gamma_bounds(attrs->gamma4, attrs->gamma5)
1106 || !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
1107 return -EINVAL;
1108 if (!check_gamma5_errata(attrs->gamma5))
1109 return -EINVAL;
1110 return 0;
1111}
1112
1113int intel_overlay_attrs(struct drm_device *dev, void *data,
1114 struct drm_file *file_priv)
1115{
1116 struct drm_intel_overlay_attrs *attrs = data;
1117 drm_i915_private_t *dev_priv = dev->dev_private;
1118 struct intel_overlay *overlay;
1119 struct overlay_registers *regs;
1120 int ret;
1121
1122 if (!dev_priv) {
1123 DRM_ERROR("called with no initialization\n");
1124 return -EINVAL;
1125 }
1126
1127 overlay = dev_priv->overlay;
1128 if (!overlay) {
1129 DRM_DEBUG("userspace bug: no overlay\n");
1130 return -ENODEV;
1131 }
1132
1133 mutex_lock(&dev->mode_config.mutex);
1134 mutex_lock(&dev->struct_mutex);
1135
1136 if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) {
1137 attrs->color_key = overlay->color_key;
1138 attrs->brightness = overlay->brightness;
1139 attrs->contrast = overlay->contrast;
1140 attrs->saturation = overlay->saturation;
1141
1142 if (IS_I9XX(dev)) {
1143 attrs->gamma0 = I915_READ(OGAMC0);
1144 attrs->gamma1 = I915_READ(OGAMC1);
1145 attrs->gamma2 = I915_READ(OGAMC2);
1146 attrs->gamma3 = I915_READ(OGAMC3);
1147 attrs->gamma4 = I915_READ(OGAMC4);
1148 attrs->gamma5 = I915_READ(OGAMC5);
1149 }
1150 ret = 0;
1151 } else {
1152 overlay->color_key = attrs->color_key;
1153 if (attrs->brightness >= -128 && attrs->brightness <= 127) {
1154 overlay->brightness = attrs->brightness;
1155 } else {
1156 ret = -EINVAL;
1157 goto out_unlock;
1158 }
1159 if (attrs->contrast <= 255) {
1160 overlay->contrast = attrs->contrast;
1161 } else {
1162 ret = -EINVAL;
1163 goto out_unlock;
1164 }
1165 if (attrs->saturation <= 1023) {
1166 overlay->saturation = attrs->saturation;
1167 } else {
1168 ret = -EINVAL;
1169 goto out_unlock;
1170 }
1171
1172 regs = intel_overlay_map_regs_atomic(overlay);
1173 if (!regs) {
1174 ret = -ENOMEM;
1175 goto out_unlock;
1176 }
1177
1178 update_reg_attrs(overlay, regs);
1179
1180 intel_overlay_unmap_regs_atomic(overlay);
1181
1182 if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) {
1183 if (!IS_I9XX(dev)) {
1184 ret = -EINVAL;
1185 goto out_unlock;
1186 }
1187
1188 if (overlay->active) {
1189 ret = -EBUSY;
1190 goto out_unlock;
1191 }
1192
1193 ret = check_gamma(attrs);
1194 if (ret != 0)
1195 goto out_unlock;
1196
1197 I915_WRITE(OGAMC0, attrs->gamma0);
1198 I915_WRITE(OGAMC1, attrs->gamma1);
1199 I915_WRITE(OGAMC2, attrs->gamma2);
1200 I915_WRITE(OGAMC3, attrs->gamma3);
1201 I915_WRITE(OGAMC4, attrs->gamma4);
1202 I915_WRITE(OGAMC5, attrs->gamma5);
1203 }
1204 ret = 0;
1205 }
1206
1207out_unlock:
1208 mutex_unlock(&dev->struct_mutex);
1209 mutex_unlock(&dev->mode_config.mutex);
1210
1211 return ret;
1212}
1213
1214void intel_setup_overlay(struct drm_device *dev)
1215{
1216 drm_i915_private_t *dev_priv = dev->dev_private;
1217 struct intel_overlay *overlay;
1218 struct drm_gem_object *reg_bo;
1219 struct overlay_registers *regs;
1220 int ret;
1221
1222 if (!OVERLAY_EXISTS(dev))
1223 return;
1224
1225 overlay = kzalloc(sizeof(struct intel_overlay), GFP_KERNEL);
1226 if (!overlay)
1227 return;
1228 overlay->dev = dev;
1229
1230 reg_bo = drm_gem_object_alloc(dev, PAGE_SIZE);
1231 if (!reg_bo)
1232 goto out_free;
1233 overlay->reg_bo = reg_bo->driver_private;
1234
1235 if (OVERLAY_NONPHYSICAL(dev)) {
1236 ret = i915_gem_object_pin(reg_bo, PAGE_SIZE);
1237 if (ret) {
1238 DRM_ERROR("failed to pin overlay register bo\n");
1239 goto out_free_bo;
1240 }
1241 overlay->flip_addr = overlay->reg_bo->gtt_offset;
1242 } else {
1243 ret = i915_gem_attach_phys_object(dev, reg_bo,
1244 I915_GEM_PHYS_OVERLAY_REGS);
1245 if (ret) {
1246 DRM_ERROR("failed to attach phys overlay regs\n");
1247 goto out_free_bo;
1248 }
1249 overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr;
1250 }
1251
1252 /* init all values */
1253 overlay->color_key = 0x0101fe;
1254 overlay->brightness = -19;
1255 overlay->contrast = 75;
1256 overlay->saturation = 146;
1257
1258 regs = intel_overlay_map_regs_atomic(overlay);
1259 if (!regs)
1260 goto out_free_bo;
1261
1262 memset(regs, 0, sizeof(struct overlay_registers));
1263 update_polyphase_filter(regs);
1264
1265 update_reg_attrs(overlay, regs);
1266
1267 intel_overlay_unmap_regs_atomic(overlay);
1268
1269 dev_priv->overlay = overlay;
1270 DRM_INFO("initialized overlay support\n");
1271 return;
1272
1273out_free_bo:
1274 drm_gem_object_unreference(reg_bo);
1275out_free:
1276 kfree(overlay);
1277 return;
1278}
1279
1280void intel_cleanup_overlay(struct drm_device *dev)
1281{
1282 drm_i915_private_t *dev_priv = dev->dev_private;
1283
1284 if (dev_priv->overlay) {
1285 /* The bo's should be free'd by the generic code already.
1286 * Furthermore modesetting teardown happens beforehand so the
1287 * hardware should be off already */
1288 BUG_ON(dev_priv->overlay->active);
1289
1290 kfree(dev_priv->overlay);
1291 }
1292}