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