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