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