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