xref: /dflybsd-src/sys/dev/drm/i915/intel_overlay.c (revision aee94f86171368465eaa15d649743f13cea3363a)
1e3adcf8fSFrançois Tigeot /*
2e3adcf8fSFrançois Tigeot  * Copyright © 2009
3e3adcf8fSFrançois Tigeot  *
4e3adcf8fSFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
5e3adcf8fSFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
6e3adcf8fSFrançois Tigeot  * to deal in the Software without restriction, including without limitation
7e3adcf8fSFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8e3adcf8fSFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
9e3adcf8fSFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
10e3adcf8fSFrançois Tigeot  *
11e3adcf8fSFrançois Tigeot  * The above copyright notice and this permission notice (including the next
12e3adcf8fSFrançois Tigeot  * paragraph) shall be included in all copies or substantial portions of the
13e3adcf8fSFrançois Tigeot  * Software.
14e3adcf8fSFrançois Tigeot  *
15e3adcf8fSFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16e3adcf8fSFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17e3adcf8fSFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18e3adcf8fSFrançois Tigeot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19e3adcf8fSFrançois Tigeot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20e3adcf8fSFrançois Tigeot  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21e3adcf8fSFrançois Tigeot  * SOFTWARE.
22e3adcf8fSFrançois Tigeot  *
23e3adcf8fSFrançois Tigeot  * Authors:
24e3adcf8fSFrançois Tigeot  *    Daniel Vetter <daniel@ffwll.ch>
25e3adcf8fSFrançois Tigeot  *
26e3adcf8fSFrançois Tigeot  * Derived from Xorg ddx, xf86-video-intel, src/i830_video.c
27e3adcf8fSFrançois Tigeot  */
2818e26a6dSFrançois Tigeot #include <drm/drmP.h>
295c6c6f23SFrançois Tigeot #include <drm/i915_drm.h>
30e3adcf8fSFrançois Tigeot #include "i915_drv.h"
31e3adcf8fSFrançois Tigeot #include "i915_reg.h"
32e3adcf8fSFrançois Tigeot #include "intel_drv.h"
33e3adcf8fSFrançois Tigeot 
34e3adcf8fSFrançois Tigeot /* Limits for overlay size. According to intel doc, the real limits are:
35e3adcf8fSFrançois Tigeot  * Y width: 4095, UV width (planar): 2047, Y height: 2047,
36e3adcf8fSFrançois Tigeot  * UV width (planar): * 1023. But the xorg thinks 2048 for height and width. Use
37e3adcf8fSFrançois Tigeot  * the mininum of both.  */
38e3adcf8fSFrançois Tigeot #define IMAGE_MAX_WIDTH		2048
39e3adcf8fSFrançois Tigeot #define IMAGE_MAX_HEIGHT	2046 /* 2 * 1023 */
40e3adcf8fSFrançois Tigeot /* on 830 and 845 these large limits result in the card hanging */
41e3adcf8fSFrançois Tigeot #define IMAGE_MAX_WIDTH_LEGACY	1024
42e3adcf8fSFrançois Tigeot #define IMAGE_MAX_HEIGHT_LEGACY	1088
43e3adcf8fSFrançois Tigeot 
44e3adcf8fSFrançois Tigeot /* overlay register definitions */
45e3adcf8fSFrançois Tigeot /* OCMD register */
46e3adcf8fSFrançois Tigeot #define OCMD_TILED_SURFACE	(0x1<<19)
47e3adcf8fSFrançois Tigeot #define OCMD_MIRROR_MASK	(0x3<<17)
48e3adcf8fSFrançois Tigeot #define OCMD_MIRROR_MODE	(0x3<<17)
49e3adcf8fSFrançois Tigeot #define OCMD_MIRROR_HORIZONTAL	(0x1<<17)
50e3adcf8fSFrançois Tigeot #define OCMD_MIRROR_VERTICAL	(0x2<<17)
51e3adcf8fSFrançois Tigeot #define OCMD_MIRROR_BOTH	(0x3<<17)
52e3adcf8fSFrançois Tigeot #define OCMD_BYTEORDER_MASK	(0x3<<14) /* zero for YUYV or FOURCC YUY2 */
53e3adcf8fSFrançois Tigeot #define OCMD_UV_SWAP		(0x1<<14) /* YVYU */
54e3adcf8fSFrançois Tigeot #define OCMD_Y_SWAP		(0x2<<14) /* UYVY or FOURCC UYVY */
55e3adcf8fSFrançois Tigeot #define OCMD_Y_AND_UV_SWAP	(0x3<<14) /* VYUY */
56e3adcf8fSFrançois Tigeot #define OCMD_SOURCE_FORMAT_MASK (0xf<<10)
57e3adcf8fSFrançois Tigeot #define OCMD_RGB_888		(0x1<<10) /* not in i965 Intel docs */
58e3adcf8fSFrançois Tigeot #define OCMD_RGB_555		(0x2<<10) /* not in i965 Intel docs */
59e3adcf8fSFrançois Tigeot #define OCMD_RGB_565		(0x3<<10) /* not in i965 Intel docs */
60e3adcf8fSFrançois Tigeot #define OCMD_YUV_422_PACKED	(0x8<<10)
61e3adcf8fSFrançois Tigeot #define OCMD_YUV_411_PACKED	(0x9<<10) /* not in i965 Intel docs */
62e3adcf8fSFrançois Tigeot #define OCMD_YUV_420_PLANAR	(0xc<<10)
63e3adcf8fSFrançois Tigeot #define OCMD_YUV_422_PLANAR	(0xd<<10)
64e3adcf8fSFrançois Tigeot #define OCMD_YUV_410_PLANAR	(0xe<<10) /* also 411 */
65e3adcf8fSFrançois Tigeot #define OCMD_TVSYNCFLIP_PARITY	(0x1<<9)
66e3adcf8fSFrançois Tigeot #define OCMD_TVSYNCFLIP_ENABLE	(0x1<<7)
67e3adcf8fSFrançois Tigeot #define OCMD_BUF_TYPE_MASK	(0x1<<5)
68e3adcf8fSFrançois Tigeot #define OCMD_BUF_TYPE_FRAME	(0x0<<5)
69e3adcf8fSFrançois Tigeot #define OCMD_BUF_TYPE_FIELD	(0x1<<5)
70e3adcf8fSFrançois Tigeot #define OCMD_TEST_MODE		(0x1<<4)
71e3adcf8fSFrançois Tigeot #define OCMD_BUFFER_SELECT	(0x3<<2)
72e3adcf8fSFrançois Tigeot #define OCMD_BUFFER0		(0x0<<2)
73e3adcf8fSFrançois Tigeot #define OCMD_BUFFER1		(0x1<<2)
74e3adcf8fSFrançois Tigeot #define OCMD_FIELD_SELECT	(0x1<<2)
75e3adcf8fSFrançois Tigeot #define OCMD_FIELD0		(0x0<<1)
76e3adcf8fSFrançois Tigeot #define OCMD_FIELD1		(0x1<<1)
77e3adcf8fSFrançois Tigeot #define OCMD_ENABLE		(0x1<<0)
78e3adcf8fSFrançois Tigeot 
79e3adcf8fSFrançois Tigeot /* OCONFIG register */
80e3adcf8fSFrançois Tigeot #define OCONF_PIPE_MASK		(0x1<<18)
81e3adcf8fSFrançois Tigeot #define OCONF_PIPE_A		(0x0<<18)
82e3adcf8fSFrançois Tigeot #define OCONF_PIPE_B		(0x1<<18)
83e3adcf8fSFrançois Tigeot #define OCONF_GAMMA2_ENABLE	(0x1<<16)
84e3adcf8fSFrançois Tigeot #define OCONF_CSC_MODE_BT601	(0x0<<5)
85e3adcf8fSFrançois Tigeot #define OCONF_CSC_MODE_BT709	(0x1<<5)
86e3adcf8fSFrançois Tigeot #define OCONF_CSC_BYPASS	(0x1<<4)
87e3adcf8fSFrançois Tigeot #define OCONF_CC_OUT_8BIT	(0x1<<3)
88e3adcf8fSFrançois Tigeot #define OCONF_TEST_MODE		(0x1<<2)
89e3adcf8fSFrançois Tigeot #define OCONF_THREE_LINE_BUFFER	(0x1<<0)
90e3adcf8fSFrançois Tigeot #define OCONF_TWO_LINE_BUFFER	(0x0<<0)
91e3adcf8fSFrançois Tigeot 
92e3adcf8fSFrançois Tigeot /* DCLRKM (dst-key) register */
93e3adcf8fSFrançois Tigeot #define DST_KEY_ENABLE		(0x1<<31)
94e3adcf8fSFrançois Tigeot #define CLK_RGB24_MASK		0x0
95e3adcf8fSFrançois Tigeot #define CLK_RGB16_MASK		0x070307
96e3adcf8fSFrançois Tigeot #define CLK_RGB15_MASK		0x070707
97e3adcf8fSFrançois Tigeot #define CLK_RGB8I_MASK		0xffffff
98e3adcf8fSFrançois Tigeot 
99e3adcf8fSFrançois Tigeot #define RGB16_TO_COLORKEY(c) \
100e3adcf8fSFrançois Tigeot 	(((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3))
101e3adcf8fSFrançois Tigeot #define RGB15_TO_COLORKEY(c) \
102e3adcf8fSFrançois Tigeot 	(((c & 0x7c00) << 9) | ((c & 0x03E0) << 6) | ((c & 0x001F) << 3))
103e3adcf8fSFrançois Tigeot 
104e3adcf8fSFrançois Tigeot /* overlay flip addr flag */
105e3adcf8fSFrançois Tigeot #define OFC_UPDATE		0x1
106e3adcf8fSFrançois Tigeot 
107e3adcf8fSFrançois Tigeot /* polyphase filter coefficients */
108e3adcf8fSFrançois Tigeot #define N_HORIZ_Y_TAPS          5
109e3adcf8fSFrançois Tigeot #define N_VERT_Y_TAPS           3
110e3adcf8fSFrançois Tigeot #define N_HORIZ_UV_TAPS         3
111e3adcf8fSFrançois Tigeot #define N_VERT_UV_TAPS          3
112e3adcf8fSFrançois Tigeot #define N_PHASES                17
113e3adcf8fSFrançois Tigeot #define MAX_TAPS                5
114e3adcf8fSFrançois Tigeot 
115e3adcf8fSFrançois Tigeot /* memory bufferd overlay registers */
116e3adcf8fSFrançois Tigeot struct overlay_registers {
117e3adcf8fSFrançois Tigeot 	u32 OBUF_0Y;
118e3adcf8fSFrançois Tigeot 	u32 OBUF_1Y;
119e3adcf8fSFrançois Tigeot 	u32 OBUF_0U;
120e3adcf8fSFrançois Tigeot 	u32 OBUF_0V;
121e3adcf8fSFrançois Tigeot 	u32 OBUF_1U;
122e3adcf8fSFrançois Tigeot 	u32 OBUF_1V;
123e3adcf8fSFrançois Tigeot 	u32 OSTRIDE;
124e3adcf8fSFrançois Tigeot 	u32 YRGB_VPH;
125e3adcf8fSFrançois Tigeot 	u32 UV_VPH;
126e3adcf8fSFrançois Tigeot 	u32 HORZ_PH;
127e3adcf8fSFrançois Tigeot 	u32 INIT_PHS;
128e3adcf8fSFrançois Tigeot 	u32 DWINPOS;
129e3adcf8fSFrançois Tigeot 	u32 DWINSZ;
130e3adcf8fSFrançois Tigeot 	u32 SWIDTH;
131e3adcf8fSFrançois Tigeot 	u32 SWIDTHSW;
132e3adcf8fSFrançois Tigeot 	u32 SHEIGHT;
133e3adcf8fSFrançois Tigeot 	u32 YRGBSCALE;
134e3adcf8fSFrançois Tigeot 	u32 UVSCALE;
135e3adcf8fSFrançois Tigeot 	u32 OCLRC0;
136e3adcf8fSFrançois Tigeot 	u32 OCLRC1;
137e3adcf8fSFrançois Tigeot 	u32 DCLRKV;
138e3adcf8fSFrançois Tigeot 	u32 DCLRKM;
139e3adcf8fSFrançois Tigeot 	u32 SCLRKVH;
140e3adcf8fSFrançois Tigeot 	u32 SCLRKVL;
141e3adcf8fSFrançois Tigeot 	u32 SCLRKEN;
142e3adcf8fSFrançois Tigeot 	u32 OCONFIG;
143e3adcf8fSFrançois Tigeot 	u32 OCMD;
144e3adcf8fSFrançois Tigeot 	u32 RESERVED1; /* 0x6C */
145e3adcf8fSFrançois Tigeot 	u32 OSTART_0Y;
146e3adcf8fSFrançois Tigeot 	u32 OSTART_1Y;
147e3adcf8fSFrançois Tigeot 	u32 OSTART_0U;
148e3adcf8fSFrançois Tigeot 	u32 OSTART_0V;
149e3adcf8fSFrançois Tigeot 	u32 OSTART_1U;
150e3adcf8fSFrançois Tigeot 	u32 OSTART_1V;
151e3adcf8fSFrançois Tigeot 	u32 OTILEOFF_0Y;
152e3adcf8fSFrançois Tigeot 	u32 OTILEOFF_1Y;
153e3adcf8fSFrançois Tigeot 	u32 OTILEOFF_0U;
154e3adcf8fSFrançois Tigeot 	u32 OTILEOFF_0V;
155e3adcf8fSFrançois Tigeot 	u32 OTILEOFF_1U;
156e3adcf8fSFrançois Tigeot 	u32 OTILEOFF_1V;
157e3adcf8fSFrançois Tigeot 	u32 FASTHSCALE; /* 0xA0 */
158e3adcf8fSFrançois Tigeot 	u32 UVSCALEV; /* 0xA4 */
159e3adcf8fSFrançois Tigeot 	u32 RESERVEDC[(0x200 - 0xA8) / 4]; /* 0xA8 - 0x1FC */
160e3adcf8fSFrançois Tigeot 	u16 Y_VCOEFS[N_VERT_Y_TAPS * N_PHASES]; /* 0x200 */
161e3adcf8fSFrançois Tigeot 	u16 RESERVEDD[0x100 / 2 - N_VERT_Y_TAPS * N_PHASES];
162e3adcf8fSFrançois Tigeot 	u16 Y_HCOEFS[N_HORIZ_Y_TAPS * N_PHASES]; /* 0x300 */
163e3adcf8fSFrançois Tigeot 	u16 RESERVEDE[0x200 / 2 - N_HORIZ_Y_TAPS * N_PHASES];
164e3adcf8fSFrançois Tigeot 	u16 UV_VCOEFS[N_VERT_UV_TAPS * N_PHASES]; /* 0x500 */
165e3adcf8fSFrançois Tigeot 	u16 RESERVEDF[0x100 / 2 - N_VERT_UV_TAPS * N_PHASES];
166e3adcf8fSFrançois Tigeot 	u16 UV_HCOEFS[N_HORIZ_UV_TAPS * N_PHASES]; /* 0x600 */
167e3adcf8fSFrançois Tigeot 	u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES];
168e3adcf8fSFrançois Tigeot };
169e3adcf8fSFrançois Tigeot 
170e3adcf8fSFrançois Tigeot struct intel_overlay {
171e3adcf8fSFrançois Tigeot 	struct drm_device *dev;
172e3adcf8fSFrançois Tigeot 	struct intel_crtc *crtc;
173e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *vid_bo;
174e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *old_vid_bo;
17519c468b4SFrançois Tigeot 	bool active;
17619c468b4SFrançois Tigeot 	bool pfit_active;
177e3adcf8fSFrançois Tigeot 	u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
17819c468b4SFrançois Tigeot 	u32 color_key:24;
17919c468b4SFrançois Tigeot 	u32 color_key_enabled:1;
180e3adcf8fSFrançois Tigeot 	u32 brightness, contrast, saturation;
181e3adcf8fSFrançois Tigeot 	u32 old_xscale, old_yscale;
182e3adcf8fSFrançois Tigeot 	/* register access */
183e3adcf8fSFrançois Tigeot 	u32 flip_addr;
184e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *reg_bo;
185e3adcf8fSFrançois Tigeot 	/* flip handling */
1862c9916cdSFrançois Tigeot 	struct drm_i915_gem_request *last_flip_req;
187e3adcf8fSFrançois Tigeot 	void (*flip_tail)(struct intel_overlay *);
188e3adcf8fSFrançois Tigeot };
189e3adcf8fSFrançois Tigeot 
190e3440f96SFrançois Tigeot static struct overlay_registers __iomem *
191e3adcf8fSFrançois Tigeot intel_overlay_map_regs(struct intel_overlay *overlay)
192e3adcf8fSFrançois Tigeot {
193cb170299SFrançois Tigeot 	struct drm_i915_private *dev_priv = overlay->dev->dev_private;
194e3440f96SFrançois Tigeot 	struct overlay_registers __iomem *regs;
195e3adcf8fSFrançois Tigeot 
196e3440f96SFrançois Tigeot 	if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
197ba55f2f5SFrançois Tigeot 		regs = (struct overlay_registers __iomem *)overlay->reg_bo->phys_handle->vaddr;
198e3440f96SFrançois Tigeot 	else
199cb170299SFrançois Tigeot 		regs = io_mapping_map_wc(dev_priv->gtt.mappable,
200cb170299SFrançois Tigeot 					 i915_gem_obj_ggtt_offset(overlay->reg_bo));
201e3440f96SFrançois Tigeot 
202e3440f96SFrançois Tigeot 	return regs;
203e3adcf8fSFrançois Tigeot }
204e3adcf8fSFrançois Tigeot 
205e3adcf8fSFrançois Tigeot static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
206e3440f96SFrançois Tigeot 				     struct overlay_registers __iomem *regs)
207e3adcf8fSFrançois Tigeot {
208e3adcf8fSFrançois Tigeot 	if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
209e3adcf8fSFrançois Tigeot 		pmap_unmapdev((vm_offset_t)regs, PAGE_SIZE);
210e3adcf8fSFrançois Tigeot }
211e3adcf8fSFrançois Tigeot 
212e3adcf8fSFrançois Tigeot static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
213a05eeebfSFrançois Tigeot 					 struct drm_i915_gem_request *req,
214e3adcf8fSFrançois Tigeot 					 void (*tail)(struct intel_overlay *))
215e3adcf8fSFrançois Tigeot {
216e3adcf8fSFrançois Tigeot 	int ret;
217e3adcf8fSFrançois Tigeot 
21819c468b4SFrançois Tigeot 	WARN_ON(overlay->last_flip_req);
219a05eeebfSFrançois Tigeot 	i915_gem_request_assign(&overlay->last_flip_req, req);
220a05eeebfSFrançois Tigeot 	i915_add_request(req);
221f192107fSFrançois Tigeot 
222e3adcf8fSFrançois Tigeot 	overlay->flip_tail = tail;
2232c9916cdSFrançois Tigeot 	ret = i915_wait_request(overlay->last_flip_req);
224e3adcf8fSFrançois Tigeot 	if (ret)
225e3adcf8fSFrançois Tigeot 		return ret;
226e3adcf8fSFrançois Tigeot 
2272c9916cdSFrançois Tigeot 	i915_gem_request_assign(&overlay->last_flip_req, NULL);
228e3adcf8fSFrançois Tigeot 	return 0;
229e3adcf8fSFrançois Tigeot }
230e3adcf8fSFrançois Tigeot 
231e3adcf8fSFrançois Tigeot /* overlay needs to be disable in OCMD reg */
232e3adcf8fSFrançois Tigeot static int intel_overlay_on(struct intel_overlay *overlay)
233e3adcf8fSFrançois Tigeot {
234e3adcf8fSFrançois Tigeot 	struct drm_device *dev = overlay->dev;
235e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
236ba55f2f5SFrançois Tigeot 	struct intel_engine_cs *ring = &dev_priv->ring[RCS];
237a05eeebfSFrançois Tigeot 	struct drm_i915_gem_request *req;
238e3adcf8fSFrançois Tigeot 	int ret;
239e3adcf8fSFrançois Tigeot 
24019c468b4SFrançois Tigeot 	WARN_ON(overlay->active);
2417cbd1a46SFrançois Tigeot 	WARN_ON(IS_I830(dev) && !(dev_priv->quirks & QUIRK_PIPEA_FORCE));
242e3adcf8fSFrançois Tigeot 
243a05eeebfSFrançois Tigeot 	ret = i915_gem_request_alloc(ring, ring->default_context, &req);
244f192107fSFrançois Tigeot 	if (ret)
245e3adcf8fSFrançois Tigeot 		return ret;
246f192107fSFrançois Tigeot 
247a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
248a05eeebfSFrançois Tigeot 	if (ret) {
249a05eeebfSFrançois Tigeot 		i915_gem_request_cancel(req);
250a05eeebfSFrançois Tigeot 		return ret;
251a05eeebfSFrançois Tigeot 	}
252a05eeebfSFrançois Tigeot 
25319c468b4SFrançois Tigeot 	overlay->active = true;
25419c468b4SFrançois Tigeot 
255f192107fSFrançois Tigeot 	intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_ON);
256f192107fSFrançois Tigeot 	intel_ring_emit(ring, overlay->flip_addr | OFC_UPDATE);
257f192107fSFrançois Tigeot 	intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
258f192107fSFrançois Tigeot 	intel_ring_emit(ring, MI_NOOP);
259f192107fSFrançois Tigeot 	intel_ring_advance(ring);
260f192107fSFrançois Tigeot 
261a05eeebfSFrançois Tigeot 	return intel_overlay_do_wait_request(overlay, req, NULL);
262e3adcf8fSFrançois Tigeot }
263e3adcf8fSFrançois Tigeot 
264e3adcf8fSFrançois Tigeot /* overlay needs to be enabled in OCMD reg */
265e3adcf8fSFrançois Tigeot static int intel_overlay_continue(struct intel_overlay *overlay,
266e3adcf8fSFrançois Tigeot 				  bool load_polyphase_filter)
267e3adcf8fSFrançois Tigeot {
268e3adcf8fSFrançois Tigeot 	struct drm_device *dev = overlay->dev;
269ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
270ba55f2f5SFrançois Tigeot 	struct intel_engine_cs *ring = &dev_priv->ring[RCS];
271a05eeebfSFrançois Tigeot 	struct drm_i915_gem_request *req;
272e3adcf8fSFrançois Tigeot 	u32 flip_addr = overlay->flip_addr;
273e3adcf8fSFrançois Tigeot 	u32 tmp;
274e3adcf8fSFrançois Tigeot 	int ret;
275e3adcf8fSFrançois Tigeot 
27619c468b4SFrançois Tigeot 	WARN_ON(!overlay->active);
277e3adcf8fSFrançois Tigeot 
278e3adcf8fSFrançois Tigeot 	if (load_polyphase_filter)
279e3adcf8fSFrançois Tigeot 		flip_addr |= OFC_UPDATE;
280e3adcf8fSFrançois Tigeot 
281e3adcf8fSFrançois Tigeot 	/* check for underruns */
282e3adcf8fSFrançois Tigeot 	tmp = I915_READ(DOVSTA);
283e3adcf8fSFrançois Tigeot 	if (tmp & (1 << 17))
284e3adcf8fSFrançois Tigeot 		DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
285e3adcf8fSFrançois Tigeot 
286a05eeebfSFrançois Tigeot 	ret = i915_gem_request_alloc(ring, ring->default_context, &req);
287f192107fSFrançois Tigeot 	if (ret)
288e3adcf8fSFrançois Tigeot 		return ret;
289e3adcf8fSFrançois Tigeot 
290a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
291a05eeebfSFrançois Tigeot 	if (ret) {
292a05eeebfSFrançois Tigeot 		i915_gem_request_cancel(req);
293a05eeebfSFrançois Tigeot 		return ret;
294a05eeebfSFrançois Tigeot 	}
295a05eeebfSFrançois Tigeot 
296f192107fSFrançois Tigeot 	intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
297f192107fSFrançois Tigeot 	intel_ring_emit(ring, flip_addr);
298f192107fSFrançois Tigeot 	intel_ring_advance(ring);
299e3adcf8fSFrançois Tigeot 
3002c9916cdSFrançois Tigeot 	WARN_ON(overlay->last_flip_req);
301a05eeebfSFrançois Tigeot 	i915_gem_request_assign(&overlay->last_flip_req, req);
302a05eeebfSFrançois Tigeot 	i915_add_request(req);
303a05eeebfSFrançois Tigeot 
304a05eeebfSFrançois Tigeot 	return 0;
305e3adcf8fSFrançois Tigeot }
306e3adcf8fSFrançois Tigeot 
307e3adcf8fSFrançois Tigeot static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
308e3adcf8fSFrançois Tigeot {
309e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *obj = overlay->old_vid_bo;
310e3adcf8fSFrançois Tigeot 
311ba55f2f5SFrançois Tigeot 	i915_gem_object_ggtt_unpin(obj);
312e3adcf8fSFrançois Tigeot 	drm_gem_object_unreference(&obj->base);
313e3adcf8fSFrançois Tigeot 
314e3adcf8fSFrançois Tigeot 	overlay->old_vid_bo = NULL;
315e3adcf8fSFrançois Tigeot }
316e3adcf8fSFrançois Tigeot 
317e3adcf8fSFrançois Tigeot static void intel_overlay_off_tail(struct intel_overlay *overlay)
318e3adcf8fSFrançois Tigeot {
319e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *obj = overlay->vid_bo;
320e3adcf8fSFrançois Tigeot 
321e3adcf8fSFrançois Tigeot 	/* never have the overlay hw on without showing a frame */
32219c468b4SFrançois Tigeot 	if (WARN_ON(!obj))
32319c468b4SFrançois Tigeot 		return;
324e3adcf8fSFrançois Tigeot 
325ba55f2f5SFrançois Tigeot 	i915_gem_object_ggtt_unpin(obj);
326e3adcf8fSFrançois Tigeot 	drm_gem_object_unreference(&obj->base);
327e3adcf8fSFrançois Tigeot 	overlay->vid_bo = NULL;
328e3adcf8fSFrançois Tigeot 
329e3adcf8fSFrançois Tigeot 	overlay->crtc->overlay = NULL;
330e3adcf8fSFrançois Tigeot 	overlay->crtc = NULL;
33119c468b4SFrançois Tigeot 	overlay->active = false;
332e3adcf8fSFrançois Tigeot }
333e3adcf8fSFrançois Tigeot 
334e3adcf8fSFrançois Tigeot /* overlay needs to be disabled in OCMD reg */
335e3adcf8fSFrançois Tigeot static int intel_overlay_off(struct intel_overlay *overlay)
336e3adcf8fSFrançois Tigeot {
337e3adcf8fSFrançois Tigeot 	struct drm_device *dev = overlay->dev;
338e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
339ba55f2f5SFrançois Tigeot 	struct intel_engine_cs *ring = &dev_priv->ring[RCS];
340a05eeebfSFrançois Tigeot 	struct drm_i915_gem_request *req;
341e3adcf8fSFrançois Tigeot 	u32 flip_addr = overlay->flip_addr;
342e3adcf8fSFrançois Tigeot 	int ret;
343e3adcf8fSFrançois Tigeot 
34419c468b4SFrançois Tigeot 	WARN_ON(!overlay->active);
345e3adcf8fSFrançois Tigeot 
346e3adcf8fSFrançois Tigeot 	/* According to intel docs the overlay hw may hang (when switching
347e3adcf8fSFrançois Tigeot 	 * off) without loading the filter coeffs. It is however unclear whether
348e3adcf8fSFrançois Tigeot 	 * this applies to the disabling of the overlay or to the switching off
349e3adcf8fSFrançois Tigeot 	 * of the hw. Do it in both cases */
350e3adcf8fSFrançois Tigeot 	flip_addr |= OFC_UPDATE;
351e3adcf8fSFrançois Tigeot 
352a05eeebfSFrançois Tigeot 	ret = i915_gem_request_alloc(ring, ring->default_context, &req);
353f192107fSFrançois Tigeot 	if (ret)
354e3adcf8fSFrançois Tigeot 		return ret;
355e3adcf8fSFrançois Tigeot 
356a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 6);
357a05eeebfSFrançois Tigeot 	if (ret) {
358a05eeebfSFrançois Tigeot 		i915_gem_request_cancel(req);
359a05eeebfSFrançois Tigeot 		return ret;
360a05eeebfSFrançois Tigeot 	}
361a05eeebfSFrançois Tigeot 
362f192107fSFrançois Tigeot 	/* wait for overlay to go idle */
363f192107fSFrançois Tigeot 	intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
364f192107fSFrançois Tigeot 	intel_ring_emit(ring, flip_addr);
365f192107fSFrançois Tigeot 	intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
366f192107fSFrançois Tigeot 	/* turn overlay off */
36719df918dSFrançois Tigeot 	if (IS_I830(dev)) {
36819df918dSFrançois Tigeot 		/* Workaround: Don't disable the overlay fully, since otherwise
36919df918dSFrançois Tigeot 		 * it dies on the next OVERLAY_ON cmd. */
37019df918dSFrançois Tigeot 		intel_ring_emit(ring, MI_NOOP);
37119df918dSFrançois Tigeot 		intel_ring_emit(ring, MI_NOOP);
37219df918dSFrançois Tigeot 		intel_ring_emit(ring, MI_NOOP);
37319df918dSFrançois Tigeot 	} else {
374f192107fSFrançois Tigeot 		intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
375f192107fSFrançois Tigeot 		intel_ring_emit(ring, flip_addr);
376f192107fSFrançois Tigeot 		intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
37719df918dSFrançois Tigeot 	}
378f192107fSFrançois Tigeot 	intel_ring_advance(ring);
379f192107fSFrançois Tigeot 
380a05eeebfSFrançois Tigeot 	return intel_overlay_do_wait_request(overlay, req, intel_overlay_off_tail);
381e3adcf8fSFrançois Tigeot }
382e3adcf8fSFrançois Tigeot 
383e3adcf8fSFrançois Tigeot /* recover from an interruption due to a signal
384e3adcf8fSFrançois Tigeot  * We have to be careful not to repeat work forever an make forward progess. */
385e3adcf8fSFrançois Tigeot static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
386e3adcf8fSFrançois Tigeot {
387e3adcf8fSFrançois Tigeot 	int ret;
388e3adcf8fSFrançois Tigeot 
3892c9916cdSFrançois Tigeot 	if (overlay->last_flip_req == NULL)
390e3adcf8fSFrançois Tigeot 		return 0;
391e3adcf8fSFrançois Tigeot 
3922c9916cdSFrançois Tigeot 	ret = i915_wait_request(overlay->last_flip_req);
393e3adcf8fSFrançois Tigeot 	if (ret)
394e3adcf8fSFrançois Tigeot 		return ret;
395e3adcf8fSFrançois Tigeot 
396e3adcf8fSFrançois Tigeot 	if (overlay->flip_tail)
397e3adcf8fSFrançois Tigeot 		overlay->flip_tail(overlay);
398e3adcf8fSFrançois Tigeot 
3992c9916cdSFrançois Tigeot 	i915_gem_request_assign(&overlay->last_flip_req, NULL);
400e3adcf8fSFrançois Tigeot 	return 0;
401e3adcf8fSFrançois Tigeot }
402e3adcf8fSFrançois Tigeot 
403e3adcf8fSFrançois Tigeot /* Wait for pending overlay flip and release old frame.
404e3adcf8fSFrançois Tigeot  * Needs to be called before the overlay register are changed
405e3adcf8fSFrançois Tigeot  * via intel_overlay_(un)map_regs
406e3adcf8fSFrançois Tigeot  */
407e3adcf8fSFrançois Tigeot static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
408e3adcf8fSFrançois Tigeot {
409e3adcf8fSFrançois Tigeot 	struct drm_device *dev = overlay->dev;
410ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
411ba55f2f5SFrançois Tigeot 	struct intel_engine_cs *ring = &dev_priv->ring[RCS];
412e3adcf8fSFrançois Tigeot 	int ret;
413e3adcf8fSFrançois Tigeot 
4142c9916cdSFrançois Tigeot 	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
4152c9916cdSFrançois Tigeot 
416e3adcf8fSFrançois Tigeot 	/* Only wait if there is actually an old frame to release to
417e3adcf8fSFrançois Tigeot 	 * guarantee forward progress.
418e3adcf8fSFrançois Tigeot 	 */
419e3adcf8fSFrançois Tigeot 	if (!overlay->old_vid_bo)
420e3adcf8fSFrançois Tigeot 		return 0;
421e3adcf8fSFrançois Tigeot 
422e3adcf8fSFrançois Tigeot 	if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) {
423e3adcf8fSFrançois Tigeot 		/* synchronous slowpath */
424a05eeebfSFrançois Tigeot 		struct drm_i915_gem_request *req;
425a05eeebfSFrançois Tigeot 
426a05eeebfSFrançois Tigeot 		ret = i915_gem_request_alloc(ring, ring->default_context, &req);
427f192107fSFrançois Tigeot 		if (ret)
428e3adcf8fSFrançois Tigeot 			return ret;
429e3adcf8fSFrançois Tigeot 
430a05eeebfSFrançois Tigeot 		ret = intel_ring_begin(req, 2);
431a05eeebfSFrançois Tigeot 		if (ret) {
432a05eeebfSFrançois Tigeot 			i915_gem_request_cancel(req);
433a05eeebfSFrançois Tigeot 			return ret;
434a05eeebfSFrançois Tigeot 		}
435a05eeebfSFrançois Tigeot 
436f192107fSFrançois Tigeot 		intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
437f192107fSFrançois Tigeot 		intel_ring_emit(ring, MI_NOOP);
438f192107fSFrançois Tigeot 		intel_ring_advance(ring);
439e3adcf8fSFrançois Tigeot 
440a05eeebfSFrançois Tigeot 		ret = intel_overlay_do_wait_request(overlay, req,
441e3adcf8fSFrançois Tigeot 						    intel_overlay_release_old_vid_tail);
442e3adcf8fSFrançois Tigeot 		if (ret)
443e3adcf8fSFrançois Tigeot 			return ret;
444e3adcf8fSFrançois Tigeot 	}
445e3adcf8fSFrançois Tigeot 
446e3adcf8fSFrançois Tigeot 	intel_overlay_release_old_vid_tail(overlay);
44724edb884SFrançois Tigeot 
44824edb884SFrançois Tigeot 
44924edb884SFrançois Tigeot 	i915_gem_track_fb(overlay->old_vid_bo, NULL,
45024edb884SFrançois Tigeot 			  INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe));
451e3adcf8fSFrançois Tigeot 	return 0;
452e3adcf8fSFrançois Tigeot }
453e3adcf8fSFrançois Tigeot 
4542c9916cdSFrançois Tigeot void intel_overlay_reset(struct drm_i915_private *dev_priv)
4552c9916cdSFrançois Tigeot {
4562c9916cdSFrançois Tigeot 	struct intel_overlay *overlay = dev_priv->overlay;
4572c9916cdSFrançois Tigeot 
4582c9916cdSFrançois Tigeot 	if (!overlay)
4592c9916cdSFrançois Tigeot 		return;
4602c9916cdSFrançois Tigeot 
4612c9916cdSFrançois Tigeot 	intel_overlay_release_old_vid(overlay);
4622c9916cdSFrançois Tigeot 
4632c9916cdSFrançois Tigeot 	overlay->last_flip_req = NULL;
4642c9916cdSFrançois Tigeot 	overlay->old_xscale = 0;
4652c9916cdSFrançois Tigeot 	overlay->old_yscale = 0;
4662c9916cdSFrançois Tigeot 	overlay->crtc = NULL;
4672c9916cdSFrançois Tigeot 	overlay->active = false;
4682c9916cdSFrançois Tigeot }
4692c9916cdSFrançois Tigeot 
470e3adcf8fSFrançois Tigeot struct put_image_params {
471e3adcf8fSFrançois Tigeot 	int format;
472e3adcf8fSFrançois Tigeot 	short dst_x;
473e3adcf8fSFrançois Tigeot 	short dst_y;
474e3adcf8fSFrançois Tigeot 	short dst_w;
475e3adcf8fSFrançois Tigeot 	short dst_h;
476e3adcf8fSFrançois Tigeot 	short src_w;
477e3adcf8fSFrançois Tigeot 	short src_scan_h;
478e3adcf8fSFrançois Tigeot 	short src_scan_w;
479e3adcf8fSFrançois Tigeot 	short src_h;
480e3adcf8fSFrançois Tigeot 	short stride_Y;
481e3adcf8fSFrançois Tigeot 	short stride_UV;
482e3adcf8fSFrançois Tigeot 	int offset_Y;
483e3adcf8fSFrançois Tigeot 	int offset_U;
484e3adcf8fSFrançois Tigeot 	int offset_V;
485e3adcf8fSFrançois Tigeot };
486e3adcf8fSFrançois Tigeot 
487e3adcf8fSFrançois Tigeot static int packed_depth_bytes(u32 format)
488e3adcf8fSFrançois Tigeot {
489e3adcf8fSFrançois Tigeot 	switch (format & I915_OVERLAY_DEPTH_MASK) {
490e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV422:
491e3adcf8fSFrançois Tigeot 		return 4;
492e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV411:
493e3adcf8fSFrançois Tigeot 		/* return 6; not implemented */
494e3adcf8fSFrançois Tigeot 	default:
495e3adcf8fSFrançois Tigeot 		return -EINVAL;
496e3adcf8fSFrançois Tigeot 	}
497e3adcf8fSFrançois Tigeot }
498e3adcf8fSFrançois Tigeot 
499e3adcf8fSFrançois Tigeot static int packed_width_bytes(u32 format, short width)
500e3adcf8fSFrançois Tigeot {
501e3adcf8fSFrançois Tigeot 	switch (format & I915_OVERLAY_DEPTH_MASK) {
502e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV422:
503e3adcf8fSFrançois Tigeot 		return width << 1;
504e3adcf8fSFrançois Tigeot 	default:
505e3adcf8fSFrançois Tigeot 		return -EINVAL;
506e3adcf8fSFrançois Tigeot 	}
507e3adcf8fSFrançois Tigeot }
508e3adcf8fSFrançois Tigeot 
509e3adcf8fSFrançois Tigeot static int uv_hsubsampling(u32 format)
510e3adcf8fSFrançois Tigeot {
511e3adcf8fSFrançois Tigeot 	switch (format & I915_OVERLAY_DEPTH_MASK) {
512e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV422:
513e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV420:
514e3adcf8fSFrançois Tigeot 		return 2;
515e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV411:
516e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV410:
517e3adcf8fSFrançois Tigeot 		return 4;
518e3adcf8fSFrançois Tigeot 	default:
519e3adcf8fSFrançois Tigeot 		return -EINVAL;
520e3adcf8fSFrançois Tigeot 	}
521e3adcf8fSFrançois Tigeot }
522e3adcf8fSFrançois Tigeot 
523e3adcf8fSFrançois Tigeot static int uv_vsubsampling(u32 format)
524e3adcf8fSFrançois Tigeot {
525e3adcf8fSFrançois Tigeot 	switch (format & I915_OVERLAY_DEPTH_MASK) {
526e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV420:
527e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV410:
528e3adcf8fSFrançois Tigeot 		return 2;
529e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV422:
530e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV411:
531e3adcf8fSFrançois Tigeot 		return 1;
532e3adcf8fSFrançois Tigeot 	default:
533e3adcf8fSFrançois Tigeot 		return -EINVAL;
534e3adcf8fSFrançois Tigeot 	}
535e3adcf8fSFrançois Tigeot }
536e3adcf8fSFrançois Tigeot 
537e3adcf8fSFrançois Tigeot static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width)
538e3adcf8fSFrançois Tigeot {
539e3adcf8fSFrançois Tigeot 	u32 mask, shift, ret;
540e3adcf8fSFrançois Tigeot 	if (IS_GEN2(dev)) {
541e3adcf8fSFrançois Tigeot 		mask = 0x1f;
542e3adcf8fSFrançois Tigeot 		shift = 5;
543e3adcf8fSFrançois Tigeot 	} else {
544e3adcf8fSFrançois Tigeot 		mask = 0x3f;
545e3adcf8fSFrançois Tigeot 		shift = 6;
546e3adcf8fSFrançois Tigeot 	}
547e3adcf8fSFrançois Tigeot 	ret = ((offset + width + mask) >> shift) - (offset >> shift);
548e3adcf8fSFrançois Tigeot 	if (!IS_GEN2(dev))
549e3adcf8fSFrançois Tigeot 		ret <<= 1;
550e3adcf8fSFrançois Tigeot 	ret -= 1;
551e3adcf8fSFrançois Tigeot 	return ret << 2;
552e3adcf8fSFrançois Tigeot }
553e3adcf8fSFrançois Tigeot 
554e3adcf8fSFrançois Tigeot static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = {
555e3adcf8fSFrançois Tigeot 	0x3000, 0xb4a0, 0x1930, 0x1920, 0xb4a0,
556e3adcf8fSFrançois Tigeot 	0x3000, 0xb500, 0x19d0, 0x1880, 0xb440,
557e3adcf8fSFrançois Tigeot 	0x3000, 0xb540, 0x1a88, 0x2f80, 0xb3e0,
558e3adcf8fSFrançois Tigeot 	0x3000, 0xb580, 0x1b30, 0x2e20, 0xb380,
559e3adcf8fSFrançois Tigeot 	0x3000, 0xb5c0, 0x1bd8, 0x2cc0, 0xb320,
560e3adcf8fSFrançois Tigeot 	0x3020, 0xb5e0, 0x1c60, 0x2b80, 0xb2c0,
561e3adcf8fSFrançois Tigeot 	0x3020, 0xb5e0, 0x1cf8, 0x2a20, 0xb260,
562e3adcf8fSFrançois Tigeot 	0x3020, 0xb5e0, 0x1d80, 0x28e0, 0xb200,
563e3adcf8fSFrançois Tigeot 	0x3020, 0xb5c0, 0x1e08, 0x3f40, 0xb1c0,
564e3adcf8fSFrançois Tigeot 	0x3020, 0xb580, 0x1e78, 0x3ce0, 0xb160,
565e3adcf8fSFrançois Tigeot 	0x3040, 0xb520, 0x1ed8, 0x3aa0, 0xb120,
566e3adcf8fSFrançois Tigeot 	0x3040, 0xb4a0, 0x1f30, 0x3880, 0xb0e0,
567e3adcf8fSFrançois Tigeot 	0x3040, 0xb400, 0x1f78, 0x3680, 0xb0a0,
568e3adcf8fSFrançois Tigeot 	0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060,
569e3adcf8fSFrançois Tigeot 	0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040,
570e3adcf8fSFrançois Tigeot 	0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020,
571e3adcf8fSFrançois Tigeot 	0xb000, 0x3000, 0x0800, 0x3000, 0xb000
572e3adcf8fSFrançois Tigeot };
573e3adcf8fSFrançois Tigeot 
574e3adcf8fSFrançois Tigeot static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
575e3adcf8fSFrançois Tigeot 	0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60,
576e3adcf8fSFrançois Tigeot 	0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40,
577e3adcf8fSFrançois Tigeot 	0xb040, 0x1b20, 0x29e0, 0xb060, 0x1bd8, 0x2880,
578e3adcf8fSFrançois Tigeot 	0xb080, 0x1c88, 0x3e60, 0xb0a0, 0x1d28, 0x3c00,
579e3adcf8fSFrançois Tigeot 	0xb0c0, 0x1db8, 0x39e0, 0xb0e0, 0x1e40, 0x37e0,
580e3adcf8fSFrançois Tigeot 	0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0,
581e3adcf8fSFrançois Tigeot 	0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240,
582e3adcf8fSFrançois Tigeot 	0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0,
583e3adcf8fSFrançois Tigeot 	0x3000, 0x0800, 0x3000
584e3adcf8fSFrançois Tigeot };
585e3adcf8fSFrançois Tigeot 
586e3440f96SFrançois Tigeot static void update_polyphase_filter(struct overlay_registers __iomem *regs)
587e3adcf8fSFrançois Tigeot {
588e3440f96SFrançois Tigeot 	memcpy_toio(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs));
589e3440f96SFrançois Tigeot 	memcpy_toio(regs->UV_HCOEFS, uv_static_hcoeffs,
590e3440f96SFrançois Tigeot 		    sizeof(uv_static_hcoeffs));
591e3adcf8fSFrançois Tigeot }
592e3adcf8fSFrançois Tigeot 
593e3adcf8fSFrançois Tigeot static bool update_scaling_factors(struct intel_overlay *overlay,
594e3440f96SFrançois Tigeot 				   struct overlay_registers __iomem *regs,
595e3adcf8fSFrançois Tigeot 				   struct put_image_params *params)
596e3adcf8fSFrançois Tigeot {
597e3adcf8fSFrançois Tigeot 	/* fixed point with a 12 bit shift */
598e3adcf8fSFrançois Tigeot 	u32 xscale, yscale, xscale_UV, yscale_UV;
599e3adcf8fSFrançois Tigeot #define FP_SHIFT 12
600e3adcf8fSFrançois Tigeot #define FRACT_MASK 0xfff
601e3adcf8fSFrançois Tigeot 	bool scale_changed = false;
602e3adcf8fSFrançois Tigeot 	int uv_hscale = uv_hsubsampling(params->format);
603e3adcf8fSFrançois Tigeot 	int uv_vscale = uv_vsubsampling(params->format);
604e3adcf8fSFrançois Tigeot 
605e3adcf8fSFrançois Tigeot 	if (params->dst_w > 1)
606e3adcf8fSFrançois Tigeot 		xscale = ((params->src_scan_w - 1) << FP_SHIFT)
607e3adcf8fSFrançois Tigeot 			/(params->dst_w);
608e3adcf8fSFrançois Tigeot 	else
609e3adcf8fSFrançois Tigeot 		xscale = 1 << FP_SHIFT;
610e3adcf8fSFrançois Tigeot 
611e3adcf8fSFrançois Tigeot 	if (params->dst_h > 1)
612e3adcf8fSFrançois Tigeot 		yscale = ((params->src_scan_h - 1) << FP_SHIFT)
613e3adcf8fSFrançois Tigeot 			/(params->dst_h);
614e3adcf8fSFrançois Tigeot 	else
615e3adcf8fSFrançois Tigeot 		yscale = 1 << FP_SHIFT;
616e3adcf8fSFrançois Tigeot 
617e3adcf8fSFrançois Tigeot 	/*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
618e3adcf8fSFrançois Tigeot 	xscale_UV = xscale/uv_hscale;
619e3adcf8fSFrançois Tigeot 	yscale_UV = yscale/uv_vscale;
620e3adcf8fSFrançois Tigeot 	/* make the Y scale to UV scale ratio an exact multiply */
621e3adcf8fSFrançois Tigeot 	xscale = xscale_UV * uv_hscale;
622e3adcf8fSFrançois Tigeot 	yscale = yscale_UV * uv_vscale;
623e3adcf8fSFrançois Tigeot 	/*} else {
624e3adcf8fSFrançois Tigeot 	  xscale_UV = 0;
625e3adcf8fSFrançois Tigeot 	  yscale_UV = 0;
626e3adcf8fSFrançois Tigeot 	  }*/
627e3adcf8fSFrançois Tigeot 
628e3adcf8fSFrançois Tigeot 	if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)
629e3adcf8fSFrançois Tigeot 		scale_changed = true;
630e3adcf8fSFrançois Tigeot 	overlay->old_xscale = xscale;
631e3adcf8fSFrançois Tigeot 	overlay->old_yscale = yscale;
632e3adcf8fSFrançois Tigeot 
633e3440f96SFrançois Tigeot 	iowrite32(((yscale & FRACT_MASK) << 20) |
634e3adcf8fSFrançois Tigeot 		  ((xscale >> FP_SHIFT)  << 16) |
635e3440f96SFrançois Tigeot 		  ((xscale & FRACT_MASK) << 3),
636e3440f96SFrançois Tigeot 		 &regs->YRGBSCALE);
637e3adcf8fSFrançois Tigeot 
638e3440f96SFrançois Tigeot 	iowrite32(((yscale_UV & FRACT_MASK) << 20) |
639e3adcf8fSFrançois Tigeot 		  ((xscale_UV >> FP_SHIFT)  << 16) |
640e3440f96SFrançois Tigeot 		  ((xscale_UV & FRACT_MASK) << 3),
641e3440f96SFrançois Tigeot 		 &regs->UVSCALE);
642e3adcf8fSFrançois Tigeot 
643e3440f96SFrançois Tigeot 	iowrite32((((yscale    >> FP_SHIFT) << 16) |
644e3440f96SFrançois Tigeot 		   ((yscale_UV >> FP_SHIFT) << 0)),
645e3440f96SFrançois Tigeot 		 &regs->UVSCALEV);
646e3adcf8fSFrançois Tigeot 
647e3adcf8fSFrançois Tigeot 	if (scale_changed)
648e3adcf8fSFrançois Tigeot 		update_polyphase_filter(regs);
649e3adcf8fSFrançois Tigeot 
650e3adcf8fSFrançois Tigeot 	return scale_changed;
651e3adcf8fSFrançois Tigeot }
652e3adcf8fSFrançois Tigeot 
653e3adcf8fSFrançois Tigeot static void update_colorkey(struct intel_overlay *overlay,
654e3440f96SFrançois Tigeot 			    struct overlay_registers __iomem *regs)
655e3adcf8fSFrançois Tigeot {
656e3adcf8fSFrançois Tigeot 	u32 key = overlay->color_key;
65719c468b4SFrançois Tigeot 	u32 flags;
65819c468b4SFrançois Tigeot 
65919c468b4SFrançois Tigeot 	flags = 0;
66019c468b4SFrançois Tigeot 	if (overlay->color_key_enabled)
66119c468b4SFrançois Tigeot 		flags |= DST_KEY_ENABLE;
662e3adcf8fSFrançois Tigeot 
663ba55f2f5SFrançois Tigeot 	switch (overlay->crtc->base.primary->fb->bits_per_pixel) {
664e3adcf8fSFrançois Tigeot 	case 8:
66519c468b4SFrançois Tigeot 		key = 0;
66619c468b4SFrançois Tigeot 		flags |= CLK_RGB8I_MASK;
667e3adcf8fSFrançois Tigeot 		break;
668e3adcf8fSFrançois Tigeot 
669e3adcf8fSFrançois Tigeot 	case 16:
670ba55f2f5SFrançois Tigeot 		if (overlay->crtc->base.primary->fb->depth == 15) {
67119c468b4SFrançois Tigeot 			key = RGB15_TO_COLORKEY(key);
67219c468b4SFrançois Tigeot 			flags |= CLK_RGB15_MASK;
673e3adcf8fSFrançois Tigeot 		} else {
67419c468b4SFrançois Tigeot 			key = RGB16_TO_COLORKEY(key);
67519c468b4SFrançois Tigeot 			flags |= CLK_RGB16_MASK;
676e3adcf8fSFrançois Tigeot 		}
677e3adcf8fSFrançois Tigeot 		break;
678e3adcf8fSFrançois Tigeot 
679e3adcf8fSFrançois Tigeot 	case 24:
680e3adcf8fSFrançois Tigeot 	case 32:
68119c468b4SFrançois Tigeot 		flags |= CLK_RGB24_MASK;
682e3adcf8fSFrançois Tigeot 		break;
683e3adcf8fSFrançois Tigeot 	}
68419c468b4SFrançois Tigeot 
68519c468b4SFrançois Tigeot 	iowrite32(key, &regs->DCLRKV);
68619c468b4SFrançois Tigeot 	iowrite32(flags, &regs->DCLRKM);
687e3adcf8fSFrançois Tigeot }
688e3adcf8fSFrançois Tigeot 
689e3adcf8fSFrançois Tigeot static u32 overlay_cmd_reg(struct put_image_params *params)
690e3adcf8fSFrançois Tigeot {
691e3adcf8fSFrançois Tigeot 	u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0;
692e3adcf8fSFrançois Tigeot 
693e3adcf8fSFrançois Tigeot 	if (params->format & I915_OVERLAY_YUV_PLANAR) {
694e3adcf8fSFrançois Tigeot 		switch (params->format & I915_OVERLAY_DEPTH_MASK) {
695e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_YUV422:
696e3adcf8fSFrançois Tigeot 			cmd |= OCMD_YUV_422_PLANAR;
697e3adcf8fSFrançois Tigeot 			break;
698e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_YUV420:
699e3adcf8fSFrançois Tigeot 			cmd |= OCMD_YUV_420_PLANAR;
700e3adcf8fSFrançois Tigeot 			break;
701e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_YUV411:
702e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_YUV410:
703e3adcf8fSFrançois Tigeot 			cmd |= OCMD_YUV_410_PLANAR;
704e3adcf8fSFrançois Tigeot 			break;
705e3adcf8fSFrançois Tigeot 		}
706e3adcf8fSFrançois Tigeot 	} else { /* YUV packed */
707e3adcf8fSFrançois Tigeot 		switch (params->format & I915_OVERLAY_DEPTH_MASK) {
708e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_YUV422:
709e3adcf8fSFrançois Tigeot 			cmd |= OCMD_YUV_422_PACKED;
710e3adcf8fSFrançois Tigeot 			break;
711e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_YUV411:
712e3adcf8fSFrançois Tigeot 			cmd |= OCMD_YUV_411_PACKED;
713e3adcf8fSFrançois Tigeot 			break;
714e3adcf8fSFrançois Tigeot 		}
715e3adcf8fSFrançois Tigeot 
716e3adcf8fSFrançois Tigeot 		switch (params->format & I915_OVERLAY_SWAP_MASK) {
717e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_NO_SWAP:
718e3adcf8fSFrançois Tigeot 			break;
719e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_UV_SWAP:
720e3adcf8fSFrançois Tigeot 			cmd |= OCMD_UV_SWAP;
721e3adcf8fSFrançois Tigeot 			break;
722e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_Y_SWAP:
723e3adcf8fSFrançois Tigeot 			cmd |= OCMD_Y_SWAP;
724e3adcf8fSFrançois Tigeot 			break;
725e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_Y_AND_UV_SWAP:
726e3adcf8fSFrançois Tigeot 			cmd |= OCMD_Y_AND_UV_SWAP;
727e3adcf8fSFrançois Tigeot 			break;
728e3adcf8fSFrançois Tigeot 		}
729e3adcf8fSFrançois Tigeot 	}
730e3adcf8fSFrançois Tigeot 
731e3adcf8fSFrançois Tigeot 	return cmd;
732e3adcf8fSFrançois Tigeot }
733e3adcf8fSFrançois Tigeot 
734e3adcf8fSFrançois Tigeot static int intel_overlay_do_put_image(struct intel_overlay *overlay,
735e3adcf8fSFrançois Tigeot 				      struct drm_i915_gem_object *new_bo,
736e3adcf8fSFrançois Tigeot 				      struct put_image_params *params)
737e3adcf8fSFrançois Tigeot {
738e3adcf8fSFrançois Tigeot 	int ret, tmp_width;
739e3440f96SFrançois Tigeot 	struct overlay_registers __iomem *regs;
740e3adcf8fSFrançois Tigeot 	bool scale_changed = false;
741e3440f96SFrançois Tigeot 	struct drm_device *dev = overlay->dev;
742e3440f96SFrançois Tigeot 	u32 swidth, swidthsw, sheight, ostride;
74324edb884SFrançois Tigeot 	enum i915_pipe pipe = overlay->crtc->pipe;
744e3adcf8fSFrançois Tigeot 
74519c468b4SFrançois Tigeot 	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
74619c468b4SFrançois Tigeot 	WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
747e3adcf8fSFrançois Tigeot 
748e3adcf8fSFrançois Tigeot 	ret = intel_overlay_release_old_vid(overlay);
749e3adcf8fSFrançois Tigeot 	if (ret != 0)
750e3adcf8fSFrançois Tigeot 		return ret;
751e3adcf8fSFrançois Tigeot 
752*aee94f86SFrançois Tigeot 	ret = i915_gem_object_pin_to_display_plane(new_bo, 0,
753477eb7f9SFrançois Tigeot 						   &i915_ggtt_view_normal);
754e3adcf8fSFrançois Tigeot 	if (ret != 0)
755e3440f96SFrançois Tigeot 		return ret;
756e3adcf8fSFrançois Tigeot 
757e3adcf8fSFrançois Tigeot 	ret = i915_gem_object_put_fence(new_bo);
758e3adcf8fSFrançois Tigeot 	if (ret)
759e3adcf8fSFrançois Tigeot 		goto out_unpin;
760e3adcf8fSFrançois Tigeot 
761e3adcf8fSFrançois Tigeot 	if (!overlay->active) {
762e3440f96SFrançois Tigeot 		u32 oconfig;
763e3adcf8fSFrançois Tigeot 		regs = intel_overlay_map_regs(overlay);
764e3adcf8fSFrançois Tigeot 		if (!regs) {
765e3adcf8fSFrançois Tigeot 			ret = -ENOMEM;
766e3adcf8fSFrançois Tigeot 			goto out_unpin;
767e3adcf8fSFrançois Tigeot 		}
768e3440f96SFrançois Tigeot 		oconfig = OCONF_CC_OUT_8BIT;
769e3adcf8fSFrançois Tigeot 		if (IS_GEN4(overlay->dev))
770e3440f96SFrançois Tigeot 			oconfig |= OCONF_CSC_MODE_BT709;
77124edb884SFrançois Tigeot 		oconfig |= pipe == 0 ?
772e3adcf8fSFrançois Tigeot 			OCONF_PIPE_A : OCONF_PIPE_B;
773e3440f96SFrançois Tigeot 		iowrite32(oconfig, &regs->OCONFIG);
774e3adcf8fSFrançois Tigeot 		intel_overlay_unmap_regs(overlay, regs);
775e3adcf8fSFrançois Tigeot 
776e3adcf8fSFrançois Tigeot 		ret = intel_overlay_on(overlay);
777e3adcf8fSFrançois Tigeot 		if (ret != 0)
778e3adcf8fSFrançois Tigeot 			goto out_unpin;
779e3adcf8fSFrançois Tigeot 	}
780e3adcf8fSFrançois Tigeot 
781e3adcf8fSFrançois Tigeot 	regs = intel_overlay_map_regs(overlay);
782e3adcf8fSFrançois Tigeot 	if (!regs) {
783e3adcf8fSFrançois Tigeot 		ret = -ENOMEM;
784e3adcf8fSFrançois Tigeot 		goto out_unpin;
785e3adcf8fSFrançois Tigeot 	}
786e3adcf8fSFrançois Tigeot 
787e3440f96SFrançois Tigeot 	iowrite32((params->dst_y << 16) | params->dst_x, &regs->DWINPOS);
788e3440f96SFrançois Tigeot 	iowrite32((params->dst_h << 16) | params->dst_w, &regs->DWINSZ);
789e3adcf8fSFrançois Tigeot 
790e3adcf8fSFrançois Tigeot 	if (params->format & I915_OVERLAY_YUV_PACKED)
791e3adcf8fSFrançois Tigeot 		tmp_width = packed_width_bytes(params->format, params->src_w);
792e3adcf8fSFrançois Tigeot 	else
793e3adcf8fSFrançois Tigeot 		tmp_width = params->src_w;
794e3adcf8fSFrançois Tigeot 
795e3440f96SFrançois Tigeot 	swidth = params->src_w;
796e3440f96SFrançois Tigeot 	swidthsw = calc_swidthsw(overlay->dev, params->offset_Y, tmp_width);
797e3440f96SFrançois Tigeot 	sheight = params->src_h;
7989edbd4a0SFrançois Tigeot 	iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_Y, &regs->OBUF_0Y);
799e3440f96SFrançois Tigeot 	ostride = params->stride_Y;
800e3adcf8fSFrançois Tigeot 
801e3adcf8fSFrançois Tigeot 	if (params->format & I915_OVERLAY_YUV_PLANAR) {
802e3adcf8fSFrançois Tigeot 		int uv_hscale = uv_hsubsampling(params->format);
803e3adcf8fSFrançois Tigeot 		int uv_vscale = uv_vsubsampling(params->format);
804e3adcf8fSFrançois Tigeot 		u32 tmp_U, tmp_V;
805e3440f96SFrançois Tigeot 		swidth |= (params->src_w/uv_hscale) << 16;
806e3adcf8fSFrançois Tigeot 		tmp_U = calc_swidthsw(overlay->dev, params->offset_U,
807e3adcf8fSFrançois Tigeot 				      params->src_w/uv_hscale);
808e3adcf8fSFrançois Tigeot 		tmp_V = calc_swidthsw(overlay->dev, params->offset_V,
809e3adcf8fSFrançois Tigeot 				      params->src_w/uv_hscale);
810e3440f96SFrançois Tigeot 		swidthsw |= max_t(u32, tmp_U, tmp_V) << 16;
811e3440f96SFrançois Tigeot 		sheight |= (params->src_h/uv_vscale) << 16;
8129edbd4a0SFrançois Tigeot 		iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_U, &regs->OBUF_0U);
8139edbd4a0SFrançois Tigeot 		iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_V, &regs->OBUF_0V);
814e3440f96SFrançois Tigeot 		ostride |= params->stride_UV << 16;
815e3adcf8fSFrançois Tigeot 	}
816e3adcf8fSFrançois Tigeot 
817e3440f96SFrançois Tigeot 	iowrite32(swidth, &regs->SWIDTH);
818e3440f96SFrançois Tigeot 	iowrite32(swidthsw, &regs->SWIDTHSW);
819e3440f96SFrançois Tigeot 	iowrite32(sheight, &regs->SHEIGHT);
820e3440f96SFrançois Tigeot 	iowrite32(ostride, &regs->OSTRIDE);
821e3440f96SFrançois Tigeot 
822e3adcf8fSFrançois Tigeot 	scale_changed = update_scaling_factors(overlay, regs, params);
823e3adcf8fSFrançois Tigeot 
824e3adcf8fSFrançois Tigeot 	update_colorkey(overlay, regs);
825e3adcf8fSFrançois Tigeot 
826e3440f96SFrançois Tigeot 	iowrite32(overlay_cmd_reg(params), &regs->OCMD);
827e3adcf8fSFrançois Tigeot 
828e3adcf8fSFrançois Tigeot 	intel_overlay_unmap_regs(overlay, regs);
829e3adcf8fSFrançois Tigeot 
830e3adcf8fSFrançois Tigeot 	ret = intel_overlay_continue(overlay, scale_changed);
831e3adcf8fSFrançois Tigeot 	if (ret)
832e3adcf8fSFrançois Tigeot 		goto out_unpin;
833e3adcf8fSFrançois Tigeot 
83424edb884SFrançois Tigeot 	i915_gem_track_fb(overlay->vid_bo, new_bo,
83524edb884SFrançois Tigeot 			  INTEL_FRONTBUFFER_OVERLAY(pipe));
83624edb884SFrançois Tigeot 
837e3adcf8fSFrançois Tigeot 	overlay->old_vid_bo = overlay->vid_bo;
838e3adcf8fSFrançois Tigeot 	overlay->vid_bo = new_bo;
839e3adcf8fSFrançois Tigeot 
84024edb884SFrançois Tigeot 	intel_frontbuffer_flip(dev,
84124edb884SFrançois Tigeot 			       INTEL_FRONTBUFFER_OVERLAY(pipe));
84224edb884SFrançois Tigeot 
843e3adcf8fSFrançois Tigeot 	return 0;
844e3adcf8fSFrançois Tigeot 
845e3adcf8fSFrançois Tigeot out_unpin:
846ba55f2f5SFrançois Tigeot 	i915_gem_object_ggtt_unpin(new_bo);
847e3adcf8fSFrançois Tigeot 	return ret;
848e3adcf8fSFrançois Tigeot }
849e3adcf8fSFrançois Tigeot 
850e3adcf8fSFrançois Tigeot int intel_overlay_switch_off(struct intel_overlay *overlay)
851e3adcf8fSFrançois Tigeot {
852e3440f96SFrançois Tigeot 	struct overlay_registers __iomem *regs;
853e3440f96SFrançois Tigeot 	struct drm_device *dev = overlay->dev;
854e3adcf8fSFrançois Tigeot 	int ret;
855e3adcf8fSFrançois Tigeot 
85619c468b4SFrançois Tigeot 	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
85719c468b4SFrançois Tigeot 	WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
858e3adcf8fSFrançois Tigeot 
859e3adcf8fSFrançois Tigeot 	ret = intel_overlay_recover_from_interrupt(overlay);
860e3adcf8fSFrançois Tigeot 	if (ret != 0)
861e3adcf8fSFrançois Tigeot 		return ret;
862e3adcf8fSFrançois Tigeot 
863e3adcf8fSFrançois Tigeot 	if (!overlay->active)
864e3adcf8fSFrançois Tigeot 		return 0;
865e3adcf8fSFrançois Tigeot 
866e3adcf8fSFrançois Tigeot 	ret = intel_overlay_release_old_vid(overlay);
867e3adcf8fSFrançois Tigeot 	if (ret != 0)
868e3adcf8fSFrançois Tigeot 		return ret;
869e3adcf8fSFrançois Tigeot 
870e3adcf8fSFrançois Tigeot 	regs = intel_overlay_map_regs(overlay);
871e3440f96SFrançois Tigeot 	iowrite32(0, &regs->OCMD);
872e3adcf8fSFrançois Tigeot 	intel_overlay_unmap_regs(overlay, regs);
873e3adcf8fSFrançois Tigeot 
874e3adcf8fSFrançois Tigeot 	ret = intel_overlay_off(overlay);
875e3adcf8fSFrançois Tigeot 	if (ret != 0)
876e3adcf8fSFrançois Tigeot 		return ret;
877e3adcf8fSFrançois Tigeot 
878e3adcf8fSFrançois Tigeot 	intel_overlay_off_tail(overlay);
879e3adcf8fSFrançois Tigeot 	return 0;
880e3adcf8fSFrançois Tigeot }
881e3adcf8fSFrançois Tigeot 
882e3adcf8fSFrançois Tigeot static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
883e3adcf8fSFrançois Tigeot 					  struct intel_crtc *crtc)
884e3adcf8fSFrançois Tigeot {
885e3adcf8fSFrançois Tigeot 	if (!crtc->active)
886e3adcf8fSFrançois Tigeot 		return -EINVAL;
887e3adcf8fSFrançois Tigeot 
888e3adcf8fSFrançois Tigeot 	/* can't use the overlay with double wide pipe */
8892c9916cdSFrançois Tigeot 	if (crtc->config->double_wide)
890e3adcf8fSFrançois Tigeot 		return -EINVAL;
891e3adcf8fSFrançois Tigeot 
892e3adcf8fSFrançois Tigeot 	return 0;
893e3adcf8fSFrançois Tigeot }
894e3adcf8fSFrançois Tigeot 
895e3adcf8fSFrançois Tigeot static void update_pfit_vscale_ratio(struct intel_overlay *overlay)
896e3adcf8fSFrançois Tigeot {
897e3adcf8fSFrançois Tigeot 	struct drm_device *dev = overlay->dev;
898ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
899e3adcf8fSFrançois Tigeot 	u32 pfit_control = I915_READ(PFIT_CONTROL);
900e3adcf8fSFrançois Tigeot 	u32 ratio;
901e3adcf8fSFrançois Tigeot 
902e3adcf8fSFrançois Tigeot 	/* XXX: This is not the same logic as in the xorg driver, but more in
903e3adcf8fSFrançois Tigeot 	 * line with the intel documentation for the i965
904e3adcf8fSFrançois Tigeot 	 */
905e3adcf8fSFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 4) {
906e3adcf8fSFrançois Tigeot 		/* on i965 use the PGM reg to read out the autoscaler values */
907e3adcf8fSFrançois Tigeot 		ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965;
908e3adcf8fSFrançois Tigeot 	} else {
909e3adcf8fSFrançois Tigeot 		if (pfit_control & VERT_AUTO_SCALE)
910e3adcf8fSFrançois Tigeot 			ratio = I915_READ(PFIT_AUTO_RATIOS);
911e3adcf8fSFrançois Tigeot 		else
912e3adcf8fSFrançois Tigeot 			ratio = I915_READ(PFIT_PGM_RATIOS);
913e3adcf8fSFrançois Tigeot 		ratio >>= PFIT_VERT_SCALE_SHIFT;
914e3adcf8fSFrançois Tigeot 	}
915e3adcf8fSFrançois Tigeot 
916e3adcf8fSFrançois Tigeot 	overlay->pfit_vscale_ratio = ratio;
917e3adcf8fSFrançois Tigeot }
918e3adcf8fSFrançois Tigeot 
919e3adcf8fSFrançois Tigeot static int check_overlay_dst(struct intel_overlay *overlay,
920e3adcf8fSFrançois Tigeot 			     struct drm_intel_overlay_put_image *rec)
921e3adcf8fSFrançois Tigeot {
922e3adcf8fSFrançois Tigeot 	struct drm_display_mode *mode = &overlay->crtc->base.mode;
923e3adcf8fSFrançois Tigeot 
924e3adcf8fSFrançois Tigeot 	if (rec->dst_x < mode->hdisplay &&
925e3adcf8fSFrançois Tigeot 	    rec->dst_x + rec->dst_width <= mode->hdisplay &&
926e3adcf8fSFrançois Tigeot 	    rec->dst_y < mode->vdisplay &&
927e3adcf8fSFrançois Tigeot 	    rec->dst_y + rec->dst_height <= mode->vdisplay)
928e3adcf8fSFrançois Tigeot 		return 0;
929e3adcf8fSFrançois Tigeot 	else
930e3adcf8fSFrançois Tigeot 		return -EINVAL;
931e3adcf8fSFrançois Tigeot }
932e3adcf8fSFrançois Tigeot 
933e3adcf8fSFrançois Tigeot static int check_overlay_scaling(struct put_image_params *rec)
934e3adcf8fSFrançois Tigeot {
935e3adcf8fSFrançois Tigeot 	u32 tmp;
936e3adcf8fSFrançois Tigeot 
937e3adcf8fSFrançois Tigeot 	/* downscaling limit is 8.0 */
938e3adcf8fSFrançois Tigeot 	tmp = ((rec->src_scan_h << 16) / rec->dst_h) >> 16;
939e3adcf8fSFrançois Tigeot 	if (tmp > 7)
940e3adcf8fSFrançois Tigeot 		return -EINVAL;
941e3adcf8fSFrançois Tigeot 	tmp = ((rec->src_scan_w << 16) / rec->dst_w) >> 16;
942e3adcf8fSFrançois Tigeot 	if (tmp > 7)
943e3adcf8fSFrançois Tigeot 		return -EINVAL;
944e3adcf8fSFrançois Tigeot 
945e3adcf8fSFrançois Tigeot 	return 0;
946e3adcf8fSFrançois Tigeot }
947e3adcf8fSFrançois Tigeot 
948e3adcf8fSFrançois Tigeot static int check_overlay_src(struct drm_device *dev,
949e3adcf8fSFrançois Tigeot 			     struct drm_intel_overlay_put_image *rec,
950e3adcf8fSFrançois Tigeot 			     struct drm_i915_gem_object *new_bo)
951e3adcf8fSFrançois Tigeot {
952e3adcf8fSFrançois Tigeot 	int uv_hscale = uv_hsubsampling(rec->flags);
953e3adcf8fSFrançois Tigeot 	int uv_vscale = uv_vsubsampling(rec->flags);
954e3adcf8fSFrançois Tigeot 	u32 stride_mask;
955e3adcf8fSFrançois Tigeot 	int depth;
956e3adcf8fSFrançois Tigeot 	u32 tmp;
957e3adcf8fSFrançois Tigeot 
958e3adcf8fSFrançois Tigeot 	/* check src dimensions */
959e3adcf8fSFrançois Tigeot 	if (IS_845G(dev) || IS_I830(dev)) {
960e3adcf8fSFrançois Tigeot 		if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY ||
961e3adcf8fSFrançois Tigeot 		    rec->src_width  > IMAGE_MAX_WIDTH_LEGACY)
962e3adcf8fSFrançois Tigeot 			return -EINVAL;
963e3adcf8fSFrançois Tigeot 	} else {
964e3adcf8fSFrançois Tigeot 		if (rec->src_height > IMAGE_MAX_HEIGHT ||
965e3adcf8fSFrançois Tigeot 		    rec->src_width  > IMAGE_MAX_WIDTH)
966e3adcf8fSFrançois Tigeot 			return -EINVAL;
967e3adcf8fSFrançois Tigeot 	}
968e3adcf8fSFrançois Tigeot 
969e3adcf8fSFrançois Tigeot 	/* better safe than sorry, use 4 as the maximal subsampling ratio */
970e3adcf8fSFrançois Tigeot 	if (rec->src_height < N_VERT_Y_TAPS*4 ||
971e3adcf8fSFrançois Tigeot 	    rec->src_width  < N_HORIZ_Y_TAPS*4)
972e3adcf8fSFrançois Tigeot 		return -EINVAL;
973e3adcf8fSFrançois Tigeot 
974e3adcf8fSFrançois Tigeot 	/* check alignment constraints */
975e3adcf8fSFrançois Tigeot 	switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
976e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_RGB:
977e3adcf8fSFrançois Tigeot 		/* not implemented */
978e3adcf8fSFrançois Tigeot 		return -EINVAL;
979e3adcf8fSFrançois Tigeot 
980e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV_PACKED:
981e3adcf8fSFrançois Tigeot 		if (uv_vscale != 1)
982e3adcf8fSFrançois Tigeot 			return -EINVAL;
983e3adcf8fSFrançois Tigeot 
984e3adcf8fSFrançois Tigeot 		depth = packed_depth_bytes(rec->flags);
985e3adcf8fSFrançois Tigeot 		if (depth < 0)
986e3adcf8fSFrançois Tigeot 			return depth;
987e3adcf8fSFrançois Tigeot 
988e3adcf8fSFrançois Tigeot 		/* ignore UV planes */
989e3adcf8fSFrançois Tigeot 		rec->stride_UV = 0;
990e3adcf8fSFrançois Tigeot 		rec->offset_U = 0;
991e3adcf8fSFrançois Tigeot 		rec->offset_V = 0;
992e3adcf8fSFrançois Tigeot 		/* check pixel alignment */
993e3adcf8fSFrançois Tigeot 		if (rec->offset_Y % depth)
994e3adcf8fSFrançois Tigeot 			return -EINVAL;
995e3adcf8fSFrançois Tigeot 		break;
996e3adcf8fSFrançois Tigeot 
997e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV_PLANAR:
998e3adcf8fSFrançois Tigeot 		if (uv_vscale < 0 || uv_hscale < 0)
999e3adcf8fSFrançois Tigeot 			return -EINVAL;
1000e3adcf8fSFrançois Tigeot 		/* no offset restrictions for planar formats */
1001e3adcf8fSFrançois Tigeot 		break;
1002e3adcf8fSFrançois Tigeot 
1003e3adcf8fSFrançois Tigeot 	default:
1004e3adcf8fSFrançois Tigeot 		return -EINVAL;
1005e3adcf8fSFrançois Tigeot 	}
1006e3adcf8fSFrançois Tigeot 
1007e3adcf8fSFrançois Tigeot 	if (rec->src_width % uv_hscale)
1008e3adcf8fSFrançois Tigeot 		return -EINVAL;
1009e3adcf8fSFrançois Tigeot 
1010e3adcf8fSFrançois Tigeot 	/* stride checking */
1011e3adcf8fSFrançois Tigeot 	if (IS_I830(dev) || IS_845G(dev))
1012e3adcf8fSFrançois Tigeot 		stride_mask = 255;
1013e3adcf8fSFrançois Tigeot 	else
1014e3adcf8fSFrançois Tigeot 		stride_mask = 63;
1015e3adcf8fSFrançois Tigeot 
1016e3adcf8fSFrançois Tigeot 	if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
1017e3adcf8fSFrançois Tigeot 		return -EINVAL;
1018e3adcf8fSFrançois Tigeot 	if (IS_GEN4(dev) && rec->stride_Y < 512)
1019e3adcf8fSFrançois Tigeot 		return -EINVAL;
1020e3adcf8fSFrançois Tigeot 
1021e3adcf8fSFrançois Tigeot 	tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ?
1022e3adcf8fSFrançois Tigeot 		4096 : 8192;
1023e3adcf8fSFrançois Tigeot 	if (rec->stride_Y > tmp || rec->stride_UV > 2*1024)
1024e3adcf8fSFrançois Tigeot 		return -EINVAL;
1025e3adcf8fSFrançois Tigeot 
1026e3adcf8fSFrançois Tigeot 	/* check buffer dimensions */
1027e3adcf8fSFrançois Tigeot 	switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
1028e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_RGB:
1029e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV_PACKED:
1030e3adcf8fSFrançois Tigeot 		/* always 4 Y values per depth pixels */
1031e3adcf8fSFrançois Tigeot 		if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y)
1032e3adcf8fSFrançois Tigeot 			return -EINVAL;
1033e3adcf8fSFrançois Tigeot 
1034e3adcf8fSFrançois Tigeot 		tmp = rec->stride_Y*rec->src_height;
1035e3adcf8fSFrançois Tigeot 		if (rec->offset_Y + tmp > new_bo->base.size)
1036e3adcf8fSFrançois Tigeot 			return -EINVAL;
1037e3adcf8fSFrançois Tigeot 		break;
1038e3adcf8fSFrançois Tigeot 
1039e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV_PLANAR:
1040e3adcf8fSFrançois Tigeot 		if (rec->src_width > rec->stride_Y)
1041e3adcf8fSFrançois Tigeot 			return -EINVAL;
1042e3adcf8fSFrançois Tigeot 		if (rec->src_width/uv_hscale > rec->stride_UV)
1043e3adcf8fSFrançois Tigeot 			return -EINVAL;
1044e3adcf8fSFrançois Tigeot 
1045e3adcf8fSFrançois Tigeot 		tmp = rec->stride_Y * rec->src_height;
1046e3adcf8fSFrançois Tigeot 		if (rec->offset_Y + tmp > new_bo->base.size)
1047e3adcf8fSFrançois Tigeot 			return -EINVAL;
1048e3adcf8fSFrançois Tigeot 
1049e3adcf8fSFrançois Tigeot 		tmp = rec->stride_UV * (rec->src_height / uv_vscale);
1050e3adcf8fSFrançois Tigeot 		if (rec->offset_U + tmp > new_bo->base.size ||
1051e3adcf8fSFrançois Tigeot 		    rec->offset_V + tmp > new_bo->base.size)
1052e3adcf8fSFrançois Tigeot 			return -EINVAL;
1053e3adcf8fSFrançois Tigeot 		break;
1054e3adcf8fSFrançois Tigeot 	}
1055e3adcf8fSFrançois Tigeot 
1056e3adcf8fSFrançois Tigeot 	return 0;
1057e3adcf8fSFrançois Tigeot }
1058e3adcf8fSFrançois Tigeot 
1059e3adcf8fSFrançois Tigeot /**
1060e3adcf8fSFrançois Tigeot  * Return the pipe currently connected to the panel fitter,
1061e3adcf8fSFrançois Tigeot  * or -1 if the panel fitter is not present or not in use
1062e3adcf8fSFrançois Tigeot  */
1063e3adcf8fSFrançois Tigeot static int intel_panel_fitter_pipe(struct drm_device *dev)
1064e3adcf8fSFrançois Tigeot {
1065e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1066e3adcf8fSFrançois Tigeot 	u32  pfit_control;
1067e3adcf8fSFrançois Tigeot 
1068e3adcf8fSFrançois Tigeot 	/* i830 doesn't have a panel fitter */
10699edbd4a0SFrançois Tigeot 	if (INTEL_INFO(dev)->gen <= 3 && (IS_I830(dev) || !IS_MOBILE(dev)))
1070e3adcf8fSFrançois Tigeot 		return -1;
1071e3adcf8fSFrançois Tigeot 
1072e3adcf8fSFrançois Tigeot 	pfit_control = I915_READ(PFIT_CONTROL);
1073e3adcf8fSFrançois Tigeot 
1074e3adcf8fSFrançois Tigeot 	/* See if the panel fitter is in use */
1075e3adcf8fSFrançois Tigeot 	if ((pfit_control & PFIT_ENABLE) == 0)
1076e3adcf8fSFrançois Tigeot 		return -1;
1077e3adcf8fSFrançois Tigeot 
1078e3adcf8fSFrançois Tigeot 	/* 965 can place panel fitter on either pipe */
1079e3adcf8fSFrançois Tigeot 	if (IS_GEN4(dev))
1080e3adcf8fSFrançois Tigeot 		return (pfit_control >> 29) & 0x3;
1081e3adcf8fSFrançois Tigeot 
1082e3adcf8fSFrançois Tigeot 	/* older chips can only use pipe 1 */
1083e3adcf8fSFrançois Tigeot 	return 1;
1084e3adcf8fSFrançois Tigeot }
1085e3adcf8fSFrançois Tigeot 
1086e3adcf8fSFrançois Tigeot int intel_overlay_put_image(struct drm_device *dev, void *data,
1087e3adcf8fSFrançois Tigeot 			    struct drm_file *file_priv)
1088e3adcf8fSFrançois Tigeot {
1089e3adcf8fSFrançois Tigeot 	struct drm_intel_overlay_put_image *put_image_rec = data;
1090ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1091e3adcf8fSFrançois Tigeot 	struct intel_overlay *overlay;
109224edb884SFrançois Tigeot 	struct drm_crtc *drmmode_crtc;
1093e3adcf8fSFrançois Tigeot 	struct intel_crtc *crtc;
1094e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *new_bo;
1095e3adcf8fSFrançois Tigeot 	struct put_image_params *params;
1096e3adcf8fSFrançois Tigeot 	int ret;
1097e3adcf8fSFrançois Tigeot 
1098e3adcf8fSFrançois Tigeot 	overlay = dev_priv->overlay;
1099e3adcf8fSFrançois Tigeot 	if (!overlay) {
1100e3adcf8fSFrançois Tigeot 		DRM_DEBUG("userspace bug: no overlay\n");
1101e3adcf8fSFrançois Tigeot 		return -ENODEV;
1102e3adcf8fSFrançois Tigeot 	}
1103e3adcf8fSFrançois Tigeot 
1104e3adcf8fSFrançois Tigeot 	if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) {
1105a2fdbec6SFrançois Tigeot 		drm_modeset_lock_all(dev);
1106a2fdbec6SFrançois Tigeot 		mutex_lock(&dev->struct_mutex);
1107e3adcf8fSFrançois Tigeot 
1108e3adcf8fSFrançois Tigeot 		ret = intel_overlay_switch_off(overlay);
1109e3adcf8fSFrançois Tigeot 
1110a2fdbec6SFrançois Tigeot 		mutex_unlock(&dev->struct_mutex);
1111a2fdbec6SFrançois Tigeot 		drm_modeset_unlock_all(dev);
1112e3adcf8fSFrançois Tigeot 
1113e3adcf8fSFrançois Tigeot 		return ret;
1114e3adcf8fSFrançois Tigeot 	}
1115e3adcf8fSFrançois Tigeot 
11169edbd4a0SFrançois Tigeot 	params = kmalloc(sizeof(*params), M_DRM, M_WAITOK);
1117e3440f96SFrançois Tigeot 	if (!params)
1118e3440f96SFrançois Tigeot 		return -ENOMEM;
1119e3adcf8fSFrançois Tigeot 
112024edb884SFrançois Tigeot 	drmmode_crtc = drm_crtc_find(dev, put_image_rec->crtc_id);
112124edb884SFrançois Tigeot 	if (!drmmode_crtc) {
1122e3adcf8fSFrançois Tigeot 		ret = -ENOENT;
1123e3adcf8fSFrançois Tigeot 		goto out_free;
1124e3adcf8fSFrançois Tigeot 	}
112524edb884SFrançois Tigeot 	crtc = to_intel_crtc(drmmode_crtc);
1126e3adcf8fSFrançois Tigeot 
1127e3adcf8fSFrançois Tigeot 	new_bo = to_intel_bo(drm_gem_object_lookup(dev, file_priv,
1128e3adcf8fSFrançois Tigeot 						   put_image_rec->bo_handle));
1129e3adcf8fSFrançois Tigeot 	if (&new_bo->base == NULL) {
1130e3adcf8fSFrançois Tigeot 		ret = -ENOENT;
1131e3adcf8fSFrançois Tigeot 		goto out_free;
1132e3adcf8fSFrançois Tigeot 	}
1133e3adcf8fSFrançois Tigeot 
1134a2fdbec6SFrançois Tigeot 	drm_modeset_lock_all(dev);
1135a2fdbec6SFrançois Tigeot 	mutex_lock(&dev->struct_mutex);
1136e3adcf8fSFrançois Tigeot 
1137e3adcf8fSFrançois Tigeot 	if (new_bo->tiling_mode) {
1138ba55f2f5SFrançois Tigeot 		DRM_DEBUG_KMS("buffer used for overlay image can not be tiled\n");
1139e3adcf8fSFrançois Tigeot 		ret = -EINVAL;
1140e3adcf8fSFrançois Tigeot 		goto out_unlock;
1141e3adcf8fSFrançois Tigeot 	}
1142e3adcf8fSFrançois Tigeot 
1143e3adcf8fSFrançois Tigeot 	ret = intel_overlay_recover_from_interrupt(overlay);
1144e3adcf8fSFrançois Tigeot 	if (ret != 0)
1145e3adcf8fSFrançois Tigeot 		goto out_unlock;
1146e3adcf8fSFrançois Tigeot 
1147e3adcf8fSFrançois Tigeot 	if (overlay->crtc != crtc) {
1148e3adcf8fSFrançois Tigeot 		struct drm_display_mode *mode = &crtc->base.mode;
1149e3adcf8fSFrançois Tigeot 		ret = intel_overlay_switch_off(overlay);
1150e3adcf8fSFrançois Tigeot 		if (ret != 0)
1151e3adcf8fSFrançois Tigeot 			goto out_unlock;
1152e3adcf8fSFrançois Tigeot 
1153e3adcf8fSFrançois Tigeot 		ret = check_overlay_possible_on_crtc(overlay, crtc);
1154e3adcf8fSFrançois Tigeot 		if (ret != 0)
1155e3adcf8fSFrançois Tigeot 			goto out_unlock;
1156e3adcf8fSFrançois Tigeot 
1157e3adcf8fSFrançois Tigeot 		overlay->crtc = crtc;
1158e3adcf8fSFrançois Tigeot 		crtc->overlay = overlay;
1159e3adcf8fSFrançois Tigeot 
1160e3adcf8fSFrançois Tigeot 		/* line too wide, i.e. one-line-mode */
1161e3adcf8fSFrançois Tigeot 		if (mode->hdisplay > 1024 &&
1162e3adcf8fSFrançois Tigeot 		    intel_panel_fitter_pipe(dev) == crtc->pipe) {
116319c468b4SFrançois Tigeot 			overlay->pfit_active = true;
1164e3adcf8fSFrançois Tigeot 			update_pfit_vscale_ratio(overlay);
1165e3adcf8fSFrançois Tigeot 		} else
116619c468b4SFrançois Tigeot 			overlay->pfit_active = false;
1167e3adcf8fSFrançois Tigeot 	}
1168e3adcf8fSFrançois Tigeot 
1169e3adcf8fSFrançois Tigeot 	ret = check_overlay_dst(overlay, put_image_rec);
1170e3adcf8fSFrançois Tigeot 	if (ret != 0)
1171e3adcf8fSFrançois Tigeot 		goto out_unlock;
1172e3adcf8fSFrançois Tigeot 
1173e3adcf8fSFrançois Tigeot 	if (overlay->pfit_active) {
1174e3adcf8fSFrançois Tigeot 		params->dst_y = ((((u32)put_image_rec->dst_y) << 12) /
1175e3adcf8fSFrançois Tigeot 				 overlay->pfit_vscale_ratio);
1176e3adcf8fSFrançois Tigeot 		/* shifting right rounds downwards, so add 1 */
1177e3adcf8fSFrançois Tigeot 		params->dst_h = ((((u32)put_image_rec->dst_height) << 12) /
1178e3adcf8fSFrançois Tigeot 				 overlay->pfit_vscale_ratio) + 1;
1179e3adcf8fSFrançois Tigeot 	} else {
1180e3adcf8fSFrançois Tigeot 		params->dst_y = put_image_rec->dst_y;
1181e3adcf8fSFrançois Tigeot 		params->dst_h = put_image_rec->dst_height;
1182e3adcf8fSFrançois Tigeot 	}
1183e3adcf8fSFrançois Tigeot 	params->dst_x = put_image_rec->dst_x;
1184e3adcf8fSFrançois Tigeot 	params->dst_w = put_image_rec->dst_width;
1185e3adcf8fSFrançois Tigeot 
1186e3adcf8fSFrançois Tigeot 	params->src_w = put_image_rec->src_width;
1187e3adcf8fSFrançois Tigeot 	params->src_h = put_image_rec->src_height;
1188e3adcf8fSFrançois Tigeot 	params->src_scan_w = put_image_rec->src_scan_width;
1189e3adcf8fSFrançois Tigeot 	params->src_scan_h = put_image_rec->src_scan_height;
1190e3adcf8fSFrançois Tigeot 	if (params->src_scan_h > params->src_h ||
1191e3adcf8fSFrançois Tigeot 	    params->src_scan_w > params->src_w) {
1192e3adcf8fSFrançois Tigeot 		ret = -EINVAL;
1193e3adcf8fSFrançois Tigeot 		goto out_unlock;
1194e3adcf8fSFrançois Tigeot 	}
1195e3adcf8fSFrançois Tigeot 
1196e3adcf8fSFrançois Tigeot 	ret = check_overlay_src(dev, put_image_rec, new_bo);
1197e3adcf8fSFrançois Tigeot 	if (ret != 0)
1198e3adcf8fSFrançois Tigeot 		goto out_unlock;
1199e3adcf8fSFrançois Tigeot 	params->format = put_image_rec->flags & ~I915_OVERLAY_FLAGS_MASK;
1200e3adcf8fSFrançois Tigeot 	params->stride_Y = put_image_rec->stride_Y;
1201e3adcf8fSFrançois Tigeot 	params->stride_UV = put_image_rec->stride_UV;
1202e3adcf8fSFrançois Tigeot 	params->offset_Y = put_image_rec->offset_Y;
1203e3adcf8fSFrançois Tigeot 	params->offset_U = put_image_rec->offset_U;
1204e3adcf8fSFrançois Tigeot 	params->offset_V = put_image_rec->offset_V;
1205e3adcf8fSFrançois Tigeot 
1206e3adcf8fSFrançois Tigeot 	/* Check scaling after src size to prevent a divide-by-zero. */
1207e3adcf8fSFrançois Tigeot 	ret = check_overlay_scaling(params);
1208e3adcf8fSFrançois Tigeot 	if (ret != 0)
1209e3adcf8fSFrançois Tigeot 		goto out_unlock;
1210e3adcf8fSFrançois Tigeot 
1211e3adcf8fSFrançois Tigeot 	ret = intel_overlay_do_put_image(overlay, new_bo, params);
1212e3adcf8fSFrançois Tigeot 	if (ret != 0)
1213e3adcf8fSFrançois Tigeot 		goto out_unlock;
1214e3adcf8fSFrançois Tigeot 
1215a2fdbec6SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
1216a2fdbec6SFrançois Tigeot 	drm_modeset_unlock_all(dev);
1217e3adcf8fSFrançois Tigeot 
1218158486a6SFrançois Tigeot 	kfree(params);
1219e3adcf8fSFrançois Tigeot 
1220e3adcf8fSFrançois Tigeot 	return 0;
1221e3adcf8fSFrançois Tigeot 
1222e3adcf8fSFrançois Tigeot out_unlock:
1223a2fdbec6SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
1224a2fdbec6SFrançois Tigeot 	drm_modeset_unlock_all(dev);
1225e3adcf8fSFrançois Tigeot 	drm_gem_object_unreference_unlocked(&new_bo->base);
1226e3adcf8fSFrançois Tigeot out_free:
1227158486a6SFrançois Tigeot 	kfree(params);
1228e3adcf8fSFrançois Tigeot 
1229e3adcf8fSFrançois Tigeot 	return ret;
1230e3adcf8fSFrançois Tigeot }
1231e3adcf8fSFrançois Tigeot 
1232e3adcf8fSFrançois Tigeot static void update_reg_attrs(struct intel_overlay *overlay,
1233e3440f96SFrançois Tigeot 			     struct overlay_registers __iomem *regs)
1234e3adcf8fSFrançois Tigeot {
1235e3440f96SFrançois Tigeot 	iowrite32((overlay->contrast << 18) | (overlay->brightness & 0xff),
1236e3440f96SFrançois Tigeot 		  &regs->OCLRC0);
1237e3440f96SFrançois Tigeot 	iowrite32(overlay->saturation, &regs->OCLRC1);
1238e3adcf8fSFrançois Tigeot }
1239e3adcf8fSFrançois Tigeot 
1240e3adcf8fSFrançois Tigeot static bool check_gamma_bounds(u32 gamma1, u32 gamma2)
1241e3adcf8fSFrançois Tigeot {
1242e3adcf8fSFrançois Tigeot 	int i;
1243e3adcf8fSFrançois Tigeot 
1244e3adcf8fSFrançois Tigeot 	if (gamma1 & 0xff000000 || gamma2 & 0xff000000)
1245e3adcf8fSFrançois Tigeot 		return false;
1246e3adcf8fSFrançois Tigeot 
1247e3adcf8fSFrançois Tigeot 	for (i = 0; i < 3; i++) {
1248e3adcf8fSFrançois Tigeot 		if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
1249e3adcf8fSFrançois Tigeot 			return false;
1250e3adcf8fSFrançois Tigeot 	}
1251e3adcf8fSFrançois Tigeot 
1252e3adcf8fSFrançois Tigeot 	return true;
1253e3adcf8fSFrançois Tigeot }
1254e3adcf8fSFrançois Tigeot 
1255e3adcf8fSFrançois Tigeot static bool check_gamma5_errata(u32 gamma5)
1256e3adcf8fSFrançois Tigeot {
1257e3adcf8fSFrançois Tigeot 	int i;
1258e3adcf8fSFrançois Tigeot 
1259e3adcf8fSFrançois Tigeot 	for (i = 0; i < 3; i++) {
1260e3adcf8fSFrançois Tigeot 		if (((gamma5 >> i*8) & 0xff) == 0x80)
1261e3adcf8fSFrançois Tigeot 			return false;
1262e3adcf8fSFrançois Tigeot 	}
1263e3adcf8fSFrançois Tigeot 
1264e3adcf8fSFrançois Tigeot 	return true;
1265e3adcf8fSFrançois Tigeot }
1266e3adcf8fSFrançois Tigeot 
1267e3adcf8fSFrançois Tigeot static int check_gamma(struct drm_intel_overlay_attrs *attrs)
1268e3adcf8fSFrançois Tigeot {
1269e3adcf8fSFrançois Tigeot 	if (!check_gamma_bounds(0, attrs->gamma0) ||
1270e3adcf8fSFrançois Tigeot 	    !check_gamma_bounds(attrs->gamma0, attrs->gamma1) ||
1271e3adcf8fSFrançois Tigeot 	    !check_gamma_bounds(attrs->gamma1, attrs->gamma2) ||
1272e3adcf8fSFrançois Tigeot 	    !check_gamma_bounds(attrs->gamma2, attrs->gamma3) ||
1273e3adcf8fSFrançois Tigeot 	    !check_gamma_bounds(attrs->gamma3, attrs->gamma4) ||
1274e3adcf8fSFrançois Tigeot 	    !check_gamma_bounds(attrs->gamma4, attrs->gamma5) ||
1275e3adcf8fSFrançois Tigeot 	    !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
1276e3adcf8fSFrançois Tigeot 		return -EINVAL;
1277e3adcf8fSFrançois Tigeot 
1278e3adcf8fSFrançois Tigeot 	if (!check_gamma5_errata(attrs->gamma5))
1279e3adcf8fSFrançois Tigeot 		return -EINVAL;
1280e3adcf8fSFrançois Tigeot 
1281e3adcf8fSFrançois Tigeot 	return 0;
1282e3adcf8fSFrançois Tigeot }
1283e3adcf8fSFrançois Tigeot 
1284e3adcf8fSFrançois Tigeot int intel_overlay_attrs(struct drm_device *dev, void *data,
1285e3adcf8fSFrançois Tigeot 			struct drm_file *file_priv)
1286e3adcf8fSFrançois Tigeot {
1287e3adcf8fSFrançois Tigeot 	struct drm_intel_overlay_attrs *attrs = data;
1288ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1289e3adcf8fSFrançois Tigeot 	struct intel_overlay *overlay;
1290e3440f96SFrançois Tigeot 	struct overlay_registers __iomem *regs;
1291e3adcf8fSFrançois Tigeot 	int ret;
1292e3adcf8fSFrançois Tigeot 
1293e3adcf8fSFrançois Tigeot 	overlay = dev_priv->overlay;
1294e3adcf8fSFrançois Tigeot 	if (!overlay) {
1295e3adcf8fSFrançois Tigeot 		DRM_DEBUG("userspace bug: no overlay\n");
1296e3adcf8fSFrançois Tigeot 		return -ENODEV;
1297e3adcf8fSFrançois Tigeot 	}
1298e3adcf8fSFrançois Tigeot 
1299a2fdbec6SFrançois Tigeot 	drm_modeset_lock_all(dev);
1300a2fdbec6SFrançois Tigeot 	mutex_lock(&dev->struct_mutex);
1301e3adcf8fSFrançois Tigeot 
1302e3adcf8fSFrançois Tigeot 	ret = -EINVAL;
1303e3adcf8fSFrançois Tigeot 	if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) {
1304e3adcf8fSFrançois Tigeot 		attrs->color_key  = overlay->color_key;
1305e3adcf8fSFrançois Tigeot 		attrs->brightness = overlay->brightness;
1306e3adcf8fSFrançois Tigeot 		attrs->contrast   = overlay->contrast;
1307e3adcf8fSFrançois Tigeot 		attrs->saturation = overlay->saturation;
1308e3adcf8fSFrançois Tigeot 
1309e3adcf8fSFrançois Tigeot 		if (!IS_GEN2(dev)) {
1310e3adcf8fSFrançois Tigeot 			attrs->gamma0 = I915_READ(OGAMC0);
1311e3adcf8fSFrançois Tigeot 			attrs->gamma1 = I915_READ(OGAMC1);
1312e3adcf8fSFrançois Tigeot 			attrs->gamma2 = I915_READ(OGAMC2);
1313e3adcf8fSFrançois Tigeot 			attrs->gamma3 = I915_READ(OGAMC3);
1314e3adcf8fSFrançois Tigeot 			attrs->gamma4 = I915_READ(OGAMC4);
1315e3adcf8fSFrançois Tigeot 			attrs->gamma5 = I915_READ(OGAMC5);
1316e3adcf8fSFrançois Tigeot 		}
1317e3adcf8fSFrançois Tigeot 	} else {
1318e3adcf8fSFrançois Tigeot 		if (attrs->brightness < -128 || attrs->brightness > 127)
1319e3adcf8fSFrançois Tigeot 			goto out_unlock;
1320e3adcf8fSFrançois Tigeot 		if (attrs->contrast > 255)
1321e3adcf8fSFrançois Tigeot 			goto out_unlock;
1322e3adcf8fSFrançois Tigeot 		if (attrs->saturation > 1023)
1323e3adcf8fSFrançois Tigeot 			goto out_unlock;
1324e3adcf8fSFrançois Tigeot 
1325e3adcf8fSFrançois Tigeot 		overlay->color_key  = attrs->color_key;
1326e3adcf8fSFrançois Tigeot 		overlay->brightness = attrs->brightness;
1327e3adcf8fSFrançois Tigeot 		overlay->contrast   = attrs->contrast;
1328e3adcf8fSFrançois Tigeot 		overlay->saturation = attrs->saturation;
1329e3adcf8fSFrançois Tigeot 
1330e3adcf8fSFrançois Tigeot 		regs = intel_overlay_map_regs(overlay);
1331e3adcf8fSFrançois Tigeot 		if (!regs) {
1332e3adcf8fSFrançois Tigeot 			ret = -ENOMEM;
1333e3adcf8fSFrançois Tigeot 			goto out_unlock;
1334e3adcf8fSFrançois Tigeot 		}
1335e3adcf8fSFrançois Tigeot 
1336e3adcf8fSFrançois Tigeot 		update_reg_attrs(overlay, regs);
1337e3adcf8fSFrançois Tigeot 
1338e3adcf8fSFrançois Tigeot 		intel_overlay_unmap_regs(overlay, regs);
1339e3adcf8fSFrançois Tigeot 
1340e3adcf8fSFrançois Tigeot 		if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) {
1341e3adcf8fSFrançois Tigeot 			if (IS_GEN2(dev))
1342e3adcf8fSFrançois Tigeot 				goto out_unlock;
1343e3adcf8fSFrançois Tigeot 
1344e3adcf8fSFrançois Tigeot 			if (overlay->active) {
1345e3adcf8fSFrançois Tigeot 				ret = -EBUSY;
1346e3adcf8fSFrançois Tigeot 				goto out_unlock;
1347e3adcf8fSFrançois Tigeot 			}
1348e3adcf8fSFrançois Tigeot 
1349e3adcf8fSFrançois Tigeot 			ret = check_gamma(attrs);
1350e3adcf8fSFrançois Tigeot 			if (ret)
1351e3adcf8fSFrançois Tigeot 				goto out_unlock;
1352e3adcf8fSFrançois Tigeot 
1353e3adcf8fSFrançois Tigeot 			I915_WRITE(OGAMC0, attrs->gamma0);
1354e3adcf8fSFrançois Tigeot 			I915_WRITE(OGAMC1, attrs->gamma1);
1355e3adcf8fSFrançois Tigeot 			I915_WRITE(OGAMC2, attrs->gamma2);
1356e3adcf8fSFrançois Tigeot 			I915_WRITE(OGAMC3, attrs->gamma3);
1357e3adcf8fSFrançois Tigeot 			I915_WRITE(OGAMC4, attrs->gamma4);
1358e3adcf8fSFrançois Tigeot 			I915_WRITE(OGAMC5, attrs->gamma5);
1359e3adcf8fSFrançois Tigeot 		}
1360e3adcf8fSFrançois Tigeot 	}
136119c468b4SFrançois Tigeot 	overlay->color_key_enabled = (attrs->flags & I915_OVERLAY_DISABLE_DEST_COLORKEY) == 0;
1362e3adcf8fSFrançois Tigeot 
1363e3adcf8fSFrançois Tigeot 	ret = 0;
1364e3adcf8fSFrançois Tigeot out_unlock:
1365a2fdbec6SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
1366a2fdbec6SFrançois Tigeot 	drm_modeset_unlock_all(dev);
1367e3adcf8fSFrançois Tigeot 
1368e3adcf8fSFrançois Tigeot 	return ret;
1369e3adcf8fSFrançois Tigeot }
1370e3adcf8fSFrançois Tigeot 
1371e3adcf8fSFrançois Tigeot void intel_setup_overlay(struct drm_device *dev)
1372e3adcf8fSFrançois Tigeot {
1373ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1374e3adcf8fSFrançois Tigeot 	struct intel_overlay *overlay;
1375e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *reg_bo;
1376e3440f96SFrançois Tigeot 	struct overlay_registers __iomem *regs;
1377e3adcf8fSFrançois Tigeot 	int ret;
1378e3adcf8fSFrançois Tigeot 
1379e3adcf8fSFrançois Tigeot 	if (!HAS_OVERLAY(dev))
1380e3adcf8fSFrançois Tigeot 		return;
1381e3adcf8fSFrançois Tigeot 
13829edbd4a0SFrançois Tigeot 	overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
1383e3440f96SFrançois Tigeot 	if (!overlay)
1384e3440f96SFrançois Tigeot 		return;
1385e3440f96SFrançois Tigeot 
1386a2fdbec6SFrançois Tigeot 	mutex_lock(&dev->struct_mutex);
1387e3440f96SFrançois Tigeot 	if (WARN_ON(dev_priv->overlay))
1388e3adcf8fSFrançois Tigeot 		goto out_free;
1389e3440f96SFrançois Tigeot 
1390e3adcf8fSFrançois Tigeot 	overlay->dev = dev;
1391e3adcf8fSFrançois Tigeot 
13929edbd4a0SFrançois Tigeot 	reg_bo = NULL;
13939edbd4a0SFrançois Tigeot 	if (!OVERLAY_NEEDS_PHYSICAL(dev))
13949edbd4a0SFrançois Tigeot 		reg_bo = i915_gem_object_create_stolen(dev, PAGE_SIZE);
13959edbd4a0SFrançois Tigeot 	if (reg_bo == NULL)
1396e3adcf8fSFrançois Tigeot 		reg_bo = i915_gem_alloc_object(dev, PAGE_SIZE);
13979edbd4a0SFrançois Tigeot 	if (reg_bo == NULL)
1398e3adcf8fSFrançois Tigeot 		goto out_free;
1399e3adcf8fSFrançois Tigeot 	overlay->reg_bo = reg_bo;
1400e3adcf8fSFrançois Tigeot 
1401e3adcf8fSFrançois Tigeot 	if (OVERLAY_NEEDS_PHYSICAL(dev)) {
1402ba55f2f5SFrançois Tigeot 		ret = i915_gem_object_attach_phys(reg_bo, PAGE_SIZE);
1403e3adcf8fSFrançois Tigeot 		if (ret) {
1404e3adcf8fSFrançois Tigeot 			DRM_ERROR("failed to attach phys overlay regs\n");
1405e3adcf8fSFrançois Tigeot 			goto out_free_bo;
1406e3adcf8fSFrançois Tigeot 		}
1407ba55f2f5SFrançois Tigeot 		overlay->flip_addr = reg_bo->phys_handle->busaddr;
1408e3adcf8fSFrançois Tigeot 	} else {
1409ba55f2f5SFrançois Tigeot 		ret = i915_gem_obj_ggtt_pin(reg_bo, PAGE_SIZE, PIN_MAPPABLE);
1410e3adcf8fSFrançois Tigeot 		if (ret) {
1411e3adcf8fSFrançois Tigeot 			DRM_ERROR("failed to pin overlay register bo\n");
1412e3adcf8fSFrançois Tigeot 			goto out_free_bo;
1413e3adcf8fSFrançois Tigeot 		}
14149edbd4a0SFrançois Tigeot 		overlay->flip_addr = i915_gem_obj_ggtt_offset(reg_bo);
1415e3adcf8fSFrançois Tigeot 
1416e3adcf8fSFrançois Tigeot 		ret = i915_gem_object_set_to_gtt_domain(reg_bo, true);
1417e3adcf8fSFrançois Tigeot 		if (ret) {
1418e3adcf8fSFrançois Tigeot 			DRM_ERROR("failed to move overlay register bo into the GTT\n");
1419e3adcf8fSFrançois Tigeot 			goto out_unpin_bo;
1420e3adcf8fSFrançois Tigeot 		}
1421e3adcf8fSFrançois Tigeot 	}
1422e3adcf8fSFrançois Tigeot 
1423e3adcf8fSFrançois Tigeot 	/* init all values */
1424e3adcf8fSFrançois Tigeot 	overlay->color_key = 0x0101fe;
142519c468b4SFrançois Tigeot 	overlay->color_key_enabled = true;
1426e3adcf8fSFrançois Tigeot 	overlay->brightness = -19;
1427e3adcf8fSFrançois Tigeot 	overlay->contrast = 75;
1428e3adcf8fSFrançois Tigeot 	overlay->saturation = 146;
1429e3adcf8fSFrançois Tigeot 
1430e3adcf8fSFrançois Tigeot 	regs = intel_overlay_map_regs(overlay);
1431e3adcf8fSFrançois Tigeot 	if (!regs)
1432e3adcf8fSFrançois Tigeot 		goto out_unpin_bo;
1433e3adcf8fSFrançois Tigeot 
1434e3440f96SFrançois Tigeot 	memset_io(regs, 0, sizeof(struct overlay_registers));
1435e3adcf8fSFrançois Tigeot 	update_polyphase_filter(regs);
1436e3adcf8fSFrançois Tigeot 	update_reg_attrs(overlay, regs);
1437e3adcf8fSFrançois Tigeot 
1438e3adcf8fSFrançois Tigeot 	intel_overlay_unmap_regs(overlay, regs);
1439e3adcf8fSFrançois Tigeot 
1440e3adcf8fSFrançois Tigeot 	dev_priv->overlay = overlay;
1441a2fdbec6SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
1442e3440f96SFrançois Tigeot 	DRM_INFO("initialized overlay support\n");
1443e3adcf8fSFrançois Tigeot 	return;
1444e3adcf8fSFrançois Tigeot 
1445e3adcf8fSFrançois Tigeot out_unpin_bo:
1446e3adcf8fSFrançois Tigeot 	if (!OVERLAY_NEEDS_PHYSICAL(dev))
1447ba55f2f5SFrançois Tigeot 		i915_gem_object_ggtt_unpin(reg_bo);
1448e3adcf8fSFrançois Tigeot out_free_bo:
1449e3adcf8fSFrançois Tigeot 	drm_gem_object_unreference(&reg_bo->base);
1450e3adcf8fSFrançois Tigeot out_free:
1451a2fdbec6SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
1452158486a6SFrançois Tigeot 	kfree(overlay);
1453e3adcf8fSFrançois Tigeot 	return;
1454e3adcf8fSFrançois Tigeot }
1455e3adcf8fSFrançois Tigeot 
1456e3adcf8fSFrançois Tigeot void intel_cleanup_overlay(struct drm_device *dev)
1457e3adcf8fSFrançois Tigeot {
1458ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1459e3adcf8fSFrançois Tigeot 
1460e3adcf8fSFrançois Tigeot 	if (!dev_priv->overlay)
1461e3adcf8fSFrançois Tigeot 		return;
1462e3adcf8fSFrançois Tigeot 
1463e3adcf8fSFrançois Tigeot 	/* The bo's should be free'd by the generic code already.
1464e3adcf8fSFrançois Tigeot 	 * Furthermore modesetting teardown happens beforehand so the
1465e3adcf8fSFrançois Tigeot 	 * hardware should be off already */
146619c468b4SFrançois Tigeot 	WARN_ON(dev_priv->overlay->active);
1467e3adcf8fSFrançois Tigeot 
1468e3adcf8fSFrançois Tigeot 	drm_gem_object_unreference_unlocked(&dev_priv->overlay->reg_bo->base);
1469158486a6SFrançois Tigeot 	kfree(dev_priv->overlay);
1470e3adcf8fSFrançois Tigeot }
1471e3adcf8fSFrançois Tigeot 
1472e3adcf8fSFrançois Tigeot struct intel_overlay_error_state {
1473e3adcf8fSFrançois Tigeot 	struct overlay_registers regs;
1474e3adcf8fSFrançois Tigeot 	unsigned long base;
1475e3adcf8fSFrançois Tigeot 	u32 dovsta;
1476e3adcf8fSFrançois Tigeot 	u32 isr;
1477e3adcf8fSFrançois Tigeot };
1478e3adcf8fSFrançois Tigeot 
14799edbd4a0SFrançois Tigeot #if 0
1480e3440f96SFrançois Tigeot static struct overlay_registers __iomem *
1481e3440f96SFrançois Tigeot intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
1482e3440f96SFrançois Tigeot {
1483ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = overlay->dev->dev_private;
1484e3440f96SFrançois Tigeot 	struct overlay_registers __iomem *regs;
1485e3440f96SFrançois Tigeot 
1486e3440f96SFrançois Tigeot 	if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
1487e3440f96SFrançois Tigeot 		/* Cast to make sparse happy, but it's wc memory anyway, so
1488e3440f96SFrançois Tigeot 		 * equivalent to the wc io mapping on X86. */
1489e3440f96SFrançois Tigeot 		regs = (struct overlay_registers __iomem *)
14902c9916cdSFrançois Tigeot 			overlay->reg_bo->phys_handle->vaddr;
1491e3440f96SFrançois Tigeot 	else
1492a2fdbec6SFrançois Tigeot 		regs = io_mapping_map_atomic_wc(dev_priv->gtt.mappable,
14939edbd4a0SFrançois Tigeot 						i915_gem_obj_ggtt_offset(overlay->reg_bo));
1494e3440f96SFrançois Tigeot 
1495e3440f96SFrançois Tigeot 	return regs;
1496e3440f96SFrançois Tigeot }
1497e3440f96SFrançois Tigeot 
1498e3440f96SFrançois Tigeot static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay,
1499e3440f96SFrançois Tigeot 					struct overlay_registers __iomem *regs)
1500e3440f96SFrançois Tigeot {
1501e3440f96SFrançois Tigeot 	if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
1502e3440f96SFrançois Tigeot 		io_mapping_unmap_atomic(regs);
1503e3440f96SFrançois Tigeot }
1504e3440f96SFrançois Tigeot 
1505ba55f2f5SFrançois Tigeot 
1506e3adcf8fSFrançois Tigeot struct intel_overlay_error_state *
1507e3adcf8fSFrançois Tigeot intel_overlay_capture_error_state(struct drm_device *dev)
1508e3adcf8fSFrançois Tigeot {
1509ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1510e3adcf8fSFrançois Tigeot 	struct intel_overlay *overlay = dev_priv->overlay;
1511e3adcf8fSFrançois Tigeot 	struct intel_overlay_error_state *error;
1512e3adcf8fSFrançois Tigeot 	struct overlay_registers __iomem *regs;
1513e3adcf8fSFrançois Tigeot 
1514e3adcf8fSFrançois Tigeot 	if (!overlay || !overlay->active)
1515e3adcf8fSFrançois Tigeot 		return NULL;
1516e3adcf8fSFrançois Tigeot 
1517ba55f2f5SFrançois Tigeot 	error = kmalloc(sizeof(*error), GFP_ATOMIC);
1518e3adcf8fSFrançois Tigeot 	if (error == NULL)
1519e3adcf8fSFrançois Tigeot 		return NULL;
1520e3adcf8fSFrançois Tigeot 
1521e3adcf8fSFrançois Tigeot 	error->dovsta = I915_READ(DOVSTA);
1522e3adcf8fSFrançois Tigeot 	error->isr = I915_READ(ISR);
1523e3adcf8fSFrançois Tigeot 	if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
15242c9916cdSFrançois Tigeot 		error->base = (__force long)overlay->reg_bo->phys_handle->vaddr;
1525e3adcf8fSFrançois Tigeot 	else
15269edbd4a0SFrançois Tigeot 		error->base = i915_gem_obj_ggtt_offset(overlay->reg_bo);
1527e3adcf8fSFrançois Tigeot 
1528e3440f96SFrançois Tigeot 	regs = intel_overlay_map_regs_atomic(overlay);
1529e3adcf8fSFrançois Tigeot 	if (!regs)
1530e3adcf8fSFrançois Tigeot 		goto err;
1531e3adcf8fSFrançois Tigeot 
1532e3440f96SFrançois Tigeot 	memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers));
1533e3440f96SFrançois Tigeot 	intel_overlay_unmap_regs_atomic(overlay, regs);
1534e3adcf8fSFrançois Tigeot 
1535e3440f96SFrançois Tigeot 	return error;
1536e3adcf8fSFrançois Tigeot 
1537e3adcf8fSFrançois Tigeot err:
1538158486a6SFrançois Tigeot 	kfree(error);
1539e3440f96SFrançois Tigeot 	return NULL;
1540e3adcf8fSFrançois Tigeot }
1541e3adcf8fSFrançois Tigeot 
1542e3adcf8fSFrançois Tigeot void
15435d0b1887SFrançois Tigeot intel_overlay_print_error_state(struct drm_i915_error_state_buf *m,
15445d0b1887SFrançois Tigeot 				struct intel_overlay_error_state *error)
1545e3adcf8fSFrançois Tigeot {
15465d0b1887SFrançois Tigeot 	i915_error_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",
1547e3adcf8fSFrançois Tigeot 			  error->dovsta, error->isr);
15485d0b1887SFrançois Tigeot 	i915_error_printf(m, "  Register file at 0x%08lx:\n",
1549e3adcf8fSFrançois Tigeot 			  error->base);
1550e3adcf8fSFrançois Tigeot 
15515d0b1887SFrançois Tigeot #define P(x) i915_error_printf(m, "    " #x ":	0x%08x\n", error->regs.x)
1552e3adcf8fSFrançois Tigeot 	P(OBUF_0Y);
1553e3adcf8fSFrançois Tigeot 	P(OBUF_1Y);
1554e3adcf8fSFrançois Tigeot 	P(OBUF_0U);
1555e3adcf8fSFrançois Tigeot 	P(OBUF_0V);
1556e3adcf8fSFrançois Tigeot 	P(OBUF_1U);
1557e3adcf8fSFrançois Tigeot 	P(OBUF_1V);
1558e3adcf8fSFrançois Tigeot 	P(OSTRIDE);
1559e3adcf8fSFrançois Tigeot 	P(YRGB_VPH);
1560e3adcf8fSFrançois Tigeot 	P(UV_VPH);
1561e3adcf8fSFrançois Tigeot 	P(HORZ_PH);
1562e3adcf8fSFrançois Tigeot 	P(INIT_PHS);
1563e3adcf8fSFrançois Tigeot 	P(DWINPOS);
1564e3adcf8fSFrançois Tigeot 	P(DWINSZ);
1565e3adcf8fSFrançois Tigeot 	P(SWIDTH);
1566e3adcf8fSFrançois Tigeot 	P(SWIDTHSW);
1567e3adcf8fSFrançois Tigeot 	P(SHEIGHT);
1568e3adcf8fSFrançois Tigeot 	P(YRGBSCALE);
1569e3adcf8fSFrançois Tigeot 	P(UVSCALE);
1570e3adcf8fSFrançois Tigeot 	P(OCLRC0);
1571e3adcf8fSFrançois Tigeot 	P(OCLRC1);
1572e3adcf8fSFrançois Tigeot 	P(DCLRKV);
1573e3adcf8fSFrançois Tigeot 	P(DCLRKM);
1574e3adcf8fSFrançois Tigeot 	P(SCLRKVH);
1575e3adcf8fSFrançois Tigeot 	P(SCLRKVL);
1576e3adcf8fSFrançois Tigeot 	P(SCLRKEN);
1577e3adcf8fSFrançois Tigeot 	P(OCONFIG);
1578e3adcf8fSFrançois Tigeot 	P(OCMD);
1579e3adcf8fSFrançois Tigeot 	P(OSTART_0Y);
1580e3adcf8fSFrançois Tigeot 	P(OSTART_1Y);
1581e3adcf8fSFrançois Tigeot 	P(OSTART_0U);
1582e3adcf8fSFrançois Tigeot 	P(OSTART_0V);
1583e3adcf8fSFrançois Tigeot 	P(OSTART_1U);
1584e3adcf8fSFrançois Tigeot 	P(OSTART_1V);
1585e3adcf8fSFrançois Tigeot 	P(OTILEOFF_0Y);
1586e3adcf8fSFrançois Tigeot 	P(OTILEOFF_1Y);
1587e3adcf8fSFrançois Tigeot 	P(OTILEOFF_0U);
1588e3adcf8fSFrançois Tigeot 	P(OTILEOFF_0V);
1589e3adcf8fSFrançois Tigeot 	P(OTILEOFF_1U);
1590e3adcf8fSFrançois Tigeot 	P(OTILEOFF_1V);
1591e3adcf8fSFrançois Tigeot 	P(FASTHSCALE);
1592e3adcf8fSFrançois Tigeot 	P(UVSCALEV);
1593e3adcf8fSFrançois Tigeot #undef P
1594e3adcf8fSFrançois Tigeot }
15953f2f609dSFrançois Tigeot #endif
1596