blob: b0aea47cb4452fc0e66d20a6240ff03bf81f8d06 [file] [log] [blame]
Daniel Vetter02e792f2009-09-15 22:57:34 +02001/*
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 */
Andrew Mortone1679762010-08-24 16:35:52 -070028
29#include <linux/seq_file.h>
Daniel Vetter02e792f2009-09-15 22:57:34 +020030#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)
Chris Wilsond7961362010-07-13 13:52:17 +010070#define OCMD_BUF_TYPE_MASK (0x1<<5)
Daniel Vetter02e792f2009-09-15 22:57:34 +020071#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
173/* overlay flip addr flag */
174#define OFC_UPDATE 0x1
175
Chris Wilson8d74f652010-08-12 10:35:26 +0100176static struct overlay_registers *
177intel_overlay_map_regs_atomic(struct intel_overlay *overlay,
178 int slot)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200179{
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
Chris Wilson315781482010-08-12 09:42:51 +0100186 if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) {
187 regs = overlay->reg_bo->phys_obj->handle->vaddr;
188 } else {
Daniel Vetter02e792f2009-09-15 22:57:34 +0200189 regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
Chris Wilsonfca3ec02010-08-04 14:34:24 +0100190 overlay->reg_bo->gtt_offset,
Chris Wilson8d74f652010-08-12 10:35:26 +0100191 slot);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200192
193 if (!regs) {
194 DRM_ERROR("failed to map overlay regs in GTT\n");
195 return NULL;
196 }
Chris Wilson315781482010-08-12 09:42:51 +0100197 }
Daniel Vetter02e792f2009-09-15 22:57:34 +0200198
199 return overlay->virt_addr = regs;
200}
201
Chris Wilson8d74f652010-08-12 10:35:26 +0100202static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay,
203 int slot)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200204{
Chris Wilson315781482010-08-12 09:42:51 +0100205 if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
Chris Wilson8d74f652010-08-12 10:35:26 +0100206 io_mapping_unmap_atomic(overlay->virt_addr, slot);
207
208 overlay->virt_addr = NULL;
209
210 return;
211}
212
213static struct overlay_registers *
214intel_overlay_map_regs(struct intel_overlay *overlay)
215{
216 drm_i915_private_t *dev_priv = overlay->dev->dev_private;
217 struct overlay_registers *regs;
218
219 /* no recursive mappings */
220 BUG_ON(overlay->virt_addr);
221
222 if (OVERLAY_NEEDS_PHYSICAL(overlay->dev)) {
223 regs = overlay->reg_bo->phys_obj->handle->vaddr;
224 } else {
225 regs = io_mapping_map_wc(dev_priv->mm.gtt_mapping,
226 overlay->reg_bo->gtt_offset);
227
228 if (!regs) {
229 DRM_ERROR("failed to map overlay regs in GTT\n");
230 return NULL;
231 }
232 }
233
234 return overlay->virt_addr = regs;
235}
236
237static void intel_overlay_unmap_regs(struct intel_overlay *overlay)
238{
239 if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
240 io_mapping_unmap(overlay->virt_addr);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200241
242 overlay->virt_addr = NULL;
243
Daniel Vetter02e792f2009-09-15 22:57:34 +0200244 return;
245}
246
247/* overlay needs to be disable in OCMD reg */
248static int intel_overlay_on(struct intel_overlay *overlay)
249{
250 struct drm_device *dev = overlay->dev;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200251 int ret;
Zou Nan hai852835f2010-05-21 09:08:56 +0800252 drm_i915_private_t *dev_priv = dev->dev_private;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200253
254 BUG_ON(overlay->active);
255
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200256 overlay->active = 1;
257 overlay->hw_wedged = NEEDS_WAIT_FOR_FLIP;
258
Daniel Vetter4f8a5672010-02-11 14:14:43 +0100259 BEGIN_LP_RING(4);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200260 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON);
261 OUT_RING(overlay->flip_addr | OFC_UPDATE);
262 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
263 OUT_RING(MI_NOOP);
264 ADVANCE_LP_RING();
265
Zou Nan hai852835f2010-05-21 09:08:56 +0800266 overlay->last_flip_req =
Daniel Vetter8a1a49f2010-02-11 22:29:04 +0100267 i915_add_request(dev, NULL, &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200268 if (overlay->last_flip_req == 0)
269 return -ENOMEM;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200270
Zou Nan hai852835f2010-05-21 09:08:56 +0800271 ret = i915_do_wait_request(dev,
Chris Wilson722506f2010-08-12 09:28:50 +0100272 overlay->last_flip_req, true,
273 &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200274 if (ret != 0)
275 return ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200276
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200277 overlay->hw_wedged = 0;
278 overlay->last_flip_req = 0;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200279 return 0;
280}
281
282/* overlay needs to be enabled in OCMD reg */
283static void intel_overlay_continue(struct intel_overlay *overlay,
Chris Wilson722506f2010-08-12 09:28:50 +0100284 bool load_polyphase_filter)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200285{
286 struct drm_device *dev = overlay->dev;
287 drm_i915_private_t *dev_priv = dev->dev_private;
288 u32 flip_addr = overlay->flip_addr;
289 u32 tmp;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200290
291 BUG_ON(!overlay->active);
292
293 if (load_polyphase_filter)
294 flip_addr |= OFC_UPDATE;
295
296 /* check for underruns */
297 tmp = I915_READ(DOVSTA);
298 if (tmp & (1 << 17))
299 DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
300
Daniel Vetter4f8a5672010-02-11 14:14:43 +0100301 BEGIN_LP_RING(2);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200302 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
303 OUT_RING(flip_addr);
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200304 ADVANCE_LP_RING();
305
Zou Nan hai852835f2010-05-21 09:08:56 +0800306 overlay->last_flip_req =
Daniel Vetter8a1a49f2010-02-11 22:29:04 +0100307 i915_add_request(dev, NULL, &dev_priv->render_ring);
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200308}
309
310static int intel_overlay_wait_flip(struct intel_overlay *overlay)
311{
312 struct drm_device *dev = overlay->dev;
Chris Wilson722506f2010-08-12 09:28:50 +0100313 drm_i915_private_t *dev_priv = dev->dev_private;
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200314 int ret;
315 u32 tmp;
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200316
317 if (overlay->last_flip_req != 0) {
Chris Wilson722506f2010-08-12 09:28:50 +0100318 ret = i915_do_wait_request(dev,
319 overlay->last_flip_req, true,
320 &dev_priv->render_ring);
Daniel Vetter5c5a4352009-10-04 15:00:36 +0200321 if (ret == 0) {
322 overlay->last_flip_req = 0;
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200323
Daniel Vetter5c5a4352009-10-04 15:00:36 +0200324 tmp = I915_READ(ISR);
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200325
Daniel Vetter5c5a4352009-10-04 15:00:36 +0200326 if (!(tmp & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT))
327 return 0;
328 }
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200329 }
330
331 /* synchronous slowpath */
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200332 overlay->hw_wedged = RELEASE_OLD_VID;
333
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200334 BEGIN_LP_RING(2);
Chris Wilson722506f2010-08-12 09:28:50 +0100335 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
336 OUT_RING(MI_NOOP);
337 ADVANCE_LP_RING();
Daniel Vetter02e792f2009-09-15 22:57:34 +0200338
Zou Nan hai852835f2010-05-21 09:08:56 +0800339 overlay->last_flip_req =
Daniel Vetter8a1a49f2010-02-11 22:29:04 +0100340 i915_add_request(dev, NULL, &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200341 if (overlay->last_flip_req == 0)
342 return -ENOMEM;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200343
Chris Wilson722506f2010-08-12 09:28:50 +0100344 ret = i915_do_wait_request(dev,
345 overlay->last_flip_req, true,
346 &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200347 if (ret != 0)
348 return ret;
349
350 overlay->hw_wedged = 0;
351 overlay->last_flip_req = 0;
352 return 0;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200353}
354
355/* overlay needs to be disabled in OCMD reg */
356static int intel_overlay_off(struct intel_overlay *overlay)
357{
358 u32 flip_addr = overlay->flip_addr;
359 struct drm_device *dev = overlay->dev;
Zou Nan hai852835f2010-05-21 09:08:56 +0800360 drm_i915_private_t *dev_priv = dev->dev_private;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200361 int ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200362
363 BUG_ON(!overlay->active);
364
365 /* According to intel docs the overlay hw may hang (when switching
366 * off) without loading the filter coeffs. It is however unclear whether
367 * this applies to the disabling of the overlay or to the switching off
368 * of the hw. Do it in both cases */
369 flip_addr |= OFC_UPDATE;
370
371 /* wait for overlay to go idle */
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200372 overlay->hw_wedged = SWITCH_OFF_STAGE_1;
373
Daniel Vetter4f8a5672010-02-11 14:14:43 +0100374 BEGIN_LP_RING(4);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200375 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
376 OUT_RING(flip_addr);
Chris Wilson722506f2010-08-12 09:28:50 +0100377 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
378 OUT_RING(MI_NOOP);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200379 ADVANCE_LP_RING();
380
Zou Nan hai852835f2010-05-21 09:08:56 +0800381 overlay->last_flip_req =
Daniel Vetter8a1a49f2010-02-11 22:29:04 +0100382 i915_add_request(dev, NULL, &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200383 if (overlay->last_flip_req == 0)
384 return -ENOMEM;
385
Chris Wilson722506f2010-08-12 09:28:50 +0100386 ret = i915_do_wait_request(dev,
387 overlay->last_flip_req, true,
388 &dev_priv->render_ring);
389 if (ret != 0)
390 return ret;
391
392 /* turn overlay off */
393 overlay->hw_wedged = SWITCH_OFF_STAGE_2;
394
395 BEGIN_LP_RING(4);
396 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
397 OUT_RING(flip_addr);
398 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
399 OUT_RING(MI_NOOP);
400 ADVANCE_LP_RING();
401
402 overlay->last_flip_req =
403 i915_add_request(dev, NULL, &dev_priv->render_ring);
404 if (overlay->last_flip_req == 0)
405 return -ENOMEM;
406
407 ret = i915_do_wait_request(dev,
408 overlay->last_flip_req, true,
409 &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200410 if (ret != 0)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200411 return ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200412
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200413 overlay->hw_wedged = 0;
414 overlay->last_flip_req = 0;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200415 return ret;
416}
417
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200418static void intel_overlay_off_tail(struct intel_overlay *overlay)
419{
420 struct drm_gem_object *obj;
421
422 /* never have the overlay hw on without showing a frame */
423 BUG_ON(!overlay->vid_bo);
Daniel Vettera8089e82010-04-09 19:05:09 +0000424 obj = &overlay->vid_bo->base;
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200425
426 i915_gem_object_unpin(obj);
427 drm_gem_object_unreference(obj);
428 overlay->vid_bo = NULL;
429
430 overlay->crtc->overlay = NULL;
431 overlay->crtc = NULL;
432 overlay->active = 0;
433}
434
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200435/* recover from an interruption due to a signal
436 * We have to be careful not to repeat work forever an make forward progess. */
437int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
Chris Wilson722506f2010-08-12 09:28:50 +0100438 bool interruptible)
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200439{
440 struct drm_device *dev = overlay->dev;
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200441 struct drm_gem_object *obj;
Zou Nan hai852835f2010-05-21 09:08:56 +0800442 drm_i915_private_t *dev_priv = dev->dev_private;
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200443 u32 flip_addr;
444 int ret;
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200445
446 if (overlay->hw_wedged == HW_WEDGED)
447 return -EIO;
448
449 if (overlay->last_flip_req == 0) {
Zou Nan hai852835f2010-05-21 09:08:56 +0800450 overlay->last_flip_req =
Daniel Vetter8a1a49f2010-02-11 22:29:04 +0100451 i915_add_request(dev, NULL, &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200452 if (overlay->last_flip_req == 0)
453 return -ENOMEM;
454 }
455
Zou Nan hai852835f2010-05-21 09:08:56 +0800456 ret = i915_do_wait_request(dev, overlay->last_flip_req,
Chris Wilson722506f2010-08-12 09:28:50 +0100457 interruptible, &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200458 if (ret != 0)
459 return ret;
460
461 switch (overlay->hw_wedged) {
Chris Wilson722506f2010-08-12 09:28:50 +0100462 case RELEASE_OLD_VID:
463 obj = &overlay->old_vid_bo->base;
464 i915_gem_object_unpin(obj);
465 drm_gem_object_unreference(obj);
466 overlay->old_vid_bo = NULL;
467 break;
468 case SWITCH_OFF_STAGE_1:
469 flip_addr = overlay->flip_addr;
470 flip_addr |= OFC_UPDATE;
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200471
Chris Wilson722506f2010-08-12 09:28:50 +0100472 overlay->hw_wedged = SWITCH_OFF_STAGE_2;
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200473
Chris Wilson722506f2010-08-12 09:28:50 +0100474 BEGIN_LP_RING(4);
475 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
476 OUT_RING(flip_addr);
477 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
478 OUT_RING(MI_NOOP);
479 ADVANCE_LP_RING();
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200480
Chris Wilson722506f2010-08-12 09:28:50 +0100481 overlay->last_flip_req =
482 i915_add_request(dev, NULL,
483 &dev_priv->render_ring);
484 if (overlay->last_flip_req == 0)
485 return -ENOMEM;
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200486
Chris Wilson722506f2010-08-12 09:28:50 +0100487 ret = i915_do_wait_request(dev, overlay->last_flip_req,
488 interruptible,
489 &dev_priv->render_ring);
490 if (ret != 0)
491 return ret;
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200492
Chris Wilson722506f2010-08-12 09:28:50 +0100493 case SWITCH_OFF_STAGE_2:
494 intel_overlay_off_tail(overlay);
495 break;
496 default:
497 BUG_ON(overlay->hw_wedged != NEEDS_WAIT_FOR_FLIP);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200498 }
499
500 overlay->hw_wedged = 0;
501 overlay->last_flip_req = 0;
502 return 0;
503}
504
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200505/* Wait for pending overlay flip and release old frame.
506 * Needs to be called before the overlay register are changed
Chris Wilson8d74f652010-08-12 10:35:26 +0100507 * via intel_overlay_(un)map_regs
508 */
Daniel Vetter02e792f2009-09-15 22:57:34 +0200509static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
510{
511 int ret;
512 struct drm_gem_object *obj;
513
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200514 /* only wait if there is actually an old frame to release to
515 * guarantee forward progress */
516 if (!overlay->old_vid_bo)
517 return 0;
518
Daniel Vetter02e792f2009-09-15 22:57:34 +0200519 ret = intel_overlay_wait_flip(overlay);
520 if (ret != 0)
521 return ret;
522
Daniel Vettera8089e82010-04-09 19:05:09 +0000523 obj = &overlay->old_vid_bo->base;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200524 i915_gem_object_unpin(obj);
525 drm_gem_object_unreference(obj);
526 overlay->old_vid_bo = NULL;
527
528 return 0;
529}
530
531struct put_image_params {
532 int format;
533 short dst_x;
534 short dst_y;
535 short dst_w;
536 short dst_h;
537 short src_w;
538 short src_scan_h;
539 short src_scan_w;
540 short src_h;
541 short stride_Y;
542 short stride_UV;
543 int offset_Y;
544 int offset_U;
545 int offset_V;
546};
547
548static int packed_depth_bytes(u32 format)
549{
550 switch (format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100551 case I915_OVERLAY_YUV422:
552 return 4;
553 case I915_OVERLAY_YUV411:
554 /* return 6; not implemented */
555 default:
556 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200557 }
558}
559
560static int packed_width_bytes(u32 format, short width)
561{
562 switch (format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100563 case I915_OVERLAY_YUV422:
564 return width << 1;
565 default:
566 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200567 }
568}
569
570static int uv_hsubsampling(u32 format)
571{
572 switch (format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100573 case I915_OVERLAY_YUV422:
574 case I915_OVERLAY_YUV420:
575 return 2;
576 case I915_OVERLAY_YUV411:
577 case I915_OVERLAY_YUV410:
578 return 4;
579 default:
580 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200581 }
582}
583
584static int uv_vsubsampling(u32 format)
585{
586 switch (format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100587 case I915_OVERLAY_YUV420:
588 case I915_OVERLAY_YUV410:
589 return 2;
590 case I915_OVERLAY_YUV422:
591 case I915_OVERLAY_YUV411:
592 return 1;
593 default:
594 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200595 }
596}
597
598static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width)
599{
600 u32 mask, shift, ret;
601 if (IS_I9XX(dev)) {
602 mask = 0x3f;
603 shift = 6;
604 } else {
605 mask = 0x1f;
606 shift = 5;
607 }
608 ret = ((offset + width + mask) >> shift) - (offset >> shift);
609 if (IS_I9XX(dev))
610 ret <<= 1;
611 ret -=1;
612 return ret << 2;
613}
614
615static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = {
616 0x3000, 0xb4a0, 0x1930, 0x1920, 0xb4a0,
617 0x3000, 0xb500, 0x19d0, 0x1880, 0xb440,
618 0x3000, 0xb540, 0x1a88, 0x2f80, 0xb3e0,
619 0x3000, 0xb580, 0x1b30, 0x2e20, 0xb380,
620 0x3000, 0xb5c0, 0x1bd8, 0x2cc0, 0xb320,
621 0x3020, 0xb5e0, 0x1c60, 0x2b80, 0xb2c0,
622 0x3020, 0xb5e0, 0x1cf8, 0x2a20, 0xb260,
623 0x3020, 0xb5e0, 0x1d80, 0x28e0, 0xb200,
624 0x3020, 0xb5c0, 0x1e08, 0x3f40, 0xb1c0,
625 0x3020, 0xb580, 0x1e78, 0x3ce0, 0xb160,
626 0x3040, 0xb520, 0x1ed8, 0x3aa0, 0xb120,
627 0x3040, 0xb4a0, 0x1f30, 0x3880, 0xb0e0,
628 0x3040, 0xb400, 0x1f78, 0x3680, 0xb0a0,
629 0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060,
630 0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040,
631 0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020,
Chris Wilson722506f2010-08-12 09:28:50 +0100632 0xb000, 0x3000, 0x0800, 0x3000, 0xb000
633};
634
Daniel Vetter02e792f2009-09-15 22:57:34 +0200635static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
636 0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60,
637 0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40,
638 0xb040, 0x1b20, 0x29e0, 0xb060, 0x1bd8, 0x2880,
639 0xb080, 0x1c88, 0x3e60, 0xb0a0, 0x1d28, 0x3c00,
640 0xb0c0, 0x1db8, 0x39e0, 0xb0e0, 0x1e40, 0x37e0,
641 0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0,
642 0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240,
643 0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0,
Chris Wilson722506f2010-08-12 09:28:50 +0100644 0x3000, 0x0800, 0x3000
645};
Daniel Vetter02e792f2009-09-15 22:57:34 +0200646
647static void update_polyphase_filter(struct overlay_registers *regs)
648{
649 memcpy(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs));
650 memcpy(regs->UV_HCOEFS, uv_static_hcoeffs, sizeof(uv_static_hcoeffs));
651}
652
653static bool update_scaling_factors(struct intel_overlay *overlay,
654 struct overlay_registers *regs,
655 struct put_image_params *params)
656{
657 /* fixed point with a 12 bit shift */
658 u32 xscale, yscale, xscale_UV, yscale_UV;
659#define FP_SHIFT 12
660#define FRACT_MASK 0xfff
661 bool scale_changed = false;
662 int uv_hscale = uv_hsubsampling(params->format);
663 int uv_vscale = uv_vsubsampling(params->format);
664
665 if (params->dst_w > 1)
666 xscale = ((params->src_scan_w - 1) << FP_SHIFT)
667 /(params->dst_w);
668 else
669 xscale = 1 << FP_SHIFT;
670
671 if (params->dst_h > 1)
672 yscale = ((params->src_scan_h - 1) << FP_SHIFT)
673 /(params->dst_h);
674 else
675 yscale = 1 << FP_SHIFT;
676
677 /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
Chris Wilson722506f2010-08-12 09:28:50 +0100678 xscale_UV = xscale/uv_hscale;
679 yscale_UV = yscale/uv_vscale;
680 /* make the Y scale to UV scale ratio an exact multiply */
681 xscale = xscale_UV * uv_hscale;
682 yscale = yscale_UV * uv_vscale;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200683 /*} else {
Chris Wilson722506f2010-08-12 09:28:50 +0100684 xscale_UV = 0;
685 yscale_UV = 0;
686 }*/
Daniel Vetter02e792f2009-09-15 22:57:34 +0200687
688 if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)
689 scale_changed = true;
690 overlay->old_xscale = xscale;
691 overlay->old_yscale = yscale;
692
Chris Wilson722506f2010-08-12 09:28:50 +0100693 regs->YRGBSCALE = (((yscale & FRACT_MASK) << 20) |
694 ((xscale >> FP_SHIFT) << 16) |
695 ((xscale & FRACT_MASK) << 3));
696
697 regs->UVSCALE = (((yscale_UV & FRACT_MASK) << 20) |
698 ((xscale_UV >> FP_SHIFT) << 16) |
699 ((xscale_UV & FRACT_MASK) << 3));
700
701 regs->UVSCALEV = ((((yscale >> FP_SHIFT) << 16) |
702 ((yscale_UV >> FP_SHIFT) << 0)));
Daniel Vetter02e792f2009-09-15 22:57:34 +0200703
704 if (scale_changed)
705 update_polyphase_filter(regs);
706
707 return scale_changed;
708}
709
710static void update_colorkey(struct intel_overlay *overlay,
711 struct overlay_registers *regs)
712{
713 u32 key = overlay->color_key;
Chris Wilson6ba3ddd2010-08-12 09:30:58 +0100714
Daniel Vetter02e792f2009-09-15 22:57:34 +0200715 switch (overlay->crtc->base.fb->bits_per_pixel) {
Chris Wilson722506f2010-08-12 09:28:50 +0100716 case 8:
717 regs->DCLRKV = 0;
718 regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;
Chris Wilson6ba3ddd2010-08-12 09:30:58 +0100719 break;
720
Chris Wilson722506f2010-08-12 09:28:50 +0100721 case 16:
722 if (overlay->crtc->base.fb->depth == 15) {
723 regs->DCLRKV = RGB15_TO_COLORKEY(key);
724 regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;
725 } else {
726 regs->DCLRKV = RGB16_TO_COLORKEY(key);
727 regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;
728 }
Chris Wilson6ba3ddd2010-08-12 09:30:58 +0100729 break;
730
Chris Wilson722506f2010-08-12 09:28:50 +0100731 case 24:
732 case 32:
733 regs->DCLRKV = key;
734 regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;
Chris Wilson6ba3ddd2010-08-12 09:30:58 +0100735 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200736 }
737}
738
739static u32 overlay_cmd_reg(struct put_image_params *params)
740{
741 u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0;
742
743 if (params->format & I915_OVERLAY_YUV_PLANAR) {
744 switch (params->format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100745 case I915_OVERLAY_YUV422:
746 cmd |= OCMD_YUV_422_PLANAR;
747 break;
748 case I915_OVERLAY_YUV420:
749 cmd |= OCMD_YUV_420_PLANAR;
750 break;
751 case I915_OVERLAY_YUV411:
752 case I915_OVERLAY_YUV410:
753 cmd |= OCMD_YUV_410_PLANAR;
754 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200755 }
756 } else { /* YUV packed */
757 switch (params->format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100758 case I915_OVERLAY_YUV422:
759 cmd |= OCMD_YUV_422_PACKED;
760 break;
761 case I915_OVERLAY_YUV411:
762 cmd |= OCMD_YUV_411_PACKED;
763 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200764 }
765
766 switch (params->format & I915_OVERLAY_SWAP_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100767 case I915_OVERLAY_NO_SWAP:
768 break;
769 case I915_OVERLAY_UV_SWAP:
770 cmd |= OCMD_UV_SWAP;
771 break;
772 case I915_OVERLAY_Y_SWAP:
773 cmd |= OCMD_Y_SWAP;
774 break;
775 case I915_OVERLAY_Y_AND_UV_SWAP:
776 cmd |= OCMD_Y_AND_UV_SWAP;
777 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200778 }
779 }
780
781 return cmd;
782}
783
784int intel_overlay_do_put_image(struct intel_overlay *overlay,
785 struct drm_gem_object *new_bo,
786 struct put_image_params *params)
787{
788 int ret, tmp_width;
789 struct overlay_registers *regs;
790 bool scale_changed = false;
Daniel Vetter23010e42010-03-08 13:35:02 +0100791 struct drm_i915_gem_object *bo_priv = to_intel_bo(new_bo);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200792 struct drm_device *dev = overlay->dev;
793
794 BUG_ON(!mutex_is_locked(&dev->struct_mutex));
795 BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
796 BUG_ON(!overlay);
797
Daniel Vetter02e792f2009-09-15 22:57:34 +0200798 ret = intel_overlay_release_old_vid(overlay);
799 if (ret != 0)
800 return ret;
801
802 ret = i915_gem_object_pin(new_bo, PAGE_SIZE);
803 if (ret != 0)
804 return ret;
805
806 ret = i915_gem_object_set_to_gtt_domain(new_bo, 0);
807 if (ret != 0)
808 goto out_unpin;
809
810 if (!overlay->active) {
Chris Wilson8d74f652010-08-12 10:35:26 +0100811 regs = intel_overlay_map_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200812 if (!regs) {
813 ret = -ENOMEM;
814 goto out_unpin;
815 }
816 regs->OCONFIG = OCONF_CC_OUT_8BIT;
817 if (IS_I965GM(overlay->dev))
818 regs->OCONFIG |= OCONF_CSC_MODE_BT709;
819 regs->OCONFIG |= overlay->crtc->pipe == 0 ?
820 OCONF_PIPE_A : OCONF_PIPE_B;
Chris Wilson8d74f652010-08-12 10:35:26 +0100821 intel_overlay_unmap_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200822
823 ret = intel_overlay_on(overlay);
824 if (ret != 0)
825 goto out_unpin;
826 }
827
Chris Wilson8d74f652010-08-12 10:35:26 +0100828 regs = intel_overlay_map_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200829 if (!regs) {
830 ret = -ENOMEM;
831 goto out_unpin;
832 }
833
834 regs->DWINPOS = (params->dst_y << 16) | params->dst_x;
835 regs->DWINSZ = (params->dst_h << 16) | params->dst_w;
836
837 if (params->format & I915_OVERLAY_YUV_PACKED)
838 tmp_width = packed_width_bytes(params->format, params->src_w);
839 else
840 tmp_width = params->src_w;
841
842 regs->SWIDTH = params->src_w;
843 regs->SWIDTHSW = calc_swidthsw(overlay->dev,
Chris Wilson722506f2010-08-12 09:28:50 +0100844 params->offset_Y, tmp_width);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200845 regs->SHEIGHT = params->src_h;
846 regs->OBUF_0Y = bo_priv->gtt_offset + params-> offset_Y;
847 regs->OSTRIDE = params->stride_Y;
848
849 if (params->format & I915_OVERLAY_YUV_PLANAR) {
850 int uv_hscale = uv_hsubsampling(params->format);
851 int uv_vscale = uv_vsubsampling(params->format);
852 u32 tmp_U, tmp_V;
853 regs->SWIDTH |= (params->src_w/uv_hscale) << 16;
854 tmp_U = calc_swidthsw(overlay->dev, params->offset_U,
Chris Wilson722506f2010-08-12 09:28:50 +0100855 params->src_w/uv_hscale);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200856 tmp_V = calc_swidthsw(overlay->dev, params->offset_V,
Chris Wilson722506f2010-08-12 09:28:50 +0100857 params->src_w/uv_hscale);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200858 regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16;
859 regs->SHEIGHT |= (params->src_h/uv_vscale) << 16;
860 regs->OBUF_0U = bo_priv->gtt_offset + params->offset_U;
861 regs->OBUF_0V = bo_priv->gtt_offset + params->offset_V;
862 regs->OSTRIDE |= params->stride_UV << 16;
863 }
864
865 scale_changed = update_scaling_factors(overlay, regs, params);
866
867 update_colorkey(overlay, regs);
868
869 regs->OCMD = overlay_cmd_reg(params);
870
Chris Wilson8d74f652010-08-12 10:35:26 +0100871 intel_overlay_unmap_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200872
873 intel_overlay_continue(overlay, scale_changed);
874
875 overlay->old_vid_bo = overlay->vid_bo;
Daniel Vetter23010e42010-03-08 13:35:02 +0100876 overlay->vid_bo = to_intel_bo(new_bo);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200877
878 return 0;
879
880out_unpin:
881 i915_gem_object_unpin(new_bo);
882 return ret;
883}
884
885int intel_overlay_switch_off(struct intel_overlay *overlay)
886{
887 int ret;
888 struct overlay_registers *regs;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200889 struct drm_device *dev = overlay->dev;
890
891 BUG_ON(!mutex_is_locked(&dev->struct_mutex));
892 BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
893
Daniel Vetter9bedb972009-11-30 15:55:49 +0100894 if (overlay->hw_wedged) {
895 ret = intel_overlay_recover_from_interrupt(overlay, 1);
896 if (ret != 0)
897 return ret;
898 }
899
Daniel Vetter02e792f2009-09-15 22:57:34 +0200900 if (!overlay->active)
901 return 0;
902
Daniel Vetter02e792f2009-09-15 22:57:34 +0200903 ret = intel_overlay_release_old_vid(overlay);
904 if (ret != 0)
905 return ret;
906
Chris Wilson8d74f652010-08-12 10:35:26 +0100907 regs = intel_overlay_map_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200908 regs->OCMD = 0;
Chris Wilson8d74f652010-08-12 10:35:26 +0100909 intel_overlay_unmap_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200910
911 ret = intel_overlay_off(overlay);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200912 if (ret != 0)
913 return ret;
914
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200915 intel_overlay_off_tail(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200916
917 return 0;
918}
919
920static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
921 struct intel_crtc *crtc)
922{
Chris Wilson722506f2010-08-12 09:28:50 +0100923 drm_i915_private_t *dev_priv = overlay->dev->dev_private;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200924 u32 pipeconf;
925 int pipeconf_reg = (crtc->pipe == 0) ? PIPEACONF : PIPEBCONF;
926
927 if (!crtc->base.enabled || crtc->dpms_mode != DRM_MODE_DPMS_ON)
928 return -EINVAL;
929
930 pipeconf = I915_READ(pipeconf_reg);
931
932 /* can't use the overlay with double wide pipe */
933 if (!IS_I965G(overlay->dev) && pipeconf & PIPEACONF_DOUBLE_WIDE)
934 return -EINVAL;
935
936 return 0;
937}
938
939static void update_pfit_vscale_ratio(struct intel_overlay *overlay)
940{
941 struct drm_device *dev = overlay->dev;
Chris Wilson722506f2010-08-12 09:28:50 +0100942 drm_i915_private_t *dev_priv = dev->dev_private;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200943 u32 ratio;
944 u32 pfit_control = I915_READ(PFIT_CONTROL);
945
946 /* XXX: This is not the same logic as in the xorg driver, but more in
947 * line with the intel documentation for the i965 */
948 if (!IS_I965G(dev) && (pfit_control & VERT_AUTO_SCALE)) {
949 ratio = I915_READ(PFIT_AUTO_RATIOS) >> PFIT_VERT_SCALE_SHIFT;
950 } else { /* on i965 use the PGM reg to read out the autoscaler values */
951 ratio = I915_READ(PFIT_PGM_RATIOS);
952 if (IS_I965G(dev))
953 ratio >>= PFIT_VERT_SCALE_SHIFT_965;
954 else
955 ratio >>= PFIT_VERT_SCALE_SHIFT;
956 }
957
958 overlay->pfit_vscale_ratio = ratio;
959}
960
961static int check_overlay_dst(struct intel_overlay *overlay,
962 struct drm_intel_overlay_put_image *rec)
963{
964 struct drm_display_mode *mode = &overlay->crtc->base.mode;
965
Chris Wilson722506f2010-08-12 09:28:50 +0100966 if (rec->dst_x < mode->crtc_hdisplay &&
967 rec->dst_x + rec->dst_width <= mode->crtc_hdisplay &&
968 rec->dst_y < mode->crtc_vdisplay &&
969 rec->dst_y + rec->dst_height <= mode->crtc_vdisplay)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200970 return 0;
971 else
972 return -EINVAL;
973}
974
975static int check_overlay_scaling(struct put_image_params *rec)
976{
977 u32 tmp;
978
979 /* downscaling limit is 8.0 */
980 tmp = ((rec->src_scan_h << 16) / rec->dst_h) >> 16;
981 if (tmp > 7)
982 return -EINVAL;
983 tmp = ((rec->src_scan_w << 16) / rec->dst_w) >> 16;
984 if (tmp > 7)
985 return -EINVAL;
986
987 return 0;
988}
989
990static int check_overlay_src(struct drm_device *dev,
991 struct drm_intel_overlay_put_image *rec,
992 struct drm_gem_object *new_bo)
993{
994 u32 stride_mask;
995 int depth;
996 int uv_hscale = uv_hsubsampling(rec->flags);
997 int uv_vscale = uv_vsubsampling(rec->flags);
998 size_t tmp;
999
1000 /* check src dimensions */
1001 if (IS_845G(dev) || IS_I830(dev)) {
Chris Wilson722506f2010-08-12 09:28:50 +01001002 if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY ||
1003 rec->src_width > IMAGE_MAX_WIDTH_LEGACY)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001004 return -EINVAL;
1005 } else {
Chris Wilson722506f2010-08-12 09:28:50 +01001006 if (rec->src_height > IMAGE_MAX_HEIGHT ||
1007 rec->src_width > IMAGE_MAX_WIDTH)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001008 return -EINVAL;
1009 }
1010 /* better safe than sorry, use 4 as the maximal subsampling ratio */
Chris Wilson722506f2010-08-12 09:28:50 +01001011 if (rec->src_height < N_VERT_Y_TAPS*4 ||
1012 rec->src_width < N_HORIZ_Y_TAPS*4)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001013 return -EINVAL;
1014
Chris Wilsona1efd142010-07-12 19:35:38 +01001015 /* check alignment constraints */
Daniel Vetter02e792f2009-09-15 22:57:34 +02001016 switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +01001017 case I915_OVERLAY_RGB:
1018 /* not implemented */
1019 return -EINVAL;
1020 case I915_OVERLAY_YUV_PACKED:
1021 depth = packed_depth_bytes(rec->flags);
1022 if (uv_vscale != 1)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001023 return -EINVAL;
Chris Wilson722506f2010-08-12 09:28:50 +01001024 if (depth < 0)
1025 return depth;
1026 /* ignore UV planes */
1027 rec->stride_UV = 0;
1028 rec->offset_U = 0;
1029 rec->offset_V = 0;
1030 /* check pixel alignment */
1031 if (rec->offset_Y % depth)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001032 return -EINVAL;
Chris Wilson722506f2010-08-12 09:28:50 +01001033 break;
1034 case I915_OVERLAY_YUV_PLANAR:
1035 if (uv_vscale < 0 || uv_hscale < 0)
1036 return -EINVAL;
1037 /* no offset restrictions for planar formats */
1038 break;
1039 default:
1040 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001041 }
1042
1043 if (rec->src_width % uv_hscale)
1044 return -EINVAL;
1045
1046 /* stride checking */
Chris Wilsona1efd142010-07-12 19:35:38 +01001047 if (IS_I830(dev) || IS_845G(dev))
1048 stride_mask = 255;
1049 else
1050 stride_mask = 63;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001051
1052 if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
1053 return -EINVAL;
1054 if (IS_I965G(dev) && rec->stride_Y < 512)
1055 return -EINVAL;
1056
1057 tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ?
1058 4 : 8;
1059 if (rec->stride_Y > tmp*1024 || rec->stride_UV > 2*1024)
1060 return -EINVAL;
1061
1062 /* check buffer dimensions */
1063 switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +01001064 case I915_OVERLAY_RGB:
1065 case I915_OVERLAY_YUV_PACKED:
1066 /* always 4 Y values per depth pixels */
1067 if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y)
1068 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001069
Chris Wilson722506f2010-08-12 09:28:50 +01001070 tmp = rec->stride_Y*rec->src_height;
1071 if (rec->offset_Y + tmp > new_bo->size)
1072 return -EINVAL;
1073 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001074
Chris Wilson722506f2010-08-12 09:28:50 +01001075 case I915_OVERLAY_YUV_PLANAR:
1076 if (rec->src_width > rec->stride_Y)
1077 return -EINVAL;
1078 if (rec->src_width/uv_hscale > rec->stride_UV)
1079 return -EINVAL;
1080
1081 tmp = rec->stride_Y*rec->src_height;
1082 if (rec->offset_Y + tmp > new_bo->size)
1083 return -EINVAL;
1084 tmp = rec->stride_UV*rec->src_height;
1085 tmp /= uv_vscale;
1086 if (rec->offset_U + tmp > new_bo->size ||
1087 rec->offset_V + tmp > new_bo->size)
1088 return -EINVAL;
1089 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001090 }
1091
1092 return 0;
1093}
1094
1095int intel_overlay_put_image(struct drm_device *dev, void *data,
1096 struct drm_file *file_priv)
1097{
1098 struct drm_intel_overlay_put_image *put_image_rec = data;
1099 drm_i915_private_t *dev_priv = dev->dev_private;
1100 struct intel_overlay *overlay;
1101 struct drm_mode_object *drmmode_obj;
1102 struct intel_crtc *crtc;
1103 struct drm_gem_object *new_bo;
1104 struct put_image_params *params;
1105 int ret;
1106
1107 if (!dev_priv) {
1108 DRM_ERROR("called with no initialization\n");
1109 return -EINVAL;
1110 }
1111
1112 overlay = dev_priv->overlay;
1113 if (!overlay) {
1114 DRM_DEBUG("userspace bug: no overlay\n");
1115 return -ENODEV;
1116 }
1117
1118 if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) {
1119 mutex_lock(&dev->mode_config.mutex);
1120 mutex_lock(&dev->struct_mutex);
1121
1122 ret = intel_overlay_switch_off(overlay);
1123
1124 mutex_unlock(&dev->struct_mutex);
1125 mutex_unlock(&dev->mode_config.mutex);
1126
1127 return ret;
1128 }
1129
1130 params = kmalloc(sizeof(struct put_image_params), GFP_KERNEL);
1131 if (!params)
1132 return -ENOMEM;
1133
1134 drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id,
Chris Wilson722506f2010-08-12 09:28:50 +01001135 DRM_MODE_OBJECT_CRTC);
Dan Carpenter915a4282010-03-06 14:05:39 +03001136 if (!drmmode_obj) {
1137 ret = -ENOENT;
1138 goto out_free;
1139 }
Daniel Vetter02e792f2009-09-15 22:57:34 +02001140 crtc = to_intel_crtc(obj_to_crtc(drmmode_obj));
1141
1142 new_bo = drm_gem_object_lookup(dev, file_priv,
Chris Wilson722506f2010-08-12 09:28:50 +01001143 put_image_rec->bo_handle);
Dan Carpenter915a4282010-03-06 14:05:39 +03001144 if (!new_bo) {
1145 ret = -ENOENT;
1146 goto out_free;
1147 }
Daniel Vetter02e792f2009-09-15 22:57:34 +02001148
1149 mutex_lock(&dev->mode_config.mutex);
1150 mutex_lock(&dev->struct_mutex);
1151
Daniel Vetter03f77ea2009-09-15 22:57:37 +02001152 if (overlay->hw_wedged) {
1153 ret = intel_overlay_recover_from_interrupt(overlay, 1);
1154 if (ret != 0)
1155 goto out_unlock;
1156 }
1157
Daniel Vetter02e792f2009-09-15 22:57:34 +02001158 if (overlay->crtc != crtc) {
1159 struct drm_display_mode *mode = &crtc->base.mode;
1160 ret = intel_overlay_switch_off(overlay);
1161 if (ret != 0)
1162 goto out_unlock;
1163
1164 ret = check_overlay_possible_on_crtc(overlay, crtc);
1165 if (ret != 0)
1166 goto out_unlock;
1167
1168 overlay->crtc = crtc;
1169 crtc->overlay = overlay;
1170
1171 if (intel_panel_fitter_pipe(dev) == crtc->pipe
1172 /* and line to wide, i.e. one-line-mode */
1173 && mode->hdisplay > 1024) {
1174 overlay->pfit_active = 1;
1175 update_pfit_vscale_ratio(overlay);
1176 } else
1177 overlay->pfit_active = 0;
1178 }
1179
1180 ret = check_overlay_dst(overlay, put_image_rec);
1181 if (ret != 0)
1182 goto out_unlock;
1183
1184 if (overlay->pfit_active) {
1185 params->dst_y = ((((u32)put_image_rec->dst_y) << 12) /
Chris Wilson722506f2010-08-12 09:28:50 +01001186 overlay->pfit_vscale_ratio);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001187 /* shifting right rounds downwards, so add 1 */
1188 params->dst_h = ((((u32)put_image_rec->dst_height) << 12) /
Chris Wilson722506f2010-08-12 09:28:50 +01001189 overlay->pfit_vscale_ratio) + 1;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001190 } else {
1191 params->dst_y = put_image_rec->dst_y;
1192 params->dst_h = put_image_rec->dst_height;
1193 }
1194 params->dst_x = put_image_rec->dst_x;
1195 params->dst_w = put_image_rec->dst_width;
1196
1197 params->src_w = put_image_rec->src_width;
1198 params->src_h = put_image_rec->src_height;
1199 params->src_scan_w = put_image_rec->src_scan_width;
1200 params->src_scan_h = put_image_rec->src_scan_height;
Chris Wilson722506f2010-08-12 09:28:50 +01001201 if (params->src_scan_h > params->src_h ||
1202 params->src_scan_w > params->src_w) {
Daniel Vetter02e792f2009-09-15 22:57:34 +02001203 ret = -EINVAL;
1204 goto out_unlock;
1205 }
1206
1207 ret = check_overlay_src(dev, put_image_rec, new_bo);
1208 if (ret != 0)
1209 goto out_unlock;
1210 params->format = put_image_rec->flags & ~I915_OVERLAY_FLAGS_MASK;
1211 params->stride_Y = put_image_rec->stride_Y;
1212 params->stride_UV = put_image_rec->stride_UV;
1213 params->offset_Y = put_image_rec->offset_Y;
1214 params->offset_U = put_image_rec->offset_U;
1215 params->offset_V = put_image_rec->offset_V;
1216
1217 /* Check scaling after src size to prevent a divide-by-zero. */
1218 ret = check_overlay_scaling(params);
1219 if (ret != 0)
1220 goto out_unlock;
1221
1222 ret = intel_overlay_do_put_image(overlay, new_bo, params);
1223 if (ret != 0)
1224 goto out_unlock;
1225
1226 mutex_unlock(&dev->struct_mutex);
1227 mutex_unlock(&dev->mode_config.mutex);
1228
1229 kfree(params);
1230
1231 return 0;
1232
1233out_unlock:
1234 mutex_unlock(&dev->struct_mutex);
1235 mutex_unlock(&dev->mode_config.mutex);
Luca Barbieribc9025b2010-02-09 05:49:12 +00001236 drm_gem_object_unreference_unlocked(new_bo);
Dan Carpenter915a4282010-03-06 14:05:39 +03001237out_free:
Daniel Vetter02e792f2009-09-15 22:57:34 +02001238 kfree(params);
1239
1240 return ret;
1241}
1242
1243static void update_reg_attrs(struct intel_overlay *overlay,
1244 struct overlay_registers *regs)
1245{
1246 regs->OCLRC0 = (overlay->contrast << 18) | (overlay->brightness & 0xff);
1247 regs->OCLRC1 = overlay->saturation;
1248}
1249
1250static bool check_gamma_bounds(u32 gamma1, u32 gamma2)
1251{
1252 int i;
1253
1254 if (gamma1 & 0xff000000 || gamma2 & 0xff000000)
1255 return false;
1256
1257 for (i = 0; i < 3; i++) {
Chris Wilson722506f2010-08-12 09:28:50 +01001258 if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
Daniel Vetter02e792f2009-09-15 22:57:34 +02001259 return false;
1260 }
1261
1262 return true;
1263}
1264
1265static bool check_gamma5_errata(u32 gamma5)
1266{
1267 int i;
1268
1269 for (i = 0; i < 3; i++) {
1270 if (((gamma5 >> i*8) & 0xff) == 0x80)
1271 return false;
1272 }
1273
1274 return true;
1275}
1276
1277static int check_gamma(struct drm_intel_overlay_attrs *attrs)
1278{
Chris Wilson722506f2010-08-12 09:28:50 +01001279 if (!check_gamma_bounds(0, attrs->gamma0) ||
1280 !check_gamma_bounds(attrs->gamma0, attrs->gamma1) ||
1281 !check_gamma_bounds(attrs->gamma1, attrs->gamma2) ||
1282 !check_gamma_bounds(attrs->gamma2, attrs->gamma3) ||
1283 !check_gamma_bounds(attrs->gamma3, attrs->gamma4) ||
1284 !check_gamma_bounds(attrs->gamma4, attrs->gamma5) ||
1285 !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
Daniel Vetter02e792f2009-09-15 22:57:34 +02001286 return -EINVAL;
Chris Wilson722506f2010-08-12 09:28:50 +01001287
Daniel Vetter02e792f2009-09-15 22:57:34 +02001288 if (!check_gamma5_errata(attrs->gamma5))
1289 return -EINVAL;
Chris Wilson722506f2010-08-12 09:28:50 +01001290
Daniel Vetter02e792f2009-09-15 22:57:34 +02001291 return 0;
1292}
1293
1294int intel_overlay_attrs(struct drm_device *dev, void *data,
1295 struct drm_file *file_priv)
1296{
1297 struct drm_intel_overlay_attrs *attrs = data;
1298 drm_i915_private_t *dev_priv = dev->dev_private;
1299 struct intel_overlay *overlay;
1300 struct overlay_registers *regs;
1301 int ret;
1302
1303 if (!dev_priv) {
1304 DRM_ERROR("called with no initialization\n");
1305 return -EINVAL;
1306 }
1307
1308 overlay = dev_priv->overlay;
1309 if (!overlay) {
1310 DRM_DEBUG("userspace bug: no overlay\n");
1311 return -ENODEV;
1312 }
1313
1314 mutex_lock(&dev->mode_config.mutex);
1315 mutex_lock(&dev->struct_mutex);
1316
Chris Wilson60fc3322010-08-12 10:44:45 +01001317 ret = -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001318 if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) {
Chris Wilson60fc3322010-08-12 10:44:45 +01001319 attrs->color_key = overlay->color_key;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001320 attrs->brightness = overlay->brightness;
Chris Wilson60fc3322010-08-12 10:44:45 +01001321 attrs->contrast = overlay->contrast;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001322 attrs->saturation = overlay->saturation;
1323
1324 if (IS_I9XX(dev)) {
1325 attrs->gamma0 = I915_READ(OGAMC0);
1326 attrs->gamma1 = I915_READ(OGAMC1);
1327 attrs->gamma2 = I915_READ(OGAMC2);
1328 attrs->gamma3 = I915_READ(OGAMC3);
1329 attrs->gamma4 = I915_READ(OGAMC4);
1330 attrs->gamma5 = I915_READ(OGAMC5);
1331 }
Daniel Vetter02e792f2009-09-15 22:57:34 +02001332 } else {
Chris Wilson60fc3322010-08-12 10:44:45 +01001333 if (attrs->brightness < -128 || attrs->brightness > 127)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001334 goto out_unlock;
Chris Wilson60fc3322010-08-12 10:44:45 +01001335 if (attrs->contrast > 255)
1336 goto out_unlock;
1337 if (attrs->saturation > 1023)
1338 goto out_unlock;
Chris Wilson722506f2010-08-12 09:28:50 +01001339
Chris Wilson60fc3322010-08-12 10:44:45 +01001340 overlay->color_key = attrs->color_key;
1341 overlay->brightness = attrs->brightness;
1342 overlay->contrast = attrs->contrast;
1343 overlay->saturation = attrs->saturation;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001344
Chris Wilson8d74f652010-08-12 10:35:26 +01001345 regs = intel_overlay_map_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001346 if (!regs) {
1347 ret = -ENOMEM;
1348 goto out_unlock;
1349 }
1350
1351 update_reg_attrs(overlay, regs);
1352
Chris Wilson8d74f652010-08-12 10:35:26 +01001353 intel_overlay_unmap_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001354
1355 if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) {
Chris Wilson60fc3322010-08-12 10:44:45 +01001356 if (!IS_I9XX(dev))
Daniel Vetter02e792f2009-09-15 22:57:34 +02001357 goto out_unlock;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001358
1359 if (overlay->active) {
1360 ret = -EBUSY;
1361 goto out_unlock;
1362 }
1363
1364 ret = check_gamma(attrs);
Chris Wilson60fc3322010-08-12 10:44:45 +01001365 if (ret)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001366 goto out_unlock;
1367
1368 I915_WRITE(OGAMC0, attrs->gamma0);
1369 I915_WRITE(OGAMC1, attrs->gamma1);
1370 I915_WRITE(OGAMC2, attrs->gamma2);
1371 I915_WRITE(OGAMC3, attrs->gamma3);
1372 I915_WRITE(OGAMC4, attrs->gamma4);
1373 I915_WRITE(OGAMC5, attrs->gamma5);
1374 }
Daniel Vetter02e792f2009-09-15 22:57:34 +02001375 }
1376
Chris Wilson60fc3322010-08-12 10:44:45 +01001377 ret = 0;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001378out_unlock:
1379 mutex_unlock(&dev->struct_mutex);
1380 mutex_unlock(&dev->mode_config.mutex);
1381
1382 return ret;
1383}
1384
1385void intel_setup_overlay(struct drm_device *dev)
1386{
1387 drm_i915_private_t *dev_priv = dev->dev_private;
1388 struct intel_overlay *overlay;
1389 struct drm_gem_object *reg_bo;
1390 struct overlay_registers *regs;
1391 int ret;
1392
Chris Wilson315781482010-08-12 09:42:51 +01001393 if (!HAS_OVERLAY(dev))
Daniel Vetter02e792f2009-09-15 22:57:34 +02001394 return;
1395
1396 overlay = kzalloc(sizeof(struct intel_overlay), GFP_KERNEL);
1397 if (!overlay)
1398 return;
1399 overlay->dev = dev;
1400
Daniel Vetterac52bc52010-04-09 19:05:06 +00001401 reg_bo = i915_gem_alloc_object(dev, PAGE_SIZE);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001402 if (!reg_bo)
1403 goto out_free;
Daniel Vetter23010e42010-03-08 13:35:02 +01001404 overlay->reg_bo = to_intel_bo(reg_bo);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001405
Chris Wilson315781482010-08-12 09:42:51 +01001406 if (OVERLAY_NEEDS_PHYSICAL(dev)) {
1407 ret = i915_gem_attach_phys_object(dev, reg_bo,
1408 I915_GEM_PHYS_OVERLAY_REGS,
Chris Wilsona2930122010-08-12 10:47:56 +01001409 PAGE_SIZE);
Chris Wilson315781482010-08-12 09:42:51 +01001410 if (ret) {
1411 DRM_ERROR("failed to attach phys overlay regs\n");
1412 goto out_free_bo;
1413 }
1414 overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr;
1415 } else {
Daniel Vetter02e792f2009-09-15 22:57:34 +02001416 ret = i915_gem_object_pin(reg_bo, PAGE_SIZE);
1417 if (ret) {
1418 DRM_ERROR("failed to pin overlay register bo\n");
1419 goto out_free_bo;
1420 }
1421 overlay->flip_addr = overlay->reg_bo->gtt_offset;
Chris Wilson0ddc1282010-08-12 09:35:00 +01001422
1423 ret = i915_gem_object_set_to_gtt_domain(reg_bo, true);
1424 if (ret) {
1425 DRM_ERROR("failed to move overlay register bo into the GTT\n");
1426 goto out_unpin_bo;
1427 }
Daniel Vetter02e792f2009-09-15 22:57:34 +02001428 }
1429
1430 /* init all values */
1431 overlay->color_key = 0x0101fe;
1432 overlay->brightness = -19;
1433 overlay->contrast = 75;
1434 overlay->saturation = 146;
1435
Chris Wilson8d74f652010-08-12 10:35:26 +01001436 regs = intel_overlay_map_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001437 if (!regs)
1438 goto out_free_bo;
1439
1440 memset(regs, 0, sizeof(struct overlay_registers));
1441 update_polyphase_filter(regs);
1442
1443 update_reg_attrs(overlay, regs);
1444
Chris Wilson8d74f652010-08-12 10:35:26 +01001445 intel_overlay_unmap_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001446
1447 dev_priv->overlay = overlay;
1448 DRM_INFO("initialized overlay support\n");
1449 return;
1450
Chris Wilson0ddc1282010-08-12 09:35:00 +01001451out_unpin_bo:
1452 i915_gem_object_unpin(reg_bo);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001453out_free_bo:
1454 drm_gem_object_unreference(reg_bo);
1455out_free:
1456 kfree(overlay);
1457 return;
1458}
1459
1460void intel_cleanup_overlay(struct drm_device *dev)
1461{
Chris Wilson722506f2010-08-12 09:28:50 +01001462 drm_i915_private_t *dev_priv = dev->dev_private;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001463
1464 if (dev_priv->overlay) {
1465 /* The bo's should be free'd by the generic code already.
1466 * Furthermore modesetting teardown happens beforehand so the
1467 * hardware should be off already */
1468 BUG_ON(dev_priv->overlay->active);
1469
1470 kfree(dev_priv->overlay);
1471 }
1472}
Chris Wilson6ef3d422010-08-04 20:26:07 +01001473
1474struct intel_overlay_error_state {
1475 struct overlay_registers regs;
1476 unsigned long base;
1477 u32 dovsta;
1478 u32 isr;
1479};
1480
1481struct intel_overlay_error_state *
1482intel_overlay_capture_error_state(struct drm_device *dev)
1483{
1484 drm_i915_private_t *dev_priv = dev->dev_private;
1485 struct intel_overlay *overlay = dev_priv->overlay;
1486 struct intel_overlay_error_state *error;
1487 struct overlay_registers __iomem *regs;
1488
1489 if (!overlay || !overlay->active)
1490 return NULL;
1491
1492 error = kmalloc(sizeof(*error), GFP_ATOMIC);
1493 if (error == NULL)
1494 return NULL;
1495
1496 error->dovsta = I915_READ(DOVSTA);
1497 error->isr = I915_READ(ISR);
Chris Wilson315781482010-08-12 09:42:51 +01001498 if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
Chris Wilson6ef3d422010-08-04 20:26:07 +01001499 error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr;
Chris Wilson315781482010-08-12 09:42:51 +01001500 else
1501 error->base = (long) overlay->reg_bo->gtt_offset;
Chris Wilson6ef3d422010-08-04 20:26:07 +01001502
Chris Wilson8d74f652010-08-12 10:35:26 +01001503 regs = intel_overlay_map_regs_atomic(overlay, KM_IRQ0);
Chris Wilson6ef3d422010-08-04 20:26:07 +01001504 if (!regs)
1505 goto err;
1506
1507 memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers));
Chris Wilson8d74f652010-08-12 10:35:26 +01001508 intel_overlay_unmap_regs_atomic(overlay, KM_IRQ0);
Chris Wilson6ef3d422010-08-04 20:26:07 +01001509
1510 return error;
1511
1512err:
1513 kfree(error);
1514 return NULL;
1515}
1516
1517void
1518intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error)
1519{
1520 seq_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",
1521 error->dovsta, error->isr);
1522 seq_printf(m, " Register file at 0x%08lx:\n",
1523 error->base);
1524
1525#define P(x) seq_printf(m, " " #x ": 0x%08x\n", error->regs.x)
1526 P(OBUF_0Y);
1527 P(OBUF_1Y);
1528 P(OBUF_0U);
1529 P(OBUF_0V);
1530 P(OBUF_1U);
1531 P(OBUF_1V);
1532 P(OSTRIDE);
1533 P(YRGB_VPH);
1534 P(UV_VPH);
1535 P(HORZ_PH);
1536 P(INIT_PHS);
1537 P(DWINPOS);
1538 P(DWINSZ);
1539 P(SWIDTH);
1540 P(SWIDTHSW);
1541 P(SHEIGHT);
1542 P(YRGBSCALE);
1543 P(UVSCALE);
1544 P(OCLRC0);
1545 P(OCLRC1);
1546 P(DCLRKV);
1547 P(DCLRKM);
1548 P(SCLRKVH);
1549 P(SCLRKVL);
1550 P(SCLRKEN);
1551 P(OCONFIG);
1552 P(OCMD);
1553 P(OSTART_0Y);
1554 P(OSTART_1Y);
1555 P(OSTART_0U);
1556 P(OSTART_0V);
1557 P(OSTART_1U);
1558 P(OSTART_1V);
1559 P(OTILEOFF_0Y);
1560 P(OTILEOFF_1Y);
1561 P(OTILEOFF_0U);
1562 P(OTILEOFF_0V);
1563 P(OTILEOFF_1U);
1564 P(OTILEOFF_1V);
1565 P(FASTHSCALE);
1566 P(UVSCALEV);
1567#undef P
1568}