blob: a203b5c7ff71ae9aa41e4ec94c6b50de529ae94a [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
176#define OVERLAY_NONPHYSICAL(dev) (IS_G33(dev) || IS_I965G(dev))
Eric Anholtbad720f2009-10-22 16:11:14 -0700177#define OVERLAY_EXISTS(dev) (!IS_G4X(dev) && !IS_IRONLAKE(dev) && !IS_GEN6(dev))
Daniel Vetter02e792f2009-09-15 22:57:34 +0200178
179
180static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
181{
182 drm_i915_private_t *dev_priv = overlay->dev->dev_private;
183 struct overlay_registers *regs;
184
185 /* no recursive mappings */
186 BUG_ON(overlay->virt_addr);
187
188 if (OVERLAY_NONPHYSICAL(overlay->dev)) {
189 regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
Chris Wilsonfca3ec02010-08-04 14:34:24 +0100190 overlay->reg_bo->gtt_offset,
191 KM_USER0);
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 }
197 } else
198 regs = overlay->reg_bo->phys_obj->handle->vaddr;
199
200 return overlay->virt_addr = regs;
201}
202
203static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay)
204{
Daniel Vetter02e792f2009-09-15 22:57:34 +0200205 if (OVERLAY_NONPHYSICAL(overlay->dev))
Chris Wilsonfca3ec02010-08-04 14:34:24 +0100206 io_mapping_unmap_atomic(overlay->virt_addr, KM_USER0);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200207
208 overlay->virt_addr = NULL;
209
Daniel Vetter02e792f2009-09-15 22:57:34 +0200210 return;
211}
212
213/* overlay needs to be disable in OCMD reg */
214static int intel_overlay_on(struct intel_overlay *overlay)
215{
216 struct drm_device *dev = overlay->dev;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200217 int ret;
Zou Nan hai852835f2010-05-21 09:08:56 +0800218 drm_i915_private_t *dev_priv = dev->dev_private;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200219
220 BUG_ON(overlay->active);
221
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200222 overlay->active = 1;
223 overlay->hw_wedged = NEEDS_WAIT_FOR_FLIP;
224
Daniel Vetter4f8a5672010-02-11 14:14:43 +0100225 BEGIN_LP_RING(4);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200226 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON);
227 OUT_RING(overlay->flip_addr | OFC_UPDATE);
228 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
229 OUT_RING(MI_NOOP);
230 ADVANCE_LP_RING();
231
Zou Nan hai852835f2010-05-21 09:08:56 +0800232 overlay->last_flip_req =
Daniel Vetter8a1a49f2010-02-11 22:29:04 +0100233 i915_add_request(dev, NULL, &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200234 if (overlay->last_flip_req == 0)
235 return -ENOMEM;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200236
Zou Nan hai852835f2010-05-21 09:08:56 +0800237 ret = i915_do_wait_request(dev,
238 overlay->last_flip_req, 1, &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200239 if (ret != 0)
240 return ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200241
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200242 overlay->hw_wedged = 0;
243 overlay->last_flip_req = 0;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200244 return 0;
245}
246
247/* overlay needs to be enabled in OCMD reg */
248static void intel_overlay_continue(struct intel_overlay *overlay,
249 bool load_polyphase_filter)
250{
251 struct drm_device *dev = overlay->dev;
252 drm_i915_private_t *dev_priv = dev->dev_private;
253 u32 flip_addr = overlay->flip_addr;
254 u32 tmp;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200255
256 BUG_ON(!overlay->active);
257
258 if (load_polyphase_filter)
259 flip_addr |= OFC_UPDATE;
260
261 /* check for underruns */
262 tmp = I915_READ(DOVSTA);
263 if (tmp & (1 << 17))
264 DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
265
Daniel Vetter4f8a5672010-02-11 14:14:43 +0100266 BEGIN_LP_RING(2);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200267 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
268 OUT_RING(flip_addr);
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200269 ADVANCE_LP_RING();
270
Zou Nan hai852835f2010-05-21 09:08:56 +0800271 overlay->last_flip_req =
Daniel Vetter8a1a49f2010-02-11 22:29:04 +0100272 i915_add_request(dev, NULL, &dev_priv->render_ring);
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200273}
274
275static int intel_overlay_wait_flip(struct intel_overlay *overlay)
276{
277 struct drm_device *dev = overlay->dev;
278 drm_i915_private_t *dev_priv = dev->dev_private;
279 int ret;
280 u32 tmp;
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200281
282 if (overlay->last_flip_req != 0) {
Zou Nan hai852835f2010-05-21 09:08:56 +0800283 ret = i915_do_wait_request(dev, overlay->last_flip_req,
284 1, &dev_priv->render_ring);
Daniel Vetter5c5a4352009-10-04 15:00:36 +0200285 if (ret == 0) {
286 overlay->last_flip_req = 0;
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200287
Daniel Vetter5c5a4352009-10-04 15:00:36 +0200288 tmp = I915_READ(ISR);
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200289
Daniel Vetter5c5a4352009-10-04 15:00:36 +0200290 if (!(tmp & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT))
291 return 0;
292 }
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200293 }
294
295 /* synchronous slowpath */
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200296 overlay->hw_wedged = RELEASE_OLD_VID;
297
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200298 BEGIN_LP_RING(2);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200299 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
300 OUT_RING(MI_NOOP);
301 ADVANCE_LP_RING();
302
Zou Nan hai852835f2010-05-21 09:08:56 +0800303 overlay->last_flip_req =
Daniel Vetter8a1a49f2010-02-11 22:29:04 +0100304 i915_add_request(dev, NULL, &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200305 if (overlay->last_flip_req == 0)
306 return -ENOMEM;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200307
Zou Nan hai852835f2010-05-21 09:08:56 +0800308 ret = i915_do_wait_request(dev, overlay->last_flip_req,
309 1, &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200310 if (ret != 0)
311 return ret;
312
313 overlay->hw_wedged = 0;
314 overlay->last_flip_req = 0;
315 return 0;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200316}
317
318/* overlay needs to be disabled in OCMD reg */
319static int intel_overlay_off(struct intel_overlay *overlay)
320{
321 u32 flip_addr = overlay->flip_addr;
322 struct drm_device *dev = overlay->dev;
Zou Nan hai852835f2010-05-21 09:08:56 +0800323 drm_i915_private_t *dev_priv = dev->dev_private;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200324 int ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200325
326 BUG_ON(!overlay->active);
327
328 /* According to intel docs the overlay hw may hang (when switching
329 * off) without loading the filter coeffs. It is however unclear whether
330 * this applies to the disabling of the overlay or to the switching off
331 * of the hw. Do it in both cases */
332 flip_addr |= OFC_UPDATE;
333
334 /* wait for overlay to go idle */
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200335 overlay->hw_wedged = SWITCH_OFF_STAGE_1;
336
Daniel Vetter4f8a5672010-02-11 14:14:43 +0100337 BEGIN_LP_RING(4);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200338 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
339 OUT_RING(flip_addr);
340 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
341 OUT_RING(MI_NOOP);
342 ADVANCE_LP_RING();
343
Zou Nan hai852835f2010-05-21 09:08:56 +0800344 overlay->last_flip_req =
Daniel Vetter8a1a49f2010-02-11 22:29:04 +0100345 i915_add_request(dev, NULL, &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200346 if (overlay->last_flip_req == 0)
347 return -ENOMEM;
348
Zou Nan hai852835f2010-05-21 09:08:56 +0800349 ret = i915_do_wait_request(dev, overlay->last_flip_req,
350 1, &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200351 if (ret != 0)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200352 return ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200353
354 /* turn overlay off */
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200355 overlay->hw_wedged = SWITCH_OFF_STAGE_2;
356
Daniel Vetter4f8a5672010-02-11 14:14:43 +0100357 BEGIN_LP_RING(4);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200358 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
359 OUT_RING(flip_addr);
360 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
361 OUT_RING(MI_NOOP);
362 ADVANCE_LP_RING();
363
Zou Nan hai852835f2010-05-21 09:08:56 +0800364 overlay->last_flip_req =
Daniel Vetter8a1a49f2010-02-11 22:29:04 +0100365 i915_add_request(dev, NULL, &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200366 if (overlay->last_flip_req == 0)
367 return -ENOMEM;
368
Zou Nan hai852835f2010-05-21 09:08:56 +0800369 ret = i915_do_wait_request(dev, overlay->last_flip_req,
370 1, &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200371 if (ret != 0)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200372 return ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200373
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200374 overlay->hw_wedged = 0;
375 overlay->last_flip_req = 0;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200376 return ret;
377}
378
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200379static void intel_overlay_off_tail(struct intel_overlay *overlay)
380{
381 struct drm_gem_object *obj;
382
383 /* never have the overlay hw on without showing a frame */
384 BUG_ON(!overlay->vid_bo);
Daniel Vettera8089e82010-04-09 19:05:09 +0000385 obj = &overlay->vid_bo->base;
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200386
387 i915_gem_object_unpin(obj);
388 drm_gem_object_unreference(obj);
389 overlay->vid_bo = NULL;
390
391 overlay->crtc->overlay = NULL;
392 overlay->crtc = NULL;
393 overlay->active = 0;
394}
395
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200396/* recover from an interruption due to a signal
397 * We have to be careful not to repeat work forever an make forward progess. */
398int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
399 int interruptible)
400{
401 struct drm_device *dev = overlay->dev;
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200402 struct drm_gem_object *obj;
Zou Nan hai852835f2010-05-21 09:08:56 +0800403 drm_i915_private_t *dev_priv = dev->dev_private;
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200404 u32 flip_addr;
405 int ret;
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200406
407 if (overlay->hw_wedged == HW_WEDGED)
408 return -EIO;
409
410 if (overlay->last_flip_req == 0) {
Zou Nan hai852835f2010-05-21 09:08:56 +0800411 overlay->last_flip_req =
Daniel Vetter8a1a49f2010-02-11 22:29:04 +0100412 i915_add_request(dev, NULL, &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200413 if (overlay->last_flip_req == 0)
414 return -ENOMEM;
415 }
416
Zou Nan hai852835f2010-05-21 09:08:56 +0800417 ret = i915_do_wait_request(dev, overlay->last_flip_req,
418 interruptible, &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200419 if (ret != 0)
420 return ret;
421
422 switch (overlay->hw_wedged) {
423 case RELEASE_OLD_VID:
Daniel Vettera8089e82010-04-09 19:05:09 +0000424 obj = &overlay->old_vid_bo->base;
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200425 i915_gem_object_unpin(obj);
426 drm_gem_object_unreference(obj);
427 overlay->old_vid_bo = NULL;
428 break;
429 case SWITCH_OFF_STAGE_1:
430 flip_addr = overlay->flip_addr;
431 flip_addr |= OFC_UPDATE;
432
433 overlay->hw_wedged = SWITCH_OFF_STAGE_2;
434
Daniel Vetter4f8a5672010-02-11 14:14:43 +0100435 BEGIN_LP_RING(4);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200436 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
437 OUT_RING(flip_addr);
438 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
439 OUT_RING(MI_NOOP);
440 ADVANCE_LP_RING();
441
Daniel Vetter8a1a49f2010-02-11 22:29:04 +0100442 overlay->last_flip_req =
443 i915_add_request(dev, NULL,
444 &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200445 if (overlay->last_flip_req == 0)
446 return -ENOMEM;
447
448 ret = i915_do_wait_request(dev, overlay->last_flip_req,
Zou Nan hai852835f2010-05-21 09:08:56 +0800449 interruptible, &dev_priv->render_ring);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200450 if (ret != 0)
451 return ret;
452
453 case SWITCH_OFF_STAGE_2:
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200454 intel_overlay_off_tail(overlay);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200455 break;
456 default:
457 BUG_ON(overlay->hw_wedged != NEEDS_WAIT_FOR_FLIP);
458 }
459
460 overlay->hw_wedged = 0;
461 overlay->last_flip_req = 0;
462 return 0;
463}
464
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200465/* Wait for pending overlay flip and release old frame.
466 * Needs to be called before the overlay register are changed
467 * via intel_overlay_(un)map_regs_atomic */
Daniel Vetter02e792f2009-09-15 22:57:34 +0200468static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
469{
470 int ret;
471 struct drm_gem_object *obj;
472
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200473 /* only wait if there is actually an old frame to release to
474 * guarantee forward progress */
475 if (!overlay->old_vid_bo)
476 return 0;
477
Daniel Vetter02e792f2009-09-15 22:57:34 +0200478 ret = intel_overlay_wait_flip(overlay);
479 if (ret != 0)
480 return ret;
481
Daniel Vettera8089e82010-04-09 19:05:09 +0000482 obj = &overlay->old_vid_bo->base;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200483 i915_gem_object_unpin(obj);
484 drm_gem_object_unreference(obj);
485 overlay->old_vid_bo = NULL;
486
487 return 0;
488}
489
490struct put_image_params {
491 int format;
492 short dst_x;
493 short dst_y;
494 short dst_w;
495 short dst_h;
496 short src_w;
497 short src_scan_h;
498 short src_scan_w;
499 short src_h;
500 short stride_Y;
501 short stride_UV;
502 int offset_Y;
503 int offset_U;
504 int offset_V;
505};
506
507static int packed_depth_bytes(u32 format)
508{
509 switch (format & I915_OVERLAY_DEPTH_MASK) {
510 case I915_OVERLAY_YUV422:
511 return 4;
512 case I915_OVERLAY_YUV411:
513 /* return 6; not implemented */
514 default:
515 return -EINVAL;
516 }
517}
518
519static int packed_width_bytes(u32 format, short width)
520{
521 switch (format & I915_OVERLAY_DEPTH_MASK) {
522 case I915_OVERLAY_YUV422:
523 return width << 1;
524 default:
525 return -EINVAL;
526 }
527}
528
529static int uv_hsubsampling(u32 format)
530{
531 switch (format & I915_OVERLAY_DEPTH_MASK) {
532 case I915_OVERLAY_YUV422:
533 case I915_OVERLAY_YUV420:
534 return 2;
535 case I915_OVERLAY_YUV411:
536 case I915_OVERLAY_YUV410:
537 return 4;
538 default:
539 return -EINVAL;
540 }
541}
542
543static int uv_vsubsampling(u32 format)
544{
545 switch (format & I915_OVERLAY_DEPTH_MASK) {
546 case I915_OVERLAY_YUV420:
547 case I915_OVERLAY_YUV410:
548 return 2;
549 case I915_OVERLAY_YUV422:
550 case I915_OVERLAY_YUV411:
551 return 1;
552 default:
553 return -EINVAL;
554 }
555}
556
557static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width)
558{
559 u32 mask, shift, ret;
560 if (IS_I9XX(dev)) {
561 mask = 0x3f;
562 shift = 6;
563 } else {
564 mask = 0x1f;
565 shift = 5;
566 }
567 ret = ((offset + width + mask) >> shift) - (offset >> shift);
568 if (IS_I9XX(dev))
569 ret <<= 1;
570 ret -=1;
571 return ret << 2;
572}
573
574static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = {
575 0x3000, 0xb4a0, 0x1930, 0x1920, 0xb4a0,
576 0x3000, 0xb500, 0x19d0, 0x1880, 0xb440,
577 0x3000, 0xb540, 0x1a88, 0x2f80, 0xb3e0,
578 0x3000, 0xb580, 0x1b30, 0x2e20, 0xb380,
579 0x3000, 0xb5c0, 0x1bd8, 0x2cc0, 0xb320,
580 0x3020, 0xb5e0, 0x1c60, 0x2b80, 0xb2c0,
581 0x3020, 0xb5e0, 0x1cf8, 0x2a20, 0xb260,
582 0x3020, 0xb5e0, 0x1d80, 0x28e0, 0xb200,
583 0x3020, 0xb5c0, 0x1e08, 0x3f40, 0xb1c0,
584 0x3020, 0xb580, 0x1e78, 0x3ce0, 0xb160,
585 0x3040, 0xb520, 0x1ed8, 0x3aa0, 0xb120,
586 0x3040, 0xb4a0, 0x1f30, 0x3880, 0xb0e0,
587 0x3040, 0xb400, 0x1f78, 0x3680, 0xb0a0,
588 0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060,
589 0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040,
590 0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020,
591 0xb000, 0x3000, 0x0800, 0x3000, 0xb000};
592static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
593 0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60,
594 0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40,
595 0xb040, 0x1b20, 0x29e0, 0xb060, 0x1bd8, 0x2880,
596 0xb080, 0x1c88, 0x3e60, 0xb0a0, 0x1d28, 0x3c00,
597 0xb0c0, 0x1db8, 0x39e0, 0xb0e0, 0x1e40, 0x37e0,
598 0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0,
599 0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240,
600 0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0,
601 0x3000, 0x0800, 0x3000};
602
603static void update_polyphase_filter(struct overlay_registers *regs)
604{
605 memcpy(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs));
606 memcpy(regs->UV_HCOEFS, uv_static_hcoeffs, sizeof(uv_static_hcoeffs));
607}
608
609static bool update_scaling_factors(struct intel_overlay *overlay,
610 struct overlay_registers *regs,
611 struct put_image_params *params)
612{
613 /* fixed point with a 12 bit shift */
614 u32 xscale, yscale, xscale_UV, yscale_UV;
615#define FP_SHIFT 12
616#define FRACT_MASK 0xfff
617 bool scale_changed = false;
618 int uv_hscale = uv_hsubsampling(params->format);
619 int uv_vscale = uv_vsubsampling(params->format);
620
621 if (params->dst_w > 1)
622 xscale = ((params->src_scan_w - 1) << FP_SHIFT)
623 /(params->dst_w);
624 else
625 xscale = 1 << FP_SHIFT;
626
627 if (params->dst_h > 1)
628 yscale = ((params->src_scan_h - 1) << FP_SHIFT)
629 /(params->dst_h);
630 else
631 yscale = 1 << FP_SHIFT;
632
633 /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
634 xscale_UV = xscale/uv_hscale;
635 yscale_UV = yscale/uv_vscale;
636 /* make the Y scale to UV scale ratio an exact multiply */
637 xscale = xscale_UV * uv_hscale;
638 yscale = yscale_UV * uv_vscale;
639 /*} else {
640 xscale_UV = 0;
641 yscale_UV = 0;
642 }*/
643
644 if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)
645 scale_changed = true;
646 overlay->old_xscale = xscale;
647 overlay->old_yscale = yscale;
648
649 regs->YRGBSCALE = ((yscale & FRACT_MASK) << 20)
650 | ((xscale >> FP_SHIFT) << 16)
651 | ((xscale & FRACT_MASK) << 3);
652 regs->UVSCALE = ((yscale_UV & FRACT_MASK) << 20)
653 | ((xscale_UV >> FP_SHIFT) << 16)
654 | ((xscale_UV & FRACT_MASK) << 3);
655 regs->UVSCALEV = ((yscale >> FP_SHIFT) << 16)
656 | ((yscale_UV >> FP_SHIFT) << 0);
657
658 if (scale_changed)
659 update_polyphase_filter(regs);
660
661 return scale_changed;
662}
663
664static void update_colorkey(struct intel_overlay *overlay,
665 struct overlay_registers *regs)
666{
667 u32 key = overlay->color_key;
668 switch (overlay->crtc->base.fb->bits_per_pixel) {
669 case 8:
670 regs->DCLRKV = 0;
671 regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;
672 case 16:
673 if (overlay->crtc->base.fb->depth == 15) {
674 regs->DCLRKV = RGB15_TO_COLORKEY(key);
675 regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;
676 } else {
677 regs->DCLRKV = RGB16_TO_COLORKEY(key);
678 regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;
679 }
680 case 24:
681 case 32:
682 regs->DCLRKV = key;
683 regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;
684 }
685}
686
687static u32 overlay_cmd_reg(struct put_image_params *params)
688{
689 u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0;
690
691 if (params->format & I915_OVERLAY_YUV_PLANAR) {
692 switch (params->format & I915_OVERLAY_DEPTH_MASK) {
693 case I915_OVERLAY_YUV422:
694 cmd |= OCMD_YUV_422_PLANAR;
695 break;
696 case I915_OVERLAY_YUV420:
697 cmd |= OCMD_YUV_420_PLANAR;
698 break;
699 case I915_OVERLAY_YUV411:
700 case I915_OVERLAY_YUV410:
701 cmd |= OCMD_YUV_410_PLANAR;
702 break;
703 }
704 } else { /* YUV packed */
705 switch (params->format & I915_OVERLAY_DEPTH_MASK) {
706 case I915_OVERLAY_YUV422:
707 cmd |= OCMD_YUV_422_PACKED;
708 break;
709 case I915_OVERLAY_YUV411:
710 cmd |= OCMD_YUV_411_PACKED;
711 break;
712 }
713
714 switch (params->format & I915_OVERLAY_SWAP_MASK) {
715 case I915_OVERLAY_NO_SWAP:
716 break;
717 case I915_OVERLAY_UV_SWAP:
718 cmd |= OCMD_UV_SWAP;
719 break;
720 case I915_OVERLAY_Y_SWAP:
721 cmd |= OCMD_Y_SWAP;
722 break;
723 case I915_OVERLAY_Y_AND_UV_SWAP:
724 cmd |= OCMD_Y_AND_UV_SWAP;
725 break;
726 }
727 }
728
729 return cmd;
730}
731
732int intel_overlay_do_put_image(struct intel_overlay *overlay,
733 struct drm_gem_object *new_bo,
734 struct put_image_params *params)
735{
736 int ret, tmp_width;
737 struct overlay_registers *regs;
738 bool scale_changed = false;
Daniel Vetter23010e42010-03-08 13:35:02 +0100739 struct drm_i915_gem_object *bo_priv = to_intel_bo(new_bo);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200740 struct drm_device *dev = overlay->dev;
741
742 BUG_ON(!mutex_is_locked(&dev->struct_mutex));
743 BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
744 BUG_ON(!overlay);
745
Daniel Vetter02e792f2009-09-15 22:57:34 +0200746 ret = intel_overlay_release_old_vid(overlay);
747 if (ret != 0)
748 return ret;
749
750 ret = i915_gem_object_pin(new_bo, PAGE_SIZE);
751 if (ret != 0)
752 return ret;
753
754 ret = i915_gem_object_set_to_gtt_domain(new_bo, 0);
755 if (ret != 0)
756 goto out_unpin;
757
758 if (!overlay->active) {
759 regs = intel_overlay_map_regs_atomic(overlay);
760 if (!regs) {
761 ret = -ENOMEM;
762 goto out_unpin;
763 }
764 regs->OCONFIG = OCONF_CC_OUT_8BIT;
765 if (IS_I965GM(overlay->dev))
766 regs->OCONFIG |= OCONF_CSC_MODE_BT709;
767 regs->OCONFIG |= overlay->crtc->pipe == 0 ?
768 OCONF_PIPE_A : OCONF_PIPE_B;
769 intel_overlay_unmap_regs_atomic(overlay);
770
771 ret = intel_overlay_on(overlay);
772 if (ret != 0)
773 goto out_unpin;
774 }
775
776 regs = intel_overlay_map_regs_atomic(overlay);
777 if (!regs) {
778 ret = -ENOMEM;
779 goto out_unpin;
780 }
781
782 regs->DWINPOS = (params->dst_y << 16) | params->dst_x;
783 regs->DWINSZ = (params->dst_h << 16) | params->dst_w;
784
785 if (params->format & I915_OVERLAY_YUV_PACKED)
786 tmp_width = packed_width_bytes(params->format, params->src_w);
787 else
788 tmp_width = params->src_w;
789
790 regs->SWIDTH = params->src_w;
791 regs->SWIDTHSW = calc_swidthsw(overlay->dev,
792 params->offset_Y, tmp_width);
793 regs->SHEIGHT = params->src_h;
794 regs->OBUF_0Y = bo_priv->gtt_offset + params-> offset_Y;
795 regs->OSTRIDE = params->stride_Y;
796
797 if (params->format & I915_OVERLAY_YUV_PLANAR) {
798 int uv_hscale = uv_hsubsampling(params->format);
799 int uv_vscale = uv_vsubsampling(params->format);
800 u32 tmp_U, tmp_V;
801 regs->SWIDTH |= (params->src_w/uv_hscale) << 16;
802 tmp_U = calc_swidthsw(overlay->dev, params->offset_U,
803 params->src_w/uv_hscale);
804 tmp_V = calc_swidthsw(overlay->dev, params->offset_V,
805 params->src_w/uv_hscale);
806 regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16;
807 regs->SHEIGHT |= (params->src_h/uv_vscale) << 16;
808 regs->OBUF_0U = bo_priv->gtt_offset + params->offset_U;
809 regs->OBUF_0V = bo_priv->gtt_offset + params->offset_V;
810 regs->OSTRIDE |= params->stride_UV << 16;
811 }
812
813 scale_changed = update_scaling_factors(overlay, regs, params);
814
815 update_colorkey(overlay, regs);
816
817 regs->OCMD = overlay_cmd_reg(params);
818
819 intel_overlay_unmap_regs_atomic(overlay);
820
821 intel_overlay_continue(overlay, scale_changed);
822
823 overlay->old_vid_bo = overlay->vid_bo;
Daniel Vetter23010e42010-03-08 13:35:02 +0100824 overlay->vid_bo = to_intel_bo(new_bo);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200825
826 return 0;
827
828out_unpin:
829 i915_gem_object_unpin(new_bo);
830 return ret;
831}
832
833int intel_overlay_switch_off(struct intel_overlay *overlay)
834{
835 int ret;
836 struct overlay_registers *regs;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200837 struct drm_device *dev = overlay->dev;
838
839 BUG_ON(!mutex_is_locked(&dev->struct_mutex));
840 BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
841
Daniel Vetter9bedb972009-11-30 15:55:49 +0100842 if (overlay->hw_wedged) {
843 ret = intel_overlay_recover_from_interrupt(overlay, 1);
844 if (ret != 0)
845 return ret;
846 }
847
Daniel Vetter02e792f2009-09-15 22:57:34 +0200848 if (!overlay->active)
849 return 0;
850
Daniel Vetter02e792f2009-09-15 22:57:34 +0200851 ret = intel_overlay_release_old_vid(overlay);
852 if (ret != 0)
853 return ret;
854
855 regs = intel_overlay_map_regs_atomic(overlay);
856 regs->OCMD = 0;
857 intel_overlay_unmap_regs_atomic(overlay);
858
859 ret = intel_overlay_off(overlay);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200860 if (ret != 0)
861 return ret;
862
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200863 intel_overlay_off_tail(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200864
865 return 0;
866}
867
868static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
869 struct intel_crtc *crtc)
870{
871 drm_i915_private_t *dev_priv = overlay->dev->dev_private;
872 u32 pipeconf;
873 int pipeconf_reg = (crtc->pipe == 0) ? PIPEACONF : PIPEBCONF;
874
875 if (!crtc->base.enabled || crtc->dpms_mode != DRM_MODE_DPMS_ON)
876 return -EINVAL;
877
878 pipeconf = I915_READ(pipeconf_reg);
879
880 /* can't use the overlay with double wide pipe */
881 if (!IS_I965G(overlay->dev) && pipeconf & PIPEACONF_DOUBLE_WIDE)
882 return -EINVAL;
883
884 return 0;
885}
886
887static void update_pfit_vscale_ratio(struct intel_overlay *overlay)
888{
889 struct drm_device *dev = overlay->dev;
890 drm_i915_private_t *dev_priv = dev->dev_private;
891 u32 ratio;
892 u32 pfit_control = I915_READ(PFIT_CONTROL);
893
894 /* XXX: This is not the same logic as in the xorg driver, but more in
895 * line with the intel documentation for the i965 */
896 if (!IS_I965G(dev) && (pfit_control & VERT_AUTO_SCALE)) {
897 ratio = I915_READ(PFIT_AUTO_RATIOS) >> PFIT_VERT_SCALE_SHIFT;
898 } else { /* on i965 use the PGM reg to read out the autoscaler values */
899 ratio = I915_READ(PFIT_PGM_RATIOS);
900 if (IS_I965G(dev))
901 ratio >>= PFIT_VERT_SCALE_SHIFT_965;
902 else
903 ratio >>= PFIT_VERT_SCALE_SHIFT;
904 }
905
906 overlay->pfit_vscale_ratio = ratio;
907}
908
909static int check_overlay_dst(struct intel_overlay *overlay,
910 struct drm_intel_overlay_put_image *rec)
911{
912 struct drm_display_mode *mode = &overlay->crtc->base.mode;
913
914 if ((rec->dst_x < mode->crtc_hdisplay)
915 && (rec->dst_x + rec->dst_width
916 <= mode->crtc_hdisplay)
917 && (rec->dst_y < mode->crtc_vdisplay)
918 && (rec->dst_y + rec->dst_height
919 <= mode->crtc_vdisplay))
920 return 0;
921 else
922 return -EINVAL;
923}
924
925static int check_overlay_scaling(struct put_image_params *rec)
926{
927 u32 tmp;
928
929 /* downscaling limit is 8.0 */
930 tmp = ((rec->src_scan_h << 16) / rec->dst_h) >> 16;
931 if (tmp > 7)
932 return -EINVAL;
933 tmp = ((rec->src_scan_w << 16) / rec->dst_w) >> 16;
934 if (tmp > 7)
935 return -EINVAL;
936
937 return 0;
938}
939
940static int check_overlay_src(struct drm_device *dev,
941 struct drm_intel_overlay_put_image *rec,
942 struct drm_gem_object *new_bo)
943{
944 u32 stride_mask;
945 int depth;
946 int uv_hscale = uv_hsubsampling(rec->flags);
947 int uv_vscale = uv_vsubsampling(rec->flags);
948 size_t tmp;
949
950 /* check src dimensions */
951 if (IS_845G(dev) || IS_I830(dev)) {
952 if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY
953 || rec->src_width > IMAGE_MAX_WIDTH_LEGACY)
954 return -EINVAL;
955 } else {
956 if (rec->src_height > IMAGE_MAX_HEIGHT
957 || rec->src_width > IMAGE_MAX_WIDTH)
958 return -EINVAL;
959 }
960 /* better safe than sorry, use 4 as the maximal subsampling ratio */
961 if (rec->src_height < N_VERT_Y_TAPS*4
962 || rec->src_width < N_HORIZ_Y_TAPS*4)
963 return -EINVAL;
964
Chris Wilsona1efd142010-07-12 19:35:38 +0100965 /* check alignment constraints */
Daniel Vetter02e792f2009-09-15 22:57:34 +0200966 switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
967 case I915_OVERLAY_RGB:
968 /* not implemented */
969 return -EINVAL;
970 case I915_OVERLAY_YUV_PACKED:
971 depth = packed_depth_bytes(rec->flags);
972 if (uv_vscale != 1)
973 return -EINVAL;
974 if (depth < 0)
975 return depth;
976 /* ignore UV planes */
977 rec->stride_UV = 0;
978 rec->offset_U = 0;
979 rec->offset_V = 0;
980 /* check pixel alignment */
981 if (rec->offset_Y % depth)
982 return -EINVAL;
983 break;
984 case I915_OVERLAY_YUV_PLANAR:
985 if (uv_vscale < 0 || uv_hscale < 0)
986 return -EINVAL;
987 /* no offset restrictions for planar formats */
988 break;
989 default:
990 return -EINVAL;
991 }
992
993 if (rec->src_width % uv_hscale)
994 return -EINVAL;
995
996 /* stride checking */
Chris Wilsona1efd142010-07-12 19:35:38 +0100997 if (IS_I830(dev) || IS_845G(dev))
998 stride_mask = 255;
999 else
1000 stride_mask = 63;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001001
1002 if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
1003 return -EINVAL;
1004 if (IS_I965G(dev) && rec->stride_Y < 512)
1005 return -EINVAL;
1006
1007 tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ?
1008 4 : 8;
1009 if (rec->stride_Y > tmp*1024 || rec->stride_UV > 2*1024)
1010 return -EINVAL;
1011
1012 /* check buffer dimensions */
1013 switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
1014 case I915_OVERLAY_RGB:
1015 case I915_OVERLAY_YUV_PACKED:
1016 /* always 4 Y values per depth pixels */
1017 if (packed_width_bytes(rec->flags, rec->src_width)
1018 > rec->stride_Y)
1019 return -EINVAL;
1020
1021 tmp = rec->stride_Y*rec->src_height;
1022 if (rec->offset_Y + tmp > new_bo->size)
1023 return -EINVAL;
1024 break;
1025 case I915_OVERLAY_YUV_PLANAR:
1026 if (rec->src_width > rec->stride_Y)
1027 return -EINVAL;
1028 if (rec->src_width/uv_hscale > rec->stride_UV)
1029 return -EINVAL;
1030
1031 tmp = rec->stride_Y*rec->src_height;
1032 if (rec->offset_Y + tmp > new_bo->size)
1033 return -EINVAL;
1034 tmp = rec->stride_UV*rec->src_height;
1035 tmp /= uv_vscale;
1036 if (rec->offset_U + tmp > new_bo->size
1037 || rec->offset_V + tmp > new_bo->size)
1038 return -EINVAL;
1039 break;
1040 }
1041
1042 return 0;
1043}
1044
1045int intel_overlay_put_image(struct drm_device *dev, void *data,
1046 struct drm_file *file_priv)
1047{
1048 struct drm_intel_overlay_put_image *put_image_rec = data;
1049 drm_i915_private_t *dev_priv = dev->dev_private;
1050 struct intel_overlay *overlay;
1051 struct drm_mode_object *drmmode_obj;
1052 struct intel_crtc *crtc;
1053 struct drm_gem_object *new_bo;
1054 struct put_image_params *params;
1055 int ret;
1056
1057 if (!dev_priv) {
1058 DRM_ERROR("called with no initialization\n");
1059 return -EINVAL;
1060 }
1061
1062 overlay = dev_priv->overlay;
1063 if (!overlay) {
1064 DRM_DEBUG("userspace bug: no overlay\n");
1065 return -ENODEV;
1066 }
1067
1068 if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) {
1069 mutex_lock(&dev->mode_config.mutex);
1070 mutex_lock(&dev->struct_mutex);
1071
1072 ret = intel_overlay_switch_off(overlay);
1073
1074 mutex_unlock(&dev->struct_mutex);
1075 mutex_unlock(&dev->mode_config.mutex);
1076
1077 return ret;
1078 }
1079
1080 params = kmalloc(sizeof(struct put_image_params), GFP_KERNEL);
1081 if (!params)
1082 return -ENOMEM;
1083
1084 drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id,
1085 DRM_MODE_OBJECT_CRTC);
Dan Carpenter915a4282010-03-06 14:05:39 +03001086 if (!drmmode_obj) {
1087 ret = -ENOENT;
1088 goto out_free;
1089 }
Daniel Vetter02e792f2009-09-15 22:57:34 +02001090 crtc = to_intel_crtc(obj_to_crtc(drmmode_obj));
1091
1092 new_bo = drm_gem_object_lookup(dev, file_priv,
1093 put_image_rec->bo_handle);
Dan Carpenter915a4282010-03-06 14:05:39 +03001094 if (!new_bo) {
1095 ret = -ENOENT;
1096 goto out_free;
1097 }
Daniel Vetter02e792f2009-09-15 22:57:34 +02001098
1099 mutex_lock(&dev->mode_config.mutex);
1100 mutex_lock(&dev->struct_mutex);
1101
Daniel Vetter03f77ea2009-09-15 22:57:37 +02001102 if (overlay->hw_wedged) {
1103 ret = intel_overlay_recover_from_interrupt(overlay, 1);
1104 if (ret != 0)
1105 goto out_unlock;
1106 }
1107
Daniel Vetter02e792f2009-09-15 22:57:34 +02001108 if (overlay->crtc != crtc) {
1109 struct drm_display_mode *mode = &crtc->base.mode;
1110 ret = intel_overlay_switch_off(overlay);
1111 if (ret != 0)
1112 goto out_unlock;
1113
1114 ret = check_overlay_possible_on_crtc(overlay, crtc);
1115 if (ret != 0)
1116 goto out_unlock;
1117
1118 overlay->crtc = crtc;
1119 crtc->overlay = overlay;
1120
1121 if (intel_panel_fitter_pipe(dev) == crtc->pipe
1122 /* and line to wide, i.e. one-line-mode */
1123 && mode->hdisplay > 1024) {
1124 overlay->pfit_active = 1;
1125 update_pfit_vscale_ratio(overlay);
1126 } else
1127 overlay->pfit_active = 0;
1128 }
1129
1130 ret = check_overlay_dst(overlay, put_image_rec);
1131 if (ret != 0)
1132 goto out_unlock;
1133
1134 if (overlay->pfit_active) {
1135 params->dst_y = ((((u32)put_image_rec->dst_y) << 12) /
1136 overlay->pfit_vscale_ratio);
1137 /* shifting right rounds downwards, so add 1 */
1138 params->dst_h = ((((u32)put_image_rec->dst_height) << 12) /
1139 overlay->pfit_vscale_ratio) + 1;
1140 } else {
1141 params->dst_y = put_image_rec->dst_y;
1142 params->dst_h = put_image_rec->dst_height;
1143 }
1144 params->dst_x = put_image_rec->dst_x;
1145 params->dst_w = put_image_rec->dst_width;
1146
1147 params->src_w = put_image_rec->src_width;
1148 params->src_h = put_image_rec->src_height;
1149 params->src_scan_w = put_image_rec->src_scan_width;
1150 params->src_scan_h = put_image_rec->src_scan_height;
1151 if (params->src_scan_h > params->src_h
1152 || params->src_scan_w > params->src_w) {
1153 ret = -EINVAL;
1154 goto out_unlock;
1155 }
1156
1157 ret = check_overlay_src(dev, put_image_rec, new_bo);
1158 if (ret != 0)
1159 goto out_unlock;
1160 params->format = put_image_rec->flags & ~I915_OVERLAY_FLAGS_MASK;
1161 params->stride_Y = put_image_rec->stride_Y;
1162 params->stride_UV = put_image_rec->stride_UV;
1163 params->offset_Y = put_image_rec->offset_Y;
1164 params->offset_U = put_image_rec->offset_U;
1165 params->offset_V = put_image_rec->offset_V;
1166
1167 /* Check scaling after src size to prevent a divide-by-zero. */
1168 ret = check_overlay_scaling(params);
1169 if (ret != 0)
1170 goto out_unlock;
1171
1172 ret = intel_overlay_do_put_image(overlay, new_bo, params);
1173 if (ret != 0)
1174 goto out_unlock;
1175
1176 mutex_unlock(&dev->struct_mutex);
1177 mutex_unlock(&dev->mode_config.mutex);
1178
1179 kfree(params);
1180
1181 return 0;
1182
1183out_unlock:
1184 mutex_unlock(&dev->struct_mutex);
1185 mutex_unlock(&dev->mode_config.mutex);
Luca Barbieribc9025b2010-02-09 05:49:12 +00001186 drm_gem_object_unreference_unlocked(new_bo);
Dan Carpenter915a4282010-03-06 14:05:39 +03001187out_free:
Daniel Vetter02e792f2009-09-15 22:57:34 +02001188 kfree(params);
1189
1190 return ret;
1191}
1192
1193static void update_reg_attrs(struct intel_overlay *overlay,
1194 struct overlay_registers *regs)
1195{
1196 regs->OCLRC0 = (overlay->contrast << 18) | (overlay->brightness & 0xff);
1197 regs->OCLRC1 = overlay->saturation;
1198}
1199
1200static bool check_gamma_bounds(u32 gamma1, u32 gamma2)
1201{
1202 int i;
1203
1204 if (gamma1 & 0xff000000 || gamma2 & 0xff000000)
1205 return false;
1206
1207 for (i = 0; i < 3; i++) {
1208 if (((gamma1 >> i * 8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
1209 return false;
1210 }
1211
1212 return true;
1213}
1214
1215static bool check_gamma5_errata(u32 gamma5)
1216{
1217 int i;
1218
1219 for (i = 0; i < 3; i++) {
1220 if (((gamma5 >> i*8) & 0xff) == 0x80)
1221 return false;
1222 }
1223
1224 return true;
1225}
1226
1227static int check_gamma(struct drm_intel_overlay_attrs *attrs)
1228{
1229 if (!check_gamma_bounds(0, attrs->gamma0)
1230 || !check_gamma_bounds(attrs->gamma0, attrs->gamma1)
1231 || !check_gamma_bounds(attrs->gamma1, attrs->gamma2)
1232 || !check_gamma_bounds(attrs->gamma2, attrs->gamma3)
1233 || !check_gamma_bounds(attrs->gamma3, attrs->gamma4)
1234 || !check_gamma_bounds(attrs->gamma4, attrs->gamma5)
1235 || !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
1236 return -EINVAL;
1237 if (!check_gamma5_errata(attrs->gamma5))
1238 return -EINVAL;
1239 return 0;
1240}
1241
1242int intel_overlay_attrs(struct drm_device *dev, void *data,
1243 struct drm_file *file_priv)
1244{
1245 struct drm_intel_overlay_attrs *attrs = data;
1246 drm_i915_private_t *dev_priv = dev->dev_private;
1247 struct intel_overlay *overlay;
1248 struct overlay_registers *regs;
1249 int ret;
1250
1251 if (!dev_priv) {
1252 DRM_ERROR("called with no initialization\n");
1253 return -EINVAL;
1254 }
1255
1256 overlay = dev_priv->overlay;
1257 if (!overlay) {
1258 DRM_DEBUG("userspace bug: no overlay\n");
1259 return -ENODEV;
1260 }
1261
1262 mutex_lock(&dev->mode_config.mutex);
1263 mutex_lock(&dev->struct_mutex);
1264
1265 if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) {
1266 attrs->color_key = overlay->color_key;
1267 attrs->brightness = overlay->brightness;
1268 attrs->contrast = overlay->contrast;
1269 attrs->saturation = overlay->saturation;
1270
1271 if (IS_I9XX(dev)) {
1272 attrs->gamma0 = I915_READ(OGAMC0);
1273 attrs->gamma1 = I915_READ(OGAMC1);
1274 attrs->gamma2 = I915_READ(OGAMC2);
1275 attrs->gamma3 = I915_READ(OGAMC3);
1276 attrs->gamma4 = I915_READ(OGAMC4);
1277 attrs->gamma5 = I915_READ(OGAMC5);
1278 }
1279 ret = 0;
1280 } else {
1281 overlay->color_key = attrs->color_key;
1282 if (attrs->brightness >= -128 && attrs->brightness <= 127) {
1283 overlay->brightness = attrs->brightness;
1284 } else {
1285 ret = -EINVAL;
1286 goto out_unlock;
1287 }
1288 if (attrs->contrast <= 255) {
1289 overlay->contrast = attrs->contrast;
1290 } else {
1291 ret = -EINVAL;
1292 goto out_unlock;
1293 }
1294 if (attrs->saturation <= 1023) {
1295 overlay->saturation = attrs->saturation;
1296 } else {
1297 ret = -EINVAL;
1298 goto out_unlock;
1299 }
1300
1301 regs = intel_overlay_map_regs_atomic(overlay);
1302 if (!regs) {
1303 ret = -ENOMEM;
1304 goto out_unlock;
1305 }
1306
1307 update_reg_attrs(overlay, regs);
1308
1309 intel_overlay_unmap_regs_atomic(overlay);
1310
1311 if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) {
1312 if (!IS_I9XX(dev)) {
1313 ret = -EINVAL;
1314 goto out_unlock;
1315 }
1316
1317 if (overlay->active) {
1318 ret = -EBUSY;
1319 goto out_unlock;
1320 }
1321
1322 ret = check_gamma(attrs);
1323 if (ret != 0)
1324 goto out_unlock;
1325
1326 I915_WRITE(OGAMC0, attrs->gamma0);
1327 I915_WRITE(OGAMC1, attrs->gamma1);
1328 I915_WRITE(OGAMC2, attrs->gamma2);
1329 I915_WRITE(OGAMC3, attrs->gamma3);
1330 I915_WRITE(OGAMC4, attrs->gamma4);
1331 I915_WRITE(OGAMC5, attrs->gamma5);
1332 }
1333 ret = 0;
1334 }
1335
1336out_unlock:
1337 mutex_unlock(&dev->struct_mutex);
1338 mutex_unlock(&dev->mode_config.mutex);
1339
1340 return ret;
1341}
1342
1343void intel_setup_overlay(struct drm_device *dev)
1344{
1345 drm_i915_private_t *dev_priv = dev->dev_private;
1346 struct intel_overlay *overlay;
1347 struct drm_gem_object *reg_bo;
1348 struct overlay_registers *regs;
1349 int ret;
1350
1351 if (!OVERLAY_EXISTS(dev))
1352 return;
1353
1354 overlay = kzalloc(sizeof(struct intel_overlay), GFP_KERNEL);
1355 if (!overlay)
1356 return;
1357 overlay->dev = dev;
1358
Daniel Vetterac52bc52010-04-09 19:05:06 +00001359 reg_bo = i915_gem_alloc_object(dev, PAGE_SIZE);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001360 if (!reg_bo)
1361 goto out_free;
Daniel Vetter23010e42010-03-08 13:35:02 +01001362 overlay->reg_bo = to_intel_bo(reg_bo);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001363
1364 if (OVERLAY_NONPHYSICAL(dev)) {
1365 ret = i915_gem_object_pin(reg_bo, PAGE_SIZE);
1366 if (ret) {
1367 DRM_ERROR("failed to pin overlay register bo\n");
1368 goto out_free_bo;
1369 }
1370 overlay->flip_addr = overlay->reg_bo->gtt_offset;
1371 } else {
1372 ret = i915_gem_attach_phys_object(dev, reg_bo,
Chris Wilson6eeefaf2010-08-07 11:01:39 +01001373 I915_GEM_PHYS_OVERLAY_REGS,
1374 0);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001375 if (ret) {
1376 DRM_ERROR("failed to attach phys overlay regs\n");
1377 goto out_free_bo;
1378 }
1379 overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr;
1380 }
1381
1382 /* init all values */
1383 overlay->color_key = 0x0101fe;
1384 overlay->brightness = -19;
1385 overlay->contrast = 75;
1386 overlay->saturation = 146;
1387
1388 regs = intel_overlay_map_regs_atomic(overlay);
1389 if (!regs)
1390 goto out_free_bo;
1391
1392 memset(regs, 0, sizeof(struct overlay_registers));
1393 update_polyphase_filter(regs);
1394
1395 update_reg_attrs(overlay, regs);
1396
1397 intel_overlay_unmap_regs_atomic(overlay);
1398
1399 dev_priv->overlay = overlay;
1400 DRM_INFO("initialized overlay support\n");
1401 return;
1402
1403out_free_bo:
1404 drm_gem_object_unreference(reg_bo);
1405out_free:
1406 kfree(overlay);
1407 return;
1408}
1409
1410void intel_cleanup_overlay(struct drm_device *dev)
1411{
1412 drm_i915_private_t *dev_priv = dev->dev_private;
1413
1414 if (dev_priv->overlay) {
1415 /* The bo's should be free'd by the generic code already.
1416 * Furthermore modesetting teardown happens beforehand so the
1417 * hardware should be off already */
1418 BUG_ON(dev_priv->overlay->active);
1419
1420 kfree(dev_priv->overlay);
1421 }
1422}
Chris Wilson6ef3d422010-08-04 20:26:07 +01001423
1424struct intel_overlay_error_state {
1425 struct overlay_registers regs;
1426 unsigned long base;
1427 u32 dovsta;
1428 u32 isr;
1429};
1430
1431struct intel_overlay_error_state *
1432intel_overlay_capture_error_state(struct drm_device *dev)
1433{
1434 drm_i915_private_t *dev_priv = dev->dev_private;
1435 struct intel_overlay *overlay = dev_priv->overlay;
1436 struct intel_overlay_error_state *error;
1437 struct overlay_registers __iomem *regs;
1438
1439 if (!overlay || !overlay->active)
1440 return NULL;
1441
1442 error = kmalloc(sizeof(*error), GFP_ATOMIC);
1443 if (error == NULL)
1444 return NULL;
1445
1446 error->dovsta = I915_READ(DOVSTA);
1447 error->isr = I915_READ(ISR);
1448 if (OVERLAY_NONPHYSICAL(overlay->dev))
1449 error->base = (long) overlay->reg_bo->gtt_offset;
1450 else
1451 error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr;
1452
1453 regs = intel_overlay_map_regs_atomic(overlay);
1454 if (!regs)
1455 goto err;
1456
1457 memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers));
1458 intel_overlay_unmap_regs_atomic(overlay);
1459
1460 return error;
1461
1462err:
1463 kfree(error);
1464 return NULL;
1465}
1466
1467void
1468intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error)
1469{
1470 seq_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",
1471 error->dovsta, error->isr);
1472 seq_printf(m, " Register file at 0x%08lx:\n",
1473 error->base);
1474
1475#define P(x) seq_printf(m, " " #x ": 0x%08x\n", error->regs.x)
1476 P(OBUF_0Y);
1477 P(OBUF_1Y);
1478 P(OBUF_0U);
1479 P(OBUF_0V);
1480 P(OBUF_1U);
1481 P(OBUF_1V);
1482 P(OSTRIDE);
1483 P(YRGB_VPH);
1484 P(UV_VPH);
1485 P(HORZ_PH);
1486 P(INIT_PHS);
1487 P(DWINPOS);
1488 P(DWINSZ);
1489 P(SWIDTH);
1490 P(SWIDTHSW);
1491 P(SHEIGHT);
1492 P(YRGBSCALE);
1493 P(UVSCALE);
1494 P(OCLRC0);
1495 P(OCLRC1);
1496 P(DCLRKV);
1497 P(DCLRKM);
1498 P(SCLRKVH);
1499 P(SCLRKVL);
1500 P(SCLRKEN);
1501 P(OCONFIG);
1502 P(OCMD);
1503 P(OSTART_0Y);
1504 P(OSTART_1Y);
1505 P(OSTART_0U);
1506 P(OSTART_0V);
1507 P(OSTART_1U);
1508 P(OSTART_1V);
1509 P(OTILEOFF_0Y);
1510 P(OTILEOFF_1Y);
1511 P(OTILEOFF_0U);
1512 P(OTILEOFF_0V);
1513 P(OTILEOFF_1U);
1514 P(OTILEOFF_1V);
1515 P(FASTHSCALE);
1516 P(UVSCALEV);
1517#undef P
1518}