blob: d0c1add393a3a84df4b7b9ec9d93e51b24ef26f6 [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
Chris Wilson23f09ce2010-08-12 13:53:37 +0100173struct intel_overlay {
174 struct drm_device *dev;
175 struct intel_crtc *crtc;
176 struct drm_i915_gem_object *vid_bo;
177 struct drm_i915_gem_object *old_vid_bo;
178 int active;
179 int pfit_active;
180 u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
181 u32 color_key;
182 u32 brightness, contrast, saturation;
183 u32 old_xscale, old_yscale;
184 /* register access */
185 u32 flip_addr;
186 struct drm_i915_gem_object *reg_bo;
187 /* flip handling */
188 uint32_t last_flip_req;
Chris Wilsonb303cf92010-08-12 14:03:48 +0100189 void (*flip_tail)(struct intel_overlay *);
Chris Wilson23f09ce2010-08-12 13:53:37 +0100190};
Daniel Vetter02e792f2009-09-15 22:57:34 +0200191
Chris Wilson8d74f652010-08-12 10:35:26 +0100192static struct overlay_registers *
Chris Wilson8d74f652010-08-12 10:35:26 +0100193intel_overlay_map_regs(struct intel_overlay *overlay)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200194{
195 drm_i915_private_t *dev_priv = overlay->dev->dev_private;
196 struct overlay_registers *regs;
197
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100198 if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
Daniel Vetter02e792f2009-09-15 22:57:34 +0200199 regs = overlay->reg_bo->phys_obj->handle->vaddr;
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100200 else
Chris Wilson8d74f652010-08-12 10:35:26 +0100201 regs = io_mapping_map_wc(dev_priv->mm.gtt_mapping,
202 overlay->reg_bo->gtt_offset);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200203
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100204 return regs;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200205}
206
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100207static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
208 struct overlay_registers *regs)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200209{
Chris Wilson8d74f652010-08-12 10:35:26 +0100210 if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100211 io_mapping_unmap(regs);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200212}
Daniel Vetter02e792f2009-09-15 22:57:34 +0200213
Chris Wilsonb6c028e2010-08-12 11:55:08 +0100214static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
Chris Wilson8dc5d142010-08-12 12:36:12 +0100215 struct drm_i915_gem_request *request,
Chris Wilsonb6c028e2010-08-12 11:55:08 +0100216 bool interruptible,
Chris Wilsonb303cf92010-08-12 14:03:48 +0100217 void (*tail)(struct intel_overlay *))
Chris Wilsonb6c028e2010-08-12 11:55:08 +0100218{
219 struct drm_device *dev = overlay->dev;
220 drm_i915_private_t *dev_priv = dev->dev_private;
221 int ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200222
Chris Wilsonb303cf92010-08-12 14:03:48 +0100223 BUG_ON(overlay->last_flip_req);
Chris Wilson3cce4692010-10-27 16:11:02 +0100224 ret = i915_add_request(dev, NULL, request, &dev_priv->render_ring);
225 if (ret) {
226 kfree(request);
227 return ret;
228 }
229 overlay->last_flip_req = request->seqno;
Chris Wilsonb303cf92010-08-12 14:03:48 +0100230 overlay->flip_tail = tail;
Chris Wilsonb6c028e2010-08-12 11:55:08 +0100231 ret = i915_do_wait_request(dev,
232 overlay->last_flip_req, true,
233 &dev_priv->render_ring);
234 if (ret)
235 return ret;
236
Chris Wilsonb6c028e2010-08-12 11:55:08 +0100237 overlay->last_flip_req = 0;
238 return 0;
239}
240
Chris Wilson106dada2010-07-16 17:13:01 +0100241/* Workaround for i830 bug where pipe a must be enable to change control regs */
242static int
243i830_activate_pipe_a(struct drm_device *dev)
244{
245 drm_i915_private_t *dev_priv = dev->dev_private;
246 struct intel_crtc *crtc;
247 struct drm_crtc_helper_funcs *crtc_funcs;
248 struct drm_display_mode vesa_640x480 = {
249 DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
250 752, 800, 0, 480, 489, 492, 525, 0,
251 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)
252 }, *mode;
253
254 crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[0]);
255 if (crtc->dpms_mode == DRM_MODE_DPMS_ON)
256 return 0;
257
258 /* most i8xx have pipe a forced on, so don't trust dpms mode */
Chris Wilson5eddb702010-09-11 13:48:45 +0100259 if (I915_READ(PIPEACONF) & PIPECONF_ENABLE)
Chris Wilson106dada2010-07-16 17:13:01 +0100260 return 0;
261
262 crtc_funcs = crtc->base.helper_private;
263 if (crtc_funcs->dpms == NULL)
264 return 0;
265
266 DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n");
267
268 mode = drm_mode_duplicate(dev, &vesa_640x480);
269 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
270 if(!drm_crtc_helper_set_mode(&crtc->base, mode,
271 crtc->base.x, crtc->base.y,
272 crtc->base.fb))
273 return 0;
274
275 crtc_funcs->dpms(&crtc->base, DRM_MODE_DPMS_ON);
276 return 1;
277}
278
279static void
280i830_deactivate_pipe_a(struct drm_device *dev)
281{
282 drm_i915_private_t *dev_priv = dev->dev_private;
283 struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0];
284 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
285
286 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200287}
288
289/* overlay needs to be disable in OCMD reg */
290static int intel_overlay_on(struct intel_overlay *overlay)
291{
292 struct drm_device *dev = overlay->dev;
Chris Wilsone1f99ce2010-10-27 12:45:26 +0100293 struct drm_i915_private *dev_priv = dev->dev_private;
Chris Wilson8dc5d142010-08-12 12:36:12 +0100294 struct drm_i915_gem_request *request;
Chris Wilson106dada2010-07-16 17:13:01 +0100295 int pipe_a_quirk = 0;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200296 int ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200297
298 BUG_ON(overlay->active);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200299 overlay->active = 1;
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200300
Chris Wilson106dada2010-07-16 17:13:01 +0100301 if (IS_I830(dev)) {
302 pipe_a_quirk = i830_activate_pipe_a(dev);
303 if (pipe_a_quirk < 0)
304 return pipe_a_quirk;
305 }
306
Chris Wilson8dc5d142010-08-12 12:36:12 +0100307 request = kzalloc(sizeof(*request), GFP_KERNEL);
Chris Wilson106dada2010-07-16 17:13:01 +0100308 if (request == NULL) {
309 ret = -ENOMEM;
310 goto out;
311 }
Daniel Vetter02e792f2009-09-15 22:57:34 +0200312
Chris Wilsone1f99ce2010-10-27 12:45:26 +0100313 ret = BEGIN_LP_RING(4);
314 if (ret) {
315 kfree(request);
316 goto out;
317 }
318
Daniel Vetter02e792f2009-09-15 22:57:34 +0200319 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON);
320 OUT_RING(overlay->flip_addr | OFC_UPDATE);
321 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
322 OUT_RING(MI_NOOP);
323 ADVANCE_LP_RING();
324
Chris Wilsonb303cf92010-08-12 14:03:48 +0100325 ret = intel_overlay_do_wait_request(overlay, request, true, NULL);
Chris Wilson106dada2010-07-16 17:13:01 +0100326out:
327 if (pipe_a_quirk)
328 i830_deactivate_pipe_a(dev);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200329
Chris Wilson106dada2010-07-16 17:13:01 +0100330 return ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200331}
332
333/* overlay needs to be enabled in OCMD reg */
Chris Wilson8dc5d142010-08-12 12:36:12 +0100334static int intel_overlay_continue(struct intel_overlay *overlay,
335 bool load_polyphase_filter)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200336{
337 struct drm_device *dev = overlay->dev;
338 drm_i915_private_t *dev_priv = dev->dev_private;
Chris Wilson8dc5d142010-08-12 12:36:12 +0100339 struct drm_i915_gem_request *request;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200340 u32 flip_addr = overlay->flip_addr;
341 u32 tmp;
Chris Wilsone1f99ce2010-10-27 12:45:26 +0100342 int ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200343
344 BUG_ON(!overlay->active);
345
Chris Wilson8dc5d142010-08-12 12:36:12 +0100346 request = kzalloc(sizeof(*request), GFP_KERNEL);
347 if (request == NULL)
348 return -ENOMEM;
349
Daniel Vetter02e792f2009-09-15 22:57:34 +0200350 if (load_polyphase_filter)
351 flip_addr |= OFC_UPDATE;
352
353 /* check for underruns */
354 tmp = I915_READ(DOVSTA);
355 if (tmp & (1 << 17))
356 DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
357
Chris Wilsone1f99ce2010-10-27 12:45:26 +0100358 ret = BEGIN_LP_RING(2);
359 if (ret) {
360 kfree(request);
361 return ret;
362 }
Daniel Vetter02e792f2009-09-15 22:57:34 +0200363 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
364 OUT_RING(flip_addr);
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200365 ADVANCE_LP_RING();
366
Chris Wilson3cce4692010-10-27 16:11:02 +0100367 ret = i915_add_request(dev, NULL, request, &dev_priv->render_ring);
368 if (ret) {
369 kfree(request);
370 return ret;
371 }
372
373 overlay->last_flip_req = request->seqno;
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200374 return 0;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200375}
376
Chris Wilsonb303cf92010-08-12 14:03:48 +0100377static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200378{
Chris Wilson05394f32010-11-08 19:18:58 +0000379 struct drm_i915_gem_object *obj = overlay->old_vid_bo;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200380
Chris Wilsonb303cf92010-08-12 14:03:48 +0100381 i915_gem_object_unpin(obj);
Chris Wilson05394f32010-11-08 19:18:58 +0000382 drm_gem_object_unreference(&obj->base);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200383
Chris Wilsonb303cf92010-08-12 14:03:48 +0100384 overlay->old_vid_bo = NULL;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200385}
386
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200387static void intel_overlay_off_tail(struct intel_overlay *overlay)
388{
Chris Wilson05394f32010-11-08 19:18:58 +0000389 struct drm_i915_gem_object *obj = overlay->vid_bo;
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200390
391 /* never have the overlay hw on without showing a frame */
392 BUG_ON(!overlay->vid_bo);
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200393
394 i915_gem_object_unpin(obj);
Chris Wilson05394f32010-11-08 19:18:58 +0000395 drm_gem_object_unreference(&obj->base);
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200396 overlay->vid_bo = NULL;
397
398 overlay->crtc->overlay = NULL;
399 overlay->crtc = NULL;
400 overlay->active = 0;
401}
402
Daniel Vetter02e792f2009-09-15 22:57:34 +0200403/* overlay needs to be disabled in OCMD reg */
Chris Wilson5dcdbcb2010-08-12 13:50:28 +0100404static int intel_overlay_off(struct intel_overlay *overlay,
405 bool interruptible)
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200406{
407 struct drm_device *dev = overlay->dev;
Chris Wilsone1f99ce2010-10-27 12:45:26 +0100408 struct drm_i915_private *dev_priv = dev->dev_private;
Chris Wilson8dc5d142010-08-12 12:36:12 +0100409 u32 flip_addr = overlay->flip_addr;
410 struct drm_i915_gem_request *request;
Chris Wilsone1f99ce2010-10-27 12:45:26 +0100411 int ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200412
413 BUG_ON(!overlay->active);
414
Chris Wilson8dc5d142010-08-12 12:36:12 +0100415 request = kzalloc(sizeof(*request), GFP_KERNEL);
416 if (request == NULL)
417 return -ENOMEM;
418
Daniel Vetter02e792f2009-09-15 22:57:34 +0200419 /* According to intel docs the overlay hw may hang (when switching
420 * off) without loading the filter coeffs. It is however unclear whether
421 * this applies to the disabling of the overlay or to the switching off
422 * of the hw. Do it in both cases */
423 flip_addr |= OFC_UPDATE;
424
Chris Wilsone1f99ce2010-10-27 12:45:26 +0100425 ret = BEGIN_LP_RING(6);
426 if (ret) {
427 kfree(request);
428 return ret;
429 }
Daniel Vetter02e792f2009-09-15 22:57:34 +0200430 /* wait for overlay to go idle */
Daniel Vetter02e792f2009-09-15 22:57:34 +0200431 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
432 OUT_RING(flip_addr);
Chris Wilson722506f2010-08-12 09:28:50 +0100433 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
Chris Wilson722506f2010-08-12 09:28:50 +0100434 /* turn overlay off */
Chris Wilson722506f2010-08-12 09:28:50 +0100435 OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
436 OUT_RING(flip_addr);
437 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
Chris Wilson722506f2010-08-12 09:28:50 +0100438 ADVANCE_LP_RING();
439
Chris Wilson5dcdbcb2010-08-12 13:50:28 +0100440 return intel_overlay_do_wait_request(overlay, request, interruptible,
Chris Wilsonb303cf92010-08-12 14:03:48 +0100441 intel_overlay_off_tail);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200442}
443
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200444/* recover from an interruption due to a signal
445 * We have to be careful not to repeat work forever an make forward progess. */
Chris Wilson5dcdbcb2010-08-12 13:50:28 +0100446static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
447 bool interruptible)
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200448{
449 struct drm_device *dev = overlay->dev;
Zou Nan hai852835f2010-05-21 09:08:56 +0800450 drm_i915_private_t *dev_priv = dev->dev_private;
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200451 int ret;
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200452
Chris Wilsonb303cf92010-08-12 14:03:48 +0100453 if (overlay->last_flip_req == 0)
454 return 0;
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200455
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);
Chris Wilsonb6c028e2010-08-12 11:55:08 +0100458 if (ret)
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200459 return ret;
460
Chris Wilsonb303cf92010-08-12 14:03:48 +0100461 if (overlay->flip_tail)
462 overlay->flip_tail(overlay);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200463
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200464 overlay->last_flip_req = 0;
465 return 0;
466}
467
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200468/* Wait for pending overlay flip and release old frame.
469 * Needs to be called before the overlay register are changed
Chris Wilson8d74f652010-08-12 10:35:26 +0100470 * via intel_overlay_(un)map_regs
471 */
Daniel Vetter02e792f2009-09-15 22:57:34 +0200472static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
473{
Chris Wilson5cd68c92010-08-12 12:21:54 +0100474 struct drm_device *dev = overlay->dev;
475 drm_i915_private_t *dev_priv = dev->dev_private;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200476 int ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200477
Chris Wilson5cd68c92010-08-12 12:21:54 +0100478 /* Only wait if there is actually an old frame to release to
479 * guarantee forward progress.
480 */
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200481 if (!overlay->old_vid_bo)
482 return 0;
483
Chris Wilson5cd68c92010-08-12 12:21:54 +0100484 if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) {
Chris Wilson8dc5d142010-08-12 12:36:12 +0100485 struct drm_i915_gem_request *request;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200486
Chris Wilson5cd68c92010-08-12 12:21:54 +0100487 /* synchronous slowpath */
Chris Wilson8dc5d142010-08-12 12:36:12 +0100488 request = kzalloc(sizeof(*request), GFP_KERNEL);
489 if (request == NULL)
490 return -ENOMEM;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200491
Chris Wilsone1f99ce2010-10-27 12:45:26 +0100492 ret = BEGIN_LP_RING(2);
493 if (ret) {
494 kfree(request);
495 return ret;
496 }
497
Chris Wilson5cd68c92010-08-12 12:21:54 +0100498 OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
499 OUT_RING(MI_NOOP);
500 ADVANCE_LP_RING();
Daniel Vetter02e792f2009-09-15 22:57:34 +0200501
Chris Wilson8dc5d142010-08-12 12:36:12 +0100502 ret = intel_overlay_do_wait_request(overlay, request, true,
Chris Wilsonb303cf92010-08-12 14:03:48 +0100503 intel_overlay_release_old_vid_tail);
Chris Wilson5cd68c92010-08-12 12:21:54 +0100504 if (ret)
505 return ret;
506 }
Daniel Vetter02e792f2009-09-15 22:57:34 +0200507
Chris Wilson5cd68c92010-08-12 12:21:54 +0100508 intel_overlay_release_old_vid_tail(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200509 return 0;
510}
511
512struct put_image_params {
513 int format;
514 short dst_x;
515 short dst_y;
516 short dst_w;
517 short dst_h;
518 short src_w;
519 short src_scan_h;
520 short src_scan_w;
521 short src_h;
522 short stride_Y;
523 short stride_UV;
524 int offset_Y;
525 int offset_U;
526 int offset_V;
527};
528
529static int packed_depth_bytes(u32 format)
530{
531 switch (format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100532 case I915_OVERLAY_YUV422:
533 return 4;
534 case I915_OVERLAY_YUV411:
535 /* return 6; not implemented */
536 default:
537 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200538 }
539}
540
541static int packed_width_bytes(u32 format, short width)
542{
543 switch (format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100544 case I915_OVERLAY_YUV422:
545 return width << 1;
546 default:
547 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200548 }
549}
550
551static int uv_hsubsampling(u32 format)
552{
553 switch (format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100554 case I915_OVERLAY_YUV422:
555 case I915_OVERLAY_YUV420:
556 return 2;
557 case I915_OVERLAY_YUV411:
558 case I915_OVERLAY_YUV410:
559 return 4;
560 default:
561 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200562 }
563}
564
565static int uv_vsubsampling(u32 format)
566{
567 switch (format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100568 case I915_OVERLAY_YUV420:
569 case I915_OVERLAY_YUV410:
570 return 2;
571 case I915_OVERLAY_YUV422:
572 case I915_OVERLAY_YUV411:
573 return 1;
574 default:
575 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200576 }
577}
578
579static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width)
580{
581 u32 mask, shift, ret;
Chris Wilsona6c45cf2010-09-17 00:32:17 +0100582 if (IS_GEN2(dev)) {
Daniel Vetter02e792f2009-09-15 22:57:34 +0200583 mask = 0x1f;
584 shift = 5;
Chris Wilsona6c45cf2010-09-17 00:32:17 +0100585 } else {
586 mask = 0x3f;
587 shift = 6;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200588 }
589 ret = ((offset + width + mask) >> shift) - (offset >> shift);
Chris Wilsona6c45cf2010-09-17 00:32:17 +0100590 if (!IS_GEN2(dev))
Daniel Vetter02e792f2009-09-15 22:57:34 +0200591 ret <<= 1;
592 ret -=1;
593 return ret << 2;
594}
595
596static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = {
597 0x3000, 0xb4a0, 0x1930, 0x1920, 0xb4a0,
598 0x3000, 0xb500, 0x19d0, 0x1880, 0xb440,
599 0x3000, 0xb540, 0x1a88, 0x2f80, 0xb3e0,
600 0x3000, 0xb580, 0x1b30, 0x2e20, 0xb380,
601 0x3000, 0xb5c0, 0x1bd8, 0x2cc0, 0xb320,
602 0x3020, 0xb5e0, 0x1c60, 0x2b80, 0xb2c0,
603 0x3020, 0xb5e0, 0x1cf8, 0x2a20, 0xb260,
604 0x3020, 0xb5e0, 0x1d80, 0x28e0, 0xb200,
605 0x3020, 0xb5c0, 0x1e08, 0x3f40, 0xb1c0,
606 0x3020, 0xb580, 0x1e78, 0x3ce0, 0xb160,
607 0x3040, 0xb520, 0x1ed8, 0x3aa0, 0xb120,
608 0x3040, 0xb4a0, 0x1f30, 0x3880, 0xb0e0,
609 0x3040, 0xb400, 0x1f78, 0x3680, 0xb0a0,
610 0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060,
611 0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040,
612 0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020,
Chris Wilson722506f2010-08-12 09:28:50 +0100613 0xb000, 0x3000, 0x0800, 0x3000, 0xb000
614};
615
Daniel Vetter02e792f2009-09-15 22:57:34 +0200616static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
617 0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60,
618 0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40,
619 0xb040, 0x1b20, 0x29e0, 0xb060, 0x1bd8, 0x2880,
620 0xb080, 0x1c88, 0x3e60, 0xb0a0, 0x1d28, 0x3c00,
621 0xb0c0, 0x1db8, 0x39e0, 0xb0e0, 0x1e40, 0x37e0,
622 0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0,
623 0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240,
624 0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0,
Chris Wilson722506f2010-08-12 09:28:50 +0100625 0x3000, 0x0800, 0x3000
626};
Daniel Vetter02e792f2009-09-15 22:57:34 +0200627
628static void update_polyphase_filter(struct overlay_registers *regs)
629{
630 memcpy(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs));
631 memcpy(regs->UV_HCOEFS, uv_static_hcoeffs, sizeof(uv_static_hcoeffs));
632}
633
634static bool update_scaling_factors(struct intel_overlay *overlay,
635 struct overlay_registers *regs,
636 struct put_image_params *params)
637{
638 /* fixed point with a 12 bit shift */
639 u32 xscale, yscale, xscale_UV, yscale_UV;
640#define FP_SHIFT 12
641#define FRACT_MASK 0xfff
642 bool scale_changed = false;
643 int uv_hscale = uv_hsubsampling(params->format);
644 int uv_vscale = uv_vsubsampling(params->format);
645
646 if (params->dst_w > 1)
647 xscale = ((params->src_scan_w - 1) << FP_SHIFT)
648 /(params->dst_w);
649 else
650 xscale = 1 << FP_SHIFT;
651
652 if (params->dst_h > 1)
653 yscale = ((params->src_scan_h - 1) << FP_SHIFT)
654 /(params->dst_h);
655 else
656 yscale = 1 << FP_SHIFT;
657
658 /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
Chris Wilson722506f2010-08-12 09:28:50 +0100659 xscale_UV = xscale/uv_hscale;
660 yscale_UV = yscale/uv_vscale;
661 /* make the Y scale to UV scale ratio an exact multiply */
662 xscale = xscale_UV * uv_hscale;
663 yscale = yscale_UV * uv_vscale;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200664 /*} else {
Chris Wilson722506f2010-08-12 09:28:50 +0100665 xscale_UV = 0;
666 yscale_UV = 0;
667 }*/
Daniel Vetter02e792f2009-09-15 22:57:34 +0200668
669 if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)
670 scale_changed = true;
671 overlay->old_xscale = xscale;
672 overlay->old_yscale = yscale;
673
Chris Wilson722506f2010-08-12 09:28:50 +0100674 regs->YRGBSCALE = (((yscale & FRACT_MASK) << 20) |
675 ((xscale >> FP_SHIFT) << 16) |
676 ((xscale & FRACT_MASK) << 3));
677
678 regs->UVSCALE = (((yscale_UV & FRACT_MASK) << 20) |
679 ((xscale_UV >> FP_SHIFT) << 16) |
680 ((xscale_UV & FRACT_MASK) << 3));
681
682 regs->UVSCALEV = ((((yscale >> FP_SHIFT) << 16) |
683 ((yscale_UV >> FP_SHIFT) << 0)));
Daniel Vetter02e792f2009-09-15 22:57:34 +0200684
685 if (scale_changed)
686 update_polyphase_filter(regs);
687
688 return scale_changed;
689}
690
691static void update_colorkey(struct intel_overlay *overlay,
692 struct overlay_registers *regs)
693{
694 u32 key = overlay->color_key;
Chris Wilson6ba3ddd2010-08-12 09:30:58 +0100695
Daniel Vetter02e792f2009-09-15 22:57:34 +0200696 switch (overlay->crtc->base.fb->bits_per_pixel) {
Chris Wilson722506f2010-08-12 09:28:50 +0100697 case 8:
698 regs->DCLRKV = 0;
699 regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;
Chris Wilson6ba3ddd2010-08-12 09:30:58 +0100700 break;
701
Chris Wilson722506f2010-08-12 09:28:50 +0100702 case 16:
703 if (overlay->crtc->base.fb->depth == 15) {
704 regs->DCLRKV = RGB15_TO_COLORKEY(key);
705 regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;
706 } else {
707 regs->DCLRKV = RGB16_TO_COLORKEY(key);
708 regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;
709 }
Chris Wilson6ba3ddd2010-08-12 09:30:58 +0100710 break;
711
Chris Wilson722506f2010-08-12 09:28:50 +0100712 case 24:
713 case 32:
714 regs->DCLRKV = key;
715 regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;
Chris Wilson6ba3ddd2010-08-12 09:30:58 +0100716 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200717 }
718}
719
720static u32 overlay_cmd_reg(struct put_image_params *params)
721{
722 u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0;
723
724 if (params->format & I915_OVERLAY_YUV_PLANAR) {
725 switch (params->format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100726 case I915_OVERLAY_YUV422:
727 cmd |= OCMD_YUV_422_PLANAR;
728 break;
729 case I915_OVERLAY_YUV420:
730 cmd |= OCMD_YUV_420_PLANAR;
731 break;
732 case I915_OVERLAY_YUV411:
733 case I915_OVERLAY_YUV410:
734 cmd |= OCMD_YUV_410_PLANAR;
735 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200736 }
737 } else { /* YUV packed */
738 switch (params->format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100739 case I915_OVERLAY_YUV422:
740 cmd |= OCMD_YUV_422_PACKED;
741 break;
742 case I915_OVERLAY_YUV411:
743 cmd |= OCMD_YUV_411_PACKED;
744 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200745 }
746
747 switch (params->format & I915_OVERLAY_SWAP_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100748 case I915_OVERLAY_NO_SWAP:
749 break;
750 case I915_OVERLAY_UV_SWAP:
751 cmd |= OCMD_UV_SWAP;
752 break;
753 case I915_OVERLAY_Y_SWAP:
754 cmd |= OCMD_Y_SWAP;
755 break;
756 case I915_OVERLAY_Y_AND_UV_SWAP:
757 cmd |= OCMD_Y_AND_UV_SWAP;
758 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200759 }
760 }
761
762 return cmd;
763}
764
Chris Wilson5fe82c52010-08-12 12:38:21 +0100765static int intel_overlay_do_put_image(struct intel_overlay *overlay,
Chris Wilson05394f32010-11-08 19:18:58 +0000766 struct drm_i915_gem_object *new_bo,
Chris Wilson5fe82c52010-08-12 12:38:21 +0100767 struct put_image_params *params)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200768{
769 int ret, tmp_width;
770 struct overlay_registers *regs;
771 bool scale_changed = false;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200772 struct drm_device *dev = overlay->dev;
773
774 BUG_ON(!mutex_is_locked(&dev->struct_mutex));
775 BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
776 BUG_ON(!overlay);
777
Daniel Vetter02e792f2009-09-15 22:57:34 +0200778 ret = intel_overlay_release_old_vid(overlay);
779 if (ret != 0)
780 return ret;
781
Daniel Vetter75e9e912010-11-04 17:11:09 +0100782 ret = i915_gem_object_pin(new_bo, PAGE_SIZE, true);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200783 if (ret != 0)
784 return ret;
785
786 ret = i915_gem_object_set_to_gtt_domain(new_bo, 0);
787 if (ret != 0)
788 goto out_unpin;
789
Chris Wilsond9e86c02010-11-10 16:40:20 +0000790 ret = i915_gem_object_put_fence(new_bo);
791 if (ret)
792 goto out_unpin;
793
Daniel Vetter02e792f2009-09-15 22:57:34 +0200794 if (!overlay->active) {
Chris Wilson8d74f652010-08-12 10:35:26 +0100795 regs = intel_overlay_map_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200796 if (!regs) {
797 ret = -ENOMEM;
798 goto out_unpin;
799 }
800 regs->OCONFIG = OCONF_CC_OUT_8BIT;
Chris Wilsona6c45cf2010-09-17 00:32:17 +0100801 if (IS_GEN4(overlay->dev))
Daniel Vetter02e792f2009-09-15 22:57:34 +0200802 regs->OCONFIG |= OCONF_CSC_MODE_BT709;
803 regs->OCONFIG |= overlay->crtc->pipe == 0 ?
804 OCONF_PIPE_A : OCONF_PIPE_B;
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100805 intel_overlay_unmap_regs(overlay, regs);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200806
807 ret = intel_overlay_on(overlay);
808 if (ret != 0)
809 goto out_unpin;
810 }
811
Chris Wilson8d74f652010-08-12 10:35:26 +0100812 regs = intel_overlay_map_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200813 if (!regs) {
814 ret = -ENOMEM;
815 goto out_unpin;
816 }
817
818 regs->DWINPOS = (params->dst_y << 16) | params->dst_x;
819 regs->DWINSZ = (params->dst_h << 16) | params->dst_w;
820
821 if (params->format & I915_OVERLAY_YUV_PACKED)
822 tmp_width = packed_width_bytes(params->format, params->src_w);
823 else
824 tmp_width = params->src_w;
825
826 regs->SWIDTH = params->src_w;
827 regs->SWIDTHSW = calc_swidthsw(overlay->dev,
Chris Wilson722506f2010-08-12 09:28:50 +0100828 params->offset_Y, tmp_width);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200829 regs->SHEIGHT = params->src_h;
Chris Wilson05394f32010-11-08 19:18:58 +0000830 regs->OBUF_0Y = new_bo->gtt_offset + params-> offset_Y;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200831 regs->OSTRIDE = params->stride_Y;
832
833 if (params->format & I915_OVERLAY_YUV_PLANAR) {
834 int uv_hscale = uv_hsubsampling(params->format);
835 int uv_vscale = uv_vsubsampling(params->format);
836 u32 tmp_U, tmp_V;
837 regs->SWIDTH |= (params->src_w/uv_hscale) << 16;
838 tmp_U = calc_swidthsw(overlay->dev, params->offset_U,
Chris Wilson722506f2010-08-12 09:28:50 +0100839 params->src_w/uv_hscale);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200840 tmp_V = calc_swidthsw(overlay->dev, params->offset_V,
Chris Wilson722506f2010-08-12 09:28:50 +0100841 params->src_w/uv_hscale);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200842 regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16;
843 regs->SHEIGHT |= (params->src_h/uv_vscale) << 16;
Chris Wilson05394f32010-11-08 19:18:58 +0000844 regs->OBUF_0U = new_bo->gtt_offset + params->offset_U;
845 regs->OBUF_0V = new_bo->gtt_offset + params->offset_V;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200846 regs->OSTRIDE |= params->stride_UV << 16;
847 }
848
849 scale_changed = update_scaling_factors(overlay, regs, params);
850
851 update_colorkey(overlay, regs);
852
853 regs->OCMD = overlay_cmd_reg(params);
854
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100855 intel_overlay_unmap_regs(overlay, regs);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200856
Chris Wilson8dc5d142010-08-12 12:36:12 +0100857 ret = intel_overlay_continue(overlay, scale_changed);
858 if (ret)
859 goto out_unpin;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200860
861 overlay->old_vid_bo = overlay->vid_bo;
Chris Wilson05394f32010-11-08 19:18:58 +0000862 overlay->vid_bo = new_bo;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200863
864 return 0;
865
866out_unpin:
867 i915_gem_object_unpin(new_bo);
868 return ret;
869}
870
Chris Wilson5dcdbcb2010-08-12 13:50:28 +0100871int intel_overlay_switch_off(struct intel_overlay *overlay,
872 bool interruptible)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200873{
Daniel Vetter02e792f2009-09-15 22:57:34 +0200874 struct overlay_registers *regs;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200875 struct drm_device *dev = overlay->dev;
Chris Wilson5dcdbcb2010-08-12 13:50:28 +0100876 int ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200877
878 BUG_ON(!mutex_is_locked(&dev->struct_mutex));
879 BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
880
Chris Wilsonb303cf92010-08-12 14:03:48 +0100881 ret = intel_overlay_recover_from_interrupt(overlay, interruptible);
882 if (ret != 0)
883 return ret;
Daniel Vetter9bedb972009-11-30 15:55:49 +0100884
Daniel Vetter02e792f2009-09-15 22:57:34 +0200885 if (!overlay->active)
886 return 0;
887
Daniel Vetter02e792f2009-09-15 22:57:34 +0200888 ret = intel_overlay_release_old_vid(overlay);
889 if (ret != 0)
890 return ret;
891
Chris Wilson8d74f652010-08-12 10:35:26 +0100892 regs = intel_overlay_map_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200893 regs->OCMD = 0;
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100894 intel_overlay_unmap_regs(overlay, regs);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200895
Chris Wilson5dcdbcb2010-08-12 13:50:28 +0100896 ret = intel_overlay_off(overlay, interruptible);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200897 if (ret != 0)
898 return ret;
899
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200900 intel_overlay_off_tail(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200901 return 0;
902}
903
904static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
905 struct intel_crtc *crtc)
906{
Chris Wilson722506f2010-08-12 09:28:50 +0100907 drm_i915_private_t *dev_priv = overlay->dev->dev_private;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200908
Chris Wilsonf7abfe82010-09-13 14:19:16 +0100909 if (!crtc->active)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200910 return -EINVAL;
911
Daniel Vetter02e792f2009-09-15 22:57:34 +0200912 /* can't use the overlay with double wide pipe */
Chris Wilsona6c45cf2010-09-17 00:32:17 +0100913 if (INTEL_INFO(overlay->dev)->gen < 4 &&
Chris Wilsonf7abfe82010-09-13 14:19:16 +0100914 (I915_READ(PIPECONF(crtc->pipe)) & (PIPECONF_DOUBLE_WIDE | PIPECONF_ENABLE)) != PIPECONF_ENABLE)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200915 return -EINVAL;
916
917 return 0;
918}
919
920static void update_pfit_vscale_ratio(struct intel_overlay *overlay)
921{
922 struct drm_device *dev = overlay->dev;
Chris Wilson722506f2010-08-12 09:28:50 +0100923 drm_i915_private_t *dev_priv = dev->dev_private;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200924 u32 pfit_control = I915_READ(PFIT_CONTROL);
Chris Wilson446d2182010-08-12 11:15:58 +0100925 u32 ratio;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200926
927 /* XXX: This is not the same logic as in the xorg driver, but more in
Chris Wilson446d2182010-08-12 11:15:58 +0100928 * line with the intel documentation for the i965
929 */
Chris Wilsona6c45cf2010-09-17 00:32:17 +0100930 if (INTEL_INFO(dev)->gen >= 4) {
931 /* on i965 use the PGM reg to read out the autoscaler values */
932 ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965;
933 } else {
Chris Wilson446d2182010-08-12 11:15:58 +0100934 if (pfit_control & VERT_AUTO_SCALE)
935 ratio = I915_READ(PFIT_AUTO_RATIOS);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200936 else
Chris Wilson446d2182010-08-12 11:15:58 +0100937 ratio = I915_READ(PFIT_PGM_RATIOS);
938 ratio >>= PFIT_VERT_SCALE_SHIFT;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200939 }
940
941 overlay->pfit_vscale_ratio = ratio;
942}
943
944static int check_overlay_dst(struct intel_overlay *overlay,
945 struct drm_intel_overlay_put_image *rec)
946{
947 struct drm_display_mode *mode = &overlay->crtc->base.mode;
948
Chris Wilson722506f2010-08-12 09:28:50 +0100949 if (rec->dst_x < mode->crtc_hdisplay &&
950 rec->dst_x + rec->dst_width <= mode->crtc_hdisplay &&
951 rec->dst_y < mode->crtc_vdisplay &&
952 rec->dst_y + rec->dst_height <= mode->crtc_vdisplay)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200953 return 0;
954 else
955 return -EINVAL;
956}
957
958static int check_overlay_scaling(struct put_image_params *rec)
959{
960 u32 tmp;
961
962 /* downscaling limit is 8.0 */
963 tmp = ((rec->src_scan_h << 16) / rec->dst_h) >> 16;
964 if (tmp > 7)
965 return -EINVAL;
966 tmp = ((rec->src_scan_w << 16) / rec->dst_w) >> 16;
967 if (tmp > 7)
968 return -EINVAL;
969
970 return 0;
971}
972
973static int check_overlay_src(struct drm_device *dev,
974 struct drm_intel_overlay_put_image *rec,
Chris Wilson05394f32010-11-08 19:18:58 +0000975 struct drm_i915_gem_object *new_bo)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200976{
Daniel Vetter02e792f2009-09-15 22:57:34 +0200977 int uv_hscale = uv_hsubsampling(rec->flags);
978 int uv_vscale = uv_vsubsampling(rec->flags);
Dan Carpenter8f28f542010-10-27 23:17:25 +0200979 u32 stride_mask;
980 int depth;
981 u32 tmp;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200982
983 /* check src dimensions */
984 if (IS_845G(dev) || IS_I830(dev)) {
Chris Wilson722506f2010-08-12 09:28:50 +0100985 if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY ||
Chris Wilson9f7c3f42010-08-12 11:29:34 +0100986 rec->src_width > IMAGE_MAX_WIDTH_LEGACY)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200987 return -EINVAL;
988 } else {
Chris Wilson722506f2010-08-12 09:28:50 +0100989 if (rec->src_height > IMAGE_MAX_HEIGHT ||
Chris Wilson9f7c3f42010-08-12 11:29:34 +0100990 rec->src_width > IMAGE_MAX_WIDTH)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200991 return -EINVAL;
992 }
Chris Wilson9f7c3f42010-08-12 11:29:34 +0100993
Daniel Vetter02e792f2009-09-15 22:57:34 +0200994 /* better safe than sorry, use 4 as the maximal subsampling ratio */
Chris Wilson722506f2010-08-12 09:28:50 +0100995 if (rec->src_height < N_VERT_Y_TAPS*4 ||
Chris Wilson9f7c3f42010-08-12 11:29:34 +0100996 rec->src_width < N_HORIZ_Y_TAPS*4)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200997 return -EINVAL;
998
Chris Wilsona1efd142010-07-12 19:35:38 +0100999 /* check alignment constraints */
Daniel Vetter02e792f2009-09-15 22:57:34 +02001000 switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +01001001 case I915_OVERLAY_RGB:
1002 /* not implemented */
1003 return -EINVAL;
Chris Wilson9f7c3f42010-08-12 11:29:34 +01001004
Chris Wilson722506f2010-08-12 09:28:50 +01001005 case I915_OVERLAY_YUV_PACKED:
Chris Wilson722506f2010-08-12 09:28:50 +01001006 if (uv_vscale != 1)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001007 return -EINVAL;
Chris Wilson9f7c3f42010-08-12 11:29:34 +01001008
1009 depth = packed_depth_bytes(rec->flags);
Chris Wilson722506f2010-08-12 09:28:50 +01001010 if (depth < 0)
1011 return depth;
Chris Wilson9f7c3f42010-08-12 11:29:34 +01001012
Chris Wilson722506f2010-08-12 09:28:50 +01001013 /* ignore UV planes */
1014 rec->stride_UV = 0;
1015 rec->offset_U = 0;
1016 rec->offset_V = 0;
1017 /* check pixel alignment */
1018 if (rec->offset_Y % depth)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001019 return -EINVAL;
Chris Wilson722506f2010-08-12 09:28:50 +01001020 break;
Chris Wilson9f7c3f42010-08-12 11:29:34 +01001021
Chris Wilson722506f2010-08-12 09:28:50 +01001022 case I915_OVERLAY_YUV_PLANAR:
1023 if (uv_vscale < 0 || uv_hscale < 0)
1024 return -EINVAL;
1025 /* no offset restrictions for planar formats */
1026 break;
Chris Wilson9f7c3f42010-08-12 11:29:34 +01001027
Chris Wilson722506f2010-08-12 09:28:50 +01001028 default:
1029 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001030 }
1031
1032 if (rec->src_width % uv_hscale)
1033 return -EINVAL;
1034
1035 /* stride checking */
Chris Wilsona1efd142010-07-12 19:35:38 +01001036 if (IS_I830(dev) || IS_845G(dev))
1037 stride_mask = 255;
1038 else
1039 stride_mask = 63;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001040
1041 if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
1042 return -EINVAL;
Chris Wilsona6c45cf2010-09-17 00:32:17 +01001043 if (IS_GEN4(dev) && rec->stride_Y < 512)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001044 return -EINVAL;
1045
1046 tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ?
Chris Wilson9f7c3f42010-08-12 11:29:34 +01001047 4096 : 8192;
1048 if (rec->stride_Y > tmp || rec->stride_UV > 2*1024)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001049 return -EINVAL;
1050
1051 /* check buffer dimensions */
1052 switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +01001053 case I915_OVERLAY_RGB:
1054 case I915_OVERLAY_YUV_PACKED:
1055 /* always 4 Y values per depth pixels */
1056 if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y)
1057 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001058
Chris Wilson722506f2010-08-12 09:28:50 +01001059 tmp = rec->stride_Y*rec->src_height;
Chris Wilson05394f32010-11-08 19:18:58 +00001060 if (rec->offset_Y + tmp > new_bo->base.size)
Chris Wilson722506f2010-08-12 09:28:50 +01001061 return -EINVAL;
1062 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001063
Chris Wilson722506f2010-08-12 09:28:50 +01001064 case I915_OVERLAY_YUV_PLANAR:
1065 if (rec->src_width > rec->stride_Y)
1066 return -EINVAL;
1067 if (rec->src_width/uv_hscale > rec->stride_UV)
1068 return -EINVAL;
1069
Chris Wilson9f7c3f42010-08-12 11:29:34 +01001070 tmp = rec->stride_Y * rec->src_height;
Chris Wilson05394f32010-11-08 19:18:58 +00001071 if (rec->offset_Y + tmp > new_bo->base.size)
Chris Wilson722506f2010-08-12 09:28:50 +01001072 return -EINVAL;
Chris Wilson9f7c3f42010-08-12 11:29:34 +01001073
1074 tmp = rec->stride_UV * (rec->src_height / uv_vscale);
Chris Wilson05394f32010-11-08 19:18:58 +00001075 if (rec->offset_U + tmp > new_bo->base.size ||
1076 rec->offset_V + tmp > new_bo->base.size)
Chris Wilson722506f2010-08-12 09:28:50 +01001077 return -EINVAL;
1078 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001079 }
1080
1081 return 0;
1082}
1083
Chris Wilsone9e331a2010-09-13 01:16:10 +01001084/**
1085 * Return the pipe currently connected to the panel fitter,
1086 * or -1 if the panel fitter is not present or not in use
1087 */
1088static int intel_panel_fitter_pipe(struct drm_device *dev)
1089{
1090 struct drm_i915_private *dev_priv = dev->dev_private;
1091 u32 pfit_control;
1092
1093 /* i830 doesn't have a panel fitter */
1094 if (IS_I830(dev))
1095 return -1;
1096
1097 pfit_control = I915_READ(PFIT_CONTROL);
1098
1099 /* See if the panel fitter is in use */
1100 if ((pfit_control & PFIT_ENABLE) == 0)
1101 return -1;
1102
1103 /* 965 can place panel fitter on either pipe */
Chris Wilsona6c45cf2010-09-17 00:32:17 +01001104 if (IS_GEN4(dev))
Chris Wilsone9e331a2010-09-13 01:16:10 +01001105 return (pfit_control >> 29) & 0x3;
1106
1107 /* older chips can only use pipe 1 */
1108 return 1;
1109}
1110
Daniel Vetter02e792f2009-09-15 22:57:34 +02001111int intel_overlay_put_image(struct drm_device *dev, void *data,
1112 struct drm_file *file_priv)
1113{
1114 struct drm_intel_overlay_put_image *put_image_rec = data;
1115 drm_i915_private_t *dev_priv = dev->dev_private;
1116 struct intel_overlay *overlay;
1117 struct drm_mode_object *drmmode_obj;
1118 struct intel_crtc *crtc;
Chris Wilson05394f32010-11-08 19:18:58 +00001119 struct drm_i915_gem_object *new_bo;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001120 struct put_image_params *params;
1121 int ret;
1122
1123 if (!dev_priv) {
1124 DRM_ERROR("called with no initialization\n");
1125 return -EINVAL;
1126 }
1127
1128 overlay = dev_priv->overlay;
1129 if (!overlay) {
1130 DRM_DEBUG("userspace bug: no overlay\n");
1131 return -ENODEV;
1132 }
1133
1134 if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) {
1135 mutex_lock(&dev->mode_config.mutex);
1136 mutex_lock(&dev->struct_mutex);
1137
Chris Wilson5dcdbcb2010-08-12 13:50:28 +01001138 ret = intel_overlay_switch_off(overlay, true);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001139
1140 mutex_unlock(&dev->struct_mutex);
1141 mutex_unlock(&dev->mode_config.mutex);
1142
1143 return ret;
1144 }
1145
1146 params = kmalloc(sizeof(struct put_image_params), GFP_KERNEL);
1147 if (!params)
1148 return -ENOMEM;
1149
1150 drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id,
Chris Wilson722506f2010-08-12 09:28:50 +01001151 DRM_MODE_OBJECT_CRTC);
Dan Carpenter915a4282010-03-06 14:05:39 +03001152 if (!drmmode_obj) {
1153 ret = -ENOENT;
1154 goto out_free;
1155 }
Daniel Vetter02e792f2009-09-15 22:57:34 +02001156 crtc = to_intel_crtc(obj_to_crtc(drmmode_obj));
1157
Chris Wilson05394f32010-11-08 19:18:58 +00001158 new_bo = to_intel_bo(drm_gem_object_lookup(dev, file_priv,
1159 put_image_rec->bo_handle));
Dan Carpenter915a4282010-03-06 14:05:39 +03001160 if (!new_bo) {
1161 ret = -ENOENT;
1162 goto out_free;
1163 }
Daniel Vetter02e792f2009-09-15 22:57:34 +02001164
1165 mutex_lock(&dev->mode_config.mutex);
1166 mutex_lock(&dev->struct_mutex);
1167
Chris Wilsond9e86c02010-11-10 16:40:20 +00001168 if (new_bo->tiling_mode) {
1169 DRM_ERROR("buffer used for overlay image can not be tiled\n");
1170 ret = -EINVAL;
1171 goto out_unlock;
1172 }
1173
Chris Wilsonb303cf92010-08-12 14:03:48 +01001174 ret = intel_overlay_recover_from_interrupt(overlay, true);
1175 if (ret != 0)
1176 goto out_unlock;
Daniel Vetter03f77ea2009-09-15 22:57:37 +02001177
Daniel Vetter02e792f2009-09-15 22:57:34 +02001178 if (overlay->crtc != crtc) {
1179 struct drm_display_mode *mode = &crtc->base.mode;
Chris Wilson5dcdbcb2010-08-12 13:50:28 +01001180 ret = intel_overlay_switch_off(overlay, true);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001181 if (ret != 0)
1182 goto out_unlock;
1183
1184 ret = check_overlay_possible_on_crtc(overlay, crtc);
1185 if (ret != 0)
1186 goto out_unlock;
1187
1188 overlay->crtc = crtc;
1189 crtc->overlay = overlay;
1190
Chris Wilsone9e331a2010-09-13 01:16:10 +01001191 /* line too wide, i.e. one-line-mode */
1192 if (mode->hdisplay > 1024 &&
1193 intel_panel_fitter_pipe(dev) == crtc->pipe) {
Daniel Vetter02e792f2009-09-15 22:57:34 +02001194 overlay->pfit_active = 1;
1195 update_pfit_vscale_ratio(overlay);
1196 } else
1197 overlay->pfit_active = 0;
1198 }
1199
1200 ret = check_overlay_dst(overlay, put_image_rec);
1201 if (ret != 0)
1202 goto out_unlock;
1203
1204 if (overlay->pfit_active) {
1205 params->dst_y = ((((u32)put_image_rec->dst_y) << 12) /
Chris Wilson722506f2010-08-12 09:28:50 +01001206 overlay->pfit_vscale_ratio);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001207 /* shifting right rounds downwards, so add 1 */
1208 params->dst_h = ((((u32)put_image_rec->dst_height) << 12) /
Chris Wilson722506f2010-08-12 09:28:50 +01001209 overlay->pfit_vscale_ratio) + 1;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001210 } else {
1211 params->dst_y = put_image_rec->dst_y;
1212 params->dst_h = put_image_rec->dst_height;
1213 }
1214 params->dst_x = put_image_rec->dst_x;
1215 params->dst_w = put_image_rec->dst_width;
1216
1217 params->src_w = put_image_rec->src_width;
1218 params->src_h = put_image_rec->src_height;
1219 params->src_scan_w = put_image_rec->src_scan_width;
1220 params->src_scan_h = put_image_rec->src_scan_height;
Chris Wilson722506f2010-08-12 09:28:50 +01001221 if (params->src_scan_h > params->src_h ||
1222 params->src_scan_w > params->src_w) {
Daniel Vetter02e792f2009-09-15 22:57:34 +02001223 ret = -EINVAL;
1224 goto out_unlock;
1225 }
1226
1227 ret = check_overlay_src(dev, put_image_rec, new_bo);
1228 if (ret != 0)
1229 goto out_unlock;
1230 params->format = put_image_rec->flags & ~I915_OVERLAY_FLAGS_MASK;
1231 params->stride_Y = put_image_rec->stride_Y;
1232 params->stride_UV = put_image_rec->stride_UV;
1233 params->offset_Y = put_image_rec->offset_Y;
1234 params->offset_U = put_image_rec->offset_U;
1235 params->offset_V = put_image_rec->offset_V;
1236
1237 /* Check scaling after src size to prevent a divide-by-zero. */
1238 ret = check_overlay_scaling(params);
1239 if (ret != 0)
1240 goto out_unlock;
1241
1242 ret = intel_overlay_do_put_image(overlay, new_bo, params);
1243 if (ret != 0)
1244 goto out_unlock;
1245
1246 mutex_unlock(&dev->struct_mutex);
1247 mutex_unlock(&dev->mode_config.mutex);
1248
1249 kfree(params);
1250
1251 return 0;
1252
1253out_unlock:
1254 mutex_unlock(&dev->struct_mutex);
1255 mutex_unlock(&dev->mode_config.mutex);
Chris Wilson05394f32010-11-08 19:18:58 +00001256 drm_gem_object_unreference_unlocked(&new_bo->base);
Dan Carpenter915a4282010-03-06 14:05:39 +03001257out_free:
Daniel Vetter02e792f2009-09-15 22:57:34 +02001258 kfree(params);
1259
1260 return ret;
1261}
1262
1263static void update_reg_attrs(struct intel_overlay *overlay,
1264 struct overlay_registers *regs)
1265{
1266 regs->OCLRC0 = (overlay->contrast << 18) | (overlay->brightness & 0xff);
1267 regs->OCLRC1 = overlay->saturation;
1268}
1269
1270static bool check_gamma_bounds(u32 gamma1, u32 gamma2)
1271{
1272 int i;
1273
1274 if (gamma1 & 0xff000000 || gamma2 & 0xff000000)
1275 return false;
1276
1277 for (i = 0; i < 3; i++) {
Chris Wilson722506f2010-08-12 09:28:50 +01001278 if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
Daniel Vetter02e792f2009-09-15 22:57:34 +02001279 return false;
1280 }
1281
1282 return true;
1283}
1284
1285static bool check_gamma5_errata(u32 gamma5)
1286{
1287 int i;
1288
1289 for (i = 0; i < 3; i++) {
1290 if (((gamma5 >> i*8) & 0xff) == 0x80)
1291 return false;
1292 }
1293
1294 return true;
1295}
1296
1297static int check_gamma(struct drm_intel_overlay_attrs *attrs)
1298{
Chris Wilson722506f2010-08-12 09:28:50 +01001299 if (!check_gamma_bounds(0, attrs->gamma0) ||
1300 !check_gamma_bounds(attrs->gamma0, attrs->gamma1) ||
1301 !check_gamma_bounds(attrs->gamma1, attrs->gamma2) ||
1302 !check_gamma_bounds(attrs->gamma2, attrs->gamma3) ||
1303 !check_gamma_bounds(attrs->gamma3, attrs->gamma4) ||
1304 !check_gamma_bounds(attrs->gamma4, attrs->gamma5) ||
1305 !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
Daniel Vetter02e792f2009-09-15 22:57:34 +02001306 return -EINVAL;
Chris Wilson722506f2010-08-12 09:28:50 +01001307
Daniel Vetter02e792f2009-09-15 22:57:34 +02001308 if (!check_gamma5_errata(attrs->gamma5))
1309 return -EINVAL;
Chris Wilson722506f2010-08-12 09:28:50 +01001310
Daniel Vetter02e792f2009-09-15 22:57:34 +02001311 return 0;
1312}
1313
1314int intel_overlay_attrs(struct drm_device *dev, void *data,
1315 struct drm_file *file_priv)
1316{
1317 struct drm_intel_overlay_attrs *attrs = data;
1318 drm_i915_private_t *dev_priv = dev->dev_private;
1319 struct intel_overlay *overlay;
1320 struct overlay_registers *regs;
1321 int ret;
1322
1323 if (!dev_priv) {
1324 DRM_ERROR("called with no initialization\n");
1325 return -EINVAL;
1326 }
1327
1328 overlay = dev_priv->overlay;
1329 if (!overlay) {
1330 DRM_DEBUG("userspace bug: no overlay\n");
1331 return -ENODEV;
1332 }
1333
1334 mutex_lock(&dev->mode_config.mutex);
1335 mutex_lock(&dev->struct_mutex);
1336
Chris Wilson60fc3322010-08-12 10:44:45 +01001337 ret = -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001338 if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) {
Chris Wilson60fc3322010-08-12 10:44:45 +01001339 attrs->color_key = overlay->color_key;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001340 attrs->brightness = overlay->brightness;
Chris Wilson60fc3322010-08-12 10:44:45 +01001341 attrs->contrast = overlay->contrast;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001342 attrs->saturation = overlay->saturation;
1343
Chris Wilsona6c45cf2010-09-17 00:32:17 +01001344 if (!IS_GEN2(dev)) {
Daniel Vetter02e792f2009-09-15 22:57:34 +02001345 attrs->gamma0 = I915_READ(OGAMC0);
1346 attrs->gamma1 = I915_READ(OGAMC1);
1347 attrs->gamma2 = I915_READ(OGAMC2);
1348 attrs->gamma3 = I915_READ(OGAMC3);
1349 attrs->gamma4 = I915_READ(OGAMC4);
1350 attrs->gamma5 = I915_READ(OGAMC5);
1351 }
Daniel Vetter02e792f2009-09-15 22:57:34 +02001352 } else {
Chris Wilson60fc3322010-08-12 10:44:45 +01001353 if (attrs->brightness < -128 || attrs->brightness > 127)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001354 goto out_unlock;
Chris Wilson60fc3322010-08-12 10:44:45 +01001355 if (attrs->contrast > 255)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001356 goto out_unlock;
Chris Wilson60fc3322010-08-12 10:44:45 +01001357 if (attrs->saturation > 1023)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001358 goto out_unlock;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001359
Chris Wilson60fc3322010-08-12 10:44:45 +01001360 overlay->color_key = attrs->color_key;
1361 overlay->brightness = attrs->brightness;
1362 overlay->contrast = attrs->contrast;
1363 overlay->saturation = attrs->saturation;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001364
Chris Wilson8d74f652010-08-12 10:35:26 +01001365 regs = intel_overlay_map_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001366 if (!regs) {
1367 ret = -ENOMEM;
1368 goto out_unlock;
1369 }
1370
1371 update_reg_attrs(overlay, regs);
1372
Chris Wilson9bb2ff72010-08-12 12:02:11 +01001373 intel_overlay_unmap_regs(overlay, regs);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001374
1375 if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) {
Chris Wilsona6c45cf2010-09-17 00:32:17 +01001376 if (IS_GEN2(dev))
Daniel Vetter02e792f2009-09-15 22:57:34 +02001377 goto out_unlock;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001378
1379 if (overlay->active) {
1380 ret = -EBUSY;
1381 goto out_unlock;
1382 }
1383
1384 ret = check_gamma(attrs);
Chris Wilson60fc3322010-08-12 10:44:45 +01001385 if (ret)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001386 goto out_unlock;
1387
1388 I915_WRITE(OGAMC0, attrs->gamma0);
1389 I915_WRITE(OGAMC1, attrs->gamma1);
1390 I915_WRITE(OGAMC2, attrs->gamma2);
1391 I915_WRITE(OGAMC3, attrs->gamma3);
1392 I915_WRITE(OGAMC4, attrs->gamma4);
1393 I915_WRITE(OGAMC5, attrs->gamma5);
1394 }
Daniel Vetter02e792f2009-09-15 22:57:34 +02001395 }
1396
Chris Wilson60fc3322010-08-12 10:44:45 +01001397 ret = 0;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001398out_unlock:
1399 mutex_unlock(&dev->struct_mutex);
1400 mutex_unlock(&dev->mode_config.mutex);
1401
1402 return ret;
1403}
1404
1405void intel_setup_overlay(struct drm_device *dev)
1406{
1407 drm_i915_private_t *dev_priv = dev->dev_private;
1408 struct intel_overlay *overlay;
Chris Wilson05394f32010-11-08 19:18:58 +00001409 struct drm_i915_gem_object *reg_bo;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001410 struct overlay_registers *regs;
1411 int ret;
1412
Chris Wilson315781482010-08-12 09:42:51 +01001413 if (!HAS_OVERLAY(dev))
Daniel Vetter02e792f2009-09-15 22:57:34 +02001414 return;
1415
1416 overlay = kzalloc(sizeof(struct intel_overlay), GFP_KERNEL);
1417 if (!overlay)
1418 return;
1419 overlay->dev = dev;
1420
Daniel Vetterac52bc52010-04-09 19:05:06 +00001421 reg_bo = i915_gem_alloc_object(dev, PAGE_SIZE);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001422 if (!reg_bo)
1423 goto out_free;
Chris Wilson05394f32010-11-08 19:18:58 +00001424 overlay->reg_bo = reg_bo;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001425
Chris Wilson315781482010-08-12 09:42:51 +01001426 if (OVERLAY_NEEDS_PHYSICAL(dev)) {
1427 ret = i915_gem_attach_phys_object(dev, reg_bo,
1428 I915_GEM_PHYS_OVERLAY_REGS,
Chris Wilsona2930122010-08-12 10:47:56 +01001429 PAGE_SIZE);
Chris Wilson315781482010-08-12 09:42:51 +01001430 if (ret) {
1431 DRM_ERROR("failed to attach phys overlay regs\n");
1432 goto out_free_bo;
1433 }
Chris Wilson05394f32010-11-08 19:18:58 +00001434 overlay->flip_addr = reg_bo->phys_obj->handle->busaddr;
Chris Wilson315781482010-08-12 09:42:51 +01001435 } else {
Daniel Vetter75e9e912010-11-04 17:11:09 +01001436 ret = i915_gem_object_pin(reg_bo, PAGE_SIZE, true);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001437 if (ret) {
1438 DRM_ERROR("failed to pin overlay register bo\n");
1439 goto out_free_bo;
1440 }
Chris Wilson05394f32010-11-08 19:18:58 +00001441 overlay->flip_addr = reg_bo->gtt_offset;
Chris Wilson0ddc1282010-08-12 09:35:00 +01001442
1443 ret = i915_gem_object_set_to_gtt_domain(reg_bo, true);
1444 if (ret) {
1445 DRM_ERROR("failed to move overlay register bo into the GTT\n");
1446 goto out_unpin_bo;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001447 }
Daniel Vetter02e792f2009-09-15 22:57:34 +02001448 }
1449
1450 /* init all values */
1451 overlay->color_key = 0x0101fe;
1452 overlay->brightness = -19;
1453 overlay->contrast = 75;
1454 overlay->saturation = 146;
1455
Chris Wilson8d74f652010-08-12 10:35:26 +01001456 regs = intel_overlay_map_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001457 if (!regs)
1458 goto out_free_bo;
1459
1460 memset(regs, 0, sizeof(struct overlay_registers));
1461 update_polyphase_filter(regs);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001462 update_reg_attrs(overlay, regs);
1463
Chris Wilson9bb2ff72010-08-12 12:02:11 +01001464 intel_overlay_unmap_regs(overlay, regs);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001465
1466 dev_priv->overlay = overlay;
1467 DRM_INFO("initialized overlay support\n");
1468 return;
1469
Chris Wilson0ddc1282010-08-12 09:35:00 +01001470out_unpin_bo:
1471 i915_gem_object_unpin(reg_bo);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001472out_free_bo:
Chris Wilson05394f32010-11-08 19:18:58 +00001473 drm_gem_object_unreference(&reg_bo->base);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001474out_free:
1475 kfree(overlay);
1476 return;
1477}
1478
1479void intel_cleanup_overlay(struct drm_device *dev)
1480{
Chris Wilson722506f2010-08-12 09:28:50 +01001481 drm_i915_private_t *dev_priv = dev->dev_private;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001482
Chris Wilson62cf4e62010-08-12 10:50:36 +01001483 if (!dev_priv->overlay)
1484 return;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001485
Chris Wilson62cf4e62010-08-12 10:50:36 +01001486 /* The bo's should be free'd by the generic code already.
1487 * Furthermore modesetting teardown happens beforehand so the
1488 * hardware should be off already */
1489 BUG_ON(dev_priv->overlay->active);
1490
1491 drm_gem_object_unreference_unlocked(&dev_priv->overlay->reg_bo->base);
1492 kfree(dev_priv->overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001493}
Chris Wilson6ef3d422010-08-04 20:26:07 +01001494
Chris Wilson3bd3c932010-08-19 08:19:30 +01001495#ifdef CONFIG_DEBUG_FS
1496#include <linux/seq_file.h>
1497
Chris Wilson6ef3d422010-08-04 20:26:07 +01001498struct intel_overlay_error_state {
1499 struct overlay_registers regs;
1500 unsigned long base;
1501 u32 dovsta;
1502 u32 isr;
1503};
1504
Chris Wilson3bd3c932010-08-19 08:19:30 +01001505static struct overlay_registers *
Linus Torvaldsc48c43e2010-10-26 18:57:59 -07001506intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
Chris Wilson3bd3c932010-08-19 08:19:30 +01001507{
Linus Torvaldsc48c43e2010-10-26 18:57:59 -07001508 drm_i915_private_t *dev_priv = overlay->dev->dev_private;
Chris Wilson3bd3c932010-08-19 08:19:30 +01001509 struct overlay_registers *regs;
1510
1511 if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
1512 regs = overlay->reg_bo->phys_obj->handle->vaddr;
1513 else
1514 regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
Linus Torvaldsc48c43e2010-10-26 18:57:59 -07001515 overlay->reg_bo->gtt_offset);
Chris Wilson3bd3c932010-08-19 08:19:30 +01001516
1517 return regs;
1518}
1519
1520static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay,
Chris Wilson3bd3c932010-08-19 08:19:30 +01001521 struct overlay_registers *regs)
1522{
1523 if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
Linus Torvaldsc48c43e2010-10-26 18:57:59 -07001524 io_mapping_unmap_atomic(regs);
Chris Wilson3bd3c932010-08-19 08:19:30 +01001525}
1526
1527
Chris Wilson6ef3d422010-08-04 20:26:07 +01001528struct intel_overlay_error_state *
1529intel_overlay_capture_error_state(struct drm_device *dev)
1530{
1531 drm_i915_private_t *dev_priv = dev->dev_private;
1532 struct intel_overlay *overlay = dev_priv->overlay;
1533 struct intel_overlay_error_state *error;
1534 struct overlay_registers __iomem *regs;
1535
1536 if (!overlay || !overlay->active)
1537 return NULL;
1538
1539 error = kmalloc(sizeof(*error), GFP_ATOMIC);
1540 if (error == NULL)
1541 return NULL;
1542
1543 error->dovsta = I915_READ(DOVSTA);
1544 error->isr = I915_READ(ISR);
Chris Wilson315781482010-08-12 09:42:51 +01001545 if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
Chris Wilson6ef3d422010-08-04 20:26:07 +01001546 error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr;
Chris Wilson315781482010-08-12 09:42:51 +01001547 else
1548 error->base = (long) overlay->reg_bo->gtt_offset;
Chris Wilson6ef3d422010-08-04 20:26:07 +01001549
1550 regs = intel_overlay_map_regs_atomic(overlay);
1551 if (!regs)
1552 goto err;
1553
1554 memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers));
Linus Torvaldsc48c43e2010-10-26 18:57:59 -07001555 intel_overlay_unmap_regs_atomic(overlay, regs);
Chris Wilson6ef3d422010-08-04 20:26:07 +01001556
1557 return error;
1558
1559err:
1560 kfree(error);
1561 return NULL;
1562}
1563
1564void
1565intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error)
1566{
1567 seq_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",
1568 error->dovsta, error->isr);
1569 seq_printf(m, " Register file at 0x%08lx:\n",
1570 error->base);
1571
1572#define P(x) seq_printf(m, " " #x ": 0x%08x\n", error->regs.x)
1573 P(OBUF_0Y);
1574 P(OBUF_1Y);
1575 P(OBUF_0U);
1576 P(OBUF_0V);
1577 P(OBUF_1U);
1578 P(OBUF_1V);
1579 P(OSTRIDE);
1580 P(YRGB_VPH);
1581 P(UV_VPH);
1582 P(HORZ_PH);
1583 P(INIT_PHS);
1584 P(DWINPOS);
1585 P(DWINSZ);
1586 P(SWIDTH);
1587 P(SWIDTHSW);
1588 P(SHEIGHT);
1589 P(YRGBSCALE);
1590 P(UVSCALE);
1591 P(OCLRC0);
1592 P(OCLRC1);
1593 P(DCLRKV);
1594 P(DCLRKM);
1595 P(SCLRKVH);
1596 P(SCLRKVL);
1597 P(SCLRKEN);
1598 P(OCONFIG);
1599 P(OCMD);
1600 P(OSTART_0Y);
1601 P(OSTART_1Y);
1602 P(OSTART_0U);
1603 P(OSTART_0V);
1604 P(OSTART_1U);
1605 P(OSTART_1V);
1606 P(OTILEOFF_0Y);
1607 P(OTILEOFF_1Y);
1608 P(OTILEOFF_0U);
1609 P(OTILEOFF_0V);
1610 P(OTILEOFF_1U);
1611 P(OTILEOFF_1V);
1612 P(FASTHSCALE);
1613 P(UVSCALEV);
1614#undef P
1615}
Chris Wilson3bd3c932010-08-19 08:19:30 +01001616#endif