blob: 90f3ab424e01ab6cd3f7dcf02869b189951b0f15 [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"
Chris Wilson5d723d72016-08-04 16:32:35 +010033#include "intel_frontbuffer.h"
Daniel Vetter02e792f2009-09-15 22:57:34 +020034
35/* Limits for overlay size. According to intel doc, the real limits are:
36 * Y width: 4095, UV width (planar): 2047, Y height: 2047,
37 * UV width (planar): * 1023. But the xorg thinks 2048 for height and width. Use
38 * the mininum of both. */
39#define IMAGE_MAX_WIDTH 2048
40#define IMAGE_MAX_HEIGHT 2046 /* 2 * 1023 */
41/* on 830 and 845 these large limits result in the card hanging */
42#define IMAGE_MAX_WIDTH_LEGACY 1024
43#define IMAGE_MAX_HEIGHT_LEGACY 1088
44
45/* overlay register definitions */
46/* OCMD register */
47#define OCMD_TILED_SURFACE (0x1<<19)
48#define OCMD_MIRROR_MASK (0x3<<17)
49#define OCMD_MIRROR_MODE (0x3<<17)
50#define OCMD_MIRROR_HORIZONTAL (0x1<<17)
51#define OCMD_MIRROR_VERTICAL (0x2<<17)
52#define OCMD_MIRROR_BOTH (0x3<<17)
53#define OCMD_BYTEORDER_MASK (0x3<<14) /* zero for YUYV or FOURCC YUY2 */
54#define OCMD_UV_SWAP (0x1<<14) /* YVYU */
55#define OCMD_Y_SWAP (0x2<<14) /* UYVY or FOURCC UYVY */
56#define OCMD_Y_AND_UV_SWAP (0x3<<14) /* VYUY */
57#define OCMD_SOURCE_FORMAT_MASK (0xf<<10)
58#define OCMD_RGB_888 (0x1<<10) /* not in i965 Intel docs */
59#define OCMD_RGB_555 (0x2<<10) /* not in i965 Intel docs */
60#define OCMD_RGB_565 (0x3<<10) /* not in i965 Intel docs */
61#define OCMD_YUV_422_PACKED (0x8<<10)
62#define OCMD_YUV_411_PACKED (0x9<<10) /* not in i965 Intel docs */
63#define OCMD_YUV_420_PLANAR (0xc<<10)
64#define OCMD_YUV_422_PLANAR (0xd<<10)
65#define OCMD_YUV_410_PLANAR (0xe<<10) /* also 411 */
66#define OCMD_TVSYNCFLIP_PARITY (0x1<<9)
67#define OCMD_TVSYNCFLIP_ENABLE (0x1<<7)
Chris Wilsond7961362010-07-13 13:52:17 +010068#define OCMD_BUF_TYPE_MASK (0x1<<5)
Daniel Vetter02e792f2009-09-15 22:57:34 +020069#define OCMD_BUF_TYPE_FRAME (0x0<<5)
70#define OCMD_BUF_TYPE_FIELD (0x1<<5)
71#define OCMD_TEST_MODE (0x1<<4)
72#define OCMD_BUFFER_SELECT (0x3<<2)
73#define OCMD_BUFFER0 (0x0<<2)
74#define OCMD_BUFFER1 (0x1<<2)
75#define OCMD_FIELD_SELECT (0x1<<2)
76#define OCMD_FIELD0 (0x0<<1)
77#define OCMD_FIELD1 (0x1<<1)
78#define OCMD_ENABLE (0x1<<0)
79
80/* OCONFIG register */
81#define OCONF_PIPE_MASK (0x1<<18)
82#define OCONF_PIPE_A (0x0<<18)
83#define OCONF_PIPE_B (0x1<<18)
84#define OCONF_GAMMA2_ENABLE (0x1<<16)
85#define OCONF_CSC_MODE_BT601 (0x0<<5)
86#define OCONF_CSC_MODE_BT709 (0x1<<5)
87#define OCONF_CSC_BYPASS (0x1<<4)
88#define OCONF_CC_OUT_8BIT (0x1<<3)
89#define OCONF_TEST_MODE (0x1<<2)
90#define OCONF_THREE_LINE_BUFFER (0x1<<0)
91#define OCONF_TWO_LINE_BUFFER (0x0<<0)
92
93/* DCLRKM (dst-key) register */
94#define DST_KEY_ENABLE (0x1<<31)
95#define CLK_RGB24_MASK 0x0
96#define CLK_RGB16_MASK 0x070307
97#define CLK_RGB15_MASK 0x070707
98#define CLK_RGB8I_MASK 0xffffff
99
100#define RGB16_TO_COLORKEY(c) \
101 (((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3))
102#define RGB15_TO_COLORKEY(c) \
103 (((c & 0x7c00) << 9) | ((c & 0x03E0) << 6) | ((c & 0x001F) << 3))
104
105/* overlay flip addr flag */
106#define OFC_UPDATE 0x1
107
108/* polyphase filter coefficients */
109#define N_HORIZ_Y_TAPS 5
110#define N_VERT_Y_TAPS 3
111#define N_HORIZ_UV_TAPS 3
112#define N_VERT_UV_TAPS 3
113#define N_PHASES 17
114#define MAX_TAPS 5
115
116/* memory bufferd overlay registers */
117struct overlay_registers {
Akshay Joshi0206e352011-08-16 15:34:10 -0400118 u32 OBUF_0Y;
119 u32 OBUF_1Y;
120 u32 OBUF_0U;
121 u32 OBUF_0V;
122 u32 OBUF_1U;
123 u32 OBUF_1V;
124 u32 OSTRIDE;
125 u32 YRGB_VPH;
126 u32 UV_VPH;
127 u32 HORZ_PH;
128 u32 INIT_PHS;
129 u32 DWINPOS;
130 u32 DWINSZ;
131 u32 SWIDTH;
132 u32 SWIDTHSW;
133 u32 SHEIGHT;
134 u32 YRGBSCALE;
135 u32 UVSCALE;
136 u32 OCLRC0;
137 u32 OCLRC1;
138 u32 DCLRKV;
139 u32 DCLRKM;
140 u32 SCLRKVH;
141 u32 SCLRKVL;
142 u32 SCLRKEN;
143 u32 OCONFIG;
144 u32 OCMD;
145 u32 RESERVED1; /* 0x6C */
146 u32 OSTART_0Y;
147 u32 OSTART_1Y;
148 u32 OSTART_0U;
149 u32 OSTART_0V;
150 u32 OSTART_1U;
151 u32 OSTART_1V;
152 u32 OTILEOFF_0Y;
153 u32 OTILEOFF_1Y;
154 u32 OTILEOFF_0U;
155 u32 OTILEOFF_0V;
156 u32 OTILEOFF_1U;
157 u32 OTILEOFF_1V;
158 u32 FASTHSCALE; /* 0xA0 */
159 u32 UVSCALEV; /* 0xA4 */
160 u32 RESERVEDC[(0x200 - 0xA8) / 4]; /* 0xA8 - 0x1FC */
161 u16 Y_VCOEFS[N_VERT_Y_TAPS * N_PHASES]; /* 0x200 */
162 u16 RESERVEDD[0x100 / 2 - N_VERT_Y_TAPS * N_PHASES];
163 u16 Y_HCOEFS[N_HORIZ_Y_TAPS * N_PHASES]; /* 0x300 */
164 u16 RESERVEDE[0x200 / 2 - N_HORIZ_Y_TAPS * N_PHASES];
165 u16 UV_VCOEFS[N_VERT_UV_TAPS * N_PHASES]; /* 0x500 */
166 u16 RESERVEDF[0x100 / 2 - N_VERT_UV_TAPS * N_PHASES];
167 u16 UV_HCOEFS[N_HORIZ_UV_TAPS * N_PHASES]; /* 0x600 */
168 u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES];
Daniel Vetter02e792f2009-09-15 22:57:34 +0200169};
170
Chris Wilson23f09ce2010-08-12 13:53:37 +0100171struct intel_overlay {
Chris Wilson1ee8da62016-05-12 12:43:23 +0100172 struct drm_i915_private *i915;
Chris Wilson23f09ce2010-08-12 13:53:37 +0100173 struct intel_crtc *crtc;
174 struct drm_i915_gem_object *vid_bo;
175 struct drm_i915_gem_object *old_vid_bo;
Ville Syrjälä209c2a52015-03-31 10:37:23 +0300176 bool active;
177 bool pfit_active;
Chris Wilson23f09ce2010-08-12 13:53:37 +0100178 u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
Chris Wilsonea9da4e2015-04-02 10:35:08 +0100179 u32 color_key:24;
180 u32 color_key_enabled:1;
Chris Wilson23f09ce2010-08-12 13:53:37 +0100181 u32 brightness, contrast, saturation;
182 u32 old_xscale, old_yscale;
183 /* register access */
184 u32 flip_addr;
185 struct drm_i915_gem_object *reg_bo;
186 /* flip handling */
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100187 struct i915_gem_active last_flip;
Chris Wilson23f09ce2010-08-12 13:53:37 +0100188};
Daniel Vetter02e792f2009-09-15 22:57:34 +0200189
Ben Widawsky75020bc2012-04-16 14:07:43 -0700190static struct overlay_registers __iomem *
Chris Wilson8d74f652010-08-12 10:35:26 +0100191intel_overlay_map_regs(struct intel_overlay *overlay)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200192{
Chris Wilson1ee8da62016-05-12 12:43:23 +0100193 struct drm_i915_private *dev_priv = overlay->i915;
Ben Widawsky75020bc2012-04-16 14:07:43 -0700194 struct overlay_registers __iomem *regs;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200195
Chris Wilson1ee8da62016-05-12 12:43:23 +0100196 if (OVERLAY_NEEDS_PHYSICAL(dev_priv))
Chris Wilson00731152014-05-21 12:42:56 +0100197 regs = (struct overlay_registers __iomem *)overlay->reg_bo->phys_handle->vaddr;
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100198 else
Chris Wilson1ee8da62016-05-12 12:43:23 +0100199 regs = io_mapping_map_wc(dev_priv->ggtt.mappable,
Chris Wilsond8dab002016-04-28 09:56:37 +0100200 overlay->flip_addr,
201 PAGE_SIZE);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200202
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100203 return regs;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200204}
205
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100206static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
Ben Widawsky75020bc2012-04-16 14:07:43 -0700207 struct overlay_registers __iomem *regs)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200208{
Chris Wilson1ee8da62016-05-12 12:43:23 +0100209 if (!OVERLAY_NEEDS_PHYSICAL(overlay->i915))
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100210 io_mapping_unmap(regs);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200211}
Daniel Vetter02e792f2009-09-15 22:57:34 +0200212
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100213static void intel_overlay_submit_request(struct intel_overlay *overlay,
214 struct drm_i915_gem_request *req,
215 i915_gem_retire_fn retire)
216{
217 GEM_BUG_ON(i915_gem_active_peek(&overlay->last_flip,
218 &overlay->i915->drm.struct_mutex));
219 overlay->last_flip.retire = retire;
220 i915_gem_active_set(&overlay->last_flip, req);
221 i915_add_request(req);
222}
223
Chris Wilsonb6c028e2010-08-12 11:55:08 +0100224static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
John Harrisondad540c2015-05-29 17:43:47 +0100225 struct drm_i915_gem_request *req,
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100226 i915_gem_retire_fn retire)
Chris Wilsonb6c028e2010-08-12 11:55:08 +0100227{
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100228 intel_overlay_submit_request(overlay, req, retire);
229 return i915_gem_active_retire(&overlay->last_flip,
230 &overlay->i915->drm.struct_mutex);
Chris Wilsonb6c028e2010-08-12 11:55:08 +0100231}
232
Chris Wilson8e637172016-08-02 22:50:26 +0100233static struct drm_i915_gem_request *alloc_request(struct intel_overlay *overlay)
234{
235 struct drm_i915_private *dev_priv = overlay->i915;
236 struct intel_engine_cs *engine = &dev_priv->engine[RCS];
237
238 return i915_gem_request_alloc(engine, dev_priv->kernel_context);
239}
240
Daniel Vetter02e792f2009-09-15 22:57:34 +0200241/* overlay needs to be disable in OCMD reg */
242static int intel_overlay_on(struct intel_overlay *overlay)
243{
Chris Wilson1ee8da62016-05-12 12:43:23 +0100244 struct drm_i915_private *dev_priv = overlay->i915;
John Harrisondad540c2015-05-29 17:43:47 +0100245 struct drm_i915_gem_request *req;
Chris Wilson7e37f882016-08-02 22:50:21 +0100246 struct intel_ring *ring;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200247 int ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200248
Ville Syrjälä77589f52015-03-31 10:37:22 +0300249 WARN_ON(overlay->active);
Chris Wilson1ee8da62016-05-12 12:43:23 +0100250 WARN_ON(IS_I830(dev_priv) && !(dev_priv->quirks & QUIRK_PIPEA_FORCE));
Chris Wilson106dada2010-07-16 17:13:01 +0100251
Chris Wilson8e637172016-08-02 22:50:26 +0100252 req = alloc_request(overlay);
Dave Gordon26827082016-01-19 19:02:53 +0000253 if (IS_ERR(req))
254 return PTR_ERR(req);
Chris Wilsone1f99ce2010-10-27 12:45:26 +0100255
John Harrison5fb9de12015-05-29 17:44:07 +0100256 ret = intel_ring_begin(req, 4);
John Harrisondad540c2015-05-29 17:43:47 +0100257 if (ret) {
Chris Wilsonaa9b7812016-04-13 17:35:15 +0100258 i915_add_request_no_flush(req);
John Harrisondad540c2015-05-29 17:43:47 +0100259 return ret;
260 }
261
Ville Syrjälä1c7c4302015-03-31 10:37:24 +0300262 overlay->active = true;
263
Chris Wilson1dae2df2016-08-02 22:50:19 +0100264 ring = req->ring;
Chris Wilsonb5321f32016-08-02 22:50:18 +0100265 intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_ON);
266 intel_ring_emit(ring, overlay->flip_addr | OFC_UPDATE);
267 intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
268 intel_ring_emit(ring, MI_NOOP);
269 intel_ring_advance(ring);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200270
John Harrisondad540c2015-05-29 17:43:47 +0100271 return intel_overlay_do_wait_request(overlay, req, NULL);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200272}
273
274/* overlay needs to be enabled in OCMD reg */
Chris Wilson8dc5d142010-08-12 12:36:12 +0100275static int intel_overlay_continue(struct intel_overlay *overlay,
276 bool load_polyphase_filter)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200277{
Chris Wilson1ee8da62016-05-12 12:43:23 +0100278 struct drm_i915_private *dev_priv = overlay->i915;
John Harrisondad540c2015-05-29 17:43:47 +0100279 struct drm_i915_gem_request *req;
Chris Wilson7e37f882016-08-02 22:50:21 +0100280 struct intel_ring *ring;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200281 u32 flip_addr = overlay->flip_addr;
282 u32 tmp;
Chris Wilsone1f99ce2010-10-27 12:45:26 +0100283 int ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200284
Ville Syrjälä77589f52015-03-31 10:37:22 +0300285 WARN_ON(!overlay->active);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200286
287 if (load_polyphase_filter)
288 flip_addr |= OFC_UPDATE;
289
290 /* check for underruns */
291 tmp = I915_READ(DOVSTA);
292 if (tmp & (1 << 17))
293 DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
294
Chris Wilson8e637172016-08-02 22:50:26 +0100295 req = alloc_request(overlay);
Dave Gordon26827082016-01-19 19:02:53 +0000296 if (IS_ERR(req))
297 return PTR_ERR(req);
Chris Wilsonacb868d2012-09-26 13:47:30 +0100298
John Harrison5fb9de12015-05-29 17:44:07 +0100299 ret = intel_ring_begin(req, 2);
John Harrisondad540c2015-05-29 17:43:47 +0100300 if (ret) {
Chris Wilsonaa9b7812016-04-13 17:35:15 +0100301 i915_add_request_no_flush(req);
John Harrisondad540c2015-05-29 17:43:47 +0100302 return ret;
303 }
304
Chris Wilson1dae2df2016-08-02 22:50:19 +0100305 ring = req->ring;
Chris Wilsonb5321f32016-08-02 22:50:18 +0100306 intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
307 intel_ring_emit(ring, flip_addr);
308 intel_ring_advance(ring);
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200309
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100310 intel_overlay_submit_request(overlay, req, NULL);
John Harrisonbf7dc5b2015-05-29 17:43:24 +0100311
312 return 0;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200313}
314
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100315static void intel_overlay_release_old_vid_tail(struct i915_gem_active *active,
316 struct drm_i915_gem_request *req)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200317{
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100318 struct intel_overlay *overlay =
319 container_of(active, typeof(*overlay), last_flip);
Chris Wilson05394f32010-11-08 19:18:58 +0000320 struct drm_i915_gem_object *obj = overlay->old_vid_bo;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200321
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100322 i915_gem_track_fb(obj, NULL,
323 INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe));
324
Ben Widawskyd7f46fc2013-12-06 14:10:55 -0800325 i915_gem_object_ggtt_unpin(obj);
Chris Wilsonf8c417c2016-07-20 13:31:53 +0100326 i915_gem_object_put(obj);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200327
Chris Wilsonb303cf92010-08-12 14:03:48 +0100328 overlay->old_vid_bo = NULL;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200329}
330
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100331static void intel_overlay_off_tail(struct i915_gem_active *active,
332 struct drm_i915_gem_request *req)
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200333{
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100334 struct intel_overlay *overlay =
335 container_of(active, typeof(*overlay), last_flip);
Chris Wilson05394f32010-11-08 19:18:58 +0000336 struct drm_i915_gem_object *obj = overlay->vid_bo;
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200337
338 /* never have the overlay hw on without showing a frame */
Ville Syrjälä77589f52015-03-31 10:37:22 +0300339 if (WARN_ON(!obj))
340 return;
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200341
Ben Widawskyd7f46fc2013-12-06 14:10:55 -0800342 i915_gem_object_ggtt_unpin(obj);
Chris Wilsonf8c417c2016-07-20 13:31:53 +0100343 i915_gem_object_put(obj);
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200344 overlay->vid_bo = NULL;
345
346 overlay->crtc->overlay = NULL;
347 overlay->crtc = NULL;
Ville Syrjälä209c2a52015-03-31 10:37:23 +0300348 overlay->active = false;
Daniel Vetter12ca45f2037-04-25 10:08:26 +0200349}
350
Daniel Vetter02e792f2009-09-15 22:57:34 +0200351/* overlay needs to be disabled in OCMD reg */
Chris Wilsonce453d82011-02-21 14:43:56 +0000352static int intel_overlay_off(struct intel_overlay *overlay)
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200353{
Chris Wilson1ee8da62016-05-12 12:43:23 +0100354 struct drm_i915_private *dev_priv = overlay->i915;
John Harrisondad540c2015-05-29 17:43:47 +0100355 struct drm_i915_gem_request *req;
Chris Wilson7e37f882016-08-02 22:50:21 +0100356 struct intel_ring *ring;
Chris Wilson8dc5d142010-08-12 12:36:12 +0100357 u32 flip_addr = overlay->flip_addr;
Chris Wilsone1f99ce2010-10-27 12:45:26 +0100358 int ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200359
Ville Syrjälä77589f52015-03-31 10:37:22 +0300360 WARN_ON(!overlay->active);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200361
362 /* According to intel docs the overlay hw may hang (when switching
363 * off) without loading the filter coeffs. It is however unclear whether
364 * this applies to the disabling of the overlay or to the switching off
365 * of the hw. Do it in both cases */
366 flip_addr |= OFC_UPDATE;
367
Chris Wilson8e637172016-08-02 22:50:26 +0100368 req = alloc_request(overlay);
Dave Gordon26827082016-01-19 19:02:53 +0000369 if (IS_ERR(req))
370 return PTR_ERR(req);
Chris Wilsonacb868d2012-09-26 13:47:30 +0100371
John Harrison5fb9de12015-05-29 17:44:07 +0100372 ret = intel_ring_begin(req, 6);
John Harrisondad540c2015-05-29 17:43:47 +0100373 if (ret) {
Chris Wilsonaa9b7812016-04-13 17:35:15 +0100374 i915_add_request_no_flush(req);
John Harrisondad540c2015-05-29 17:43:47 +0100375 return ret;
376 }
377
Chris Wilson1dae2df2016-08-02 22:50:19 +0100378 ring = req->ring;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200379 /* wait for overlay to go idle */
Chris Wilsonb5321f32016-08-02 22:50:18 +0100380 intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
381 intel_ring_emit(ring, flip_addr);
382 intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
Chris Wilson722506f2010-08-12 09:28:50 +0100383 /* turn overlay off */
Chris Wilson1ee8da62016-05-12 12:43:23 +0100384 if (IS_I830(dev_priv)) {
Daniel Vettera9193982012-10-22 12:55:55 +0200385 /* Workaround: Don't disable the overlay fully, since otherwise
386 * it dies on the next OVERLAY_ON cmd. */
Chris Wilsonb5321f32016-08-02 22:50:18 +0100387 intel_ring_emit(ring, MI_NOOP);
388 intel_ring_emit(ring, MI_NOOP);
389 intel_ring_emit(ring, MI_NOOP);
Daniel Vettera9193982012-10-22 12:55:55 +0200390 } else {
Chris Wilsonb5321f32016-08-02 22:50:18 +0100391 intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
392 intel_ring_emit(ring, flip_addr);
393 intel_ring_emit(ring,
Tvrtko Ursuline2f80392016-03-16 11:00:36 +0000394 MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
Daniel Vettera9193982012-10-22 12:55:55 +0200395 }
Chris Wilsonb5321f32016-08-02 22:50:18 +0100396 intel_ring_advance(ring);
Chris Wilson722506f2010-08-12 09:28:50 +0100397
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100398 return intel_overlay_do_wait_request(overlay, req,
399 intel_overlay_off_tail);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200400}
401
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200402/* recover from an interruption due to a signal
403 * We have to be careful not to repeat work forever an make forward progess. */
Chris Wilsonce453d82011-02-21 14:43:56 +0000404static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200405{
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100406 return i915_gem_active_retire(&overlay->last_flip,
407 &overlay->i915->drm.struct_mutex);
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200408}
409
Daniel Vetter5a5a0c62009-09-15 22:57:36 +0200410/* Wait for pending overlay flip and release old frame.
411 * Needs to be called before the overlay register are changed
Chris Wilson8d74f652010-08-12 10:35:26 +0100412 * via intel_overlay_(un)map_regs
413 */
Daniel Vetter02e792f2009-09-15 22:57:34 +0200414static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
415{
Chris Wilson1ee8da62016-05-12 12:43:23 +0100416 struct drm_i915_private *dev_priv = overlay->i915;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200417 int ret;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200418
Chris Wilson91c8a322016-07-05 10:40:23 +0100419 lockdep_assert_held(&dev_priv->drm.struct_mutex);
Ville Syrjälä1362b772014-11-26 17:07:29 +0200420
Chris Wilson5cd68c92010-08-12 12:21:54 +0100421 /* Only wait if there is actually an old frame to release to
422 * guarantee forward progress.
423 */
Daniel Vetter03f77ea2009-09-15 22:57:37 +0200424 if (!overlay->old_vid_bo)
425 return 0;
426
Chris Wilson5cd68c92010-08-12 12:21:54 +0100427 if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) {
428 /* synchronous slowpath */
John Harrisondad540c2015-05-29 17:43:47 +0100429 struct drm_i915_gem_request *req;
Chris Wilson7e37f882016-08-02 22:50:21 +0100430 struct intel_ring *ring;
John Harrisondad540c2015-05-29 17:43:47 +0100431
Chris Wilson8e637172016-08-02 22:50:26 +0100432 req = alloc_request(overlay);
Dave Gordon26827082016-01-19 19:02:53 +0000433 if (IS_ERR(req))
434 return PTR_ERR(req);
Chris Wilsone1f99ce2010-10-27 12:45:26 +0100435
John Harrison5fb9de12015-05-29 17:44:07 +0100436 ret = intel_ring_begin(req, 2);
John Harrisondad540c2015-05-29 17:43:47 +0100437 if (ret) {
Chris Wilsonaa9b7812016-04-13 17:35:15 +0100438 i915_add_request_no_flush(req);
John Harrisondad540c2015-05-29 17:43:47 +0100439 return ret;
440 }
441
Chris Wilson1dae2df2016-08-02 22:50:19 +0100442 ring = req->ring;
Chris Wilsonb5321f32016-08-02 22:50:18 +0100443 intel_ring_emit(ring,
Tvrtko Ursuline2f80392016-03-16 11:00:36 +0000444 MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
Chris Wilsonb5321f32016-08-02 22:50:18 +0100445 intel_ring_emit(ring, MI_NOOP);
446 intel_ring_advance(ring);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200447
John Harrisondad540c2015-05-29 17:43:47 +0100448 ret = intel_overlay_do_wait_request(overlay, req,
Chris Wilsonb303cf92010-08-12 14:03:48 +0100449 intel_overlay_release_old_vid_tail);
Chris Wilson5cd68c92010-08-12 12:21:54 +0100450 if (ret)
451 return ret;
Chris Wilson0d9bdd82016-08-04 07:52:37 +0100452 } else
453 intel_overlay_release_old_vid_tail(&overlay->last_flip, NULL);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200454
455 return 0;
456}
457
Ville Syrjälä1362b772014-11-26 17:07:29 +0200458void intel_overlay_reset(struct drm_i915_private *dev_priv)
459{
460 struct intel_overlay *overlay = dev_priv->overlay;
461
462 if (!overlay)
463 return;
464
465 intel_overlay_release_old_vid(overlay);
466
Ville Syrjälä1362b772014-11-26 17:07:29 +0200467 overlay->old_xscale = 0;
468 overlay->old_yscale = 0;
469 overlay->crtc = NULL;
470 overlay->active = false;
471}
472
Daniel Vetter02e792f2009-09-15 22:57:34 +0200473struct put_image_params {
474 int format;
475 short dst_x;
476 short dst_y;
477 short dst_w;
478 short dst_h;
479 short src_w;
480 short src_scan_h;
481 short src_scan_w;
482 short src_h;
483 short stride_Y;
484 short stride_UV;
485 int offset_Y;
486 int offset_U;
487 int offset_V;
488};
489
490static int packed_depth_bytes(u32 format)
491{
492 switch (format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100493 case I915_OVERLAY_YUV422:
494 return 4;
495 case I915_OVERLAY_YUV411:
496 /* return 6; not implemented */
497 default:
498 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200499 }
500}
501
502static int packed_width_bytes(u32 format, short width)
503{
504 switch (format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100505 case I915_OVERLAY_YUV422:
506 return width << 1;
507 default:
508 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200509 }
510}
511
512static int uv_hsubsampling(u32 format)
513{
514 switch (format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100515 case I915_OVERLAY_YUV422:
516 case I915_OVERLAY_YUV420:
517 return 2;
518 case I915_OVERLAY_YUV411:
519 case I915_OVERLAY_YUV410:
520 return 4;
521 default:
522 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200523 }
524}
525
526static int uv_vsubsampling(u32 format)
527{
528 switch (format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100529 case I915_OVERLAY_YUV420:
530 case I915_OVERLAY_YUV410:
531 return 2;
532 case I915_OVERLAY_YUV422:
533 case I915_OVERLAY_YUV411:
534 return 1;
535 default:
536 return -EINVAL;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200537 }
538}
539
Chris Wilson1ee8da62016-05-12 12:43:23 +0100540static u32 calc_swidthsw(struct drm_i915_private *dev_priv, u32 offset, u32 width)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200541{
542 u32 mask, shift, ret;
Chris Wilson1ee8da62016-05-12 12:43:23 +0100543 if (IS_GEN2(dev_priv)) {
Daniel Vetter02e792f2009-09-15 22:57:34 +0200544 mask = 0x1f;
545 shift = 5;
Chris Wilsona6c45cf2010-09-17 00:32:17 +0100546 } else {
547 mask = 0x3f;
548 shift = 6;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200549 }
550 ret = ((offset + width + mask) >> shift) - (offset >> shift);
Chris Wilson1ee8da62016-05-12 12:43:23 +0100551 if (!IS_GEN2(dev_priv))
Daniel Vetter02e792f2009-09-15 22:57:34 +0200552 ret <<= 1;
Akshay Joshi0206e352011-08-16 15:34:10 -0400553 ret -= 1;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200554 return ret << 2;
555}
556
557static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = {
558 0x3000, 0xb4a0, 0x1930, 0x1920, 0xb4a0,
559 0x3000, 0xb500, 0x19d0, 0x1880, 0xb440,
560 0x3000, 0xb540, 0x1a88, 0x2f80, 0xb3e0,
561 0x3000, 0xb580, 0x1b30, 0x2e20, 0xb380,
562 0x3000, 0xb5c0, 0x1bd8, 0x2cc0, 0xb320,
563 0x3020, 0xb5e0, 0x1c60, 0x2b80, 0xb2c0,
564 0x3020, 0xb5e0, 0x1cf8, 0x2a20, 0xb260,
565 0x3020, 0xb5e0, 0x1d80, 0x28e0, 0xb200,
566 0x3020, 0xb5c0, 0x1e08, 0x3f40, 0xb1c0,
567 0x3020, 0xb580, 0x1e78, 0x3ce0, 0xb160,
568 0x3040, 0xb520, 0x1ed8, 0x3aa0, 0xb120,
569 0x3040, 0xb4a0, 0x1f30, 0x3880, 0xb0e0,
570 0x3040, 0xb400, 0x1f78, 0x3680, 0xb0a0,
571 0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060,
572 0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040,
573 0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020,
Chris Wilson722506f2010-08-12 09:28:50 +0100574 0xb000, 0x3000, 0x0800, 0x3000, 0xb000
575};
576
Daniel Vetter02e792f2009-09-15 22:57:34 +0200577static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
578 0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60,
579 0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40,
580 0xb040, 0x1b20, 0x29e0, 0xb060, 0x1bd8, 0x2880,
581 0xb080, 0x1c88, 0x3e60, 0xb0a0, 0x1d28, 0x3c00,
582 0xb0c0, 0x1db8, 0x39e0, 0xb0e0, 0x1e40, 0x37e0,
583 0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0,
584 0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240,
585 0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0,
Chris Wilson722506f2010-08-12 09:28:50 +0100586 0x3000, 0x0800, 0x3000
587};
Daniel Vetter02e792f2009-09-15 22:57:34 +0200588
Ben Widawsky75020bc2012-04-16 14:07:43 -0700589static void update_polyphase_filter(struct overlay_registers __iomem *regs)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200590{
Ben Widawsky75020bc2012-04-16 14:07:43 -0700591 memcpy_toio(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs));
592 memcpy_toio(regs->UV_HCOEFS, uv_static_hcoeffs,
593 sizeof(uv_static_hcoeffs));
Daniel Vetter02e792f2009-09-15 22:57:34 +0200594}
595
596static bool update_scaling_factors(struct intel_overlay *overlay,
Ben Widawsky75020bc2012-04-16 14:07:43 -0700597 struct overlay_registers __iomem *regs,
Daniel Vetter02e792f2009-09-15 22:57:34 +0200598 struct put_image_params *params)
599{
600 /* fixed point with a 12 bit shift */
601 u32 xscale, yscale, xscale_UV, yscale_UV;
602#define FP_SHIFT 12
603#define FRACT_MASK 0xfff
604 bool scale_changed = false;
605 int uv_hscale = uv_hsubsampling(params->format);
606 int uv_vscale = uv_vsubsampling(params->format);
607
608 if (params->dst_w > 1)
609 xscale = ((params->src_scan_w - 1) << FP_SHIFT)
610 /(params->dst_w);
611 else
612 xscale = 1 << FP_SHIFT;
613
614 if (params->dst_h > 1)
615 yscale = ((params->src_scan_h - 1) << FP_SHIFT)
616 /(params->dst_h);
617 else
618 yscale = 1 << FP_SHIFT;
619
620 /*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
Chris Wilson722506f2010-08-12 09:28:50 +0100621 xscale_UV = xscale/uv_hscale;
622 yscale_UV = yscale/uv_vscale;
623 /* make the Y scale to UV scale ratio an exact multiply */
624 xscale = xscale_UV * uv_hscale;
625 yscale = yscale_UV * uv_vscale;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200626 /*} else {
Chris Wilson722506f2010-08-12 09:28:50 +0100627 xscale_UV = 0;
628 yscale_UV = 0;
629 }*/
Daniel Vetter02e792f2009-09-15 22:57:34 +0200630
631 if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)
632 scale_changed = true;
633 overlay->old_xscale = xscale;
634 overlay->old_yscale = yscale;
635
Ben Widawsky75020bc2012-04-16 14:07:43 -0700636 iowrite32(((yscale & FRACT_MASK) << 20) |
637 ((xscale >> FP_SHIFT) << 16) |
638 ((xscale & FRACT_MASK) << 3),
639 &regs->YRGBSCALE);
Chris Wilson722506f2010-08-12 09:28:50 +0100640
Ben Widawsky75020bc2012-04-16 14:07:43 -0700641 iowrite32(((yscale_UV & FRACT_MASK) << 20) |
642 ((xscale_UV >> FP_SHIFT) << 16) |
643 ((xscale_UV & FRACT_MASK) << 3),
644 &regs->UVSCALE);
Chris Wilson722506f2010-08-12 09:28:50 +0100645
Ben Widawsky75020bc2012-04-16 14:07:43 -0700646 iowrite32((((yscale >> FP_SHIFT) << 16) |
647 ((yscale_UV >> FP_SHIFT) << 0)),
648 &regs->UVSCALEV);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200649
650 if (scale_changed)
651 update_polyphase_filter(regs);
652
653 return scale_changed;
654}
655
656static void update_colorkey(struct intel_overlay *overlay,
Ben Widawsky75020bc2012-04-16 14:07:43 -0700657 struct overlay_registers __iomem *regs)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200658{
659 u32 key = overlay->color_key;
Chris Wilsonea9da4e2015-04-02 10:35:08 +0100660 u32 flags;
661
662 flags = 0;
663 if (overlay->color_key_enabled)
664 flags |= DST_KEY_ENABLE;
Chris Wilson6ba3ddd2010-08-12 09:30:58 +0100665
Matt Roperf4510a22014-04-01 15:22:40 -0700666 switch (overlay->crtc->base.primary->fb->bits_per_pixel) {
Chris Wilson722506f2010-08-12 09:28:50 +0100667 case 8:
Chris Wilsonea9da4e2015-04-02 10:35:08 +0100668 key = 0;
669 flags |= CLK_RGB8I_MASK;
Chris Wilson6ba3ddd2010-08-12 09:30:58 +0100670 break;
671
Chris Wilson722506f2010-08-12 09:28:50 +0100672 case 16:
Matt Roperf4510a22014-04-01 15:22:40 -0700673 if (overlay->crtc->base.primary->fb->depth == 15) {
Chris Wilsonea9da4e2015-04-02 10:35:08 +0100674 key = RGB15_TO_COLORKEY(key);
675 flags |= CLK_RGB15_MASK;
Chris Wilson722506f2010-08-12 09:28:50 +0100676 } else {
Chris Wilsonea9da4e2015-04-02 10:35:08 +0100677 key = RGB16_TO_COLORKEY(key);
678 flags |= CLK_RGB16_MASK;
Chris Wilson722506f2010-08-12 09:28:50 +0100679 }
Chris Wilson6ba3ddd2010-08-12 09:30:58 +0100680 break;
681
Chris Wilson722506f2010-08-12 09:28:50 +0100682 case 24:
683 case 32:
Chris Wilsonea9da4e2015-04-02 10:35:08 +0100684 flags |= CLK_RGB24_MASK;
Chris Wilson6ba3ddd2010-08-12 09:30:58 +0100685 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200686 }
Chris Wilsonea9da4e2015-04-02 10:35:08 +0100687
688 iowrite32(key, &regs->DCLRKV);
689 iowrite32(flags, &regs->DCLRKM);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200690}
691
692static u32 overlay_cmd_reg(struct put_image_params *params)
693{
694 u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0;
695
696 if (params->format & I915_OVERLAY_YUV_PLANAR) {
697 switch (params->format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100698 case I915_OVERLAY_YUV422:
699 cmd |= OCMD_YUV_422_PLANAR;
700 break;
701 case I915_OVERLAY_YUV420:
702 cmd |= OCMD_YUV_420_PLANAR;
703 break;
704 case I915_OVERLAY_YUV411:
705 case I915_OVERLAY_YUV410:
706 cmd |= OCMD_YUV_410_PLANAR;
707 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200708 }
709 } else { /* YUV packed */
710 switch (params->format & I915_OVERLAY_DEPTH_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100711 case I915_OVERLAY_YUV422:
712 cmd |= OCMD_YUV_422_PACKED;
713 break;
714 case I915_OVERLAY_YUV411:
715 cmd |= OCMD_YUV_411_PACKED;
716 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200717 }
718
719 switch (params->format & I915_OVERLAY_SWAP_MASK) {
Chris Wilson722506f2010-08-12 09:28:50 +0100720 case I915_OVERLAY_NO_SWAP:
721 break;
722 case I915_OVERLAY_UV_SWAP:
723 cmd |= OCMD_UV_SWAP;
724 break;
725 case I915_OVERLAY_Y_SWAP:
726 cmd |= OCMD_Y_SWAP;
727 break;
728 case I915_OVERLAY_Y_AND_UV_SWAP:
729 cmd |= OCMD_Y_AND_UV_SWAP;
730 break;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200731 }
732 }
733
734 return cmd;
735}
736
Chris Wilson5fe82c52010-08-12 12:38:21 +0100737static int intel_overlay_do_put_image(struct intel_overlay *overlay,
Chris Wilson05394f32010-11-08 19:18:58 +0000738 struct drm_i915_gem_object *new_bo,
Chris Wilson5fe82c52010-08-12 12:38:21 +0100739 struct put_image_params *params)
Daniel Vetter02e792f2009-09-15 22:57:34 +0200740{
741 int ret, tmp_width;
Ben Widawsky75020bc2012-04-16 14:07:43 -0700742 struct overlay_registers __iomem *regs;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200743 bool scale_changed = false;
Chris Wilson1ee8da62016-05-12 12:43:23 +0100744 struct drm_i915_private *dev_priv = overlay->i915;
Ben Widawsky75020bc2012-04-16 14:07:43 -0700745 u32 swidth, swidthsw, sheight, ostride;
Daniel Vettera071fa02014-06-18 23:28:09 +0200746 enum pipe pipe = overlay->crtc->pipe;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200747
Chris Wilson91c8a322016-07-05 10:40:23 +0100748 lockdep_assert_held(&dev_priv->drm.struct_mutex);
749 WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex));
Daniel Vetter02e792f2009-09-15 22:57:34 +0200750
Daniel Vetter02e792f2009-09-15 22:57:34 +0200751 ret = intel_overlay_release_old_vid(overlay);
752 if (ret != 0)
753 return ret;
754
Maarten Lankhorst7580d772015-08-18 13:40:06 +0200755 ret = i915_gem_object_pin_to_display_plane(new_bo, 0,
Tvrtko Ursuline6617332015-03-23 11:10:33 +0000756 &i915_ggtt_view_normal);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200757 if (ret != 0)
758 return ret;
759
Chris Wilsond9e86c02010-11-10 16:40:20 +0000760 ret = i915_gem_object_put_fence(new_bo);
761 if (ret)
762 goto out_unpin;
763
Daniel Vetter02e792f2009-09-15 22:57:34 +0200764 if (!overlay->active) {
Ben Widawsky75020bc2012-04-16 14:07:43 -0700765 u32 oconfig;
Chris Wilson8d74f652010-08-12 10:35:26 +0100766 regs = intel_overlay_map_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200767 if (!regs) {
768 ret = -ENOMEM;
769 goto out_unpin;
770 }
Ben Widawsky75020bc2012-04-16 14:07:43 -0700771 oconfig = OCONF_CC_OUT_8BIT;
Chris Wilson1ee8da62016-05-12 12:43:23 +0100772 if (IS_GEN4(dev_priv))
Ben Widawsky75020bc2012-04-16 14:07:43 -0700773 oconfig |= OCONF_CSC_MODE_BT709;
Daniel Vettera071fa02014-06-18 23:28:09 +0200774 oconfig |= pipe == 0 ?
Daniel Vetter02e792f2009-09-15 22:57:34 +0200775 OCONF_PIPE_A : OCONF_PIPE_B;
Ben Widawsky75020bc2012-04-16 14:07:43 -0700776 iowrite32(oconfig, &regs->OCONFIG);
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100777 intel_overlay_unmap_regs(overlay, regs);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200778
779 ret = intel_overlay_on(overlay);
780 if (ret != 0)
781 goto out_unpin;
782 }
783
Chris Wilson8d74f652010-08-12 10:35:26 +0100784 regs = intel_overlay_map_regs(overlay);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200785 if (!regs) {
786 ret = -ENOMEM;
787 goto out_unpin;
788 }
789
Ben Widawsky75020bc2012-04-16 14:07:43 -0700790 iowrite32((params->dst_y << 16) | params->dst_x, &regs->DWINPOS);
791 iowrite32((params->dst_h << 16) | params->dst_w, &regs->DWINSZ);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200792
793 if (params->format & I915_OVERLAY_YUV_PACKED)
794 tmp_width = packed_width_bytes(params->format, params->src_w);
795 else
796 tmp_width = params->src_w;
797
Ben Widawsky75020bc2012-04-16 14:07:43 -0700798 swidth = params->src_w;
Chris Wilson1ee8da62016-05-12 12:43:23 +0100799 swidthsw = calc_swidthsw(dev_priv, params->offset_Y, tmp_width);
Ben Widawsky75020bc2012-04-16 14:07:43 -0700800 sheight = params->src_h;
Ben Widawskyf343c5f2013-07-05 14:41:04 -0700801 iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_Y, &regs->OBUF_0Y);
Ben Widawsky75020bc2012-04-16 14:07:43 -0700802 ostride = params->stride_Y;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200803
804 if (params->format & I915_OVERLAY_YUV_PLANAR) {
805 int uv_hscale = uv_hsubsampling(params->format);
806 int uv_vscale = uv_vsubsampling(params->format);
807 u32 tmp_U, tmp_V;
Ben Widawsky75020bc2012-04-16 14:07:43 -0700808 swidth |= (params->src_w/uv_hscale) << 16;
Chris Wilson1ee8da62016-05-12 12:43:23 +0100809 tmp_U = calc_swidthsw(dev_priv, params->offset_U,
Chris Wilson722506f2010-08-12 09:28:50 +0100810 params->src_w/uv_hscale);
Chris Wilson1ee8da62016-05-12 12:43:23 +0100811 tmp_V = calc_swidthsw(dev_priv, params->offset_V,
Chris Wilson722506f2010-08-12 09:28:50 +0100812 params->src_w/uv_hscale);
Ben Widawsky75020bc2012-04-16 14:07:43 -0700813 swidthsw |= max_t(u32, tmp_U, tmp_V) << 16;
814 sheight |= (params->src_h/uv_vscale) << 16;
Ben Widawskyf343c5f2013-07-05 14:41:04 -0700815 iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_U, &regs->OBUF_0U);
816 iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_V, &regs->OBUF_0V);
Ben Widawsky75020bc2012-04-16 14:07:43 -0700817 ostride |= params->stride_UV << 16;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200818 }
819
Ben Widawsky75020bc2012-04-16 14:07:43 -0700820 iowrite32(swidth, &regs->SWIDTH);
821 iowrite32(swidthsw, &regs->SWIDTHSW);
822 iowrite32(sheight, &regs->SHEIGHT);
823 iowrite32(ostride, &regs->OSTRIDE);
824
Daniel Vetter02e792f2009-09-15 22:57:34 +0200825 scale_changed = update_scaling_factors(overlay, regs, params);
826
827 update_colorkey(overlay, regs);
828
Ben Widawsky75020bc2012-04-16 14:07:43 -0700829 iowrite32(overlay_cmd_reg(params), &regs->OCMD);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200830
Chris Wilson9bb2ff72010-08-12 12:02:11 +0100831 intel_overlay_unmap_regs(overlay, regs);
Daniel Vetter02e792f2009-09-15 22:57:34 +0200832
Chris Wilson8dc5d142010-08-12 12:36:12 +0100833 ret = intel_overlay_continue(overlay, scale_changed);
834 if (ret)
835 goto out_unpin;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200836
Daniel Vettera071fa02014-06-18 23:28:09 +0200837 i915_gem_track_fb(overlay->vid_bo, new_bo,
838 INTEL_FRONTBUFFER_OVERLAY(pipe));
839
Daniel Vetter02e792f2009-09-15 22:57:34 +0200840 overlay->old_vid_bo = overlay->vid_bo;
Chris Wilson05394f32010-11-08 19:18:58 +0000841 overlay->vid_bo = new_bo;
Daniel Vetter02e792f2009-09-15 22:57:34 +0200842
Chris Wilson5748b6a2016-08-04 16:32:38 +0100843 intel_frontbuffer_flip(dev_priv, 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 Wilson3e510a82016-08-05 10:14:23 +01001132 if (i915_gem_object_is_tiled(new_bo)) {
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}