drm/i915: implement drmmode overlay support v4
[safe/jmp/linux-2.6] / drivers / gpu / drm / i915 / intel_overlay.c
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 */
117 struct 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
178 static 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
200 static 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 */
216 static 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 */
247 static 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
284 static 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 */
292 static 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 */
326         /* this is not done in userspace!
327         BEGIN_LP_RING(6);
328         OUT_RING(MI_FLUSH);
329         OUT_RING(MI_NOOP);
330         OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
331         OUT_RING(flip_addr);
332         OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
333         OUT_RING(MI_NOOP);
334         ADVANCE_LP_RING();
335
336         ret = i915_lp_ring_sync(dev);
337         if (ret != 0) {
338                 DRM_ERROR("intel overlay: ring sync failed, hw likely wedged\n");
339                 overlay->hw_wedged = 1;
340                 return ret;
341         }*/
342
343         overlay->active = 0;
344
345         return ret;
346 }
347
348 /* wait for pending overlay flip and release old frame */
349 static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
350 {
351         int ret;
352         struct drm_gem_object *obj;
353
354         ret = intel_overlay_wait_flip(overlay);
355         if (ret != 0)
356                 return ret;
357
358         if (!overlay->old_vid_bo)
359                 return 0;
360
361         obj = overlay->old_vid_bo->obj;
362         i915_gem_object_unpin(obj);
363         drm_gem_object_unreference(obj);
364         overlay->old_vid_bo = NULL;
365
366         return 0;
367 }
368
369 struct put_image_params {
370         int format;
371         short dst_x;
372         short dst_y;
373         short dst_w;
374         short dst_h;
375         short src_w;
376         short src_scan_h;
377         short src_scan_w;
378         short src_h;
379         short stride_Y;
380         short stride_UV;
381         int offset_Y;
382         int offset_U;
383         int offset_V;
384 };
385
386 static int packed_depth_bytes(u32 format)
387 {
388         switch (format & I915_OVERLAY_DEPTH_MASK) {
389                 case I915_OVERLAY_YUV422:
390                         return 4;
391                 case I915_OVERLAY_YUV411:
392                         /* return 6; not implemented */
393                 default:
394                         return -EINVAL;
395         }
396 }
397
398 static int packed_width_bytes(u32 format, short width)
399 {
400         switch (format & I915_OVERLAY_DEPTH_MASK) {
401                 case I915_OVERLAY_YUV422:
402                         return width << 1;
403                 default:
404                         return -EINVAL;
405         }
406 }
407
408 static int uv_hsubsampling(u32 format)
409 {
410         switch (format & I915_OVERLAY_DEPTH_MASK) {
411                 case I915_OVERLAY_YUV422:
412                 case I915_OVERLAY_YUV420:
413                         return 2;
414                 case I915_OVERLAY_YUV411:
415                 case I915_OVERLAY_YUV410:
416                         return 4;
417                 default:
418                         return -EINVAL;
419         }
420 }
421
422 static int uv_vsubsampling(u32 format)
423 {
424         switch (format & I915_OVERLAY_DEPTH_MASK) {
425                 case I915_OVERLAY_YUV420:
426                 case I915_OVERLAY_YUV410:
427                         return 2;
428                 case I915_OVERLAY_YUV422:
429                 case I915_OVERLAY_YUV411:
430                         return 1;
431                 default:
432                         return -EINVAL;
433         }
434 }
435
436 static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width)
437 {
438         u32 mask, shift, ret;
439         if (IS_I9XX(dev)) {
440                 mask = 0x3f;
441                 shift = 6;
442         } else {
443                 mask = 0x1f;
444                 shift = 5;
445         }
446         ret = ((offset + width + mask) >> shift) - (offset >> shift);
447         if (IS_I9XX(dev))
448                 ret <<= 1;
449         ret -=1;
450         return ret << 2;
451 }
452
453 static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = {
454         0x3000, 0xb4a0, 0x1930, 0x1920, 0xb4a0,
455         0x3000, 0xb500, 0x19d0, 0x1880, 0xb440,
456         0x3000, 0xb540, 0x1a88, 0x2f80, 0xb3e0,
457         0x3000, 0xb580, 0x1b30, 0x2e20, 0xb380,
458         0x3000, 0xb5c0, 0x1bd8, 0x2cc0, 0xb320,
459         0x3020, 0xb5e0, 0x1c60, 0x2b80, 0xb2c0,
460         0x3020, 0xb5e0, 0x1cf8, 0x2a20, 0xb260,
461         0x3020, 0xb5e0, 0x1d80, 0x28e0, 0xb200,
462         0x3020, 0xb5c0, 0x1e08, 0x3f40, 0xb1c0,
463         0x3020, 0xb580, 0x1e78, 0x3ce0, 0xb160,
464         0x3040, 0xb520, 0x1ed8, 0x3aa0, 0xb120,
465         0x3040, 0xb4a0, 0x1f30, 0x3880, 0xb0e0,
466         0x3040, 0xb400, 0x1f78, 0x3680, 0xb0a0,
467         0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060,
468         0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040,
469         0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020,
470         0xb000, 0x3000, 0x0800, 0x3000, 0xb000};
471 static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
472         0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60,
473         0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40,
474         0xb040, 0x1b20, 0x29e0, 0xb060, 0x1bd8, 0x2880,
475         0xb080, 0x1c88, 0x3e60, 0xb0a0, 0x1d28, 0x3c00,
476         0xb0c0, 0x1db8, 0x39e0, 0xb0e0, 0x1e40, 0x37e0,
477         0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0,
478         0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240,
479         0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0,
480         0x3000, 0x0800, 0x3000};
481
482 static void update_polyphase_filter(struct overlay_registers *regs)
483 {
484         memcpy(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs));
485         memcpy(regs->UV_HCOEFS, uv_static_hcoeffs, sizeof(uv_static_hcoeffs));
486 }
487
488 static bool update_scaling_factors(struct intel_overlay *overlay,
489                                    struct overlay_registers *regs,
490                                    struct put_image_params *params)
491 {
492         /* fixed point with a 12 bit shift */
493         u32 xscale, yscale, xscale_UV, yscale_UV;
494 #define FP_SHIFT 12
495 #define FRACT_MASK 0xfff
496         bool scale_changed = false;
497         int uv_hscale = uv_hsubsampling(params->format);
498         int uv_vscale = uv_vsubsampling(params->format);
499
500         if (params->dst_w > 1)
501                 xscale = ((params->src_scan_w - 1) << FP_SHIFT)
502                         /(params->dst_w);
503         else
504                 xscale = 1 << FP_SHIFT;
505
506         if (params->dst_h > 1)
507                 yscale = ((params->src_scan_h - 1) << FP_SHIFT)
508                         /(params->dst_h);
509         else
510                 yscale = 1 << FP_SHIFT;
511
512         /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
513                 xscale_UV = xscale/uv_hscale;
514                 yscale_UV = yscale/uv_vscale;
515                 /* make the Y scale to UV scale ratio an exact multiply */
516                 xscale = xscale_UV * uv_hscale;
517                 yscale = yscale_UV * uv_vscale;
518         /*} else {
519                 xscale_UV = 0;
520                 yscale_UV = 0;
521         }*/
522
523         if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)
524                 scale_changed = true;
525         overlay->old_xscale = xscale;
526         overlay->old_yscale = yscale;
527
528         regs->YRGBSCALE = ((yscale & FRACT_MASK) << 20)
529                 | ((xscale >> FP_SHIFT) << 16)
530                 | ((xscale & FRACT_MASK) << 3);
531         regs->UVSCALE = ((yscale_UV & FRACT_MASK) << 20)
532                 | ((xscale_UV >> FP_SHIFT) << 16)
533                 | ((xscale_UV & FRACT_MASK) << 3);
534         regs->UVSCALEV = ((yscale >> FP_SHIFT) << 16)
535                 | ((yscale_UV >> FP_SHIFT) << 0);
536
537         if (scale_changed)
538                 update_polyphase_filter(regs);
539
540         return scale_changed;
541 }
542
543 static void update_colorkey(struct intel_overlay *overlay,
544                             struct overlay_registers *regs)
545 {
546         u32 key = overlay->color_key;
547         switch (overlay->crtc->base.fb->bits_per_pixel) {
548                 case 8:
549                         regs->DCLRKV = 0;
550                         regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;
551                 case 16:
552                         if (overlay->crtc->base.fb->depth == 15) {
553                                 regs->DCLRKV = RGB15_TO_COLORKEY(key);
554                                 regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;
555                         } else {
556                                 regs->DCLRKV = RGB16_TO_COLORKEY(key);
557                                 regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;
558                         }
559                 case 24:
560                 case 32:
561                         regs->DCLRKV = key;
562                         regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;
563         }
564 }
565
566 static u32 overlay_cmd_reg(struct put_image_params *params)
567 {
568         u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0;
569
570         if (params->format & I915_OVERLAY_YUV_PLANAR) {
571                 switch (params->format & I915_OVERLAY_DEPTH_MASK) {
572                         case I915_OVERLAY_YUV422:
573                                 cmd |= OCMD_YUV_422_PLANAR;
574                                 break;
575                         case I915_OVERLAY_YUV420:
576                                 cmd |= OCMD_YUV_420_PLANAR;
577                                 break;
578                         case I915_OVERLAY_YUV411:
579                         case I915_OVERLAY_YUV410:
580                                 cmd |= OCMD_YUV_410_PLANAR;
581                                 break;
582                 }
583         } else { /* YUV packed */
584                 switch (params->format & I915_OVERLAY_DEPTH_MASK) {
585                         case I915_OVERLAY_YUV422:
586                                 cmd |= OCMD_YUV_422_PACKED;
587                                 break;
588                         case I915_OVERLAY_YUV411:
589                                 cmd |= OCMD_YUV_411_PACKED;
590                                 break;
591                 }
592
593                 switch (params->format & I915_OVERLAY_SWAP_MASK) {
594                         case I915_OVERLAY_NO_SWAP:
595                                 break;
596                         case I915_OVERLAY_UV_SWAP:
597                                 cmd |= OCMD_UV_SWAP;
598                                 break;
599                         case I915_OVERLAY_Y_SWAP:
600                                 cmd |= OCMD_Y_SWAP;
601                                 break;
602                         case I915_OVERLAY_Y_AND_UV_SWAP:
603                                 cmd |= OCMD_Y_AND_UV_SWAP;
604                                 break;
605                 }
606         }
607
608         return cmd;
609 }
610
611 int intel_overlay_do_put_image(struct intel_overlay *overlay,
612                                struct drm_gem_object *new_bo,
613                                struct put_image_params *params)
614 {
615         int ret, tmp_width;
616         struct overlay_registers *regs;
617         bool scale_changed = false;
618         struct drm_i915_gem_object *bo_priv = new_bo->driver_private;
619         struct drm_device *dev = overlay->dev;
620
621         BUG_ON(!mutex_is_locked(&dev->struct_mutex));
622         BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
623         BUG_ON(!overlay);
624
625         if (overlay->hw_wedged)
626                 return -EBUSY;
627
628         ret = intel_overlay_release_old_vid(overlay);
629         if (ret != 0)
630                 return ret;
631
632         ret = i915_gem_object_pin(new_bo, PAGE_SIZE);
633         if (ret != 0)
634                 return ret;
635
636         ret = i915_gem_object_set_to_gtt_domain(new_bo, 0);
637         if (ret != 0)
638                 goto out_unpin;
639
640         if (!overlay->active) {
641                 regs = intel_overlay_map_regs_atomic(overlay);
642                 if (!regs) {
643                         ret = -ENOMEM;
644                         goto out_unpin;
645                 }
646                 regs->OCONFIG = OCONF_CC_OUT_8BIT;
647                 if (IS_I965GM(overlay->dev))
648                         regs->OCONFIG |= OCONF_CSC_MODE_BT709;
649                 regs->OCONFIG |= overlay->crtc->pipe == 0 ?
650                         OCONF_PIPE_A : OCONF_PIPE_B;
651                 intel_overlay_unmap_regs_atomic(overlay);
652
653                 ret = intel_overlay_on(overlay);
654                 if (ret != 0)
655                         goto out_unpin;
656         }
657
658         regs = intel_overlay_map_regs_atomic(overlay);
659         if (!regs) {
660                 ret = -ENOMEM;
661                 goto out_unpin;
662         }
663
664         regs->DWINPOS = (params->dst_y << 16) | params->dst_x;
665         regs->DWINSZ = (params->dst_h << 16) | params->dst_w;
666
667         if (params->format & I915_OVERLAY_YUV_PACKED)
668                 tmp_width = packed_width_bytes(params->format, params->src_w);
669         else
670                 tmp_width = params->src_w;
671
672         regs->SWIDTH = params->src_w;
673         regs->SWIDTHSW = calc_swidthsw(overlay->dev,
674                         params->offset_Y, tmp_width);
675         regs->SHEIGHT = params->src_h;
676         regs->OBUF_0Y = bo_priv->gtt_offset + params-> offset_Y;
677         regs->OSTRIDE = params->stride_Y;
678
679         if (params->format & I915_OVERLAY_YUV_PLANAR) {
680                 int uv_hscale = uv_hsubsampling(params->format);
681                 int uv_vscale = uv_vsubsampling(params->format);
682                 u32 tmp_U, tmp_V;
683                 regs->SWIDTH |= (params->src_w/uv_hscale) << 16;
684                 tmp_U = calc_swidthsw(overlay->dev, params->offset_U,
685                                 params->src_w/uv_hscale);
686                 tmp_V = calc_swidthsw(overlay->dev, params->offset_V,
687                                 params->src_w/uv_hscale);
688                 regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16;
689                 regs->SHEIGHT |= (params->src_h/uv_vscale) << 16;
690                 regs->OBUF_0U = bo_priv->gtt_offset + params->offset_U;
691                 regs->OBUF_0V = bo_priv->gtt_offset + params->offset_V;
692                 regs->OSTRIDE |= params->stride_UV << 16;
693         }
694
695         scale_changed = update_scaling_factors(overlay, regs, params);
696
697         update_colorkey(overlay, regs);
698
699         regs->OCMD = overlay_cmd_reg(params);
700
701         intel_overlay_unmap_regs_atomic(overlay);
702
703         intel_overlay_continue(overlay, scale_changed);
704
705         overlay->old_vid_bo = overlay->vid_bo;
706         overlay->vid_bo = new_bo->driver_private;
707
708         return 0;
709
710 out_unpin:
711         i915_gem_object_unpin(new_bo);
712         return ret;
713 }
714
715 int intel_overlay_switch_off(struct intel_overlay *overlay)
716 {
717         int ret;
718         struct overlay_registers *regs;
719         struct drm_gem_object *obj;
720         struct drm_device *dev = overlay->dev;
721
722         BUG_ON(!mutex_is_locked(&dev->struct_mutex));
723         BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
724
725         if (!overlay->active)
726                 return 0;
727
728         if (overlay->hw_wedged)
729                 return -EBUSY;
730
731         ret = intel_overlay_release_old_vid(overlay);
732         if (ret != 0)
733                 return ret;
734
735         regs = intel_overlay_map_regs_atomic(overlay);
736         regs->OCMD = 0;
737         intel_overlay_unmap_regs_atomic(overlay);
738
739         ret = intel_overlay_off(overlay);
740         /* never have the overlay hw on without showing a frame */
741         BUG_ON(!overlay->vid_bo);
742         obj = overlay->vid_bo->obj;
743
744         i915_gem_object_unpin(obj);
745         drm_gem_object_unreference(obj);
746         overlay->vid_bo = NULL;
747
748         overlay->crtc->overlay = NULL;
749         overlay->crtc = NULL;
750
751         return 0;
752 }
753
754 static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
755                                           struct intel_crtc *crtc)
756 {
757         drm_i915_private_t *dev_priv = overlay->dev->dev_private;
758         u32 pipeconf;
759         int pipeconf_reg = (crtc->pipe == 0) ? PIPEACONF : PIPEBCONF;
760
761         if (!crtc->base.enabled || crtc->dpms_mode != DRM_MODE_DPMS_ON)
762                 return -EINVAL;
763
764         pipeconf = I915_READ(pipeconf_reg);
765
766         /* can't use the overlay with double wide pipe */
767         if (!IS_I965G(overlay->dev) && pipeconf & PIPEACONF_DOUBLE_WIDE)
768                 return -EINVAL;
769
770         return 0;
771 }
772
773 static void update_pfit_vscale_ratio(struct intel_overlay *overlay)
774 {
775         struct drm_device *dev = overlay->dev;
776         drm_i915_private_t *dev_priv = dev->dev_private;
777         u32 ratio;
778         u32 pfit_control = I915_READ(PFIT_CONTROL);
779
780         /* XXX: This is not the same logic as in the xorg driver, but more in
781          * line with the intel documentation for the i965 */
782         if (!IS_I965G(dev) && (pfit_control & VERT_AUTO_SCALE)) {
783                 ratio = I915_READ(PFIT_AUTO_RATIOS) >> PFIT_VERT_SCALE_SHIFT;
784         } else { /* on i965 use the PGM reg to read out the autoscaler values */
785                 ratio = I915_READ(PFIT_PGM_RATIOS);
786                 if (IS_I965G(dev))
787                         ratio >>= PFIT_VERT_SCALE_SHIFT_965;
788                 else
789                         ratio >>= PFIT_VERT_SCALE_SHIFT;
790         }
791
792         overlay->pfit_vscale_ratio = ratio;
793 }
794
795 static int check_overlay_dst(struct intel_overlay *overlay,
796                              struct drm_intel_overlay_put_image *rec)
797 {
798         struct drm_display_mode *mode = &overlay->crtc->base.mode;
799
800         if ((rec->dst_x < mode->crtc_hdisplay)
801             && (rec->dst_x + rec->dst_width
802                     <= mode->crtc_hdisplay)
803             && (rec->dst_y < mode->crtc_vdisplay)
804             && (rec->dst_y + rec->dst_height
805                     <= mode->crtc_vdisplay))
806                 return 0;
807         else
808                 return -EINVAL;
809 }
810
811 static int check_overlay_scaling(struct put_image_params *rec)
812 {
813         u32 tmp;
814
815         /* downscaling limit is 8.0 */
816         tmp = ((rec->src_scan_h << 16) / rec->dst_h) >> 16;
817         if (tmp > 7)
818                 return -EINVAL;
819         tmp = ((rec->src_scan_w << 16) / rec->dst_w) >> 16;
820         if (tmp > 7)
821                 return -EINVAL;
822
823         return 0;
824 }
825
826 static int check_overlay_src(struct drm_device *dev,
827                              struct drm_intel_overlay_put_image *rec,
828                              struct drm_gem_object *new_bo)
829 {
830         u32 stride_mask;
831         int depth;
832         int uv_hscale = uv_hsubsampling(rec->flags);
833         int uv_vscale = uv_vsubsampling(rec->flags);
834         size_t tmp;
835
836         /* check src dimensions */
837         if (IS_845G(dev) || IS_I830(dev)) {
838                 if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY
839                     || rec->src_width > IMAGE_MAX_WIDTH_LEGACY)
840                         return -EINVAL;
841         } else {
842                 if (rec->src_height > IMAGE_MAX_HEIGHT
843                     || rec->src_width > IMAGE_MAX_WIDTH)
844                         return -EINVAL;
845         }
846         /* better safe than sorry, use 4 as the maximal subsampling ratio */
847         if (rec->src_height < N_VERT_Y_TAPS*4
848             || rec->src_width < N_HORIZ_Y_TAPS*4)
849                 return -EINVAL;
850
851         /* check alingment constrains */
852         switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
853                 case I915_OVERLAY_RGB:
854                         /* not implemented */
855                         return -EINVAL;
856                 case I915_OVERLAY_YUV_PACKED:
857                         depth = packed_depth_bytes(rec->flags);
858                         if (uv_vscale != 1)
859                                 return -EINVAL;
860                         if (depth < 0)
861                                 return depth;
862                         /* ignore UV planes */
863                         rec->stride_UV = 0;
864                         rec->offset_U = 0;
865                         rec->offset_V = 0;
866                         /* check pixel alignment */
867                         if (rec->offset_Y % depth)
868                                 return -EINVAL;
869                         break;
870                 case I915_OVERLAY_YUV_PLANAR:
871                         if (uv_vscale < 0 || uv_hscale < 0)
872                                 return -EINVAL;
873                         /* no offset restrictions for planar formats */
874                         break;
875                 default:
876                         return -EINVAL;
877         }
878
879         if (rec->src_width % uv_hscale)
880                 return -EINVAL;
881
882         /* stride checking */
883         stride_mask = 63;
884
885         if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
886                 return -EINVAL;
887         if (IS_I965G(dev) && rec->stride_Y < 512)
888                 return -EINVAL;
889
890         tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ?
891                 4 : 8;
892         if (rec->stride_Y > tmp*1024 || rec->stride_UV > 2*1024)
893                 return -EINVAL;
894
895         /* check buffer dimensions */
896         switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
897                 case I915_OVERLAY_RGB:
898                 case I915_OVERLAY_YUV_PACKED:
899                         /* always 4 Y values per depth pixels */
900                         if (packed_width_bytes(rec->flags, rec->src_width)
901                                         > rec->stride_Y)
902                                 return -EINVAL;
903
904                         tmp = rec->stride_Y*rec->src_height;
905                         if (rec->offset_Y + tmp > new_bo->size)
906                                 return -EINVAL;
907                         break;
908                 case I915_OVERLAY_YUV_PLANAR:
909                         if (rec->src_width > rec->stride_Y)
910                                 return -EINVAL;
911                         if (rec->src_width/uv_hscale > rec->stride_UV)
912                                 return -EINVAL;
913
914                         tmp = rec->stride_Y*rec->src_height;
915                         if (rec->offset_Y + tmp > new_bo->size)
916                                 return -EINVAL;
917                         tmp = rec->stride_UV*rec->src_height;
918                         tmp /= uv_vscale;
919                         if (rec->offset_U + tmp > new_bo->size
920                             || rec->offset_V + tmp > new_bo->size)
921                                 return -EINVAL;
922                         break;
923         }
924
925         return 0;
926 }
927
928 int intel_overlay_put_image(struct drm_device *dev, void *data,
929                             struct drm_file *file_priv)
930 {
931         struct drm_intel_overlay_put_image *put_image_rec = data;
932         drm_i915_private_t *dev_priv = dev->dev_private;
933         struct intel_overlay *overlay;
934         struct drm_mode_object *drmmode_obj;
935         struct intel_crtc *crtc;
936         struct drm_gem_object *new_bo;
937         struct put_image_params *params;
938         int ret;
939
940         if (!dev_priv) {
941                 DRM_ERROR("called with no initialization\n");
942                 return -EINVAL;
943         }
944
945         overlay = dev_priv->overlay;
946         if (!overlay) {
947                 DRM_DEBUG("userspace bug: no overlay\n");
948                 return -ENODEV;
949         }
950
951         if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) {
952                 mutex_lock(&dev->mode_config.mutex);
953                 mutex_lock(&dev->struct_mutex);
954
955                 ret = intel_overlay_switch_off(overlay);
956
957                 mutex_unlock(&dev->struct_mutex);
958                 mutex_unlock(&dev->mode_config.mutex);
959
960                 return ret;
961         }
962
963         params = kmalloc(sizeof(struct put_image_params), GFP_KERNEL);
964         if (!params)
965                 return -ENOMEM;
966
967         drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id,
968                         DRM_MODE_OBJECT_CRTC);
969         if (!drmmode_obj)
970                 return -ENOENT;
971         crtc = to_intel_crtc(obj_to_crtc(drmmode_obj));
972
973         new_bo = drm_gem_object_lookup(dev, file_priv,
974                         put_image_rec->bo_handle);
975         if (!new_bo)
976                 return -ENOENT;
977
978         mutex_lock(&dev->mode_config.mutex);
979         mutex_lock(&dev->struct_mutex);
980
981         if (overlay->crtc != crtc) {
982                 struct drm_display_mode *mode = &crtc->base.mode;
983                 ret = intel_overlay_switch_off(overlay);
984                 if (ret != 0)
985                         goto out_unlock;
986
987                 ret = check_overlay_possible_on_crtc(overlay, crtc);
988                 if (ret != 0)
989                         goto out_unlock;
990
991                 overlay->crtc = crtc;
992                 crtc->overlay = overlay;
993
994                 if (intel_panel_fitter_pipe(dev) == crtc->pipe
995                     /* and line to wide, i.e. one-line-mode */
996                     && mode->hdisplay > 1024) {
997                         overlay->pfit_active = 1;
998                         update_pfit_vscale_ratio(overlay);
999                 } else
1000                         overlay->pfit_active = 0;
1001         }
1002
1003         ret = check_overlay_dst(overlay, put_image_rec);
1004         if (ret != 0)
1005                 goto out_unlock;
1006
1007         if (overlay->pfit_active) {
1008                 params->dst_y = ((((u32)put_image_rec->dst_y) << 12) /
1009                         overlay->pfit_vscale_ratio);
1010                 /* shifting right rounds downwards, so add 1 */
1011                 params->dst_h = ((((u32)put_image_rec->dst_height) << 12) /
1012                         overlay->pfit_vscale_ratio) + 1;
1013         } else {
1014                 params->dst_y = put_image_rec->dst_y;
1015                 params->dst_h = put_image_rec->dst_height;
1016         }
1017         params->dst_x = put_image_rec->dst_x;
1018         params->dst_w = put_image_rec->dst_width;
1019
1020         params->src_w = put_image_rec->src_width;
1021         params->src_h = put_image_rec->src_height;
1022         params->src_scan_w = put_image_rec->src_scan_width;
1023         params->src_scan_h = put_image_rec->src_scan_height;
1024         if (params->src_scan_h > params->src_h
1025             || params->src_scan_w > params->src_w) {
1026                 ret = -EINVAL;
1027                 goto out_unlock;
1028         }
1029
1030         ret = check_overlay_src(dev, put_image_rec, new_bo);
1031         if (ret != 0)
1032                 goto out_unlock;
1033         params->format = put_image_rec->flags & ~I915_OVERLAY_FLAGS_MASK;
1034         params->stride_Y = put_image_rec->stride_Y;
1035         params->stride_UV = put_image_rec->stride_UV;
1036         params->offset_Y = put_image_rec->offset_Y;
1037         params->offset_U = put_image_rec->offset_U;
1038         params->offset_V = put_image_rec->offset_V;
1039
1040         /* Check scaling after src size to prevent a divide-by-zero. */
1041         ret = check_overlay_scaling(params);
1042         if (ret != 0)
1043                 goto out_unlock;
1044
1045         ret = intel_overlay_do_put_image(overlay, new_bo, params);
1046         if (ret != 0)
1047                 goto out_unlock;
1048
1049         mutex_unlock(&dev->struct_mutex);
1050         mutex_unlock(&dev->mode_config.mutex);
1051
1052         kfree(params);
1053
1054         return 0;
1055
1056 out_unlock:
1057         mutex_unlock(&dev->struct_mutex);
1058         mutex_unlock(&dev->mode_config.mutex);
1059         drm_gem_object_unreference(new_bo);
1060         kfree(params);
1061
1062         return ret;
1063 }
1064
1065 static void update_reg_attrs(struct intel_overlay *overlay,
1066                              struct overlay_registers *regs)
1067 {
1068         regs->OCLRC0 = (overlay->contrast << 18) | (overlay->brightness & 0xff);
1069         regs->OCLRC1 = overlay->saturation;
1070 }
1071
1072 static bool check_gamma_bounds(u32 gamma1, u32 gamma2)
1073 {
1074         int i;
1075
1076         if (gamma1 & 0xff000000 || gamma2 & 0xff000000)
1077                 return false;
1078
1079         for (i = 0; i < 3; i++) {
1080                 if (((gamma1 >> i * 8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
1081                         return false;
1082         }
1083
1084         return true;
1085 }
1086
1087 static bool check_gamma5_errata(u32 gamma5)
1088 {
1089         int i;
1090
1091         for (i = 0; i < 3; i++) {
1092                 if (((gamma5 >> i*8) & 0xff) == 0x80)
1093                         return false;
1094         }
1095
1096         return true;
1097 }
1098
1099 static int check_gamma(struct drm_intel_overlay_attrs *attrs)
1100 {
1101         if (!check_gamma_bounds(0, attrs->gamma0)
1102             || !check_gamma_bounds(attrs->gamma0, attrs->gamma1)
1103             || !check_gamma_bounds(attrs->gamma1, attrs->gamma2)
1104             || !check_gamma_bounds(attrs->gamma2, attrs->gamma3)
1105             || !check_gamma_bounds(attrs->gamma3, attrs->gamma4)
1106             || !check_gamma_bounds(attrs->gamma4, attrs->gamma5)
1107             || !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
1108                 return -EINVAL;
1109         if (!check_gamma5_errata(attrs->gamma5))
1110                 return -EINVAL;
1111         return 0;
1112 }
1113
1114 int intel_overlay_attrs(struct drm_device *dev, void *data,
1115                         struct drm_file *file_priv)
1116 {
1117         struct drm_intel_overlay_attrs *attrs = data;
1118         drm_i915_private_t *dev_priv = dev->dev_private;
1119         struct intel_overlay *overlay;
1120         struct overlay_registers *regs;
1121         int ret;
1122
1123         if (!dev_priv) {
1124                 DRM_ERROR("called with no initialization\n");
1125                 return -EINVAL;
1126         }
1127
1128         overlay = dev_priv->overlay;
1129         if (!overlay) {
1130                 DRM_DEBUG("userspace bug: no overlay\n");
1131                 return -ENODEV;
1132         }
1133
1134         mutex_lock(&dev->mode_config.mutex);
1135         mutex_lock(&dev->struct_mutex);
1136
1137         if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) {
1138                 attrs->color_key = overlay->color_key;
1139                 attrs->brightness = overlay->brightness;
1140                 attrs->contrast = overlay->contrast;
1141                 attrs->saturation = overlay->saturation;
1142
1143                 if (IS_I9XX(dev)) {
1144                         attrs->gamma0 = I915_READ(OGAMC0);
1145                         attrs->gamma1 = I915_READ(OGAMC1);
1146                         attrs->gamma2 = I915_READ(OGAMC2);
1147                         attrs->gamma3 = I915_READ(OGAMC3);
1148                         attrs->gamma4 = I915_READ(OGAMC4);
1149                         attrs->gamma5 = I915_READ(OGAMC5);
1150                 }
1151                 ret = 0;
1152         } else {
1153                 overlay->color_key = attrs->color_key;
1154                 if (attrs->brightness >= -128 && attrs->brightness <= 127) {
1155                         overlay->brightness = attrs->brightness;
1156                 } else {
1157                         ret = -EINVAL;
1158                         goto out_unlock;
1159                 }
1160                 if (attrs->contrast <= 255) {
1161                         overlay->contrast = attrs->contrast;
1162                 } else {
1163                         ret = -EINVAL;
1164                         goto out_unlock;
1165                 }
1166                 if (attrs->saturation <= 1023) {
1167                         overlay->saturation = attrs->saturation;
1168                 } else {
1169                         ret = -EINVAL;
1170                         goto out_unlock;
1171                 }
1172
1173                 regs = intel_overlay_map_regs_atomic(overlay);
1174                 if (!regs) {
1175                         ret = -ENOMEM;
1176                         goto out_unlock;
1177                 }
1178
1179                 update_reg_attrs(overlay, regs);
1180
1181                 intel_overlay_unmap_regs_atomic(overlay);
1182
1183                 if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) {
1184                         if (!IS_I9XX(dev)) {
1185                                 ret = -EINVAL;
1186                                 goto out_unlock;
1187                         }
1188
1189                         if (overlay->active) {
1190                                 ret = -EBUSY;
1191                                 goto out_unlock;
1192                         }
1193
1194                         ret = check_gamma(attrs);
1195                         if (ret != 0)
1196                                 goto out_unlock;
1197
1198                         I915_WRITE(OGAMC0, attrs->gamma0);
1199                         I915_WRITE(OGAMC1, attrs->gamma1);
1200                         I915_WRITE(OGAMC2, attrs->gamma2);
1201                         I915_WRITE(OGAMC3, attrs->gamma3);
1202                         I915_WRITE(OGAMC4, attrs->gamma4);
1203                         I915_WRITE(OGAMC5, attrs->gamma5);
1204                 }
1205                 ret = 0;
1206         }
1207
1208 out_unlock:
1209         mutex_unlock(&dev->struct_mutex);
1210         mutex_unlock(&dev->mode_config.mutex);
1211
1212         return ret;
1213 }
1214
1215 void intel_setup_overlay(struct drm_device *dev)
1216 {
1217         drm_i915_private_t *dev_priv = dev->dev_private;
1218         struct intel_overlay *overlay;
1219         struct drm_gem_object *reg_bo;
1220         struct overlay_registers *regs;
1221         int ret;
1222
1223         if (!OVERLAY_EXISTS(dev))
1224                 return;
1225
1226         overlay = kzalloc(sizeof(struct intel_overlay), GFP_KERNEL);
1227         if (!overlay)
1228                 return;
1229         overlay->dev = dev;
1230
1231         reg_bo = drm_gem_object_alloc(dev, PAGE_SIZE);
1232         if (!reg_bo)
1233                 goto out_free;
1234         overlay->reg_bo = reg_bo->driver_private;
1235
1236         if (OVERLAY_NONPHYSICAL(dev)) {
1237                 ret = i915_gem_object_pin(reg_bo, PAGE_SIZE);
1238                 if (ret) {
1239                         DRM_ERROR("failed to pin overlay register bo\n");
1240                         goto out_free_bo;
1241                 }
1242                 overlay->flip_addr = overlay->reg_bo->gtt_offset;
1243         } else {
1244                 ret = i915_gem_attach_phys_object(dev, reg_bo,
1245                                 I915_GEM_PHYS_OVERLAY_REGS);
1246                 if (ret) {
1247                         DRM_ERROR("failed to attach phys overlay regs\n");
1248                         goto out_free_bo;
1249                 }
1250                 overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr;
1251         }
1252
1253         /* init all values */
1254         overlay->color_key = 0x0101fe;
1255         overlay->brightness = -19;
1256         overlay->contrast = 75;
1257         overlay->saturation = 146;
1258
1259         regs = intel_overlay_map_regs_atomic(overlay);
1260         if (!regs)
1261                 goto out_free_bo;
1262
1263         memset(regs, 0, sizeof(struct overlay_registers));
1264         update_polyphase_filter(regs);
1265
1266         update_reg_attrs(overlay, regs);
1267
1268         intel_overlay_unmap_regs_atomic(overlay);
1269
1270         dev_priv->overlay = overlay;
1271         DRM_INFO("initialized overlay support\n");
1272         return;
1273
1274 out_free_bo:
1275         drm_gem_object_unreference(reg_bo);
1276 out_free:
1277         kfree(overlay);
1278         return;
1279 }
1280
1281 void intel_cleanup_overlay(struct drm_device *dev)
1282 {
1283         drm_i915_private_t *dev_priv = dev->dev_private;
1284
1285         if (dev_priv->overlay) {
1286                 /* The bo's should be free'd by the generic code already.
1287                  * Furthermore modesetting teardown happens beforehand so the
1288                  * hardware should be off already */
1289                 BUG_ON(dev_priv->overlay->active);
1290
1291                 kfree(dev_priv->overlay);
1292         }
1293 }