blob: 217fefc49bf9238544cfcad01343b7e21719ae15 [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 */
David Howells760285e2012-10-02 18:01:07 +010028#include <drm/drmP.h>
29#include <drm/i915_drm.h>
Daniel Vetter02e792f2009-09-15 22:57:34 +020030#include "i915_drv.h"
31#include "i915_reg.h"
32#include "intel_drv.h"
33
34/* Limits for overlay size. According to intel doc, the real limits are:
35 * Y width: 4095, UV width (planar): 2047, Y height: 2047,
36 * UV width (planar): * 1023. But the xorg thinks 2048 for height and width. Use
37 * the mininum of both. */
38#define IMAGE_MAX_WIDTH 2048
39#define IMAGE_MAX_HEIGHT 2046 /* 2 * 1023 */
40/* on 830 and 845 these large limits result in the card hanging */
41#define IMAGE_MAX_WIDTH_LEGACY 1024
42#define IMAGE_MAX_HEIGHT_LEGACY 1088
43
44/* overlay register definitions */
45/* OCMD register */
46#define OCMD_TILED_SURFACE (0x1<<19)
47#define OCMD_MIRROR_MASK (0x3<<17)
48#define OCMD_MIRROR_MODE (0x3<<17)
49#define OCMD_MIRROR_HORIZONTAL (0x1<<17)
50#define OCMD_MIRROR_VERTICAL (0x2<<17)
51#define OCMD_MIRROR_BOTH (0x3<<17)
52#define OCMD_BYTEORDER_MASK (0x3<<14) /* zero for YUYV or FOURCC YUY2 */
53#define OCMD_UV_SWAP (0x1<<14) /* YVYU */
54#define OCMD_Y_SWAP (0x2<<14) /* UYVY or FOURCC UYVY */
55#define OCMD_Y_AND_UV_SWAP (0x3<<14) /* VYUY */
56#define OCMD_SOURCE_FORMAT_MASK (0xf<<10)
57#define OCMD_RGB_888 (0x1<<10) /* not in i965 Intel docs */
58#define OCMD_RGB_555 (0x2<<10) /* not in i965 Intel docs */
59#define OCMD_RGB_565 (0x3<<10) /* not in i965 Intel docs */
60#define OCMD_YUV_422_PACKED (0x8<<10)
61#define OCMD_YUV_411_PACKED (0x9<<10) /* not in i965 Intel docs */
62#define OCMD_YUV_420_PLANAR (0xc<<10)
63#define OCMD_YUV_422_PLANAR (0xd<<10)
64#define OCMD_YUV_410_PLANAR (0xe<<10) /* also 411 */
65#define OCMD_TVSYNCFLIP_PARITY (0x1<<9)
66#define OCMD_TVSYNCFLIP_ENABLE (0x1<<7)
Chris Wilsond7961362010-07-13 13:52:17 +010067#define OCMD_BUF_TYPE_MASK (0x1<<5)
Daniel Vetter02e792f2009-09-15 22:57:34 +020068#define OCMD_BUF_TYPE_FRAME (0x0<<5)
69#define OCMD_BUF_TYPE_FIELD (0x1<<5)
70#define OCMD_TEST_MODE (0x1<<4)
71#define OCMD_BUFFER_SELECT (0x3<<2)
72#define OCMD_BUFFER0 (0x0<<2)
73#define OCMD_BUFFER1 (0x1<<2)
74#define OCMD_FIELD_SELECT (0x1<<2)
75#define OCMD_FIELD0 (0x0<<1)
76#define OCMD_FIELD1 (0x1<<1)
77#define OCMD_ENABLE (0x1<<0)
78
79/* OCONFIG register */
80#define OCONF_PIPE_MASK (0x1<<18)
81#define OCONF_PIPE_A (0x0<<18)
82#define OCONF_PIPE_B (0x1<<18)
83#define OCONF_GAMMA2_ENABLE (0x1<<16)
84#define OCONF_CSC_MODE_BT601 (0x0<<5)
85#define OCONF_CSC_MODE_BT709 (0x1<<5)
86#define OCONF_CSC_BYPASS (0x1<<4)
87#define OCONF_CC_OUT_8BIT (0x1<<3)
88#define OCONF_TEST_MODE (0x1<<2)
89#define OCONF_THREE_LINE_BUFFER (0x1<<0)
90#define OCONF_TWO_LINE_BUFFER (0x0<<0)
91
92/* DCLRKM (dst-key) register */
93#define DST_KEY_ENABLE (0x1<<31)
94#define CLK_RGB24_MASK 0x0
95#define CLK_RGB16_MASK 0x070307
96#define CLK_RGB15_MASK 0x070707
97#define CLK_RGB8I_MASK 0xffffff
98
99#define RGB16_TO_COLORKEY(c) \
100 (((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3))
101#define RGB15_TO_COLORKEY(c) \
102 (((c & 0x7c00) << 9) | ((c & 0x03E0) << 6) | ((c & 0x001F) << 3))
103
104/* overlay flip addr flag */
105#define OFC_UPDATE 0x1
106
107/* polyphase filter coefficients */
108#define N_HORIZ_Y_TAPS 5
109#define N_VERT_Y_TAPS 3
110#define N_HORIZ_UV_TAPS 3
111#define N_VERT_UV_TAPS 3
112#define N_PHASES 17
113#define MAX_TAPS 5
114
115/* memory bufferd overlay registers */
116struct overlay_registers {
Akshay Joshi0206e352011-08-16 15:34:10 -0400117 u32 OBUF_0Y;
118 u32 OBUF_1Y;
119 u32 OBUF_0U;
120 u32 OBUF_0V;
121 u32 OBUF_1U;
122 u32 OBUF_1V;
123 u32 OSTRIDE;
124 u32 YRGB_VPH;
125 u32 UV_VPH;
126 u32 HORZ_PH;
127 u32 INIT_PHS;
128 u32 DWINPOS;
129 u32 DWINSZ;
130 u32 SWIDTH;
131 u32 SWIDTHSW;
132 u32 SHEIGHT;
133 u32 YRGBSCALE;
134 u32 UVSCALE;
135 u32 OCLRC0;
136 u32 OCLRC1;
137 u32 DCLRKV;
138 u32 DCLRKM;
139 u32 SCLRKVH;
140 u32 SCLRKVL;
141 u32 SCLRKEN;
142 u32 OCONFIG;
143 u32 OCMD;
144 u32 RESERVED1; /* 0x6C */
145 u32 OSTART_0Y;
146 u32 OSTART_1Y;
147 u32 OSTART_0U;
148 u32 OSTART_0V;
149 u32 OSTART_1U;
150 u32 OSTART_1V;
151 u32 OTILEOFF_0Y;
152 u32 OTILEOFF_1Y;
153 u32 OTILEOFF_0U;
154 u32 OTILEOFF_0V;
155 u32 OTILEOFF_1U;
156 u32 OTILEOFF_1V;
157 u32 FASTHSCALE; /* 0xA0 */
158 u32 UVSCALEV; /* 0xA4 */
159 u32 RESERVEDC[(0x200 - 0xA8) / 4]; /* 0xA8 - 0x1FC */
160 u16 Y_VCOEFS[N_VERT_Y_TAPS * N_PHASES]; /* 0x200 */
161 u16 RESERVEDD[0x100 / 2 - N_VERT_Y_TAPS * N_PHASES];
162 u16 Y_HCOEFS[N_HORIZ_Y_TAPS * N_PHASES]; /* 0x300 */
163 u16 RESERVEDE[0x200 / 2 - N_HORIZ_Y_TAPS * N_PHASES];
164 u16 UV_VCOEFS[N_VERT_UV_TAPS * N_PHASES]; /* 0x500 */
165 u16 RESERVEDF[0x100 / 2 - N_VERT_UV_TAPS * N_PHASES];
166 u16 UV_HCOEFS[N_HORIZ_UV_TAPS * N_PHASES]; /* 0x600 */
167 u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES];
Daniel Vetter02e792f2009-09-15 22:57:34 +0200168};
169
Chris Wilson23f09ce2010-08-12 13:53:37 +0100170struct intel_overlay {
Chris Wilson1ee8da62016-05-12 12:43:23 +0100171 struct drm_i915_private *i915;
Chris Wilson23f09ce2010-08-12 13:53:37 +0100172 struct intel_crtc *crtc;
173 struct drm_i915_gem_object *vid_bo;
174 struct drm_i915_gem_object *old_vid_bo;
Ville Syrjälä209c2a52015-03-31 10:37:23 +0300175 bool active;
176 bool pfit_active;
Chris Wilson23f09ce2010-08-12 13:53:37 +0100177 u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
Chris Wilsonea9da4e2015-04-02 10:35:08 +0100178 u32 color_key:24;
179 u32 color_key_enabled:1;
Chris Wilson23f09ce2010-08-12 13:53:37 +0100180 u32 brightness, contrast, saturation;
181 u32 old_xscale, old_yscale;
182 /* register access */
183 u32 flip_addr;
184 struct drm_i915_gem_object *reg_bo;
185 /* flip handling */
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100186 struct i915_gem_active last_flip;
Chris Wilson23f09ce2010-08-12 13:53:37 +0100187};
Daniel Vetter02e792f2009-09-15 22:57:34 +0200188
Ben Widawsky75020bc2012-04-16 14:07:43 -0700189static struct overlay_registers __iomem *
Chris Wilson8d74f652010-08-12 10:35:26 +0100190intel_overlay_map_regs(struct intel_overlay *overlay)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200191{
Chris Wilson1ee8da62016-05-12 12:43:23 +0100192 struct drm_i915_private *dev_priv = overlay->i915;
Ben Widawsky75020bc2012-04-16 14:07:43 -0700193 struct overlay_registers __iomem *regs;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200194
Chris Wilson1ee8da62016-05-12 12:43:23 +0100195 if (OVERLAY_NEEDS_PHYSICAL(dev_priv))
Chris Wilson00731152014-05-21 12:42:56 +0100196 regs = (struct overlay_registers __iomem *)overlay->reg_bo->phys_handle->vaddr;
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100197 else
Chris Wilson1ee8da62016-05-12 12:43:23 +0100198 regs = io_mapping_map_wc(dev_priv->ggtt.mappable,
Chris Wilsond8dab002016-04-28 09:56:37 +0100199 overlay->flip_addr,
200 PAGE_SIZE);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200201
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100202 return regs;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200203}
204
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100205static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
Ben Widawsky75020bc2012-04-16 14:07:43 -0700206 struct overlay_registers __iomem *regs)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200207{
Chris Wilson1ee8da62016-05-12 12:43:23 +0100208 if (!OVERLAY_NEEDS_PHYSICAL(overlay->i915))
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100209 io_mapping_unmap(regs);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200210}
Daniel Vetter02e792f2009-09-15 22:57:34 +0200211
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100212static void intel_overlay_submit_request(struct intel_overlay *overlay,
213 struct drm_i915_gem_request *req,
214 i915_gem_retire_fn retire)
215{
216 GEM_BUG_ON(i915_gem_active_peek(&overlay->last_flip,
217 &overlay->i915->drm.struct_mutex));
218 overlay->last_flip.retire = retire;
219 i915_gem_active_set(&overlay->last_flip, req);
220 i915_add_request(req);
221}
222
Chris Wilsonb6c028e2010-08-12 11:55:08 +0100223static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
John Harrisondad540c2015-05-29 17:43:47 +0100224 struct drm_i915_gem_request *req,
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100225 i915_gem_retire_fn retire)
Chris Wilsonb6c028e2010-08-12 11:55:08 +0100226{
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100227 intel_overlay_submit_request(overlay, req, retire);
228 return i915_gem_active_retire(&overlay->last_flip,
229 &overlay->i915->drm.struct_mutex);
Chris Wilsonb6c028e2010-08-12 11:55:08 +0100230}
231
Chris Wilson8e637172016-08-02 22:50:26 +0100232static struct drm_i915_gem_request *alloc_request(struct intel_overlay *overlay)
233{
234 struct drm_i915_private *dev_priv = overlay->i915;
235 struct intel_engine_cs *engine = &dev_priv->engine[RCS];
236
237 return i915_gem_request_alloc(engine, dev_priv->kernel_context);
238}
239
Daniel Vetter02e792f2009-09-15 22:57:34 +0200240/* overlay needs to be disable in OCMD reg */
241static int intel_overlay_on(struct intel_overlay *overlay)
242{
Chris Wilson1ee8da62016-05-12 12:43:23 +0100243 struct drm_i915_private *dev_priv = overlay->i915;
John Harrisondad540c2015-05-29 17:43:47 +0100244 struct drm_i915_gem_request *req;
Chris Wilson7e37f882016-08-02 22:50:21 +0100245 struct intel_ring *ring;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200246 int ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200247
Ville Syrjälä77589f52015-03-31 10:37:22 +0300248 WARN_ON(overlay->active);
Chris Wilson1ee8da62016-05-12 12:43:23 +0100249 WARN_ON(IS_I830(dev_priv) && !(dev_priv->quirks & QUIRK_PIPEA_FORCE));
Chris Wilson106dada2010-07-16 17:13:01 +0100250
Chris Wilson8e637172016-08-02 22:50:26 +0100251 req = alloc_request(overlay);
Dave Gordon26827082016-01-19 19:02:53 +0000252 if (IS_ERR(req))
253 return PTR_ERR(req);
Chris Wilsone1f99ce2010-10-27 12:45:26 +0100254
John Harrison5fb9de12015-05-29 17:44:07 +0100255 ret = intel_ring_begin(req, 4);
John Harrisondad540c2015-05-29 17:43:47 +0100256 if (ret) {
Chris Wilsonaa9b7812016-04-13 17:35:15 +0100257 i915_add_request_no_flush(req);
John Harrisondad540c2015-05-29 17:43:47 +0100258 return ret;
259 }
260
Ville Syrjälä1c7c4302015-03-31 10:37:24 +0300261 overlay->active = true;
262
Chris Wilson1dae2df2016-08-02 22:50:19 +0100263 ring = req->ring;
Chris Wilsonb5321f32016-08-02 22:50:18 +0100264 intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_ON);
265 intel_ring_emit(ring, overlay->flip_addr | OFC_UPDATE);
266 intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
267 intel_ring_emit(ring, MI_NOOP);
268 intel_ring_advance(ring);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200269
John Harrisondad540c2015-05-29 17:43:47 +0100270 return intel_overlay_do_wait_request(overlay, req, NULL);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200271}
272
273/* overlay needs to be enabled in OCMD reg */
Chris Wilson8dc5d142010-08-12 12:36:12 +0100274static int intel_overlay_continue(struct intel_overlay *overlay,
275 bool load_polyphase_filter)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200276{
Chris Wilson1ee8da62016-05-12 12:43:23 +0100277 struct drm_i915_private *dev_priv = overlay->i915;
John Harrisondad540c2015-05-29 17:43:47 +0100278 struct drm_i915_gem_request *req;
Chris Wilson7e37f882016-08-02 22:50:21 +0100279 struct intel_ring *ring;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200280 u32 flip_addr = overlay->flip_addr;
281 u32 tmp;
Chris Wilsone1f99ce2010-10-27 12:45:26 +0100282 int ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200283
Ville Syrjälä77589f52015-03-31 10:37:22 +0300284 WARN_ON(!overlay->active);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200285
286 if (load_polyphase_filter)
287 flip_addr |= OFC_UPDATE;
288
289 /* check for underruns */
290 tmp = I915_READ(DOVSTA);
291 if (tmp & (1 << 17))
292 DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
293
Chris Wilson8e637172016-08-02 22:50:26 +0100294 req = alloc_request(overlay);
Dave Gordon26827082016-01-19 19:02:53 +0000295 if (IS_ERR(req))
296 return PTR_ERR(req);
Chris Wilsonacb868d2012-09-26 13:47:30 +0100297
John Harrison5fb9de12015-05-29 17:44:07 +0100298 ret = intel_ring_begin(req, 2);
John Harrisondad540c2015-05-29 17:43:47 +0100299 if (ret) {
Chris Wilsonaa9b7812016-04-13 17:35:15 +0100300 i915_add_request_no_flush(req);
John Harrisondad540c2015-05-29 17:43:47 +0100301 return ret;
302 }
303
Chris Wilson1dae2df2016-08-02 22:50:19 +0100304 ring = req->ring;
Chris Wilsonb5321f32016-08-02 22:50:18 +0100305 intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
306 intel_ring_emit(ring, flip_addr);
307 intel_ring_advance(ring);
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200308
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100309 intel_overlay_submit_request(overlay, req, NULL);
John Harrisonbf7dc5b2015-05-29 17:43:24 +0100310
311 return 0;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200312}
313
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100314static void intel_overlay_release_old_vid_tail(struct i915_gem_active *active,
315 struct drm_i915_gem_request *req)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200316{
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100317 struct intel_overlay *overlay =
318 container_of(active, typeof(*overlay), last_flip);
Chris Wilson05394f32010-11-08 19:18:58 +0000319 struct drm_i915_gem_object *obj = overlay->old_vid_bo;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200320
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100321 i915_gem_track_fb(obj, NULL,
322 INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe));
323
Ben Widawskyd7f46fc2013-12-06 14:10:55 -0800324 i915_gem_object_ggtt_unpin(obj);
Chris Wilsonf8c417c2016-07-20 13:31:53 +0100325 i915_gem_object_put(obj);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200326
Chris Wilsonb303cf92010-08-12 14:03:48 +0100327 overlay->old_vid_bo = NULL;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200328}
329
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100330static void intel_overlay_off_tail(struct i915_gem_active *active,
331 struct drm_i915_gem_request *req)
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200332{
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100333 struct intel_overlay *overlay =
334 container_of(active, typeof(*overlay), last_flip);
Chris Wilson05394f32010-11-08 19:18:58 +0000335 struct drm_i915_gem_object *obj = overlay->vid_bo;
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200336
337 /* never have the overlay hw on without showing a frame */
Ville Syrjälä77589f52015-03-31 10:37:22 +0300338 if (WARN_ON(!obj))
339 return;
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200340
Ben Widawskyd7f46fc2013-12-06 14:10:55 -0800341 i915_gem_object_ggtt_unpin(obj);
Chris Wilsonf8c417c2016-07-20 13:31:53 +0100342 i915_gem_object_put(obj);
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200343 overlay->vid_bo = NULL;
344
345 overlay->crtc->overlay = NULL;
346 overlay->crtc = NULL;
Ville Syrjälä209c2a52015-03-31 10:37:23 +0300347 overlay->active = false;
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200348}
349
Daniel Vetter02e792f2009-09-15 22:57:34 +0200350/* overlay needs to be disabled in OCMD reg */
Chris Wilsonce453d82011-02-21 14:43:56 +0000351static int intel_overlay_off(struct intel_overlay *overlay)
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200352{
Chris Wilson1ee8da62016-05-12 12:43:23 +0100353 struct drm_i915_private *dev_priv = overlay->i915;
John Harrisondad540c2015-05-29 17:43:47 +0100354 struct drm_i915_gem_request *req;
Chris Wilson7e37f882016-08-02 22:50:21 +0100355 struct intel_ring *ring;
Chris Wilson8dc5d142010-08-12 12:36:12 +0100356 u32 flip_addr = overlay->flip_addr;
Chris Wilsone1f99ce2010-10-27 12:45:26 +0100357 int ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200358
Ville Syrjälä77589f52015-03-31 10:37:22 +0300359 WARN_ON(!overlay->active);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200360
361 /* According to intel docs the overlay hw may hang (when switching
362 * off) without loading the filter coeffs. It is however unclear whether
363 * this applies to the disabling of the overlay or to the switching off
364 * of the hw. Do it in both cases */
365 flip_addr |= OFC_UPDATE;
366
Chris Wilson8e637172016-08-02 22:50:26 +0100367 req = alloc_request(overlay);
Dave Gordon26827082016-01-19 19:02:53 +0000368 if (IS_ERR(req))
369 return PTR_ERR(req);
Chris Wilsonacb868d2012-09-26 13:47:30 +0100370
John Harrison5fb9de12015-05-29 17:44:07 +0100371 ret = intel_ring_begin(req, 6);
John Harrisondad540c2015-05-29 17:43:47 +0100372 if (ret) {
Chris Wilsonaa9b7812016-04-13 17:35:15 +0100373 i915_add_request_no_flush(req);
John Harrisondad540c2015-05-29 17:43:47 +0100374 return ret;
375 }
376
Chris Wilson1dae2df2016-08-02 22:50:19 +0100377 ring = req->ring;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200378 /* wait for overlay to go idle */
Chris Wilsonb5321f32016-08-02 22:50:18 +0100379 intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
380 intel_ring_emit(ring, flip_addr);
381 intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
Chris Wilson722506f2010-08-12 09:28:50 +0100382 /* turn overlay off */
Chris Wilson1ee8da62016-05-12 12:43:23 +0100383 if (IS_I830(dev_priv)) {
Daniel Vettera9193982012-10-22 12:55:55 +0200384 /* Workaround: Don't disable the overlay fully, since otherwise
385 * it dies on the next OVERLAY_ON cmd. */
Chris Wilsonb5321f32016-08-02 22:50:18 +0100386 intel_ring_emit(ring, MI_NOOP);
387 intel_ring_emit(ring, MI_NOOP);
388 intel_ring_emit(ring, MI_NOOP);
Daniel Vettera9193982012-10-22 12:55:55 +0200389 } else {
Chris Wilsonb5321f32016-08-02 22:50:18 +0100390 intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
391 intel_ring_emit(ring, flip_addr);
392 intel_ring_emit(ring,
Tvrtko Ursuline2f80392016-03-16 11:00:36 +0000393 MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
Daniel Vettera9193982012-10-22 12:55:55 +0200394 }
Chris Wilsonb5321f32016-08-02 22:50:18 +0100395 intel_ring_advance(ring);
Chris Wilson722506f2010-08-12 09:28:50 +0100396
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100397 return intel_overlay_do_wait_request(overlay, req,
398 intel_overlay_off_tail);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200399}
400
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200401/* recover from an interruption due to a signal
402 * We have to be careful not to repeat work forever an make forward progess. */
Chris Wilsonce453d82011-02-21 14:43:56 +0000403static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200404{
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100405 return i915_gem_active_retire(&overlay->last_flip,
406 &overlay->i915->drm.struct_mutex);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200407}
408
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200409/* Wait for pending overlay flip and release old frame.
410 * Needs to be called before the overlay register are changed
Chris Wilson8d74f652010-08-12 10:35:26 +0100411 * via intel_overlay_(un)map_regs
412 */
Daniel Vetter02e792f2009-09-15 22:57:34 +0200413static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
414{
Chris Wilson1ee8da62016-05-12 12:43:23 +0100415 struct drm_i915_private *dev_priv = overlay->i915;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200416 int ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200417
Chris Wilson91c8a322016-07-05 10:40:23 +0100418 lockdep_assert_held(&dev_priv->drm.struct_mutex);
Ville Syrjälä1362b772014-11-26 17:07:29 +0200419
Chris Wilson5cd68c92010-08-12 12:21:54 +0100420 /* Only wait if there is actually an old frame to release to
421 * guarantee forward progress.
422 */
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200423 if (!overlay->old_vid_bo)
424 return 0;
425
Chris Wilson5cd68c92010-08-12 12:21:54 +0100426 if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) {
427 /* synchronous slowpath */
John Harrisondad540c2015-05-29 17:43:47 +0100428 struct drm_i915_gem_request *req;
Chris Wilson7e37f882016-08-02 22:50:21 +0100429 struct intel_ring *ring;
John Harrisondad540c2015-05-29 17:43:47 +0100430
Chris Wilson8e637172016-08-02 22:50:26 +0100431 req = alloc_request(overlay);
Dave Gordon26827082016-01-19 19:02:53 +0000432 if (IS_ERR(req))
433 return PTR_ERR(req);
Chris Wilsone1f99ce2010-10-27 12:45:26 +0100434
John Harrison5fb9de12015-05-29 17:44:07 +0100435 ret = intel_ring_begin(req, 2);
John Harrisondad540c2015-05-29 17:43:47 +0100436 if (ret) {
Chris Wilsonaa9b7812016-04-13 17:35:15 +0100437 i915_add_request_no_flush(req);
John Harrisondad540c2015-05-29 17:43:47 +0100438 return ret;
439 }
440
Chris Wilson1dae2df2016-08-02 22:50:19 +0100441 ring = req->ring;
Chris Wilsonb5321f32016-08-02 22:50:18 +0100442 intel_ring_emit(ring,
Tvrtko Ursuline2f80392016-03-16 11:00:36 +0000443 MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
Chris Wilsonb5321f32016-08-02 22:50:18 +0100444 intel_ring_emit(ring, MI_NOOP);
445 intel_ring_advance(ring);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200446
John Harrisondad540c2015-05-29 17:43:47 +0100447 ret = intel_overlay_do_wait_request(overlay, req,
Chris Wilsonb303cf92010-08-12 14:03:48 +0100448 intel_overlay_release_old_vid_tail);
Chris Wilson5cd68c92010-08-12 12:21:54 +0100449 if (ret)
450 return ret;
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100451 } else
452 intel_overlay_release_old_vid_tail(&overlay->last_flip, NULL);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200453
454 return 0;
455}
456
Ville Syrjälä1362b772014-11-26 17:07:29 +0200457void intel_overlay_reset(struct drm_i915_private *dev_priv)
458{
459 struct intel_overlay *overlay = dev_priv->overlay;
460
461 if (!overlay)
462 return;
463
464 intel_overlay_release_old_vid(overlay);
465
Ville Syrjälä1362b772014-11-26 17:07:29 +0200466 overlay->old_xscale = 0;
467 overlay->old_yscale = 0;
468 overlay->crtc = NULL;
469 overlay->active = false;
470}
471
Daniel Vetter02e792f2009-09-15 22:57:34 +0200472struct put_image_params {
473 int format;
474 short dst_x;
475 short dst_y;
476 short dst_w;
477 short dst_h;
478 short src_w;
479 short src_scan_h;
480 short src_scan_w;
481 short src_h;
482 short stride_Y;
483 short stride_UV;
484 int offset_Y;
485 int offset_U;
486 int offset_V;
487};
488
489static int packed_depth_bytes(u32 format)
490{
491 switch (format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100492 case I915_OVERLAY_YUV422:
493 return 4;
494 case I915_OVERLAY_YUV411:
495 /* return 6; not implemented */
496 default:
497 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200498 }
499}
500
501static int packed_width_bytes(u32 format, short width)
502{
503 switch (format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100504 case I915_OVERLAY_YUV422:
505 return width << 1;
506 default:
507 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200508 }
509}
510
511static int uv_hsubsampling(u32 format)
512{
513 switch (format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100514 case I915_OVERLAY_YUV422:
515 case I915_OVERLAY_YUV420:
516 return 2;
517 case I915_OVERLAY_YUV411:
518 case I915_OVERLAY_YUV410:
519 return 4;
520 default:
521 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200522 }
523}
524
525static int uv_vsubsampling(u32 format)
526{
527 switch (format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100528 case I915_OVERLAY_YUV420:
529 case I915_OVERLAY_YUV410:
530 return 2;
531 case I915_OVERLAY_YUV422:
532 case I915_OVERLAY_YUV411:
533 return 1;
534 default:
535 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200536 }
537}
538
Chris Wilson1ee8da62016-05-12 12:43:23 +0100539static u32 calc_swidthsw(struct drm_i915_private *dev_priv, u32 offset, u32 width)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200540{
541 u32 mask, shift, ret;
Chris Wilson1ee8da62016-05-12 12:43:23 +0100542 if (IS_GEN2(dev_priv)) {
Daniel Vetter02e792f2009-09-15 22:57:34 +0200543 mask = 0x1f;
544 shift = 5;
Chris Wilsona6c45cf2010-09-17 00:32:17 +0100545 } else {
546 mask = 0x3f;
547 shift = 6;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200548 }
549 ret = ((offset + width + mask) >> shift) - (offset >> shift);
Chris Wilson1ee8da62016-05-12 12:43:23 +0100550 if (!IS_GEN2(dev_priv))
Daniel Vetter02e792f2009-09-15 22:57:34 +0200551 ret <<= 1;
Akshay Joshi0206e352011-08-16 15:34:10 -0400552 ret -= 1;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200553 return ret << 2;
554}
555
556static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = {
557 0x3000, 0xb4a0, 0x1930, 0x1920, 0xb4a0,
558 0x3000, 0xb500, 0x19d0, 0x1880, 0xb440,
559 0x3000, 0xb540, 0x1a88, 0x2f80, 0xb3e0,
560 0x3000, 0xb580, 0x1b30, 0x2e20, 0xb380,
561 0x3000, 0xb5c0, 0x1bd8, 0x2cc0, 0xb320,
562 0x3020, 0xb5e0, 0x1c60, 0x2b80, 0xb2c0,
563 0x3020, 0xb5e0, 0x1cf8, 0x2a20, 0xb260,
564 0x3020, 0xb5e0, 0x1d80, 0x28e0, 0xb200,
565 0x3020, 0xb5c0, 0x1e08, 0x3f40, 0xb1c0,
566 0x3020, 0xb580, 0x1e78, 0x3ce0, 0xb160,
567 0x3040, 0xb520, 0x1ed8, 0x3aa0, 0xb120,
568 0x3040, 0xb4a0, 0x1f30, 0x3880, 0xb0e0,
569 0x3040, 0xb400, 0x1f78, 0x3680, 0xb0a0,
570 0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060,
571 0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040,
572 0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020,
Chris Wilson722506f2010-08-12 09:28:50 +0100573 0xb000, 0x3000, 0x0800, 0x3000, 0xb000
574};
575
Daniel Vetter02e792f2009-09-15 22:57:34 +0200576static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
577 0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60,
578 0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40,
579 0xb040, 0x1b20, 0x29e0, 0xb060, 0x1bd8, 0x2880,
580 0xb080, 0x1c88, 0x3e60, 0xb0a0, 0x1d28, 0x3c00,
581 0xb0c0, 0x1db8, 0x39e0, 0xb0e0, 0x1e40, 0x37e0,
582 0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0,
583 0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240,
584 0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0,
Chris Wilson722506f2010-08-12 09:28:50 +0100585 0x3000, 0x0800, 0x3000
586};
Daniel Vetter02e792f2009-09-15 22:57:34 +0200587
Ben Widawsky75020bc2012-04-16 14:07:43 -0700588static void update_polyphase_filter(struct overlay_registers __iomem *regs)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200589{
Ben Widawsky75020bc2012-04-16 14:07:43 -0700590 memcpy_toio(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs));
591 memcpy_toio(regs->UV_HCOEFS, uv_static_hcoeffs,
592 sizeof(uv_static_hcoeffs));
Daniel Vetter02e792f2009-09-15 22:57:34 +0200593}
594
595static bool update_scaling_factors(struct intel_overlay *overlay,
Ben Widawsky75020bc2012-04-16 14:07:43 -0700596 struct overlay_registers __iomem *regs,
Daniel Vetter02e792f2009-09-15 22:57:34 +0200597 struct put_image_params *params)
598{
599 /* fixed point with a 12 bit shift */
600 u32 xscale, yscale, xscale_UV, yscale_UV;
601#define FP_SHIFT 12
602#define FRACT_MASK 0xfff
603 bool scale_changed = false;
604 int uv_hscale = uv_hsubsampling(params->format);
605 int uv_vscale = uv_vsubsampling(params->format);
606
607 if (params->dst_w > 1)
608 xscale = ((params->src_scan_w - 1) << FP_SHIFT)
609 /(params->dst_w);
610 else
611 xscale = 1 << FP_SHIFT;
612
613 if (params->dst_h > 1)
614 yscale = ((params->src_scan_h - 1) << FP_SHIFT)
615 /(params->dst_h);
616 else
617 yscale = 1 << FP_SHIFT;
618
619 /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
Chris Wilson722506f2010-08-12 09:28:50 +0100620 xscale_UV = xscale/uv_hscale;
621 yscale_UV = yscale/uv_vscale;
622 /* make the Y scale to UV scale ratio an exact multiply */
623 xscale = xscale_UV * uv_hscale;
624 yscale = yscale_UV * uv_vscale;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200625 /*} else {
Chris Wilson722506f2010-08-12 09:28:50 +0100626 xscale_UV = 0;
627 yscale_UV = 0;
628 }*/
Daniel Vetter02e792f2009-09-15 22:57:34 +0200629
630 if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)
631 scale_changed = true;
632 overlay->old_xscale = xscale;
633 overlay->old_yscale = yscale;
634
Ben Widawsky75020bc2012-04-16 14:07:43 -0700635 iowrite32(((yscale & FRACT_MASK) << 20) |
636 ((xscale >> FP_SHIFT) << 16) |
637 ((xscale & FRACT_MASK) << 3),
638 &regs->YRGBSCALE);
Chris Wilson722506f2010-08-12 09:28:50 +0100639
Ben Widawsky75020bc2012-04-16 14:07:43 -0700640 iowrite32(((yscale_UV & FRACT_MASK) << 20) |
641 ((xscale_UV >> FP_SHIFT) << 16) |
642 ((xscale_UV & FRACT_MASK) << 3),
643 &regs->UVSCALE);
Chris Wilson722506f2010-08-12 09:28:50 +0100644
Ben Widawsky75020bc2012-04-16 14:07:43 -0700645 iowrite32((((yscale >> FP_SHIFT) << 16) |
646 ((yscale_UV >> FP_SHIFT) << 0)),
647 &regs->UVSCALEV);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200648
649 if (scale_changed)
650 update_polyphase_filter(regs);
651
652 return scale_changed;
653}
654
655static void update_colorkey(struct intel_overlay *overlay,
Ben Widawsky75020bc2012-04-16 14:07:43 -0700656 struct overlay_registers __iomem *regs)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200657{
658 u32 key = overlay->color_key;
Chris Wilsonea9da4e2015-04-02 10:35:08 +0100659 u32 flags;
660
661 flags = 0;
662 if (overlay->color_key_enabled)
663 flags |= DST_KEY_ENABLE;
Chris Wilson6ba3ddd2010-08-12 09:30:58 +0100664
Matt Roperf4510a22014-04-01 15:22:40 -0700665 switch (overlay->crtc->base.primary->fb->bits_per_pixel) {
Chris Wilson722506f2010-08-12 09:28:50 +0100666 case 8:
Chris Wilsonea9da4e2015-04-02 10:35:08 +0100667 key = 0;
668 flags |= CLK_RGB8I_MASK;
Chris Wilson6ba3ddd2010-08-12 09:30:58 +0100669 break;
670
Chris Wilson722506f2010-08-12 09:28:50 +0100671 case 16:
Matt Roperf4510a22014-04-01 15:22:40 -0700672 if (overlay->crtc->base.primary->fb->depth == 15) {
Chris Wilsonea9da4e2015-04-02 10:35:08 +0100673 key = RGB15_TO_COLORKEY(key);
674 flags |= CLK_RGB15_MASK;
Chris Wilson722506f2010-08-12 09:28:50 +0100675 } else {
Chris Wilsonea9da4e2015-04-02 10:35:08 +0100676 key = RGB16_TO_COLORKEY(key);
677 flags |= CLK_RGB16_MASK;
Chris Wilson722506f2010-08-12 09:28:50 +0100678 }
Chris Wilson6ba3ddd2010-08-12 09:30:58 +0100679 break;
680
Chris Wilson722506f2010-08-12 09:28:50 +0100681 case 24:
682 case 32:
Chris Wilsonea9da4e2015-04-02 10:35:08 +0100683 flags |= CLK_RGB24_MASK;
Chris Wilson6ba3ddd2010-08-12 09:30:58 +0100684 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200685 }
Chris Wilsonea9da4e2015-04-02 10:35:08 +0100686
687 iowrite32(key, &regs->DCLRKV);
688 iowrite32(flags, &regs->DCLRKM);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200689}
690
691static u32 overlay_cmd_reg(struct put_image_params *params)
692{
693 u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0;
694
695 if (params->format & I915_OVERLAY_YUV_PLANAR) {
696 switch (params->format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100697 case I915_OVERLAY_YUV422:
698 cmd |= OCMD_YUV_422_PLANAR;
699 break;
700 case I915_OVERLAY_YUV420:
701 cmd |= OCMD_YUV_420_PLANAR;
702 break;
703 case I915_OVERLAY_YUV411:
704 case I915_OVERLAY_YUV410:
705 cmd |= OCMD_YUV_410_PLANAR;
706 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200707 }
708 } else { /* YUV packed */
709 switch (params->format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100710 case I915_OVERLAY_YUV422:
711 cmd |= OCMD_YUV_422_PACKED;
712 break;
713 case I915_OVERLAY_YUV411:
714 cmd |= OCMD_YUV_411_PACKED;
715 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200716 }
717
718 switch (params->format & I915_OVERLAY_SWAP_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100719 case I915_OVERLAY_NO_SWAP:
720 break;
721 case I915_OVERLAY_UV_SWAP:
722 cmd |= OCMD_UV_SWAP;
723 break;
724 case I915_OVERLAY_Y_SWAP:
725 cmd |= OCMD_Y_SWAP;
726 break;
727 case I915_OVERLAY_Y_AND_UV_SWAP:
728 cmd |= OCMD_Y_AND_UV_SWAP;
729 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200730 }
731 }
732
733 return cmd;
734}
735
Chris Wilson5fe82c52010-08-12 12:38:21 +0100736static int intel_overlay_do_put_image(struct intel_overlay *overlay,
Chris Wilson05394f32010-11-08 19:18:58 +0000737 struct drm_i915_gem_object *new_bo,
Chris Wilson5fe82c52010-08-12 12:38:21 +0100738 struct put_image_params *params)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200739{
740 int ret, tmp_width;
Ben Widawsky75020bc2012-04-16 14:07:43 -0700741 struct overlay_registers __iomem *regs;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200742 bool scale_changed = false;
Chris Wilson1ee8da62016-05-12 12:43:23 +0100743 struct drm_i915_private *dev_priv = overlay->i915;
Ben Widawsky75020bc2012-04-16 14:07:43 -0700744 u32 swidth, swidthsw, sheight, ostride;
Daniel Vettera071fa02014-06-18 23:28:09 +0200745 enum pipe pipe = overlay->crtc->pipe;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200746
Chris Wilson91c8a322016-07-05 10:40:23 +0100747 lockdep_assert_held(&dev_priv->drm.struct_mutex);
748 WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex));
Daniel Vetter02e792f2009-09-15 22:57:34 +0200749
Daniel Vetter02e792f2009-09-15 22:57:34 +0200750 ret = intel_overlay_release_old_vid(overlay);
751 if (ret != 0)
752 return ret;
753
Maarten Lankhorst7580d772015-08-18 13:40:06 +0200754 ret = i915_gem_object_pin_to_display_plane(new_bo, 0,
Tvrtko Ursuline6617332015-03-23 11:10:33 +0000755 &i915_ggtt_view_normal);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200756 if (ret != 0)
757 return ret;
758
Chris Wilsond9e86c02010-11-10 16:40:20 +0000759 ret = i915_gem_object_put_fence(new_bo);
760 if (ret)
761 goto out_unpin;
762
Daniel Vetter02e792f2009-09-15 22:57:34 +0200763 if (!overlay->active) {
Ben Widawsky75020bc2012-04-16 14:07:43 -0700764 u32 oconfig;
Chris Wilson8d74f652010-08-12 10:35:26 +0100765 regs = intel_overlay_map_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200766 if (!regs) {
767 ret = -ENOMEM;
768 goto out_unpin;
769 }
Ben Widawsky75020bc2012-04-16 14:07:43 -0700770 oconfig = OCONF_CC_OUT_8BIT;
Chris Wilson1ee8da62016-05-12 12:43:23 +0100771 if (IS_GEN4(dev_priv))
Ben Widawsky75020bc2012-04-16 14:07:43 -0700772 oconfig |= OCONF_CSC_MODE_BT709;
Daniel Vettera071fa02014-06-18 23:28:09 +0200773 oconfig |= pipe == 0 ?
Daniel Vetter02e792f2009-09-15 22:57:34 +0200774 OCONF_PIPE_A : OCONF_PIPE_B;
Ben Widawsky75020bc2012-04-16 14:07:43 -0700775 iowrite32(oconfig, &regs->OCONFIG);
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100776 intel_overlay_unmap_regs(overlay, regs);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200777
778 ret = intel_overlay_on(overlay);
779 if (ret != 0)
780 goto out_unpin;
781 }
782
Chris Wilson8d74f652010-08-12 10:35:26 +0100783 regs = intel_overlay_map_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200784 if (!regs) {
785 ret = -ENOMEM;
786 goto out_unpin;
787 }
788
Ben Widawsky75020bc2012-04-16 14:07:43 -0700789 iowrite32((params->dst_y << 16) | params->dst_x, &regs->DWINPOS);
790 iowrite32((params->dst_h << 16) | params->dst_w, &regs->DWINSZ);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200791
792 if (params->format & I915_OVERLAY_YUV_PACKED)
793 tmp_width = packed_width_bytes(params->format, params->src_w);
794 else
795 tmp_width = params->src_w;
796
Ben Widawsky75020bc2012-04-16 14:07:43 -0700797 swidth = params->src_w;
Chris Wilson1ee8da62016-05-12 12:43:23 +0100798 swidthsw = calc_swidthsw(dev_priv, params->offset_Y, tmp_width);
Ben Widawsky75020bc2012-04-16 14:07:43 -0700799 sheight = params->src_h;
Ben Widawskyf343c5f2013-07-05 14:41:04 -0700800 iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_Y, &regs->OBUF_0Y);
Ben Widawsky75020bc2012-04-16 14:07:43 -0700801 ostride = params->stride_Y;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200802
803 if (params->format & I915_OVERLAY_YUV_PLANAR) {
804 int uv_hscale = uv_hsubsampling(params->format);
805 int uv_vscale = uv_vsubsampling(params->format);
806 u32 tmp_U, tmp_V;
Ben Widawsky75020bc2012-04-16 14:07:43 -0700807 swidth |= (params->src_w/uv_hscale) << 16;
Chris Wilson1ee8da62016-05-12 12:43:23 +0100808 tmp_U = calc_swidthsw(dev_priv, params->offset_U,
Chris Wilson722506f2010-08-12 09:28:50 +0100809 params->src_w/uv_hscale);
Chris Wilson1ee8da62016-05-12 12:43:23 +0100810 tmp_V = calc_swidthsw(dev_priv, params->offset_V,
Chris Wilson722506f2010-08-12 09:28:50 +0100811 params->src_w/uv_hscale);
Ben Widawsky75020bc2012-04-16 14:07:43 -0700812 swidthsw |= max_t(u32, tmp_U, tmp_V) << 16;
813 sheight |= (params->src_h/uv_vscale) << 16;
Ben Widawskyf343c5f2013-07-05 14:41:04 -0700814 iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_U, &regs->OBUF_0U);
815 iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_V, &regs->OBUF_0V);
Ben Widawsky75020bc2012-04-16 14:07:43 -0700816 ostride |= params->stride_UV << 16;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200817 }
818
Ben Widawsky75020bc2012-04-16 14:07:43 -0700819 iowrite32(swidth, &regs->SWIDTH);
820 iowrite32(swidthsw, &regs->SWIDTHSW);
821 iowrite32(sheight, &regs->SHEIGHT);
822 iowrite32(ostride, &regs->OSTRIDE);
823
Daniel Vetter02e792f2009-09-15 22:57:34 +0200824 scale_changed = update_scaling_factors(overlay, regs, params);
825
826 update_colorkey(overlay, regs);
827
Ben Widawsky75020bc2012-04-16 14:07:43 -0700828 iowrite32(overlay_cmd_reg(params), &regs->OCMD);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200829
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100830 intel_overlay_unmap_regs(overlay, regs);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200831
Chris Wilson8dc5d142010-08-12 12:36:12 +0100832 ret = intel_overlay_continue(overlay, scale_changed);
833 if (ret)
834 goto out_unpin;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200835
Daniel Vettera071fa02014-06-18 23:28:09 +0200836 i915_gem_track_fb(overlay->vid_bo, new_bo,
837 INTEL_FRONTBUFFER_OVERLAY(pipe));
838
Daniel Vetter02e792f2009-09-15 22:57:34 +0200839 overlay->old_vid_bo = overlay->vid_bo;
Chris Wilson05394f32010-11-08 19:18:58 +0000840 overlay->vid_bo = new_bo;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200841
Chris Wilson91c8a322016-07-05 10:40:23 +0100842 intel_frontbuffer_flip(&dev_priv->drm,
843 INTEL_FRONTBUFFER_OVERLAY(pipe));
Daniel Vetterf99d7062014-06-19 16:01:59 +0200844
Daniel Vetter02e792f2009-09-15 22:57:34 +0200845 return 0;
846
847out_unpin:
Ben Widawskyd7f46fc2013-12-06 14:10:55 -0800848 i915_gem_object_ggtt_unpin(new_bo);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200849 return ret;
850}
851
Chris Wilsonce453d82011-02-21 14:43:56 +0000852int intel_overlay_switch_off(struct intel_overlay *overlay)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200853{
Chris Wilson1ee8da62016-05-12 12:43:23 +0100854 struct drm_i915_private *dev_priv = overlay->i915;
Ben Widawsky75020bc2012-04-16 14:07:43 -0700855 struct overlay_registers __iomem *regs;
Chris Wilson5dcdbcb2010-08-12 13:50:28 +0100856 int ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200857
Chris Wilson91c8a322016-07-05 10:40:23 +0100858 lockdep_assert_held(&dev_priv->drm.struct_mutex);
859 WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex));
Daniel Vetter02e792f2009-09-15 22:57:34 +0200860
Chris Wilsonce453d82011-02-21 14:43:56 +0000861 ret = intel_overlay_recover_from_interrupt(overlay);
Chris Wilsonb303cf92010-08-12 14:03:48 +0100862 if (ret != 0)
863 return ret;
Daniel Vetter9bedb972009-11-30 15:55:49 +0100864
Daniel Vetter02e792f2009-09-15 22:57:34 +0200865 if (!overlay->active)
866 return 0;
867
Daniel Vetter02e792f2009-09-15 22:57:34 +0200868 ret = intel_overlay_release_old_vid(overlay);
869 if (ret != 0)
870 return ret;
871
Chris Wilson8d74f652010-08-12 10:35:26 +0100872 regs = intel_overlay_map_regs(overlay);
Ben Widawsky75020bc2012-04-16 14:07:43 -0700873 iowrite32(0, &regs->OCMD);
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100874 intel_overlay_unmap_regs(overlay, regs);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200875
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100876 return intel_overlay_off(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200877}
878
879static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
880 struct intel_crtc *crtc)
881{
Chris Wilsonf7abfe82010-09-13 14:19:16 +0100882 if (!crtc->active)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200883 return -EINVAL;
884
Daniel Vetter02e792f2009-09-15 22:57:34 +0200885 /* can't use the overlay with double wide pipe */
Ander Conselvan de Oliveira6e3c9712015-01-15 14:55:25 +0200886 if (crtc->config->double_wide)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200887 return -EINVAL;
888
889 return 0;
890}
891
892static void update_pfit_vscale_ratio(struct intel_overlay *overlay)
893{
Chris Wilson1ee8da62016-05-12 12:43:23 +0100894 struct drm_i915_private *dev_priv = overlay->i915;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200895 u32 pfit_control = I915_READ(PFIT_CONTROL);
Chris Wilson446d2182010-08-12 11:15:58 +0100896 u32 ratio;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200897
898 /* XXX: This is not the same logic as in the xorg driver, but more in
Chris Wilson446d2182010-08-12 11:15:58 +0100899 * line with the intel documentation for the i965
900 */
Chris Wilson1ee8da62016-05-12 12:43:23 +0100901 if (INTEL_GEN(dev_priv) >= 4) {
Akshay Joshi0206e352011-08-16 15:34:10 -0400902 /* on i965 use the PGM reg to read out the autoscaler values */
Chris Wilsona6c45cf2010-09-17 00:32:17 +0100903 ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965;
904 } else {
Chris Wilson446d2182010-08-12 11:15:58 +0100905 if (pfit_control & VERT_AUTO_SCALE)
906 ratio = I915_READ(PFIT_AUTO_RATIOS);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200907 else
Chris Wilson446d2182010-08-12 11:15:58 +0100908 ratio = I915_READ(PFIT_PGM_RATIOS);
909 ratio >>= PFIT_VERT_SCALE_SHIFT;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200910 }
911
912 overlay->pfit_vscale_ratio = ratio;
913}
914
915static int check_overlay_dst(struct intel_overlay *overlay,
916 struct drm_intel_overlay_put_image *rec)
917{
918 struct drm_display_mode *mode = &overlay->crtc->base.mode;
919
Daniel Vetter75c13992012-01-28 23:48:46 +0100920 if (rec->dst_x < mode->hdisplay &&
921 rec->dst_x + rec->dst_width <= mode->hdisplay &&
922 rec->dst_y < mode->vdisplay &&
923 rec->dst_y + rec->dst_height <= mode->vdisplay)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200924 return 0;
925 else
926 return -EINVAL;
927}
928
929static int check_overlay_scaling(struct put_image_params *rec)
930{
931 u32 tmp;
932
933 /* downscaling limit is 8.0 */
934 tmp = ((rec->src_scan_h << 16) / rec->dst_h) >> 16;
935 if (tmp > 7)
936 return -EINVAL;
937 tmp = ((rec->src_scan_w << 16) / rec->dst_w) >> 16;
938 if (tmp > 7)
939 return -EINVAL;
940
941 return 0;
942}
943
Chris Wilson1ee8da62016-05-12 12:43:23 +0100944static int check_overlay_src(struct drm_i915_private *dev_priv,
Daniel Vetter02e792f2009-09-15 22:57:34 +0200945 struct drm_intel_overlay_put_image *rec,
Chris Wilson05394f32010-11-08 19:18:58 +0000946 struct drm_i915_gem_object *new_bo)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200947{
Daniel Vetter02e792f2009-09-15 22:57:34 +0200948 int uv_hscale = uv_hsubsampling(rec->flags);
949 int uv_vscale = uv_vsubsampling(rec->flags);
Dan Carpenter8f28f542010-10-27 23:17:25 +0200950 u32 stride_mask;
951 int depth;
952 u32 tmp;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200953
954 /* check src dimensions */
Chris Wilson1ee8da62016-05-12 12:43:23 +0100955 if (IS_845G(dev_priv) || IS_I830(dev_priv)) {
Chris Wilson722506f2010-08-12 09:28:50 +0100956 if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY ||
Chris Wilson9f7c3f42010-08-12 11:29:34 +0100957 rec->src_width > IMAGE_MAX_WIDTH_LEGACY)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200958 return -EINVAL;
959 } else {
Chris Wilson722506f2010-08-12 09:28:50 +0100960 if (rec->src_height > IMAGE_MAX_HEIGHT ||
Chris Wilson9f7c3f42010-08-12 11:29:34 +0100961 rec->src_width > IMAGE_MAX_WIDTH)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200962 return -EINVAL;
963 }
Chris Wilson9f7c3f42010-08-12 11:29:34 +0100964
Daniel Vetter02e792f2009-09-15 22:57:34 +0200965 /* better safe than sorry, use 4 as the maximal subsampling ratio */
Chris Wilson722506f2010-08-12 09:28:50 +0100966 if (rec->src_height < N_VERT_Y_TAPS*4 ||
Chris Wilson9f7c3f42010-08-12 11:29:34 +0100967 rec->src_width < N_HORIZ_Y_TAPS*4)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200968 return -EINVAL;
969
Chris Wilsona1efd142010-07-12 19:35:38 +0100970 /* check alignment constraints */
Daniel Vetter02e792f2009-09-15 22:57:34 +0200971 switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100972 case I915_OVERLAY_RGB:
973 /* not implemented */
974 return -EINVAL;
Chris Wilson9f7c3f42010-08-12 11:29:34 +0100975
Chris Wilson722506f2010-08-12 09:28:50 +0100976 case I915_OVERLAY_YUV_PACKED:
Chris Wilson722506f2010-08-12 09:28:50 +0100977 if (uv_vscale != 1)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200978 return -EINVAL;
Chris Wilson9f7c3f42010-08-12 11:29:34 +0100979
980 depth = packed_depth_bytes(rec->flags);
Chris Wilson722506f2010-08-12 09:28:50 +0100981 if (depth < 0)
982 return depth;
Chris Wilson9f7c3f42010-08-12 11:29:34 +0100983
Chris Wilson722506f2010-08-12 09:28:50 +0100984 /* ignore UV planes */
985 rec->stride_UV = 0;
986 rec->offset_U = 0;
987 rec->offset_V = 0;
988 /* check pixel alignment */
989 if (rec->offset_Y % depth)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200990 return -EINVAL;
Chris Wilson722506f2010-08-12 09:28:50 +0100991 break;
Chris Wilson9f7c3f42010-08-12 11:29:34 +0100992
Chris Wilson722506f2010-08-12 09:28:50 +0100993 case I915_OVERLAY_YUV_PLANAR:
994 if (uv_vscale < 0 || uv_hscale < 0)
995 return -EINVAL;
996 /* no offset restrictions for planar formats */
997 break;
Chris Wilson9f7c3f42010-08-12 11:29:34 +0100998
Chris Wilson722506f2010-08-12 09:28:50 +0100999 default:
1000 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001001 }
1002
1003 if (rec->src_width % uv_hscale)
1004 return -EINVAL;
1005
1006 /* stride checking */
Chris Wilson1ee8da62016-05-12 12:43:23 +01001007 if (IS_I830(dev_priv) || IS_845G(dev_priv))
Chris Wilsona1efd142010-07-12 19:35:38 +01001008 stride_mask = 255;
1009 else
1010 stride_mask = 63;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001011
1012 if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
1013 return -EINVAL;
Chris Wilson1ee8da62016-05-12 12:43:23 +01001014 if (IS_GEN4(dev_priv) && rec->stride_Y < 512)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001015 return -EINVAL;
1016
1017 tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ?
Chris Wilson9f7c3f42010-08-12 11:29:34 +01001018 4096 : 8192;
1019 if (rec->stride_Y > tmp || rec->stride_UV > 2*1024)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001020 return -EINVAL;
1021
1022 /* check buffer dimensions */
1023 switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +01001024 case I915_OVERLAY_RGB:
1025 case I915_OVERLAY_YUV_PACKED:
1026 /* always 4 Y values per depth pixels */
1027 if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y)
1028 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001029
Chris Wilson722506f2010-08-12 09:28:50 +01001030 tmp = rec->stride_Y*rec->src_height;
Chris Wilson05394f32010-11-08 19:18:58 +00001031 if (rec->offset_Y + tmp > new_bo->base.size)
Chris Wilson722506f2010-08-12 09:28:50 +01001032 return -EINVAL;
1033 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001034
Chris Wilson722506f2010-08-12 09:28:50 +01001035 case I915_OVERLAY_YUV_PLANAR:
1036 if (rec->src_width > rec->stride_Y)
1037 return -EINVAL;
1038 if (rec->src_width/uv_hscale > rec->stride_UV)
1039 return -EINVAL;
1040
Chris Wilson9f7c3f42010-08-12 11:29:34 +01001041 tmp = rec->stride_Y * rec->src_height;
Chris Wilson05394f32010-11-08 19:18:58 +00001042 if (rec->offset_Y + tmp > new_bo->base.size)
Chris Wilson722506f2010-08-12 09:28:50 +01001043 return -EINVAL;
Chris Wilson9f7c3f42010-08-12 11:29:34 +01001044
1045 tmp = rec->stride_UV * (rec->src_height / uv_vscale);
Chris Wilson05394f32010-11-08 19:18:58 +00001046 if (rec->offset_U + tmp > new_bo->base.size ||
1047 rec->offset_V + tmp > new_bo->base.size)
Chris Wilson722506f2010-08-12 09:28:50 +01001048 return -EINVAL;
1049 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001050 }
1051
1052 return 0;
1053}
1054
Chris Wilsone9e331a2010-09-13 01:16:10 +01001055/**
1056 * Return the pipe currently connected to the panel fitter,
1057 * or -1 if the panel fitter is not present or not in use
1058 */
Chris Wilson1ee8da62016-05-12 12:43:23 +01001059static int intel_panel_fitter_pipe(struct drm_i915_private *dev_priv)
Chris Wilsone9e331a2010-09-13 01:16:10 +01001060{
Chris Wilsone9e331a2010-09-13 01:16:10 +01001061 u32 pfit_control;
1062
1063 /* i830 doesn't have a panel fitter */
Chris Wilson1ee8da62016-05-12 12:43:23 +01001064 if (INTEL_GEN(dev_priv) <= 3 &&
1065 (IS_I830(dev_priv) || !IS_MOBILE(dev_priv)))
Chris Wilsone9e331a2010-09-13 01:16:10 +01001066 return -1;
1067
1068 pfit_control = I915_READ(PFIT_CONTROL);
1069
1070 /* See if the panel fitter is in use */
1071 if ((pfit_control & PFIT_ENABLE) == 0)
1072 return -1;
1073
1074 /* 965 can place panel fitter on either pipe */
Chris Wilson1ee8da62016-05-12 12:43:23 +01001075 if (IS_GEN4(dev_priv))
Chris Wilsone9e331a2010-09-13 01:16:10 +01001076 return (pfit_control >> 29) & 0x3;
1077
1078 /* older chips can only use pipe 1 */
1079 return 1;
1080}
1081
Chris Wilson1ee8da62016-05-12 12:43:23 +01001082int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data,
1083 struct drm_file *file_priv)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001084{
1085 struct drm_intel_overlay_put_image *put_image_rec = data;
Chris Wilsonfac5e232016-07-04 11:34:36 +01001086 struct drm_i915_private *dev_priv = to_i915(dev);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001087 struct intel_overlay *overlay;
Rob Clark7707e652014-07-17 23:30:04 -04001088 struct drm_crtc *drmmode_crtc;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001089 struct intel_crtc *crtc;
Chris Wilson05394f32010-11-08 19:18:58 +00001090 struct drm_i915_gem_object *new_bo;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001091 struct put_image_params *params;
1092 int ret;
1093
Daniel Vetter02e792f2009-09-15 22:57:34 +02001094 overlay = dev_priv->overlay;
1095 if (!overlay) {
1096 DRM_DEBUG("userspace bug: no overlay\n");
1097 return -ENODEV;
1098 }
1099
1100 if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) {
Daniel Vettera0e99e62012-12-02 01:05:46 +01001101 drm_modeset_lock_all(dev);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001102 mutex_lock(&dev->struct_mutex);
1103
Chris Wilsonce453d82011-02-21 14:43:56 +00001104 ret = intel_overlay_switch_off(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001105
1106 mutex_unlock(&dev->struct_mutex);
Daniel Vettera0e99e62012-12-02 01:05:46 +01001107 drm_modeset_unlock_all(dev);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001108
1109 return ret;
1110 }
1111
Daniel Vetterb14c5672013-09-19 12:18:32 +02001112 params = kmalloc(sizeof(*params), GFP_KERNEL);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001113 if (!params)
1114 return -ENOMEM;
1115
Rob Clark7707e652014-07-17 23:30:04 -04001116 drmmode_crtc = drm_crtc_find(dev, put_image_rec->crtc_id);
1117 if (!drmmode_crtc) {
Dan Carpenter915a4282010-03-06 14:05:39 +03001118 ret = -ENOENT;
1119 goto out_free;
1120 }
Rob Clark7707e652014-07-17 23:30:04 -04001121 crtc = to_intel_crtc(drmmode_crtc);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001122
Chris Wilson03ac0642016-07-20 13:31:51 +01001123 new_bo = i915_gem_object_lookup(file_priv, put_image_rec->bo_handle);
1124 if (!new_bo) {
Dan Carpenter915a4282010-03-06 14:05:39 +03001125 ret = -ENOENT;
1126 goto out_free;
1127 }
Daniel Vetter02e792f2009-09-15 22:57:34 +02001128
Daniel Vettera0e99e62012-12-02 01:05:46 +01001129 drm_modeset_lock_all(dev);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001130 mutex_lock(&dev->struct_mutex);
1131
Chris Wilsond9e86c02010-11-10 16:40:20 +00001132 if (new_bo->tiling_mode) {
Daniel Vetter3b25b312014-02-14 14:06:06 +01001133 DRM_DEBUG_KMS("buffer used for overlay image can not be tiled\n");
Chris Wilsond9e86c02010-11-10 16:40:20 +00001134 ret = -EINVAL;
1135 goto out_unlock;
1136 }
1137
Chris Wilsonce453d82011-02-21 14:43:56 +00001138 ret = intel_overlay_recover_from_interrupt(overlay);
Chris Wilsonb303cf92010-08-12 14:03:48 +01001139 if (ret != 0)
1140 goto out_unlock;
Daniel Vetter03f77ea2009-09-15 22:57:37 +02001141
Daniel Vetter02e792f2009-09-15 22:57:34 +02001142 if (overlay->crtc != crtc) {
1143 struct drm_display_mode *mode = &crtc->base.mode;
Chris Wilsonce453d82011-02-21 14:43:56 +00001144 ret = intel_overlay_switch_off(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001145 if (ret != 0)
1146 goto out_unlock;
1147
1148 ret = check_overlay_possible_on_crtc(overlay, crtc);
1149 if (ret != 0)
1150 goto out_unlock;
1151
1152 overlay->crtc = crtc;
1153 crtc->overlay = overlay;
1154
Chris Wilsone9e331a2010-09-13 01:16:10 +01001155 /* line too wide, i.e. one-line-mode */
1156 if (mode->hdisplay > 1024 &&
Chris Wilson1ee8da62016-05-12 12:43:23 +01001157 intel_panel_fitter_pipe(dev_priv) == crtc->pipe) {
Ville Syrjälä209c2a52015-03-31 10:37:23 +03001158 overlay->pfit_active = true;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001159 update_pfit_vscale_ratio(overlay);
1160 } else
Ville Syrjälä209c2a52015-03-31 10:37:23 +03001161 overlay->pfit_active = false;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001162 }
1163
1164 ret = check_overlay_dst(overlay, put_image_rec);
1165 if (ret != 0)
1166 goto out_unlock;
1167
1168 if (overlay->pfit_active) {
1169 params->dst_y = ((((u32)put_image_rec->dst_y) << 12) /
Chris Wilson722506f2010-08-12 09:28:50 +01001170 overlay->pfit_vscale_ratio);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001171 /* shifting right rounds downwards, so add 1 */
1172 params->dst_h = ((((u32)put_image_rec->dst_height) << 12) /
Chris Wilson722506f2010-08-12 09:28:50 +01001173 overlay->pfit_vscale_ratio) + 1;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001174 } else {
1175 params->dst_y = put_image_rec->dst_y;
1176 params->dst_h = put_image_rec->dst_height;
1177 }
1178 params->dst_x = put_image_rec->dst_x;
1179 params->dst_w = put_image_rec->dst_width;
1180
1181 params->src_w = put_image_rec->src_width;
1182 params->src_h = put_image_rec->src_height;
1183 params->src_scan_w = put_image_rec->src_scan_width;
1184 params->src_scan_h = put_image_rec->src_scan_height;
Chris Wilson722506f2010-08-12 09:28:50 +01001185 if (params->src_scan_h > params->src_h ||
1186 params->src_scan_w > params->src_w) {
Daniel Vetter02e792f2009-09-15 22:57:34 +02001187 ret = -EINVAL;
1188 goto out_unlock;
1189 }
1190
Chris Wilson1ee8da62016-05-12 12:43:23 +01001191 ret = check_overlay_src(dev_priv, put_image_rec, new_bo);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001192 if (ret != 0)
1193 goto out_unlock;
1194 params->format = put_image_rec->flags & ~I915_OVERLAY_FLAGS_MASK;
1195 params->stride_Y = put_image_rec->stride_Y;
1196 params->stride_UV = put_image_rec->stride_UV;
1197 params->offset_Y = put_image_rec->offset_Y;
1198 params->offset_U = put_image_rec->offset_U;
1199 params->offset_V = put_image_rec->offset_V;
1200
1201 /* Check scaling after src size to prevent a divide-by-zero. */
1202 ret = check_overlay_scaling(params);
1203 if (ret != 0)
1204 goto out_unlock;
1205
1206 ret = intel_overlay_do_put_image(overlay, new_bo, params);
1207 if (ret != 0)
1208 goto out_unlock;
1209
1210 mutex_unlock(&dev->struct_mutex);
Daniel Vettera0e99e62012-12-02 01:05:46 +01001211 drm_modeset_unlock_all(dev);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001212
1213 kfree(params);
1214
1215 return 0;
1216
1217out_unlock:
1218 mutex_unlock(&dev->struct_mutex);
Daniel Vettera0e99e62012-12-02 01:05:46 +01001219 drm_modeset_unlock_all(dev);
Dave Gordon13f17b22016-07-21 18:39:38 +01001220 i915_gem_object_put_unlocked(new_bo);
Dan Carpenter915a4282010-03-06 14:05:39 +03001221out_free:
Daniel Vetter02e792f2009-09-15 22:57:34 +02001222 kfree(params);
1223
1224 return ret;
1225}
1226
1227static void update_reg_attrs(struct intel_overlay *overlay,
Ben Widawsky75020bc2012-04-16 14:07:43 -07001228 struct overlay_registers __iomem *regs)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001229{
Ben Widawsky75020bc2012-04-16 14:07:43 -07001230 iowrite32((overlay->contrast << 18) | (overlay->brightness & 0xff),
1231 &regs->OCLRC0);
1232 iowrite32(overlay->saturation, &regs->OCLRC1);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001233}
1234
1235static bool check_gamma_bounds(u32 gamma1, u32 gamma2)
1236{
1237 int i;
1238
1239 if (gamma1 & 0xff000000 || gamma2 & 0xff000000)
1240 return false;
1241
1242 for (i = 0; i < 3; i++) {
Chris Wilson722506f2010-08-12 09:28:50 +01001243 if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
Daniel Vetter02e792f2009-09-15 22:57:34 +02001244 return false;
1245 }
1246
1247 return true;
1248}
1249
1250static bool check_gamma5_errata(u32 gamma5)
1251{
1252 int i;
1253
1254 for (i = 0; i < 3; i++) {
1255 if (((gamma5 >> i*8) & 0xff) == 0x80)
1256 return false;
1257 }
1258
1259 return true;
1260}
1261
1262static int check_gamma(struct drm_intel_overlay_attrs *attrs)
1263{
Chris Wilson722506f2010-08-12 09:28:50 +01001264 if (!check_gamma_bounds(0, attrs->gamma0) ||
1265 !check_gamma_bounds(attrs->gamma0, attrs->gamma1) ||
1266 !check_gamma_bounds(attrs->gamma1, attrs->gamma2) ||
1267 !check_gamma_bounds(attrs->gamma2, attrs->gamma3) ||
1268 !check_gamma_bounds(attrs->gamma3, attrs->gamma4) ||
1269 !check_gamma_bounds(attrs->gamma4, attrs->gamma5) ||
1270 !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
Daniel Vetter02e792f2009-09-15 22:57:34 +02001271 return -EINVAL;
Chris Wilson722506f2010-08-12 09:28:50 +01001272
Daniel Vetter02e792f2009-09-15 22:57:34 +02001273 if (!check_gamma5_errata(attrs->gamma5))
1274 return -EINVAL;
Chris Wilson722506f2010-08-12 09:28:50 +01001275
Daniel Vetter02e792f2009-09-15 22:57:34 +02001276 return 0;
1277}
1278
Chris Wilson1ee8da62016-05-12 12:43:23 +01001279int intel_overlay_attrs_ioctl(struct drm_device *dev, void *data,
1280 struct drm_file *file_priv)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001281{
1282 struct drm_intel_overlay_attrs *attrs = data;
Chris Wilsonfac5e232016-07-04 11:34:36 +01001283 struct drm_i915_private *dev_priv = to_i915(dev);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001284 struct intel_overlay *overlay;
Ben Widawsky75020bc2012-04-16 14:07:43 -07001285 struct overlay_registers __iomem *regs;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001286 int ret;
1287
Daniel Vetter02e792f2009-09-15 22:57:34 +02001288 overlay = dev_priv->overlay;
1289 if (!overlay) {
1290 DRM_DEBUG("userspace bug: no overlay\n");
1291 return -ENODEV;
1292 }
1293
Daniel Vettera0e99e62012-12-02 01:05:46 +01001294 drm_modeset_lock_all(dev);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001295 mutex_lock(&dev->struct_mutex);
1296
Chris Wilson60fc3322010-08-12 10:44:45 +01001297 ret = -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001298 if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) {
Chris Wilson60fc3322010-08-12 10:44:45 +01001299 attrs->color_key = overlay->color_key;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001300 attrs->brightness = overlay->brightness;
Chris Wilson60fc3322010-08-12 10:44:45 +01001301 attrs->contrast = overlay->contrast;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001302 attrs->saturation = overlay->saturation;
1303
Chris Wilson1ee8da62016-05-12 12:43:23 +01001304 if (!IS_GEN2(dev_priv)) {
Daniel Vetter02e792f2009-09-15 22:57:34 +02001305 attrs->gamma0 = I915_READ(OGAMC0);
1306 attrs->gamma1 = I915_READ(OGAMC1);
1307 attrs->gamma2 = I915_READ(OGAMC2);
1308 attrs->gamma3 = I915_READ(OGAMC3);
1309 attrs->gamma4 = I915_READ(OGAMC4);
1310 attrs->gamma5 = I915_READ(OGAMC5);
1311 }
Daniel Vetter02e792f2009-09-15 22:57:34 +02001312 } else {
Chris Wilson60fc3322010-08-12 10:44:45 +01001313 if (attrs->brightness < -128 || attrs->brightness > 127)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001314 goto out_unlock;
Chris Wilson60fc3322010-08-12 10:44:45 +01001315 if (attrs->contrast > 255)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001316 goto out_unlock;
Chris Wilson60fc3322010-08-12 10:44:45 +01001317 if (attrs->saturation > 1023)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001318 goto out_unlock;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001319
Chris Wilson60fc3322010-08-12 10:44:45 +01001320 overlay->color_key = attrs->color_key;
1321 overlay->brightness = attrs->brightness;
1322 overlay->contrast = attrs->contrast;
1323 overlay->saturation = attrs->saturation;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001324
Chris Wilson8d74f652010-08-12 10:35:26 +01001325 regs = intel_overlay_map_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001326 if (!regs) {
1327 ret = -ENOMEM;
1328 goto out_unlock;
1329 }
1330
1331 update_reg_attrs(overlay, regs);
1332
Chris Wilson9bb2ff72010-08-12 12:02:11 +01001333 intel_overlay_unmap_regs(overlay, regs);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001334
1335 if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) {
Chris Wilson1ee8da62016-05-12 12:43:23 +01001336 if (IS_GEN2(dev_priv))
Daniel Vetter02e792f2009-09-15 22:57:34 +02001337 goto out_unlock;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001338
1339 if (overlay->active) {
1340 ret = -EBUSY;
1341 goto out_unlock;
1342 }
1343
1344 ret = check_gamma(attrs);
Chris Wilson60fc3322010-08-12 10:44:45 +01001345 if (ret)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001346 goto out_unlock;
1347
1348 I915_WRITE(OGAMC0, attrs->gamma0);
1349 I915_WRITE(OGAMC1, attrs->gamma1);
1350 I915_WRITE(OGAMC2, attrs->gamma2);
1351 I915_WRITE(OGAMC3, attrs->gamma3);
1352 I915_WRITE(OGAMC4, attrs->gamma4);
1353 I915_WRITE(OGAMC5, attrs->gamma5);
1354 }
Daniel Vetter02e792f2009-09-15 22:57:34 +02001355 }
Chris Wilsonea9da4e2015-04-02 10:35:08 +01001356 overlay->color_key_enabled = (attrs->flags & I915_OVERLAY_DISABLE_DEST_COLORKEY) == 0;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001357
Chris Wilson60fc3322010-08-12 10:44:45 +01001358 ret = 0;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001359out_unlock:
1360 mutex_unlock(&dev->struct_mutex);
Daniel Vettera0e99e62012-12-02 01:05:46 +01001361 drm_modeset_unlock_all(dev);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001362
1363 return ret;
1364}
1365
Chris Wilson1ee8da62016-05-12 12:43:23 +01001366void intel_setup_overlay(struct drm_i915_private *dev_priv)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001367{
Daniel Vetter02e792f2009-09-15 22:57:34 +02001368 struct intel_overlay *overlay;
Chris Wilson05394f32010-11-08 19:18:58 +00001369 struct drm_i915_gem_object *reg_bo;
Ben Widawsky75020bc2012-04-16 14:07:43 -07001370 struct overlay_registers __iomem *regs;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001371 int ret;
1372
Chris Wilson1ee8da62016-05-12 12:43:23 +01001373 if (!HAS_OVERLAY(dev_priv))
Daniel Vetter02e792f2009-09-15 22:57:34 +02001374 return;
1375
Daniel Vetterb14c5672013-09-19 12:18:32 +02001376 overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001377 if (!overlay)
1378 return;
Chris Wilson79d24272011-06-28 11:27:47 +01001379
Chris Wilson91c8a322016-07-05 10:40:23 +01001380 mutex_lock(&dev_priv->drm.struct_mutex);
Chris Wilson79d24272011-06-28 11:27:47 +01001381 if (WARN_ON(dev_priv->overlay))
1382 goto out_free;
1383
Chris Wilson1ee8da62016-05-12 12:43:23 +01001384 overlay->i915 = dev_priv;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001385
Daniel Vetterf63a4842013-07-23 19:24:38 +02001386 reg_bo = NULL;
Chris Wilson1ee8da62016-05-12 12:43:23 +01001387 if (!OVERLAY_NEEDS_PHYSICAL(dev_priv))
Chris Wilson91c8a322016-07-05 10:40:23 +01001388 reg_bo = i915_gem_object_create_stolen(&dev_priv->drm,
1389 PAGE_SIZE);
Chris Wilson80405132012-11-15 11:32:29 +00001390 if (reg_bo == NULL)
Chris Wilson91c8a322016-07-05 10:40:23 +01001391 reg_bo = i915_gem_object_create(&dev_priv->drm, PAGE_SIZE);
Chris Wilsonfe3db792016-04-25 13:32:13 +01001392 if (IS_ERR(reg_bo))
Daniel Vetter02e792f2009-09-15 22:57:34 +02001393 goto out_free;
Chris Wilson05394f32010-11-08 19:18:58 +00001394 overlay->reg_bo = reg_bo;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001395
Chris Wilson1ee8da62016-05-12 12:43:23 +01001396 if (OVERLAY_NEEDS_PHYSICAL(dev_priv)) {
Chris Wilson00731152014-05-21 12:42:56 +01001397 ret = i915_gem_object_attach_phys(reg_bo, PAGE_SIZE);
Akshay Joshi0206e352011-08-16 15:34:10 -04001398 if (ret) {
1399 DRM_ERROR("failed to attach phys overlay regs\n");
1400 goto out_free_bo;
1401 }
Chris Wilson00731152014-05-21 12:42:56 +01001402 overlay->flip_addr = reg_bo->phys_handle->busaddr;
Chris Wilson315781482010-08-12 09:42:51 +01001403 } else {
Chris Wilsonde895082016-08-04 16:32:34 +01001404 ret = i915_gem_object_ggtt_pin(reg_bo, NULL,
1405 0, PAGE_SIZE, PIN_MAPPABLE);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001406 if (ret) {
Akshay Joshi0206e352011-08-16 15:34:10 -04001407 DRM_ERROR("failed to pin overlay register bo\n");
1408 goto out_free_bo;
1409 }
Ben Widawskyf343c5f2013-07-05 14:41:04 -07001410 overlay->flip_addr = i915_gem_obj_ggtt_offset(reg_bo);
Chris Wilson0ddc1282010-08-12 09:35:00 +01001411
1412 ret = i915_gem_object_set_to_gtt_domain(reg_bo, true);
1413 if (ret) {
Akshay Joshi0206e352011-08-16 15:34:10 -04001414 DRM_ERROR("failed to move overlay register bo into the GTT\n");
1415 goto out_unpin_bo;
1416 }
Daniel Vetter02e792f2009-09-15 22:57:34 +02001417 }
1418
1419 /* init all values */
1420 overlay->color_key = 0x0101fe;
Chris Wilsonea9da4e2015-04-02 10:35:08 +01001421 overlay->color_key_enabled = true;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001422 overlay->brightness = -19;
1423 overlay->contrast = 75;
1424 overlay->saturation = 146;
1425
Chris Wilson8d74f652010-08-12 10:35:26 +01001426 regs = intel_overlay_map_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001427 if (!regs)
Chris Wilson79d24272011-06-28 11:27:47 +01001428 goto out_unpin_bo;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001429
Ben Widawsky75020bc2012-04-16 14:07:43 -07001430 memset_io(regs, 0, sizeof(struct overlay_registers));
Daniel Vetter02e792f2009-09-15 22:57:34 +02001431 update_polyphase_filter(regs);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001432 update_reg_attrs(overlay, regs);
1433
Chris Wilson9bb2ff72010-08-12 12:02:11 +01001434 intel_overlay_unmap_regs(overlay, regs);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001435
1436 dev_priv->overlay = overlay;
Chris Wilson91c8a322016-07-05 10:40:23 +01001437 mutex_unlock(&dev_priv->drm.struct_mutex);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001438 DRM_INFO("initialized overlay support\n");
1439 return;
1440
Chris Wilson0ddc1282010-08-12 09:35:00 +01001441out_unpin_bo:
Chris Wilson1ee8da62016-05-12 12:43:23 +01001442 if (!OVERLAY_NEEDS_PHYSICAL(dev_priv))
Ben Widawskyd7f46fc2013-12-06 14:10:55 -08001443 i915_gem_object_ggtt_unpin(reg_bo);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001444out_free_bo:
Chris Wilsonf8c417c2016-07-20 13:31:53 +01001445 i915_gem_object_put(reg_bo);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001446out_free:
Chris Wilson91c8a322016-07-05 10:40:23 +01001447 mutex_unlock(&dev_priv->drm.struct_mutex);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001448 kfree(overlay);
1449 return;
1450}
1451
Chris Wilson1ee8da62016-05-12 12:43:23 +01001452void intel_cleanup_overlay(struct drm_i915_private *dev_priv)
Daniel Vetter02e792f2009-09-15 22:57:34 +02001453{
Chris Wilson62cf4e62010-08-12 10:50:36 +01001454 if (!dev_priv->overlay)
1455 return;
Daniel Vetter02e792f2009-09-15 22:57:34 +02001456
Chris Wilson62cf4e62010-08-12 10:50:36 +01001457 /* The bo's should be free'd by the generic code already.
1458 * Furthermore modesetting teardown happens beforehand so the
1459 * hardware should be off already */
Ville Syrjälä77589f52015-03-31 10:37:22 +03001460 WARN_ON(dev_priv->overlay->active);
Chris Wilson62cf4e62010-08-12 10:50:36 +01001461
Chris Wilson34911fd2016-07-20 13:31:54 +01001462 i915_gem_object_put_unlocked(dev_priv->overlay->reg_bo);
Chris Wilson62cf4e62010-08-12 10:50:36 +01001463 kfree(dev_priv->overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +02001464}
Chris Wilson6ef3d422010-08-04 20:26:07 +01001465
1466struct intel_overlay_error_state {
1467 struct overlay_registers regs;
1468 unsigned long base;
1469 u32 dovsta;
1470 u32 isr;
1471};
1472
Ben Widawsky75020bc2012-04-16 14:07:43 -07001473static struct overlay_registers __iomem *
Linus Torvaldsc48c43e2010-10-26 18:57:59 -07001474intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
Chris Wilson3bd3c932010-08-19 08:19:30 +01001475{
Chris Wilson1ee8da62016-05-12 12:43:23 +01001476 struct drm_i915_private *dev_priv = overlay->i915;
Ben Widawsky75020bc2012-04-16 14:07:43 -07001477 struct overlay_registers __iomem *regs;
Chris Wilson3bd3c932010-08-19 08:19:30 +01001478
Chris Wilson1ee8da62016-05-12 12:43:23 +01001479 if (OVERLAY_NEEDS_PHYSICAL(dev_priv))
Ben Widawsky75020bc2012-04-16 14:07:43 -07001480 /* Cast to make sparse happy, but it's wc memory anyway, so
1481 * equivalent to the wc io mapping on X86. */
1482 regs = (struct overlay_registers __iomem *)
Chris Wilson00731152014-05-21 12:42:56 +01001483 overlay->reg_bo->phys_handle->vaddr;
Chris Wilson3bd3c932010-08-19 08:19:30 +01001484 else
Chris Wilson1ee8da62016-05-12 12:43:23 +01001485 regs = io_mapping_map_atomic_wc(dev_priv->ggtt.mappable,
Chris Wilsonda6ca032016-04-28 09:56:36 +01001486 overlay->flip_addr);
Chris Wilson3bd3c932010-08-19 08:19:30 +01001487
1488 return regs;
1489}
1490
1491static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay,
Ben Widawsky75020bc2012-04-16 14:07:43 -07001492 struct overlay_registers __iomem *regs)
Chris Wilson3bd3c932010-08-19 08:19:30 +01001493{
Chris Wilson1ee8da62016-05-12 12:43:23 +01001494 if (!OVERLAY_NEEDS_PHYSICAL(overlay->i915))
Linus Torvaldsc48c43e2010-10-26 18:57:59 -07001495 io_mapping_unmap_atomic(regs);
Chris Wilson3bd3c932010-08-19 08:19:30 +01001496}
1497
Chris Wilson6ef3d422010-08-04 20:26:07 +01001498struct intel_overlay_error_state *
Chris Wilsonc0336662016-05-06 15:40:21 +01001499intel_overlay_capture_error_state(struct drm_i915_private *dev_priv)
Chris Wilson6ef3d422010-08-04 20:26:07 +01001500{
Chris Wilson6ef3d422010-08-04 20:26:07 +01001501 struct intel_overlay *overlay = dev_priv->overlay;
1502 struct intel_overlay_error_state *error;
1503 struct overlay_registers __iomem *regs;
1504
1505 if (!overlay || !overlay->active)
1506 return NULL;
1507
1508 error = kmalloc(sizeof(*error), GFP_ATOMIC);
1509 if (error == NULL)
1510 return NULL;
1511
1512 error->dovsta = I915_READ(DOVSTA);
1513 error->isr = I915_READ(ISR);
Chris Wilsonda6ca032016-04-28 09:56:36 +01001514 error->base = overlay->flip_addr;
Chris Wilson6ef3d422010-08-04 20:26:07 +01001515
1516 regs = intel_overlay_map_regs_atomic(overlay);
1517 if (!regs)
1518 goto err;
1519
1520 memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers));
Linus Torvaldsc48c43e2010-10-26 18:57:59 -07001521 intel_overlay_unmap_regs_atomic(overlay, regs);
Chris Wilson6ef3d422010-08-04 20:26:07 +01001522
1523 return error;
1524
1525err:
1526 kfree(error);
1527 return NULL;
1528}
1529
1530void
Mika Kuoppalaedc3d882013-05-23 13:55:35 +03001531intel_overlay_print_error_state(struct drm_i915_error_state_buf *m,
1532 struct intel_overlay_error_state *error)
Chris Wilson6ef3d422010-08-04 20:26:07 +01001533{
Mika Kuoppalaedc3d882013-05-23 13:55:35 +03001534 i915_error_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",
1535 error->dovsta, error->isr);
1536 i915_error_printf(m, " Register file at 0x%08lx:\n",
1537 error->base);
Chris Wilson6ef3d422010-08-04 20:26:07 +01001538
Mika Kuoppalaedc3d882013-05-23 13:55:35 +03001539#define P(x) i915_error_printf(m, " " #x ": 0x%08x\n", error->regs.x)
Chris Wilson6ef3d422010-08-04 20:26:07 +01001540 P(OBUF_0Y);
1541 P(OBUF_1Y);
1542 P(OBUF_0U);
1543 P(OBUF_0V);
1544 P(OBUF_1U);
1545 P(OBUF_1V);
1546 P(OSTRIDE);
1547 P(YRGB_VPH);
1548 P(UV_VPH);
1549 P(HORZ_PH);
1550 P(INIT_PHS);
1551 P(DWINPOS);
1552 P(DWINSZ);
1553 P(SWIDTH);
1554 P(SWIDTHSW);
1555 P(SHEIGHT);
1556 P(YRGBSCALE);
1557 P(UVSCALE);
1558 P(OCLRC0);
1559 P(OCLRC1);
1560 P(DCLRKV);
1561 P(DCLRKM);
1562 P(SCLRKVH);
1563 P(SCLRKVL);
1564 P(SCLRKEN);
1565 P(OCONFIG);
1566 P(OCMD);
1567 P(OSTART_0Y);
1568 P(OSTART_1Y);
1569 P(OSTART_0U);
1570 P(OSTART_0V);
1571 P(OSTART_1U);
1572 P(OSTART_1V);
1573 P(OTILEOFF_0Y);
1574 P(OTILEOFF_1Y);
1575 P(OTILEOFF_0U);
1576 P(OTILEOFF_0V);
1577 P(OTILEOFF_1U);
1578 P(OTILEOFF_1V);
1579 P(FASTHSCALE);
1580 P(UVSCALEV);
1581#undef P
1582}