xref: /dflybsd-src/sys/dev/drm/i915/intel_overlay.c (revision 1e12ee3baa16120663cde9c6c4c8e92b69b00794)
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"
3371f41f3eSFrançois Tigeot #include "intel_frontbuffer.h"
34e3adcf8fSFrançois Tigeot 
35e3adcf8fSFrançois Tigeot /* Limits for overlay size. According to intel doc, the real limits are:
36e3adcf8fSFrançois Tigeot  * Y width: 4095, UV width (planar): 2047, Y height: 2047,
37e3adcf8fSFrançois Tigeot  * UV width (planar): * 1023. But the xorg thinks 2048 for height and width. Use
38e3adcf8fSFrançois Tigeot  * the mininum of both.  */
39e3adcf8fSFrançois Tigeot #define IMAGE_MAX_WIDTH		2048
40e3adcf8fSFrançois Tigeot #define IMAGE_MAX_HEIGHT	2046 /* 2 * 1023 */
41e3adcf8fSFrançois Tigeot /* on 830 and 845 these large limits result in the card hanging */
42e3adcf8fSFrançois Tigeot #define IMAGE_MAX_WIDTH_LEGACY	1024
43e3adcf8fSFrançois Tigeot #define IMAGE_MAX_HEIGHT_LEGACY	1088
44e3adcf8fSFrançois Tigeot 
45e3adcf8fSFrançois Tigeot /* overlay register definitions */
46e3adcf8fSFrançois Tigeot /* OCMD register */
47e3adcf8fSFrançois Tigeot #define OCMD_TILED_SURFACE	(0x1<<19)
48e3adcf8fSFrançois Tigeot #define OCMD_MIRROR_MASK	(0x3<<17)
49e3adcf8fSFrançois Tigeot #define OCMD_MIRROR_MODE	(0x3<<17)
50e3adcf8fSFrançois Tigeot #define OCMD_MIRROR_HORIZONTAL	(0x1<<17)
51e3adcf8fSFrançois Tigeot #define OCMD_MIRROR_VERTICAL	(0x2<<17)
52e3adcf8fSFrançois Tigeot #define OCMD_MIRROR_BOTH	(0x3<<17)
53e3adcf8fSFrançois Tigeot #define OCMD_BYTEORDER_MASK	(0x3<<14) /* zero for YUYV or FOURCC YUY2 */
54e3adcf8fSFrançois Tigeot #define OCMD_UV_SWAP		(0x1<<14) /* YVYU */
55e3adcf8fSFrançois Tigeot #define OCMD_Y_SWAP		(0x2<<14) /* UYVY or FOURCC UYVY */
56e3adcf8fSFrançois Tigeot #define OCMD_Y_AND_UV_SWAP	(0x3<<14) /* VYUY */
57e3adcf8fSFrançois Tigeot #define OCMD_SOURCE_FORMAT_MASK (0xf<<10)
58e3adcf8fSFrançois Tigeot #define OCMD_RGB_888		(0x1<<10) /* not in i965 Intel docs */
59e3adcf8fSFrançois Tigeot #define OCMD_RGB_555		(0x2<<10) /* not in i965 Intel docs */
60e3adcf8fSFrançois Tigeot #define OCMD_RGB_565		(0x3<<10) /* not in i965 Intel docs */
61e3adcf8fSFrançois Tigeot #define OCMD_YUV_422_PACKED	(0x8<<10)
62e3adcf8fSFrançois Tigeot #define OCMD_YUV_411_PACKED	(0x9<<10) /* not in i965 Intel docs */
63e3adcf8fSFrançois Tigeot #define OCMD_YUV_420_PLANAR	(0xc<<10)
64e3adcf8fSFrançois Tigeot #define OCMD_YUV_422_PLANAR	(0xd<<10)
65e3adcf8fSFrançois Tigeot #define OCMD_YUV_410_PLANAR	(0xe<<10) /* also 411 */
66e3adcf8fSFrançois Tigeot #define OCMD_TVSYNCFLIP_PARITY	(0x1<<9)
67e3adcf8fSFrançois Tigeot #define OCMD_TVSYNCFLIP_ENABLE	(0x1<<7)
68e3adcf8fSFrançois Tigeot #define OCMD_BUF_TYPE_MASK	(0x1<<5)
69e3adcf8fSFrançois Tigeot #define OCMD_BUF_TYPE_FRAME	(0x0<<5)
70e3adcf8fSFrançois Tigeot #define OCMD_BUF_TYPE_FIELD	(0x1<<5)
71e3adcf8fSFrançois Tigeot #define OCMD_TEST_MODE		(0x1<<4)
72e3adcf8fSFrançois Tigeot #define OCMD_BUFFER_SELECT	(0x3<<2)
73e3adcf8fSFrançois Tigeot #define OCMD_BUFFER0		(0x0<<2)
74e3adcf8fSFrançois Tigeot #define OCMD_BUFFER1		(0x1<<2)
75e3adcf8fSFrançois Tigeot #define OCMD_FIELD_SELECT	(0x1<<2)
76e3adcf8fSFrançois Tigeot #define OCMD_FIELD0		(0x0<<1)
77e3adcf8fSFrançois Tigeot #define OCMD_FIELD1		(0x1<<1)
78e3adcf8fSFrançois Tigeot #define OCMD_ENABLE		(0x1<<0)
79e3adcf8fSFrançois Tigeot 
80e3adcf8fSFrançois Tigeot /* OCONFIG register */
81e3adcf8fSFrançois Tigeot #define OCONF_PIPE_MASK		(0x1<<18)
82e3adcf8fSFrançois Tigeot #define OCONF_PIPE_A		(0x0<<18)
83e3adcf8fSFrançois Tigeot #define OCONF_PIPE_B		(0x1<<18)
84e3adcf8fSFrançois Tigeot #define OCONF_GAMMA2_ENABLE	(0x1<<16)
85e3adcf8fSFrançois Tigeot #define OCONF_CSC_MODE_BT601	(0x0<<5)
86e3adcf8fSFrançois Tigeot #define OCONF_CSC_MODE_BT709	(0x1<<5)
87e3adcf8fSFrançois Tigeot #define OCONF_CSC_BYPASS	(0x1<<4)
88e3adcf8fSFrançois Tigeot #define OCONF_CC_OUT_8BIT	(0x1<<3)
89e3adcf8fSFrançois Tigeot #define OCONF_TEST_MODE		(0x1<<2)
90e3adcf8fSFrançois Tigeot #define OCONF_THREE_LINE_BUFFER	(0x1<<0)
91e3adcf8fSFrançois Tigeot #define OCONF_TWO_LINE_BUFFER	(0x0<<0)
92e3adcf8fSFrançois Tigeot 
93e3adcf8fSFrançois Tigeot /* DCLRKM (dst-key) register */
94e3adcf8fSFrançois Tigeot #define DST_KEY_ENABLE		(0x1<<31)
95e3adcf8fSFrançois Tigeot #define CLK_RGB24_MASK		0x0
96e3adcf8fSFrançois Tigeot #define CLK_RGB16_MASK		0x070307
97e3adcf8fSFrançois Tigeot #define CLK_RGB15_MASK		0x070707
98e3adcf8fSFrançois Tigeot #define CLK_RGB8I_MASK		0xffffff
99e3adcf8fSFrançois Tigeot 
100e3adcf8fSFrançois Tigeot #define RGB16_TO_COLORKEY(c) \
101e3adcf8fSFrançois Tigeot 	(((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3))
102e3adcf8fSFrançois Tigeot #define RGB15_TO_COLORKEY(c) \
103e3adcf8fSFrançois Tigeot 	(((c & 0x7c00) << 9) | ((c & 0x03E0) << 6) | ((c & 0x001F) << 3))
104e3adcf8fSFrançois Tigeot 
105e3adcf8fSFrançois Tigeot /* overlay flip addr flag */
106e3adcf8fSFrançois Tigeot #define OFC_UPDATE		0x1
107e3adcf8fSFrançois Tigeot 
108e3adcf8fSFrançois Tigeot /* polyphase filter coefficients */
109e3adcf8fSFrançois Tigeot #define N_HORIZ_Y_TAPS          5
110e3adcf8fSFrançois Tigeot #define N_VERT_Y_TAPS           3
111e3adcf8fSFrançois Tigeot #define N_HORIZ_UV_TAPS         3
112e3adcf8fSFrançois Tigeot #define N_VERT_UV_TAPS          3
113e3adcf8fSFrançois Tigeot #define N_PHASES                17
114e3adcf8fSFrançois Tigeot #define MAX_TAPS                5
115e3adcf8fSFrançois Tigeot 
116e3adcf8fSFrançois Tigeot /* memory bufferd overlay registers */
117e3adcf8fSFrançois Tigeot struct overlay_registers {
118e3adcf8fSFrançois Tigeot 	u32 OBUF_0Y;
119e3adcf8fSFrançois Tigeot 	u32 OBUF_1Y;
120e3adcf8fSFrançois Tigeot 	u32 OBUF_0U;
121e3adcf8fSFrançois Tigeot 	u32 OBUF_0V;
122e3adcf8fSFrançois Tigeot 	u32 OBUF_1U;
123e3adcf8fSFrançois Tigeot 	u32 OBUF_1V;
124e3adcf8fSFrançois Tigeot 	u32 OSTRIDE;
125e3adcf8fSFrançois Tigeot 	u32 YRGB_VPH;
126e3adcf8fSFrançois Tigeot 	u32 UV_VPH;
127e3adcf8fSFrançois Tigeot 	u32 HORZ_PH;
128e3adcf8fSFrançois Tigeot 	u32 INIT_PHS;
129e3adcf8fSFrançois Tigeot 	u32 DWINPOS;
130e3adcf8fSFrançois Tigeot 	u32 DWINSZ;
131e3adcf8fSFrançois Tigeot 	u32 SWIDTH;
132e3adcf8fSFrançois Tigeot 	u32 SWIDTHSW;
133e3adcf8fSFrançois Tigeot 	u32 SHEIGHT;
134e3adcf8fSFrançois Tigeot 	u32 YRGBSCALE;
135e3adcf8fSFrançois Tigeot 	u32 UVSCALE;
136e3adcf8fSFrançois Tigeot 	u32 OCLRC0;
137e3adcf8fSFrançois Tigeot 	u32 OCLRC1;
138e3adcf8fSFrançois Tigeot 	u32 DCLRKV;
139e3adcf8fSFrançois Tigeot 	u32 DCLRKM;
140e3adcf8fSFrançois Tigeot 	u32 SCLRKVH;
141e3adcf8fSFrançois Tigeot 	u32 SCLRKVL;
142e3adcf8fSFrançois Tigeot 	u32 SCLRKEN;
143e3adcf8fSFrançois Tigeot 	u32 OCONFIG;
144e3adcf8fSFrançois Tigeot 	u32 OCMD;
145e3adcf8fSFrançois Tigeot 	u32 RESERVED1; /* 0x6C */
146e3adcf8fSFrançois Tigeot 	u32 OSTART_0Y;
147e3adcf8fSFrançois Tigeot 	u32 OSTART_1Y;
148e3adcf8fSFrançois Tigeot 	u32 OSTART_0U;
149e3adcf8fSFrançois Tigeot 	u32 OSTART_0V;
150e3adcf8fSFrançois Tigeot 	u32 OSTART_1U;
151e3adcf8fSFrançois Tigeot 	u32 OSTART_1V;
152e3adcf8fSFrançois Tigeot 	u32 OTILEOFF_0Y;
153e3adcf8fSFrançois Tigeot 	u32 OTILEOFF_1Y;
154e3adcf8fSFrançois Tigeot 	u32 OTILEOFF_0U;
155e3adcf8fSFrançois Tigeot 	u32 OTILEOFF_0V;
156e3adcf8fSFrançois Tigeot 	u32 OTILEOFF_1U;
157e3adcf8fSFrançois Tigeot 	u32 OTILEOFF_1V;
158e3adcf8fSFrançois Tigeot 	u32 FASTHSCALE; /* 0xA0 */
159e3adcf8fSFrançois Tigeot 	u32 UVSCALEV; /* 0xA4 */
160e3adcf8fSFrançois Tigeot 	u32 RESERVEDC[(0x200 - 0xA8) / 4]; /* 0xA8 - 0x1FC */
161e3adcf8fSFrançois Tigeot 	u16 Y_VCOEFS[N_VERT_Y_TAPS * N_PHASES]; /* 0x200 */
162e3adcf8fSFrançois Tigeot 	u16 RESERVEDD[0x100 / 2 - N_VERT_Y_TAPS * N_PHASES];
163e3adcf8fSFrançois Tigeot 	u16 Y_HCOEFS[N_HORIZ_Y_TAPS * N_PHASES]; /* 0x300 */
164e3adcf8fSFrançois Tigeot 	u16 RESERVEDE[0x200 / 2 - N_HORIZ_Y_TAPS * N_PHASES];
165e3adcf8fSFrançois Tigeot 	u16 UV_VCOEFS[N_VERT_UV_TAPS * N_PHASES]; /* 0x500 */
166e3adcf8fSFrançois Tigeot 	u16 RESERVEDF[0x100 / 2 - N_VERT_UV_TAPS * N_PHASES];
167e3adcf8fSFrançois Tigeot 	u16 UV_HCOEFS[N_HORIZ_UV_TAPS * N_PHASES]; /* 0x600 */
168e3adcf8fSFrançois Tigeot 	u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES];
169e3adcf8fSFrançois Tigeot };
170e3adcf8fSFrançois Tigeot 
171e3adcf8fSFrançois Tigeot struct intel_overlay {
1721487f786SFrançois Tigeot 	struct drm_i915_private *i915;
173e3adcf8fSFrançois Tigeot 	struct intel_crtc *crtc;
174*1e12ee3bSFrançois Tigeot 	struct i915_vma *vma;
175*1e12ee3bSFrançois Tigeot 	struct i915_vma *old_vma;
17619c468b4SFrançois Tigeot 	bool active;
17719c468b4SFrançois Tigeot 	bool pfit_active;
178e3adcf8fSFrançois Tigeot 	u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
17919c468b4SFrançois Tigeot 	u32 color_key:24;
18019c468b4SFrançois Tigeot 	u32 color_key_enabled:1;
181e3adcf8fSFrançois Tigeot 	u32 brightness, contrast, saturation;
182e3adcf8fSFrançois Tigeot 	u32 old_xscale, old_yscale;
183e3adcf8fSFrançois Tigeot 	/* register access */
184e3adcf8fSFrançois Tigeot 	u32 flip_addr;
185e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *reg_bo;
186e3adcf8fSFrançois Tigeot 	/* flip handling */
18771f41f3eSFrançois Tigeot 	struct i915_gem_active last_flip;
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 {
1931487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = overlay->i915;
194e3440f96SFrançois Tigeot 	struct overlay_registers __iomem *regs;
195e3adcf8fSFrançois Tigeot 
1961487f786SFrançois Tigeot 	if (OVERLAY_NEEDS_PHYSICAL(dev_priv))
197ba55f2f5SFrançois Tigeot 		regs = (struct overlay_registers __iomem *)overlay->reg_bo->phys_handle->vaddr;
198e3440f96SFrançois Tigeot 	else
199*1e12ee3bSFrançois Tigeot 		regs = io_mapping_map_wc(&dev_priv->ggtt.mappable,
2001487f786SFrançois Tigeot 					 overlay->flip_addr,
2011487f786SFrançois Tigeot 					 PAGE_SIZE);
202e3440f96SFrançois Tigeot 
203e3440f96SFrançois Tigeot 	return regs;
204e3adcf8fSFrançois Tigeot }
205e3adcf8fSFrançois Tigeot 
206e3adcf8fSFrançois Tigeot static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
207e3440f96SFrançois Tigeot 				     struct overlay_registers __iomem *regs)
208e3adcf8fSFrançois Tigeot {
2091487f786SFrançois Tigeot 	if (!OVERLAY_NEEDS_PHYSICAL(overlay->i915))
210bf017597SFrançois Tigeot 		io_mapping_unmap(regs);
211e3adcf8fSFrançois Tigeot }
212e3adcf8fSFrançois Tigeot 
21371f41f3eSFrançois Tigeot static void intel_overlay_submit_request(struct intel_overlay *overlay,
21471f41f3eSFrançois Tigeot 					 struct drm_i915_gem_request *req,
21571f41f3eSFrançois Tigeot 					 i915_gem_retire_fn retire)
21671f41f3eSFrançois Tigeot {
21771f41f3eSFrançois Tigeot 	GEM_BUG_ON(i915_gem_active_peek(&overlay->last_flip,
21871f41f3eSFrançois Tigeot 					&overlay->i915->drm.struct_mutex));
21971f41f3eSFrançois Tigeot 	overlay->last_flip.retire = retire;
22071f41f3eSFrançois Tigeot 	i915_gem_active_set(&overlay->last_flip, req);
22171f41f3eSFrançois Tigeot 	i915_add_request(req);
22271f41f3eSFrançois Tigeot }
22371f41f3eSFrançois Tigeot 
224e3adcf8fSFrançois Tigeot static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
225a05eeebfSFrançois Tigeot 					 struct drm_i915_gem_request *req,
22671f41f3eSFrançois Tigeot 					 i915_gem_retire_fn retire)
227e3adcf8fSFrançois Tigeot {
22871f41f3eSFrançois Tigeot 	intel_overlay_submit_request(overlay, req, retire);
22971f41f3eSFrançois Tigeot 	return i915_gem_active_retire(&overlay->last_flip,
23071f41f3eSFrançois Tigeot 				      &overlay->i915->drm.struct_mutex);
23171f41f3eSFrançois Tigeot }
232e3adcf8fSFrançois Tigeot 
23371f41f3eSFrançois Tigeot static struct drm_i915_gem_request *alloc_request(struct intel_overlay *overlay)
23471f41f3eSFrançois Tigeot {
23571f41f3eSFrançois Tigeot 	struct drm_i915_private *dev_priv = overlay->i915;
236*1e12ee3bSFrançois Tigeot 	struct intel_engine_cs *engine = dev_priv->engine[RCS];
237f192107fSFrançois Tigeot 
23871f41f3eSFrançois Tigeot 	return i915_gem_request_alloc(engine, dev_priv->kernel_context);
239e3adcf8fSFrançois Tigeot }
240e3adcf8fSFrançois Tigeot 
241e3adcf8fSFrançois Tigeot /* overlay needs to be disable in OCMD reg */
242e3adcf8fSFrançois Tigeot static int intel_overlay_on(struct intel_overlay *overlay)
243e3adcf8fSFrançois Tigeot {
2441487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = overlay->i915;
245a05eeebfSFrançois Tigeot 	struct drm_i915_gem_request *req;
24671f41f3eSFrançois Tigeot 	struct intel_ring *ring;
247e3adcf8fSFrançois Tigeot 	int ret;
248e3adcf8fSFrançois Tigeot 
24919c468b4SFrançois Tigeot 	WARN_ON(overlay->active);
2501487f786SFrançois Tigeot 	WARN_ON(IS_I830(dev_priv) && !(dev_priv->quirks & QUIRK_PIPEA_FORCE));
251e3adcf8fSFrançois Tigeot 
25271f41f3eSFrançois Tigeot 	req = alloc_request(overlay);
253c0e85e96SFrançois Tigeot 	if (IS_ERR(req))
254c0e85e96SFrançois Tigeot 		return PTR_ERR(req);
255f192107fSFrançois Tigeot 
256a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
257a05eeebfSFrançois Tigeot 	if (ret) {
2588621f407SFrançois Tigeot 		i915_add_request_no_flush(req);
259a05eeebfSFrançois Tigeot 		return ret;
260a05eeebfSFrançois Tigeot 	}
261a05eeebfSFrançois Tigeot 
26219c468b4SFrançois Tigeot 	overlay->active = true;
26319c468b4SFrançois Tigeot 
26471f41f3eSFrançois Tigeot 	ring = req->ring;
26571f41f3eSFrançois Tigeot 	intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_ON);
26671f41f3eSFrançois Tigeot 	intel_ring_emit(ring, overlay->flip_addr | OFC_UPDATE);
26771f41f3eSFrançois Tigeot 	intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
26871f41f3eSFrançois Tigeot 	intel_ring_emit(ring, MI_NOOP);
26971f41f3eSFrançois Tigeot 	intel_ring_advance(ring);
270f192107fSFrançois Tigeot 
271a05eeebfSFrançois Tigeot 	return intel_overlay_do_wait_request(overlay, req, NULL);
272e3adcf8fSFrançois Tigeot }
273e3adcf8fSFrançois Tigeot 
274e3adcf8fSFrançois Tigeot /* overlay needs to be enabled in OCMD reg */
275e3adcf8fSFrançois Tigeot static int intel_overlay_continue(struct intel_overlay *overlay,
276e3adcf8fSFrançois Tigeot 				  bool load_polyphase_filter)
277e3adcf8fSFrançois Tigeot {
2781487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = overlay->i915;
279a05eeebfSFrançois Tigeot 	struct drm_i915_gem_request *req;
28071f41f3eSFrançois Tigeot 	struct intel_ring *ring;
281e3adcf8fSFrançois Tigeot 	u32 flip_addr = overlay->flip_addr;
282e3adcf8fSFrançois Tigeot 	u32 tmp;
283e3adcf8fSFrançois Tigeot 	int ret;
284e3adcf8fSFrançois Tigeot 
28519c468b4SFrançois Tigeot 	WARN_ON(!overlay->active);
286e3adcf8fSFrançois Tigeot 
287e3adcf8fSFrançois Tigeot 	if (load_polyphase_filter)
288e3adcf8fSFrançois Tigeot 		flip_addr |= OFC_UPDATE;
289e3adcf8fSFrançois Tigeot 
290e3adcf8fSFrançois Tigeot 	/* check for underruns */
291e3adcf8fSFrançois Tigeot 	tmp = I915_READ(DOVSTA);
292e3adcf8fSFrançois Tigeot 	if (tmp & (1 << 17))
293e3adcf8fSFrançois Tigeot 		DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
294e3adcf8fSFrançois Tigeot 
29571f41f3eSFrançois Tigeot 	req = alloc_request(overlay);
296c0e85e96SFrançois Tigeot 	if (IS_ERR(req))
297c0e85e96SFrançois Tigeot 		return PTR_ERR(req);
298e3adcf8fSFrançois Tigeot 
299a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
300a05eeebfSFrançois Tigeot 	if (ret) {
3018621f407SFrançois Tigeot 		i915_add_request_no_flush(req);
302a05eeebfSFrançois Tigeot 		return ret;
303a05eeebfSFrançois Tigeot 	}
304a05eeebfSFrançois Tigeot 
30571f41f3eSFrançois Tigeot 	ring = req->ring;
30671f41f3eSFrançois Tigeot 	intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
30771f41f3eSFrançois Tigeot 	intel_ring_emit(ring, flip_addr);
30871f41f3eSFrançois Tigeot 	intel_ring_advance(ring);
309e3adcf8fSFrançois Tigeot 
31071f41f3eSFrançois Tigeot 	intel_overlay_submit_request(overlay, req, NULL);
311a05eeebfSFrançois Tigeot 
312a05eeebfSFrançois Tigeot 	return 0;
313e3adcf8fSFrançois Tigeot }
314e3adcf8fSFrançois Tigeot 
31571f41f3eSFrançois Tigeot static void intel_overlay_release_old_vid_tail(struct i915_gem_active *active,
31671f41f3eSFrançois Tigeot 					       struct drm_i915_gem_request *req)
317e3adcf8fSFrançois Tigeot {
31871f41f3eSFrançois Tigeot 	struct intel_overlay *overlay =
31971f41f3eSFrançois Tigeot 		container_of(active, typeof(*overlay), last_flip);
320*1e12ee3bSFrançois Tigeot 	struct i915_vma *vma;
321e3adcf8fSFrançois Tigeot 
322*1e12ee3bSFrançois Tigeot 	vma = fetch_and_zero(&overlay->old_vma);
323*1e12ee3bSFrançois Tigeot 	if (WARN_ON(!vma))
324*1e12ee3bSFrançois Tigeot 		return;
325*1e12ee3bSFrançois Tigeot 
326*1e12ee3bSFrançois Tigeot 	i915_gem_track_fb(vma->obj, NULL,
32771f41f3eSFrançois Tigeot 			  INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe));
32871f41f3eSFrançois Tigeot 
329*1e12ee3bSFrançois Tigeot 	i915_gem_object_unpin_from_display_plane(vma);
330*1e12ee3bSFrançois Tigeot 	i915_vma_put(vma);
331e3adcf8fSFrançois Tigeot }
332e3adcf8fSFrançois Tigeot 
33371f41f3eSFrançois Tigeot static void intel_overlay_off_tail(struct i915_gem_active *active,
33471f41f3eSFrançois Tigeot 				   struct drm_i915_gem_request *req)
335e3adcf8fSFrançois Tigeot {
33671f41f3eSFrançois Tigeot 	struct intel_overlay *overlay =
33771f41f3eSFrançois Tigeot 		container_of(active, typeof(*overlay), last_flip);
338*1e12ee3bSFrançois Tigeot 	struct i915_vma *vma;
339e3adcf8fSFrançois Tigeot 
340e3adcf8fSFrançois Tigeot 	/* never have the overlay hw on without showing a frame */
341*1e12ee3bSFrançois Tigeot 	vma = fetch_and_zero(&overlay->vma);
342*1e12ee3bSFrançois Tigeot 	if (WARN_ON(!vma))
34319c468b4SFrançois Tigeot 		return;
344e3adcf8fSFrançois Tigeot 
345*1e12ee3bSFrançois Tigeot 	i915_gem_object_unpin_from_display_plane(vma);
346*1e12ee3bSFrançois Tigeot 	i915_vma_put(vma);
347e3adcf8fSFrançois Tigeot 
348e3adcf8fSFrançois Tigeot 	overlay->crtc->overlay = NULL;
349e3adcf8fSFrançois Tigeot 	overlay->crtc = NULL;
35019c468b4SFrançois Tigeot 	overlay->active = false;
351e3adcf8fSFrançois Tigeot }
352e3adcf8fSFrançois Tigeot 
353e3adcf8fSFrançois Tigeot /* overlay needs to be disabled in OCMD reg */
354e3adcf8fSFrançois Tigeot static int intel_overlay_off(struct intel_overlay *overlay)
355e3adcf8fSFrançois Tigeot {
3561487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = overlay->i915;
357a05eeebfSFrançois Tigeot 	struct drm_i915_gem_request *req;
35871f41f3eSFrançois Tigeot 	struct intel_ring *ring;
359e3adcf8fSFrançois Tigeot 	u32 flip_addr = overlay->flip_addr;
360e3adcf8fSFrançois Tigeot 	int ret;
361e3adcf8fSFrançois Tigeot 
36219c468b4SFrançois Tigeot 	WARN_ON(!overlay->active);
363e3adcf8fSFrançois Tigeot 
364e3adcf8fSFrançois Tigeot 	/* According to intel docs the overlay hw may hang (when switching
365e3adcf8fSFrançois Tigeot 	 * off) without loading the filter coeffs. It is however unclear whether
366e3adcf8fSFrançois Tigeot 	 * this applies to the disabling of the overlay or to the switching off
367e3adcf8fSFrançois Tigeot 	 * of the hw. Do it in both cases */
368e3adcf8fSFrançois Tigeot 	flip_addr |= OFC_UPDATE;
369e3adcf8fSFrançois Tigeot 
37071f41f3eSFrançois Tigeot 	req = alloc_request(overlay);
371c0e85e96SFrançois Tigeot 	if (IS_ERR(req))
372c0e85e96SFrançois Tigeot 		return PTR_ERR(req);
373e3adcf8fSFrançois Tigeot 
374a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 6);
375a05eeebfSFrançois Tigeot 	if (ret) {
3768621f407SFrançois Tigeot 		i915_add_request_no_flush(req);
377a05eeebfSFrançois Tigeot 		return ret;
378a05eeebfSFrançois Tigeot 	}
379a05eeebfSFrançois Tigeot 
38071f41f3eSFrançois Tigeot 	ring = req->ring;
381f192107fSFrançois Tigeot 	/* wait for overlay to go idle */
38271f41f3eSFrançois Tigeot 	intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
38371f41f3eSFrançois Tigeot 	intel_ring_emit(ring, flip_addr);
38471f41f3eSFrançois Tigeot 	intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
385f192107fSFrançois Tigeot 	/* turn overlay off */
3861487f786SFrançois Tigeot 	if (IS_I830(dev_priv)) {
38719df918dSFrançois Tigeot 		/* Workaround: Don't disable the overlay fully, since otherwise
38819df918dSFrançois Tigeot 		 * it dies on the next OVERLAY_ON cmd. */
38971f41f3eSFrançois Tigeot 		intel_ring_emit(ring, MI_NOOP);
39071f41f3eSFrançois Tigeot 		intel_ring_emit(ring, MI_NOOP);
39171f41f3eSFrançois Tigeot 		intel_ring_emit(ring, MI_NOOP);
39219df918dSFrançois Tigeot 	} else {
39371f41f3eSFrançois Tigeot 		intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
39471f41f3eSFrançois Tigeot 		intel_ring_emit(ring, flip_addr);
39571f41f3eSFrançois Tigeot 		intel_ring_emit(ring,
3968621f407SFrançois Tigeot 				MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
39719df918dSFrançois Tigeot 	}
39871f41f3eSFrançois Tigeot 	intel_ring_advance(ring);
399f192107fSFrançois Tigeot 
40071f41f3eSFrançois Tigeot 	return intel_overlay_do_wait_request(overlay, req,
40171f41f3eSFrançois Tigeot 					     intel_overlay_off_tail);
402e3adcf8fSFrançois Tigeot }
403e3adcf8fSFrançois Tigeot 
404e3adcf8fSFrançois Tigeot /* recover from an interruption due to a signal
405e3adcf8fSFrançois Tigeot  * We have to be careful not to repeat work forever an make forward progess. */
406e3adcf8fSFrançois Tigeot static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
407e3adcf8fSFrançois Tigeot {
40871f41f3eSFrançois Tigeot 	return i915_gem_active_retire(&overlay->last_flip,
40971f41f3eSFrançois Tigeot 				      &overlay->i915->drm.struct_mutex);
410e3adcf8fSFrançois Tigeot }
411e3adcf8fSFrançois Tigeot 
412e3adcf8fSFrançois Tigeot /* Wait for pending overlay flip and release old frame.
413e3adcf8fSFrançois Tigeot  * Needs to be called before the overlay register are changed
414e3adcf8fSFrançois Tigeot  * via intel_overlay_(un)map_regs
415e3adcf8fSFrançois Tigeot  */
416e3adcf8fSFrançois Tigeot static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
417e3adcf8fSFrançois Tigeot {
4181487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = overlay->i915;
419e3adcf8fSFrançois Tigeot 	int ret;
420e3adcf8fSFrançois Tigeot 
421303bf270SFrançois Tigeot 	lockdep_assert_held(&dev_priv->drm.struct_mutex);
4222c9916cdSFrançois Tigeot 
423e3adcf8fSFrançois Tigeot 	/* Only wait if there is actually an old frame to release to
424e3adcf8fSFrançois Tigeot 	 * guarantee forward progress.
425e3adcf8fSFrançois Tigeot 	 */
426*1e12ee3bSFrançois Tigeot 	if (!overlay->old_vma)
427e3adcf8fSFrançois Tigeot 		return 0;
428e3adcf8fSFrançois Tigeot 
429e3adcf8fSFrançois Tigeot 	if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) {
430e3adcf8fSFrançois Tigeot 		/* synchronous slowpath */
431a05eeebfSFrançois Tigeot 		struct drm_i915_gem_request *req;
43271f41f3eSFrançois Tigeot 		struct intel_ring *ring;
433a05eeebfSFrançois Tigeot 
43471f41f3eSFrançois Tigeot 		req = alloc_request(overlay);
435c0e85e96SFrançois Tigeot 		if (IS_ERR(req))
436c0e85e96SFrançois Tigeot 			return PTR_ERR(req);
437e3adcf8fSFrançois Tigeot 
438a05eeebfSFrançois Tigeot 		ret = intel_ring_begin(req, 2);
439a05eeebfSFrançois Tigeot 		if (ret) {
4408621f407SFrançois Tigeot 			i915_add_request_no_flush(req);
441a05eeebfSFrançois Tigeot 			return ret;
442a05eeebfSFrançois Tigeot 		}
443a05eeebfSFrançois Tigeot 
44471f41f3eSFrançois Tigeot 		ring = req->ring;
44571f41f3eSFrançois Tigeot 		intel_ring_emit(ring,
4468621f407SFrançois Tigeot 				MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
44771f41f3eSFrançois Tigeot 		intel_ring_emit(ring, MI_NOOP);
44871f41f3eSFrançois Tigeot 		intel_ring_advance(ring);
449e3adcf8fSFrançois Tigeot 
450a05eeebfSFrançois Tigeot 		ret = intel_overlay_do_wait_request(overlay, req,
451e3adcf8fSFrançois Tigeot 						    intel_overlay_release_old_vid_tail);
452e3adcf8fSFrançois Tigeot 		if (ret)
453e3adcf8fSFrançois Tigeot 			return ret;
45471f41f3eSFrançois Tigeot 	} else
45571f41f3eSFrançois Tigeot 		intel_overlay_release_old_vid_tail(&overlay->last_flip, NULL);
456e3adcf8fSFrançois Tigeot 
457e3adcf8fSFrançois Tigeot 	return 0;
458e3adcf8fSFrançois Tigeot }
459e3adcf8fSFrançois Tigeot 
4602c9916cdSFrançois Tigeot void intel_overlay_reset(struct drm_i915_private *dev_priv)
4612c9916cdSFrançois Tigeot {
4622c9916cdSFrançois Tigeot 	struct intel_overlay *overlay = dev_priv->overlay;
4632c9916cdSFrançois Tigeot 
4642c9916cdSFrançois Tigeot 	if (!overlay)
4652c9916cdSFrançois Tigeot 		return;
4662c9916cdSFrançois Tigeot 
4672c9916cdSFrançois Tigeot 	intel_overlay_release_old_vid(overlay);
4682c9916cdSFrançois Tigeot 
4692c9916cdSFrançois Tigeot 	overlay->old_xscale = 0;
4702c9916cdSFrançois Tigeot 	overlay->old_yscale = 0;
4712c9916cdSFrançois Tigeot 	overlay->crtc = NULL;
4722c9916cdSFrançois Tigeot 	overlay->active = false;
4732c9916cdSFrançois Tigeot }
4742c9916cdSFrançois Tigeot 
475e3adcf8fSFrançois Tigeot struct put_image_params {
476e3adcf8fSFrançois Tigeot 	int format;
477e3adcf8fSFrançois Tigeot 	short dst_x;
478e3adcf8fSFrançois Tigeot 	short dst_y;
479e3adcf8fSFrançois Tigeot 	short dst_w;
480e3adcf8fSFrançois Tigeot 	short dst_h;
481e3adcf8fSFrançois Tigeot 	short src_w;
482e3adcf8fSFrançois Tigeot 	short src_scan_h;
483e3adcf8fSFrançois Tigeot 	short src_scan_w;
484e3adcf8fSFrançois Tigeot 	short src_h;
485e3adcf8fSFrançois Tigeot 	short stride_Y;
486e3adcf8fSFrançois Tigeot 	short stride_UV;
487e3adcf8fSFrançois Tigeot 	int offset_Y;
488e3adcf8fSFrançois Tigeot 	int offset_U;
489e3adcf8fSFrançois Tigeot 	int offset_V;
490e3adcf8fSFrançois Tigeot };
491e3adcf8fSFrançois Tigeot 
492e3adcf8fSFrançois Tigeot static int packed_depth_bytes(u32 format)
493e3adcf8fSFrançois Tigeot {
494e3adcf8fSFrançois Tigeot 	switch (format & I915_OVERLAY_DEPTH_MASK) {
495e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV422:
496e3adcf8fSFrançois Tigeot 		return 4;
497e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV411:
498e3adcf8fSFrançois Tigeot 		/* return 6; not implemented */
499e3adcf8fSFrançois Tigeot 	default:
500e3adcf8fSFrançois Tigeot 		return -EINVAL;
501e3adcf8fSFrançois Tigeot 	}
502e3adcf8fSFrançois Tigeot }
503e3adcf8fSFrançois Tigeot 
504e3adcf8fSFrançois Tigeot static int packed_width_bytes(u32 format, short width)
505e3adcf8fSFrançois Tigeot {
506e3adcf8fSFrançois Tigeot 	switch (format & I915_OVERLAY_DEPTH_MASK) {
507e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV422:
508e3adcf8fSFrançois Tigeot 		return width << 1;
509e3adcf8fSFrançois Tigeot 	default:
510e3adcf8fSFrançois Tigeot 		return -EINVAL;
511e3adcf8fSFrançois Tigeot 	}
512e3adcf8fSFrançois Tigeot }
513e3adcf8fSFrançois Tigeot 
514e3adcf8fSFrançois Tigeot static int uv_hsubsampling(u32 format)
515e3adcf8fSFrançois Tigeot {
516e3adcf8fSFrançois Tigeot 	switch (format & I915_OVERLAY_DEPTH_MASK) {
517e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV422:
518e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV420:
519e3adcf8fSFrançois Tigeot 		return 2;
520e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV411:
521e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV410:
522e3adcf8fSFrançois Tigeot 		return 4;
523e3adcf8fSFrançois Tigeot 	default:
524e3adcf8fSFrançois Tigeot 		return -EINVAL;
525e3adcf8fSFrançois Tigeot 	}
526e3adcf8fSFrançois Tigeot }
527e3adcf8fSFrançois Tigeot 
528e3adcf8fSFrançois Tigeot static int uv_vsubsampling(u32 format)
529e3adcf8fSFrançois Tigeot {
530e3adcf8fSFrançois Tigeot 	switch (format & I915_OVERLAY_DEPTH_MASK) {
531e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV420:
532e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV410:
533e3adcf8fSFrançois Tigeot 		return 2;
534e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV422:
535e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV411:
536e3adcf8fSFrançois Tigeot 		return 1;
537e3adcf8fSFrançois Tigeot 	default:
538e3adcf8fSFrançois Tigeot 		return -EINVAL;
539e3adcf8fSFrançois Tigeot 	}
540e3adcf8fSFrançois Tigeot }
541e3adcf8fSFrançois Tigeot 
5421487f786SFrançois Tigeot static u32 calc_swidthsw(struct drm_i915_private *dev_priv, u32 offset, u32 width)
543e3adcf8fSFrançois Tigeot {
544e3adcf8fSFrançois Tigeot 	u32 mask, shift, ret;
5451487f786SFrançois Tigeot 	if (IS_GEN2(dev_priv)) {
546e3adcf8fSFrançois Tigeot 		mask = 0x1f;
547e3adcf8fSFrançois Tigeot 		shift = 5;
548e3adcf8fSFrançois Tigeot 	} else {
549e3adcf8fSFrançois Tigeot 		mask = 0x3f;
550e3adcf8fSFrançois Tigeot 		shift = 6;
551e3adcf8fSFrançois Tigeot 	}
552e3adcf8fSFrançois Tigeot 	ret = ((offset + width + mask) >> shift) - (offset >> shift);
5531487f786SFrançois Tigeot 	if (!IS_GEN2(dev_priv))
554e3adcf8fSFrançois Tigeot 		ret <<= 1;
555e3adcf8fSFrançois Tigeot 	ret -= 1;
556e3adcf8fSFrançois Tigeot 	return ret << 2;
557e3adcf8fSFrançois Tigeot }
558e3adcf8fSFrançois Tigeot 
559e3adcf8fSFrançois Tigeot static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = {
560e3adcf8fSFrançois Tigeot 	0x3000, 0xb4a0, 0x1930, 0x1920, 0xb4a0,
561e3adcf8fSFrançois Tigeot 	0x3000, 0xb500, 0x19d0, 0x1880, 0xb440,
562e3adcf8fSFrançois Tigeot 	0x3000, 0xb540, 0x1a88, 0x2f80, 0xb3e0,
563e3adcf8fSFrançois Tigeot 	0x3000, 0xb580, 0x1b30, 0x2e20, 0xb380,
564e3adcf8fSFrançois Tigeot 	0x3000, 0xb5c0, 0x1bd8, 0x2cc0, 0xb320,
565e3adcf8fSFrançois Tigeot 	0x3020, 0xb5e0, 0x1c60, 0x2b80, 0xb2c0,
566e3adcf8fSFrançois Tigeot 	0x3020, 0xb5e0, 0x1cf8, 0x2a20, 0xb260,
567e3adcf8fSFrançois Tigeot 	0x3020, 0xb5e0, 0x1d80, 0x28e0, 0xb200,
568e3adcf8fSFrançois Tigeot 	0x3020, 0xb5c0, 0x1e08, 0x3f40, 0xb1c0,
569e3adcf8fSFrançois Tigeot 	0x3020, 0xb580, 0x1e78, 0x3ce0, 0xb160,
570e3adcf8fSFrançois Tigeot 	0x3040, 0xb520, 0x1ed8, 0x3aa0, 0xb120,
571e3adcf8fSFrançois Tigeot 	0x3040, 0xb4a0, 0x1f30, 0x3880, 0xb0e0,
572e3adcf8fSFrançois Tigeot 	0x3040, 0xb400, 0x1f78, 0x3680, 0xb0a0,
573e3adcf8fSFrançois Tigeot 	0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060,
574e3adcf8fSFrançois Tigeot 	0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040,
575e3adcf8fSFrançois Tigeot 	0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020,
576e3adcf8fSFrançois Tigeot 	0xb000, 0x3000, 0x0800, 0x3000, 0xb000
577e3adcf8fSFrançois Tigeot };
578e3adcf8fSFrançois Tigeot 
579e3adcf8fSFrançois Tigeot static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
580e3adcf8fSFrançois Tigeot 	0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60,
581e3adcf8fSFrançois Tigeot 	0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40,
582e3adcf8fSFrançois Tigeot 	0xb040, 0x1b20, 0x29e0, 0xb060, 0x1bd8, 0x2880,
583e3adcf8fSFrançois Tigeot 	0xb080, 0x1c88, 0x3e60, 0xb0a0, 0x1d28, 0x3c00,
584e3adcf8fSFrançois Tigeot 	0xb0c0, 0x1db8, 0x39e0, 0xb0e0, 0x1e40, 0x37e0,
585e3adcf8fSFrançois Tigeot 	0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0,
586e3adcf8fSFrançois Tigeot 	0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240,
587e3adcf8fSFrançois Tigeot 	0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0,
588e3adcf8fSFrançois Tigeot 	0x3000, 0x0800, 0x3000
589e3adcf8fSFrançois Tigeot };
590e3adcf8fSFrançois Tigeot 
591e3440f96SFrançois Tigeot static void update_polyphase_filter(struct overlay_registers __iomem *regs)
592e3adcf8fSFrançois Tigeot {
593e3440f96SFrançois Tigeot 	memcpy_toio(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs));
594e3440f96SFrançois Tigeot 	memcpy_toio(regs->UV_HCOEFS, uv_static_hcoeffs,
595e3440f96SFrançois Tigeot 		    sizeof(uv_static_hcoeffs));
596e3adcf8fSFrançois Tigeot }
597e3adcf8fSFrançois Tigeot 
598e3adcf8fSFrançois Tigeot static bool update_scaling_factors(struct intel_overlay *overlay,
599e3440f96SFrançois Tigeot 				   struct overlay_registers __iomem *regs,
600e3adcf8fSFrançois Tigeot 				   struct put_image_params *params)
601e3adcf8fSFrançois Tigeot {
602e3adcf8fSFrançois Tigeot 	/* fixed point with a 12 bit shift */
603e3adcf8fSFrançois Tigeot 	u32 xscale, yscale, xscale_UV, yscale_UV;
604e3adcf8fSFrançois Tigeot #define FP_SHIFT 12
605e3adcf8fSFrançois Tigeot #define FRACT_MASK 0xfff
606e3adcf8fSFrançois Tigeot 	bool scale_changed = false;
607e3adcf8fSFrançois Tigeot 	int uv_hscale = uv_hsubsampling(params->format);
608e3adcf8fSFrançois Tigeot 	int uv_vscale = uv_vsubsampling(params->format);
609e3adcf8fSFrançois Tigeot 
610e3adcf8fSFrançois Tigeot 	if (params->dst_w > 1)
611e3adcf8fSFrançois Tigeot 		xscale = ((params->src_scan_w - 1) << FP_SHIFT)
612e3adcf8fSFrançois Tigeot 			/(params->dst_w);
613e3adcf8fSFrançois Tigeot 	else
614e3adcf8fSFrançois Tigeot 		xscale = 1 << FP_SHIFT;
615e3adcf8fSFrançois Tigeot 
616e3adcf8fSFrançois Tigeot 	if (params->dst_h > 1)
617e3adcf8fSFrançois Tigeot 		yscale = ((params->src_scan_h - 1) << FP_SHIFT)
618e3adcf8fSFrançois Tigeot 			/(params->dst_h);
619e3adcf8fSFrançois Tigeot 	else
620e3adcf8fSFrançois Tigeot 		yscale = 1 << FP_SHIFT;
621e3adcf8fSFrançois Tigeot 
622e3adcf8fSFrançois Tigeot 	/*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
623e3adcf8fSFrançois Tigeot 	xscale_UV = xscale/uv_hscale;
624e3adcf8fSFrançois Tigeot 	yscale_UV = yscale/uv_vscale;
625e3adcf8fSFrançois Tigeot 	/* make the Y scale to UV scale ratio an exact multiply */
626e3adcf8fSFrançois Tigeot 	xscale = xscale_UV * uv_hscale;
627e3adcf8fSFrançois Tigeot 	yscale = yscale_UV * uv_vscale;
628e3adcf8fSFrançois Tigeot 	/*} else {
629e3adcf8fSFrançois Tigeot 	  xscale_UV = 0;
630e3adcf8fSFrançois Tigeot 	  yscale_UV = 0;
631e3adcf8fSFrançois Tigeot 	  }*/
632e3adcf8fSFrançois Tigeot 
633e3adcf8fSFrançois Tigeot 	if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)
634e3adcf8fSFrançois Tigeot 		scale_changed = true;
635e3adcf8fSFrançois Tigeot 	overlay->old_xscale = xscale;
636e3adcf8fSFrançois Tigeot 	overlay->old_yscale = yscale;
637e3adcf8fSFrançois Tigeot 
638e3440f96SFrançois Tigeot 	iowrite32(((yscale & FRACT_MASK) << 20) |
639e3adcf8fSFrançois Tigeot 		  ((xscale >> FP_SHIFT)  << 16) |
640e3440f96SFrançois Tigeot 		  ((xscale & FRACT_MASK) << 3),
641e3440f96SFrançois Tigeot 		 &regs->YRGBSCALE);
642e3adcf8fSFrançois Tigeot 
643e3440f96SFrançois Tigeot 	iowrite32(((yscale_UV & FRACT_MASK) << 20) |
644e3adcf8fSFrançois Tigeot 		  ((xscale_UV >> FP_SHIFT)  << 16) |
645e3440f96SFrançois Tigeot 		  ((xscale_UV & FRACT_MASK) << 3),
646e3440f96SFrançois Tigeot 		 &regs->UVSCALE);
647e3adcf8fSFrançois Tigeot 
648e3440f96SFrançois Tigeot 	iowrite32((((yscale    >> FP_SHIFT) << 16) |
649e3440f96SFrançois Tigeot 		   ((yscale_UV >> FP_SHIFT) << 0)),
650e3440f96SFrançois Tigeot 		 &regs->UVSCALEV);
651e3adcf8fSFrançois Tigeot 
652e3adcf8fSFrançois Tigeot 	if (scale_changed)
653e3adcf8fSFrançois Tigeot 		update_polyphase_filter(regs);
654e3adcf8fSFrançois Tigeot 
655e3adcf8fSFrançois Tigeot 	return scale_changed;
656e3adcf8fSFrançois Tigeot }
657e3adcf8fSFrançois Tigeot 
658e3adcf8fSFrançois Tigeot static void update_colorkey(struct intel_overlay *overlay,
659e3440f96SFrançois Tigeot 			    struct overlay_registers __iomem *regs)
660e3adcf8fSFrançois Tigeot {
661e3adcf8fSFrançois Tigeot 	u32 key = overlay->color_key;
66219c468b4SFrançois Tigeot 	u32 flags;
66319c468b4SFrançois Tigeot 
66419c468b4SFrançois Tigeot 	flags = 0;
66519c468b4SFrançois Tigeot 	if (overlay->color_key_enabled)
66619c468b4SFrançois Tigeot 		flags |= DST_KEY_ENABLE;
667e3adcf8fSFrançois Tigeot 
668ba55f2f5SFrançois Tigeot 	switch (overlay->crtc->base.primary->fb->bits_per_pixel) {
669e3adcf8fSFrançois Tigeot 	case 8:
67019c468b4SFrançois Tigeot 		key = 0;
67119c468b4SFrançois Tigeot 		flags |= CLK_RGB8I_MASK;
672e3adcf8fSFrançois Tigeot 		break;
673e3adcf8fSFrançois Tigeot 
674e3adcf8fSFrançois Tigeot 	case 16:
675ba55f2f5SFrançois Tigeot 		if (overlay->crtc->base.primary->fb->depth == 15) {
67619c468b4SFrançois Tigeot 			key = RGB15_TO_COLORKEY(key);
67719c468b4SFrançois Tigeot 			flags |= CLK_RGB15_MASK;
678e3adcf8fSFrançois Tigeot 		} else {
67919c468b4SFrançois Tigeot 			key = RGB16_TO_COLORKEY(key);
68019c468b4SFrançois Tigeot 			flags |= CLK_RGB16_MASK;
681e3adcf8fSFrançois Tigeot 		}
682e3adcf8fSFrançois Tigeot 		break;
683e3adcf8fSFrançois Tigeot 
684e3adcf8fSFrançois Tigeot 	case 24:
685e3adcf8fSFrançois Tigeot 	case 32:
68619c468b4SFrançois Tigeot 		flags |= CLK_RGB24_MASK;
687e3adcf8fSFrançois Tigeot 		break;
688e3adcf8fSFrançois Tigeot 	}
68919c468b4SFrançois Tigeot 
69019c468b4SFrançois Tigeot 	iowrite32(key, &regs->DCLRKV);
69119c468b4SFrançois Tigeot 	iowrite32(flags, &regs->DCLRKM);
692e3adcf8fSFrançois Tigeot }
693e3adcf8fSFrançois Tigeot 
694e3adcf8fSFrançois Tigeot static u32 overlay_cmd_reg(struct put_image_params *params)
695e3adcf8fSFrançois Tigeot {
696e3adcf8fSFrançois Tigeot 	u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0;
697e3adcf8fSFrançois Tigeot 
698e3adcf8fSFrançois Tigeot 	if (params->format & I915_OVERLAY_YUV_PLANAR) {
699e3adcf8fSFrançois Tigeot 		switch (params->format & I915_OVERLAY_DEPTH_MASK) {
700e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_YUV422:
701e3adcf8fSFrançois Tigeot 			cmd |= OCMD_YUV_422_PLANAR;
702e3adcf8fSFrançois Tigeot 			break;
703e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_YUV420:
704e3adcf8fSFrançois Tigeot 			cmd |= OCMD_YUV_420_PLANAR;
705e3adcf8fSFrançois Tigeot 			break;
706e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_YUV411:
707e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_YUV410:
708e3adcf8fSFrançois Tigeot 			cmd |= OCMD_YUV_410_PLANAR;
709e3adcf8fSFrançois Tigeot 			break;
710e3adcf8fSFrançois Tigeot 		}
711e3adcf8fSFrançois Tigeot 	} else { /* YUV packed */
712e3adcf8fSFrançois Tigeot 		switch (params->format & I915_OVERLAY_DEPTH_MASK) {
713e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_YUV422:
714e3adcf8fSFrançois Tigeot 			cmd |= OCMD_YUV_422_PACKED;
715e3adcf8fSFrançois Tigeot 			break;
716e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_YUV411:
717e3adcf8fSFrançois Tigeot 			cmd |= OCMD_YUV_411_PACKED;
718e3adcf8fSFrançois Tigeot 			break;
719e3adcf8fSFrançois Tigeot 		}
720e3adcf8fSFrançois Tigeot 
721e3adcf8fSFrançois Tigeot 		switch (params->format & I915_OVERLAY_SWAP_MASK) {
722e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_NO_SWAP:
723e3adcf8fSFrançois Tigeot 			break;
724e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_UV_SWAP:
725e3adcf8fSFrançois Tigeot 			cmd |= OCMD_UV_SWAP;
726e3adcf8fSFrançois Tigeot 			break;
727e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_Y_SWAP:
728e3adcf8fSFrançois Tigeot 			cmd |= OCMD_Y_SWAP;
729e3adcf8fSFrançois Tigeot 			break;
730e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_Y_AND_UV_SWAP:
731e3adcf8fSFrançois Tigeot 			cmd |= OCMD_Y_AND_UV_SWAP;
732e3adcf8fSFrançois Tigeot 			break;
733e3adcf8fSFrançois Tigeot 		}
734e3adcf8fSFrançois Tigeot 	}
735e3adcf8fSFrançois Tigeot 
736e3adcf8fSFrançois Tigeot 	return cmd;
737e3adcf8fSFrançois Tigeot }
738e3adcf8fSFrançois Tigeot 
739e3adcf8fSFrançois Tigeot static int intel_overlay_do_put_image(struct intel_overlay *overlay,
740e3adcf8fSFrançois Tigeot 				      struct drm_i915_gem_object *new_bo,
741e3adcf8fSFrançois Tigeot 				      struct put_image_params *params)
742e3adcf8fSFrançois Tigeot {
743e3adcf8fSFrançois Tigeot 	int ret, tmp_width;
744e3440f96SFrançois Tigeot 	struct overlay_registers __iomem *regs;
745e3adcf8fSFrançois Tigeot 	bool scale_changed = false;
7461487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = overlay->i915;
747e3440f96SFrançois Tigeot 	u32 swidth, swidthsw, sheight, ostride;
74824edb884SFrançois Tigeot 	enum i915_pipe pipe = overlay->crtc->pipe;
749*1e12ee3bSFrançois Tigeot 	struct i915_vma *vma;
750e3adcf8fSFrançois Tigeot 
751303bf270SFrançois Tigeot 	lockdep_assert_held(&dev_priv->drm.struct_mutex);
752303bf270SFrançois Tigeot 	WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex));
753e3adcf8fSFrançois Tigeot 
754e3adcf8fSFrançois Tigeot 	ret = intel_overlay_release_old_vid(overlay);
755e3adcf8fSFrançois Tigeot 	if (ret != 0)
756e3adcf8fSFrançois Tigeot 		return ret;
757e3adcf8fSFrançois Tigeot 
758*1e12ee3bSFrançois Tigeot 	vma = i915_gem_object_pin_to_display_plane(new_bo, 0,
759477eb7f9SFrançois Tigeot 						   &i915_ggtt_view_normal);
760*1e12ee3bSFrançois Tigeot 	if (IS_ERR(vma))
761*1e12ee3bSFrançois Tigeot 		return PTR_ERR(vma);
762e3adcf8fSFrançois Tigeot 
763*1e12ee3bSFrançois Tigeot 	ret = i915_vma_put_fence(vma);
764e3adcf8fSFrançois Tigeot 	if (ret)
765e3adcf8fSFrançois Tigeot 		goto out_unpin;
766e3adcf8fSFrançois Tigeot 
767e3adcf8fSFrançois Tigeot 	if (!overlay->active) {
768e3440f96SFrançois Tigeot 		u32 oconfig;
769e3adcf8fSFrançois Tigeot 		regs = intel_overlay_map_regs(overlay);
770e3adcf8fSFrançois Tigeot 		if (!regs) {
771e3adcf8fSFrançois Tigeot 			ret = -ENOMEM;
772e3adcf8fSFrançois Tigeot 			goto out_unpin;
773e3adcf8fSFrançois Tigeot 		}
774e3440f96SFrançois Tigeot 		oconfig = OCONF_CC_OUT_8BIT;
7751487f786SFrançois Tigeot 		if (IS_GEN4(dev_priv))
776e3440f96SFrançois Tigeot 			oconfig |= OCONF_CSC_MODE_BT709;
77724edb884SFrançois Tigeot 		oconfig |= pipe == 0 ?
778e3adcf8fSFrançois Tigeot 			OCONF_PIPE_A : OCONF_PIPE_B;
779e3440f96SFrançois Tigeot 		iowrite32(oconfig, &regs->OCONFIG);
780e3adcf8fSFrançois Tigeot 		intel_overlay_unmap_regs(overlay, regs);
781e3adcf8fSFrançois Tigeot 
782e3adcf8fSFrançois Tigeot 		ret = intel_overlay_on(overlay);
783e3adcf8fSFrançois Tigeot 		if (ret != 0)
784e3adcf8fSFrançois Tigeot 			goto out_unpin;
785e3adcf8fSFrançois Tigeot 	}
786e3adcf8fSFrançois Tigeot 
787e3adcf8fSFrançois Tigeot 	regs = intel_overlay_map_regs(overlay);
788e3adcf8fSFrançois Tigeot 	if (!regs) {
789e3adcf8fSFrançois Tigeot 		ret = -ENOMEM;
790e3adcf8fSFrançois Tigeot 		goto out_unpin;
791e3adcf8fSFrançois Tigeot 	}
792e3adcf8fSFrançois Tigeot 
793e3440f96SFrançois Tigeot 	iowrite32((params->dst_y << 16) | params->dst_x, &regs->DWINPOS);
794e3440f96SFrançois Tigeot 	iowrite32((params->dst_h << 16) | params->dst_w, &regs->DWINSZ);
795e3adcf8fSFrançois Tigeot 
796e3adcf8fSFrançois Tigeot 	if (params->format & I915_OVERLAY_YUV_PACKED)
797e3adcf8fSFrançois Tigeot 		tmp_width = packed_width_bytes(params->format, params->src_w);
798e3adcf8fSFrançois Tigeot 	else
799e3adcf8fSFrançois Tigeot 		tmp_width = params->src_w;
800e3adcf8fSFrançois Tigeot 
801e3440f96SFrançois Tigeot 	swidth = params->src_w;
8021487f786SFrançois Tigeot 	swidthsw = calc_swidthsw(dev_priv, params->offset_Y, tmp_width);
803e3440f96SFrançois Tigeot 	sheight = params->src_h;
804*1e12ee3bSFrançois Tigeot 	iowrite32(i915_ggtt_offset(vma) + params->offset_Y, &regs->OBUF_0Y);
805e3440f96SFrançois Tigeot 	ostride = params->stride_Y;
806e3adcf8fSFrançois Tigeot 
807e3adcf8fSFrançois Tigeot 	if (params->format & I915_OVERLAY_YUV_PLANAR) {
808e3adcf8fSFrançois Tigeot 		int uv_hscale = uv_hsubsampling(params->format);
809e3adcf8fSFrançois Tigeot 		int uv_vscale = uv_vsubsampling(params->format);
810e3adcf8fSFrançois Tigeot 		u32 tmp_U, tmp_V;
811e3440f96SFrançois Tigeot 		swidth |= (params->src_w/uv_hscale) << 16;
8121487f786SFrançois Tigeot 		tmp_U = calc_swidthsw(dev_priv, params->offset_U,
813e3adcf8fSFrançois Tigeot 				      params->src_w/uv_hscale);
8141487f786SFrançois Tigeot 		tmp_V = calc_swidthsw(dev_priv, params->offset_V,
815e3adcf8fSFrançois Tigeot 				      params->src_w/uv_hscale);
816e3440f96SFrançois Tigeot 		swidthsw |= max_t(u32, tmp_U, tmp_V) << 16;
817e3440f96SFrançois Tigeot 		sheight |= (params->src_h/uv_vscale) << 16;
818*1e12ee3bSFrançois Tigeot 		iowrite32(i915_ggtt_offset(vma) + params->offset_U,
819*1e12ee3bSFrançois Tigeot 			  &regs->OBUF_0U);
820*1e12ee3bSFrançois Tigeot 		iowrite32(i915_ggtt_offset(vma) + params->offset_V,
821*1e12ee3bSFrançois Tigeot 			  &regs->OBUF_0V);
822e3440f96SFrançois Tigeot 		ostride |= params->stride_UV << 16;
823e3adcf8fSFrançois Tigeot 	}
824e3adcf8fSFrançois Tigeot 
825e3440f96SFrançois Tigeot 	iowrite32(swidth, &regs->SWIDTH);
826e3440f96SFrançois Tigeot 	iowrite32(swidthsw, &regs->SWIDTHSW);
827e3440f96SFrançois Tigeot 	iowrite32(sheight, &regs->SHEIGHT);
828e3440f96SFrançois Tigeot 	iowrite32(ostride, &regs->OSTRIDE);
829e3440f96SFrançois Tigeot 
830e3adcf8fSFrançois Tigeot 	scale_changed = update_scaling_factors(overlay, regs, params);
831e3adcf8fSFrançois Tigeot 
832e3adcf8fSFrançois Tigeot 	update_colorkey(overlay, regs);
833e3adcf8fSFrançois Tigeot 
834e3440f96SFrançois Tigeot 	iowrite32(overlay_cmd_reg(params), &regs->OCMD);
835e3adcf8fSFrançois Tigeot 
836e3adcf8fSFrançois Tigeot 	intel_overlay_unmap_regs(overlay, regs);
837e3adcf8fSFrançois Tigeot 
838e3adcf8fSFrançois Tigeot 	ret = intel_overlay_continue(overlay, scale_changed);
839e3adcf8fSFrançois Tigeot 	if (ret)
840e3adcf8fSFrançois Tigeot 		goto out_unpin;
841e3adcf8fSFrançois Tigeot 
842*1e12ee3bSFrançois Tigeot 	i915_gem_track_fb(overlay->vma->obj, new_bo,
84324edb884SFrançois Tigeot 			  INTEL_FRONTBUFFER_OVERLAY(pipe));
84424edb884SFrançois Tigeot 
845*1e12ee3bSFrançois Tigeot 	overlay->old_vma = overlay->vma;
846*1e12ee3bSFrançois Tigeot 	overlay->vma = vma;
847e3adcf8fSFrançois Tigeot 
84871f41f3eSFrançois Tigeot 	intel_frontbuffer_flip(dev_priv, INTEL_FRONTBUFFER_OVERLAY(pipe));
84924edb884SFrançois Tigeot 
850e3adcf8fSFrançois Tigeot 	return 0;
851e3adcf8fSFrançois Tigeot 
852e3adcf8fSFrançois Tigeot out_unpin:
853*1e12ee3bSFrançois Tigeot 	i915_gem_object_unpin_from_display_plane(vma);
854e3adcf8fSFrançois Tigeot 	return ret;
855e3adcf8fSFrançois Tigeot }
856e3adcf8fSFrançois Tigeot 
857e3adcf8fSFrançois Tigeot int intel_overlay_switch_off(struct intel_overlay *overlay)
858e3adcf8fSFrançois Tigeot {
8591487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = overlay->i915;
860e3440f96SFrançois Tigeot 	struct overlay_registers __iomem *regs;
861e3adcf8fSFrançois Tigeot 	int ret;
862e3adcf8fSFrançois Tigeot 
863303bf270SFrançois Tigeot 	lockdep_assert_held(&dev_priv->drm.struct_mutex);
864303bf270SFrançois Tigeot 	WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex));
865e3adcf8fSFrançois Tigeot 
866e3adcf8fSFrançois Tigeot 	ret = intel_overlay_recover_from_interrupt(overlay);
867e3adcf8fSFrançois Tigeot 	if (ret != 0)
868e3adcf8fSFrançois Tigeot 		return ret;
869e3adcf8fSFrançois Tigeot 
870e3adcf8fSFrançois Tigeot 	if (!overlay->active)
871e3adcf8fSFrançois Tigeot 		return 0;
872e3adcf8fSFrançois Tigeot 
873e3adcf8fSFrançois Tigeot 	ret = intel_overlay_release_old_vid(overlay);
874e3adcf8fSFrançois Tigeot 	if (ret != 0)
875e3adcf8fSFrançois Tigeot 		return ret;
876e3adcf8fSFrançois Tigeot 
877e3adcf8fSFrançois Tigeot 	regs = intel_overlay_map_regs(overlay);
878e3440f96SFrançois Tigeot 	iowrite32(0, &regs->OCMD);
879e3adcf8fSFrançois Tigeot 	intel_overlay_unmap_regs(overlay, regs);
880e3adcf8fSFrançois Tigeot 
88171f41f3eSFrançois Tigeot 	return intel_overlay_off(overlay);
882e3adcf8fSFrançois Tigeot }
883e3adcf8fSFrançois Tigeot 
884e3adcf8fSFrançois Tigeot static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
885e3adcf8fSFrançois Tigeot 					  struct intel_crtc *crtc)
886e3adcf8fSFrançois Tigeot {
887e3adcf8fSFrançois Tigeot 	if (!crtc->active)
888e3adcf8fSFrançois Tigeot 		return -EINVAL;
889e3adcf8fSFrançois Tigeot 
890e3adcf8fSFrançois Tigeot 	/* can't use the overlay with double wide pipe */
8912c9916cdSFrançois Tigeot 	if (crtc->config->double_wide)
892e3adcf8fSFrançois Tigeot 		return -EINVAL;
893e3adcf8fSFrançois Tigeot 
894e3adcf8fSFrançois Tigeot 	return 0;
895e3adcf8fSFrançois Tigeot }
896e3adcf8fSFrançois Tigeot 
897e3adcf8fSFrançois Tigeot static void update_pfit_vscale_ratio(struct intel_overlay *overlay)
898e3adcf8fSFrançois Tigeot {
8991487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = overlay->i915;
900e3adcf8fSFrançois Tigeot 	u32 pfit_control = I915_READ(PFIT_CONTROL);
901e3adcf8fSFrançois Tigeot 	u32 ratio;
902e3adcf8fSFrançois Tigeot 
903e3adcf8fSFrançois Tigeot 	/* XXX: This is not the same logic as in the xorg driver, but more in
904e3adcf8fSFrançois Tigeot 	 * line with the intel documentation for the i965
905e3adcf8fSFrançois Tigeot 	 */
9061487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 4) {
907e3adcf8fSFrançois Tigeot 		/* on i965 use the PGM reg to read out the autoscaler values */
908e3adcf8fSFrançois Tigeot 		ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965;
909e3adcf8fSFrançois Tigeot 	} else {
910e3adcf8fSFrançois Tigeot 		if (pfit_control & VERT_AUTO_SCALE)
911e3adcf8fSFrançois Tigeot 			ratio = I915_READ(PFIT_AUTO_RATIOS);
912e3adcf8fSFrançois Tigeot 		else
913e3adcf8fSFrançois Tigeot 			ratio = I915_READ(PFIT_PGM_RATIOS);
914e3adcf8fSFrançois Tigeot 		ratio >>= PFIT_VERT_SCALE_SHIFT;
915e3adcf8fSFrançois Tigeot 	}
916e3adcf8fSFrançois Tigeot 
917e3adcf8fSFrançois Tigeot 	overlay->pfit_vscale_ratio = ratio;
918e3adcf8fSFrançois Tigeot }
919e3adcf8fSFrançois Tigeot 
920e3adcf8fSFrançois Tigeot static int check_overlay_dst(struct intel_overlay *overlay,
921e3adcf8fSFrançois Tigeot 			     struct drm_intel_overlay_put_image *rec)
922e3adcf8fSFrançois Tigeot {
923e3adcf8fSFrançois Tigeot 	struct drm_display_mode *mode = &overlay->crtc->base.mode;
924e3adcf8fSFrançois Tigeot 
925e3adcf8fSFrançois Tigeot 	if (rec->dst_x < mode->hdisplay &&
926e3adcf8fSFrançois Tigeot 	    rec->dst_x + rec->dst_width <= mode->hdisplay &&
927e3adcf8fSFrançois Tigeot 	    rec->dst_y < mode->vdisplay &&
928e3adcf8fSFrançois Tigeot 	    rec->dst_y + rec->dst_height <= mode->vdisplay)
929e3adcf8fSFrançois Tigeot 		return 0;
930e3adcf8fSFrançois Tigeot 	else
931e3adcf8fSFrançois Tigeot 		return -EINVAL;
932e3adcf8fSFrançois Tigeot }
933e3adcf8fSFrançois Tigeot 
934e3adcf8fSFrançois Tigeot static int check_overlay_scaling(struct put_image_params *rec)
935e3adcf8fSFrançois Tigeot {
936e3adcf8fSFrançois Tigeot 	u32 tmp;
937e3adcf8fSFrançois Tigeot 
938e3adcf8fSFrançois Tigeot 	/* downscaling limit is 8.0 */
939e3adcf8fSFrançois Tigeot 	tmp = ((rec->src_scan_h << 16) / rec->dst_h) >> 16;
940e3adcf8fSFrançois Tigeot 	if (tmp > 7)
941e3adcf8fSFrançois Tigeot 		return -EINVAL;
942e3adcf8fSFrançois Tigeot 	tmp = ((rec->src_scan_w << 16) / rec->dst_w) >> 16;
943e3adcf8fSFrançois Tigeot 	if (tmp > 7)
944e3adcf8fSFrançois Tigeot 		return -EINVAL;
945e3adcf8fSFrançois Tigeot 
946e3adcf8fSFrançois Tigeot 	return 0;
947e3adcf8fSFrançois Tigeot }
948e3adcf8fSFrançois Tigeot 
9491487f786SFrançois Tigeot static int check_overlay_src(struct drm_i915_private *dev_priv,
950e3adcf8fSFrançois Tigeot 			     struct drm_intel_overlay_put_image *rec,
951e3adcf8fSFrançois Tigeot 			     struct drm_i915_gem_object *new_bo)
952e3adcf8fSFrançois Tigeot {
953e3adcf8fSFrançois Tigeot 	int uv_hscale = uv_hsubsampling(rec->flags);
954e3adcf8fSFrançois Tigeot 	int uv_vscale = uv_vsubsampling(rec->flags);
955e3adcf8fSFrançois Tigeot 	u32 stride_mask;
956e3adcf8fSFrançois Tigeot 	int depth;
957e3adcf8fSFrançois Tigeot 	u32 tmp;
958e3adcf8fSFrançois Tigeot 
959e3adcf8fSFrançois Tigeot 	/* check src dimensions */
9601487f786SFrançois Tigeot 	if (IS_845G(dev_priv) || IS_I830(dev_priv)) {
961e3adcf8fSFrançois Tigeot 		if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY ||
962e3adcf8fSFrançois Tigeot 		    rec->src_width  > IMAGE_MAX_WIDTH_LEGACY)
963e3adcf8fSFrançois Tigeot 			return -EINVAL;
964e3adcf8fSFrançois Tigeot 	} else {
965e3adcf8fSFrançois Tigeot 		if (rec->src_height > IMAGE_MAX_HEIGHT ||
966e3adcf8fSFrançois Tigeot 		    rec->src_width  > IMAGE_MAX_WIDTH)
967e3adcf8fSFrançois Tigeot 			return -EINVAL;
968e3adcf8fSFrançois Tigeot 	}
969e3adcf8fSFrançois Tigeot 
970e3adcf8fSFrançois Tigeot 	/* better safe than sorry, use 4 as the maximal subsampling ratio */
971e3adcf8fSFrançois Tigeot 	if (rec->src_height < N_VERT_Y_TAPS*4 ||
972e3adcf8fSFrançois Tigeot 	    rec->src_width  < N_HORIZ_Y_TAPS*4)
973e3adcf8fSFrançois Tigeot 		return -EINVAL;
974e3adcf8fSFrançois Tigeot 
975e3adcf8fSFrançois Tigeot 	/* check alignment constraints */
976e3adcf8fSFrançois Tigeot 	switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
977e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_RGB:
978e3adcf8fSFrançois Tigeot 		/* not implemented */
979e3adcf8fSFrançois Tigeot 		return -EINVAL;
980e3adcf8fSFrançois Tigeot 
981e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV_PACKED:
982e3adcf8fSFrançois Tigeot 		if (uv_vscale != 1)
983e3adcf8fSFrançois Tigeot 			return -EINVAL;
984e3adcf8fSFrançois Tigeot 
985e3adcf8fSFrançois Tigeot 		depth = packed_depth_bytes(rec->flags);
986e3adcf8fSFrançois Tigeot 		if (depth < 0)
987e3adcf8fSFrançois Tigeot 			return depth;
988e3adcf8fSFrançois Tigeot 
989e3adcf8fSFrançois Tigeot 		/* ignore UV planes */
990e3adcf8fSFrançois Tigeot 		rec->stride_UV = 0;
991e3adcf8fSFrançois Tigeot 		rec->offset_U = 0;
992e3adcf8fSFrançois Tigeot 		rec->offset_V = 0;
993e3adcf8fSFrançois Tigeot 		/* check pixel alignment */
994e3adcf8fSFrançois Tigeot 		if (rec->offset_Y % depth)
995e3adcf8fSFrançois Tigeot 			return -EINVAL;
996e3adcf8fSFrançois Tigeot 		break;
997e3adcf8fSFrançois Tigeot 
998e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV_PLANAR:
999e3adcf8fSFrançois Tigeot 		if (uv_vscale < 0 || uv_hscale < 0)
1000e3adcf8fSFrançois Tigeot 			return -EINVAL;
1001e3adcf8fSFrançois Tigeot 		/* no offset restrictions for planar formats */
1002e3adcf8fSFrançois Tigeot 		break;
1003e3adcf8fSFrançois Tigeot 
1004e3adcf8fSFrançois Tigeot 	default:
1005e3adcf8fSFrançois Tigeot 		return -EINVAL;
1006e3adcf8fSFrançois Tigeot 	}
1007e3adcf8fSFrançois Tigeot 
1008e3adcf8fSFrançois Tigeot 	if (rec->src_width % uv_hscale)
1009e3adcf8fSFrançois Tigeot 		return -EINVAL;
1010e3adcf8fSFrançois Tigeot 
1011e3adcf8fSFrançois Tigeot 	/* stride checking */
10121487f786SFrançois Tigeot 	if (IS_I830(dev_priv) || IS_845G(dev_priv))
1013e3adcf8fSFrançois Tigeot 		stride_mask = 255;
1014e3adcf8fSFrançois Tigeot 	else
1015e3adcf8fSFrançois Tigeot 		stride_mask = 63;
1016e3adcf8fSFrançois Tigeot 
1017e3adcf8fSFrançois Tigeot 	if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
1018e3adcf8fSFrançois Tigeot 		return -EINVAL;
10191487f786SFrançois Tigeot 	if (IS_GEN4(dev_priv) && rec->stride_Y < 512)
1020e3adcf8fSFrançois Tigeot 		return -EINVAL;
1021e3adcf8fSFrançois Tigeot 
1022e3adcf8fSFrançois Tigeot 	tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ?
1023e3adcf8fSFrançois Tigeot 		4096 : 8192;
1024e3adcf8fSFrançois Tigeot 	if (rec->stride_Y > tmp || rec->stride_UV > 2*1024)
1025e3adcf8fSFrançois Tigeot 		return -EINVAL;
1026e3adcf8fSFrançois Tigeot 
1027e3adcf8fSFrançois Tigeot 	/* check buffer dimensions */
1028e3adcf8fSFrançois Tigeot 	switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
1029e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_RGB:
1030e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV_PACKED:
1031e3adcf8fSFrançois Tigeot 		/* always 4 Y values per depth pixels */
1032e3adcf8fSFrançois Tigeot 		if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y)
1033e3adcf8fSFrançois Tigeot 			return -EINVAL;
1034e3adcf8fSFrançois Tigeot 
1035e3adcf8fSFrançois Tigeot 		tmp = rec->stride_Y*rec->src_height;
1036e3adcf8fSFrançois Tigeot 		if (rec->offset_Y + tmp > new_bo->base.size)
1037e3adcf8fSFrançois Tigeot 			return -EINVAL;
1038e3adcf8fSFrançois Tigeot 		break;
1039e3adcf8fSFrançois Tigeot 
1040e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV_PLANAR:
1041e3adcf8fSFrançois Tigeot 		if (rec->src_width > rec->stride_Y)
1042e3adcf8fSFrançois Tigeot 			return -EINVAL;
1043e3adcf8fSFrançois Tigeot 		if (rec->src_width/uv_hscale > rec->stride_UV)
1044e3adcf8fSFrançois Tigeot 			return -EINVAL;
1045e3adcf8fSFrançois Tigeot 
1046e3adcf8fSFrançois Tigeot 		tmp = rec->stride_Y * rec->src_height;
1047e3adcf8fSFrançois Tigeot 		if (rec->offset_Y + tmp > new_bo->base.size)
1048e3adcf8fSFrançois Tigeot 			return -EINVAL;
1049e3adcf8fSFrançois Tigeot 
1050e3adcf8fSFrançois Tigeot 		tmp = rec->stride_UV * (rec->src_height / uv_vscale);
1051e3adcf8fSFrançois Tigeot 		if (rec->offset_U + tmp > new_bo->base.size ||
1052e3adcf8fSFrançois Tigeot 		    rec->offset_V + tmp > new_bo->base.size)
1053e3adcf8fSFrançois Tigeot 			return -EINVAL;
1054e3adcf8fSFrançois Tigeot 		break;
1055e3adcf8fSFrançois Tigeot 	}
1056e3adcf8fSFrançois Tigeot 
1057e3adcf8fSFrançois Tigeot 	return 0;
1058e3adcf8fSFrançois Tigeot }
1059e3adcf8fSFrançois Tigeot 
1060e3adcf8fSFrançois Tigeot /**
1061e3adcf8fSFrançois Tigeot  * Return the pipe currently connected to the panel fitter,
1062e3adcf8fSFrançois Tigeot  * or -1 if the panel fitter is not present or not in use
1063e3adcf8fSFrançois Tigeot  */
10641487f786SFrançois Tigeot static int intel_panel_fitter_pipe(struct drm_i915_private *dev_priv)
1065e3adcf8fSFrançois Tigeot {
1066e3adcf8fSFrançois Tigeot 	u32  pfit_control;
1067e3adcf8fSFrançois Tigeot 
1068e3adcf8fSFrançois Tigeot 	/* i830 doesn't have a panel fitter */
10691487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) <= 3 &&
10701487f786SFrançois Tigeot 	    (IS_I830(dev_priv) || !IS_MOBILE(dev_priv)))
1071e3adcf8fSFrançois Tigeot 		return -1;
1072e3adcf8fSFrançois Tigeot 
1073e3adcf8fSFrançois Tigeot 	pfit_control = I915_READ(PFIT_CONTROL);
1074e3adcf8fSFrançois Tigeot 
1075e3adcf8fSFrançois Tigeot 	/* See if the panel fitter is in use */
1076e3adcf8fSFrançois Tigeot 	if ((pfit_control & PFIT_ENABLE) == 0)
1077e3adcf8fSFrançois Tigeot 		return -1;
1078e3adcf8fSFrançois Tigeot 
1079e3adcf8fSFrançois Tigeot 	/* 965 can place panel fitter on either pipe */
10801487f786SFrançois Tigeot 	if (IS_GEN4(dev_priv))
1081e3adcf8fSFrançois Tigeot 		return (pfit_control >> 29) & 0x3;
1082e3adcf8fSFrançois Tigeot 
1083e3adcf8fSFrançois Tigeot 	/* older chips can only use pipe 1 */
1084e3adcf8fSFrançois Tigeot 	return 1;
1085e3adcf8fSFrançois Tigeot }
1086e3adcf8fSFrançois Tigeot 
10871487f786SFrançois Tigeot int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data,
1088e3adcf8fSFrançois Tigeot 				  struct drm_file *file_priv)
1089e3adcf8fSFrançois Tigeot {
1090e3adcf8fSFrançois Tigeot 	struct drm_intel_overlay_put_image *put_image_rec = data;
1091bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
1092e3adcf8fSFrançois Tigeot 	struct intel_overlay *overlay;
109324edb884SFrançois Tigeot 	struct drm_crtc *drmmode_crtc;
1094e3adcf8fSFrançois Tigeot 	struct intel_crtc *crtc;
1095e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *new_bo;
1096e3adcf8fSFrançois Tigeot 	struct put_image_params *params;
1097e3adcf8fSFrançois Tigeot 	int ret;
1098e3adcf8fSFrançois Tigeot 
1099e3adcf8fSFrançois Tigeot 	overlay = dev_priv->overlay;
1100e3adcf8fSFrançois Tigeot 	if (!overlay) {
1101e3adcf8fSFrançois Tigeot 		DRM_DEBUG("userspace bug: no overlay\n");
1102e3adcf8fSFrançois Tigeot 		return -ENODEV;
1103e3adcf8fSFrançois Tigeot 	}
1104e3adcf8fSFrançois Tigeot 
1105e3adcf8fSFrançois Tigeot 	if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) {
1106a2fdbec6SFrançois Tigeot 		drm_modeset_lock_all(dev);
1107a2fdbec6SFrançois Tigeot 		mutex_lock(&dev->struct_mutex);
1108e3adcf8fSFrançois Tigeot 
1109e3adcf8fSFrançois Tigeot 		ret = intel_overlay_switch_off(overlay);
1110e3adcf8fSFrançois Tigeot 
1111a2fdbec6SFrançois Tigeot 		mutex_unlock(&dev->struct_mutex);
1112a2fdbec6SFrançois Tigeot 		drm_modeset_unlock_all(dev);
1113e3adcf8fSFrançois Tigeot 
1114e3adcf8fSFrançois Tigeot 		return ret;
1115e3adcf8fSFrançois Tigeot 	}
1116e3adcf8fSFrançois Tigeot 
1117bf017597SFrançois Tigeot 	params = kmalloc(sizeof(*params), M_DRM, GFP_KERNEL);
1118e3440f96SFrançois Tigeot 	if (!params)
1119e3440f96SFrançois Tigeot 		return -ENOMEM;
1120e3adcf8fSFrançois Tigeot 
112124edb884SFrançois Tigeot 	drmmode_crtc = drm_crtc_find(dev, put_image_rec->crtc_id);
112224edb884SFrançois Tigeot 	if (!drmmode_crtc) {
1123e3adcf8fSFrançois Tigeot 		ret = -ENOENT;
1124e3adcf8fSFrançois Tigeot 		goto out_free;
1125e3adcf8fSFrançois Tigeot 	}
112624edb884SFrançois Tigeot 	crtc = to_intel_crtc(drmmode_crtc);
1127e3adcf8fSFrançois Tigeot 
112887df8fc6SFrançois Tigeot 	new_bo = i915_gem_object_lookup(file_priv, put_image_rec->bo_handle);
112987df8fc6SFrançois Tigeot 	if (!new_bo) {
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 
113771f41f3eSFrançois Tigeot 	if (i915_gem_object_is_tiled(new_bo)) {
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 &&
11621487f786SFrançois Tigeot 		    intel_panel_fitter_pipe(dev_priv) == 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 
11961487f786SFrançois Tigeot 	ret = check_overlay_src(dev_priv, 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);
122587df8fc6SFrançois Tigeot 	i915_gem_object_put_unlocked(new_bo);
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 
12841487f786SFrançois Tigeot int intel_overlay_attrs_ioctl(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;
1288bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
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 
13091487f786SFrançois Tigeot 		if (!IS_GEN2(dev_priv)) {
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) {
13411487f786SFrançois Tigeot 			if (IS_GEN2(dev_priv))
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 
13711487f786SFrançois Tigeot void intel_setup_overlay(struct drm_i915_private *dev_priv)
1372e3adcf8fSFrançois Tigeot {
1373e3adcf8fSFrançois Tigeot 	struct intel_overlay *overlay;
1374e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *reg_bo;
1375e3440f96SFrançois Tigeot 	struct overlay_registers __iomem *regs;
1376*1e12ee3bSFrançois Tigeot 	struct i915_vma *vma = NULL;
1377e3adcf8fSFrançois Tigeot 	int ret;
1378e3adcf8fSFrançois Tigeot 
13791487f786SFrançois Tigeot 	if (!HAS_OVERLAY(dev_priv))
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 
1386303bf270SFrançois Tigeot 	mutex_lock(&dev_priv->drm.struct_mutex);
1387e3440f96SFrançois Tigeot 	if (WARN_ON(dev_priv->overlay))
1388e3adcf8fSFrançois Tigeot 		goto out_free;
1389e3440f96SFrançois Tigeot 
13901487f786SFrançois Tigeot 	overlay->i915 = dev_priv;
1391e3adcf8fSFrançois Tigeot 
13929edbd4a0SFrançois Tigeot 	reg_bo = NULL;
13931487f786SFrançois Tigeot 	if (!OVERLAY_NEEDS_PHYSICAL(dev_priv))
1394303bf270SFrançois Tigeot 		reg_bo = i915_gem_object_create_stolen(&dev_priv->drm,
1395303bf270SFrançois Tigeot 						       PAGE_SIZE);
13969edbd4a0SFrançois Tigeot 	if (reg_bo == NULL)
1397303bf270SFrançois Tigeot 		reg_bo = i915_gem_object_create(&dev_priv->drm, PAGE_SIZE);
13981487f786SFrançois Tigeot 	if (IS_ERR(reg_bo))
1399e3adcf8fSFrançois Tigeot 		goto out_free;
1400e3adcf8fSFrançois Tigeot 	overlay->reg_bo = reg_bo;
1401e3adcf8fSFrançois Tigeot 
14021487f786SFrançois Tigeot 	if (OVERLAY_NEEDS_PHYSICAL(dev_priv)) {
1403ba55f2f5SFrançois Tigeot 		ret = i915_gem_object_attach_phys(reg_bo, PAGE_SIZE);
1404e3adcf8fSFrançois Tigeot 		if (ret) {
1405e3adcf8fSFrançois Tigeot 			DRM_ERROR("failed to attach phys overlay regs\n");
1406e3adcf8fSFrançois Tigeot 			goto out_free_bo;
1407e3adcf8fSFrançois Tigeot 		}
1408ba55f2f5SFrançois Tigeot 		overlay->flip_addr = reg_bo->phys_handle->busaddr;
1409e3adcf8fSFrançois Tigeot 	} else {
1410*1e12ee3bSFrançois Tigeot 		vma = i915_gem_object_ggtt_pin(reg_bo, NULL,
141171f41f3eSFrançois Tigeot 					       0, PAGE_SIZE, PIN_MAPPABLE);
1412*1e12ee3bSFrançois Tigeot 		if (IS_ERR(vma)) {
1413e3adcf8fSFrançois Tigeot 			DRM_ERROR("failed to pin overlay register bo\n");
1414*1e12ee3bSFrançois Tigeot 			ret = PTR_ERR(vma);
1415e3adcf8fSFrançois Tigeot 			goto out_free_bo;
1416e3adcf8fSFrançois Tigeot 		}
1417*1e12ee3bSFrançois Tigeot 		overlay->flip_addr = i915_ggtt_offset(vma);
1418e3adcf8fSFrançois Tigeot 
1419e3adcf8fSFrançois Tigeot 		ret = i915_gem_object_set_to_gtt_domain(reg_bo, true);
1420e3adcf8fSFrançois Tigeot 		if (ret) {
1421e3adcf8fSFrançois Tigeot 			DRM_ERROR("failed to move overlay register bo into the GTT\n");
1422e3adcf8fSFrançois Tigeot 			goto out_unpin_bo;
1423e3adcf8fSFrançois Tigeot 		}
1424e3adcf8fSFrançois Tigeot 	}
1425e3adcf8fSFrançois Tigeot 
1426e3adcf8fSFrançois Tigeot 	/* init all values */
1427e3adcf8fSFrançois Tigeot 	overlay->color_key = 0x0101fe;
142819c468b4SFrançois Tigeot 	overlay->color_key_enabled = true;
1429e3adcf8fSFrançois Tigeot 	overlay->brightness = -19;
1430e3adcf8fSFrançois Tigeot 	overlay->contrast = 75;
1431e3adcf8fSFrançois Tigeot 	overlay->saturation = 146;
1432e3adcf8fSFrançois Tigeot 
1433e3adcf8fSFrançois Tigeot 	regs = intel_overlay_map_regs(overlay);
1434e3adcf8fSFrançois Tigeot 	if (!regs)
1435e3adcf8fSFrançois Tigeot 		goto out_unpin_bo;
1436e3adcf8fSFrançois Tigeot 
1437e3440f96SFrançois Tigeot 	memset_io(regs, 0, sizeof(struct overlay_registers));
1438e3adcf8fSFrançois Tigeot 	update_polyphase_filter(regs);
1439e3adcf8fSFrançois Tigeot 	update_reg_attrs(overlay, regs);
1440e3adcf8fSFrançois Tigeot 
1441e3adcf8fSFrançois Tigeot 	intel_overlay_unmap_regs(overlay, regs);
1442e3adcf8fSFrançois Tigeot 
1443e3adcf8fSFrançois Tigeot 	dev_priv->overlay = overlay;
1444303bf270SFrançois Tigeot 	mutex_unlock(&dev_priv->drm.struct_mutex);
1445e3440f96SFrançois Tigeot 	DRM_INFO("initialized overlay support\n");
1446e3adcf8fSFrançois Tigeot 	return;
1447e3adcf8fSFrançois Tigeot 
1448e3adcf8fSFrançois Tigeot out_unpin_bo:
1449*1e12ee3bSFrançois Tigeot 	if (vma)
1450*1e12ee3bSFrançois Tigeot 		i915_vma_unpin(vma);
1451e3adcf8fSFrançois Tigeot out_free_bo:
145287df8fc6SFrançois Tigeot 	i915_gem_object_put(reg_bo);
1453e3adcf8fSFrançois Tigeot out_free:
1454303bf270SFrançois Tigeot 	mutex_unlock(&dev_priv->drm.struct_mutex);
1455158486a6SFrançois Tigeot 	kfree(overlay);
1456e3adcf8fSFrançois Tigeot 	return;
1457e3adcf8fSFrançois Tigeot }
1458e3adcf8fSFrançois Tigeot 
14591487f786SFrançois Tigeot void intel_cleanup_overlay(struct drm_i915_private *dev_priv)
1460e3adcf8fSFrançois Tigeot {
1461e3adcf8fSFrançois Tigeot 	if (!dev_priv->overlay)
1462e3adcf8fSFrançois Tigeot 		return;
1463e3adcf8fSFrançois Tigeot 
1464e3adcf8fSFrançois Tigeot 	/* The bo's should be free'd by the generic code already.
1465e3adcf8fSFrançois Tigeot 	 * Furthermore modesetting teardown happens beforehand so the
1466e3adcf8fSFrançois Tigeot 	 * hardware should be off already */
146719c468b4SFrançois Tigeot 	WARN_ON(dev_priv->overlay->active);
1468e3adcf8fSFrançois Tigeot 
146987df8fc6SFrançois Tigeot 	i915_gem_object_put_unlocked(dev_priv->overlay->reg_bo);
1470158486a6SFrançois Tigeot 	kfree(dev_priv->overlay);
1471e3adcf8fSFrançois Tigeot }
1472e3adcf8fSFrançois Tigeot 
1473*1e12ee3bSFrançois Tigeot #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR)
1474*1e12ee3bSFrançois Tigeot 
1475e3adcf8fSFrançois Tigeot struct intel_overlay_error_state {
1476e3adcf8fSFrançois Tigeot 	struct overlay_registers regs;
1477e3adcf8fSFrançois Tigeot 	unsigned long base;
1478e3adcf8fSFrançois Tigeot 	u32 dovsta;
1479e3adcf8fSFrançois Tigeot 	u32 isr;
1480e3adcf8fSFrançois Tigeot };
1481e3adcf8fSFrançois Tigeot 
1482e3440f96SFrançois Tigeot static struct overlay_registers __iomem *
1483e3440f96SFrançois Tigeot intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
1484e3440f96SFrançois Tigeot {
14851487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = overlay->i915;
1486e3440f96SFrançois Tigeot 	struct overlay_registers __iomem *regs;
1487e3440f96SFrançois Tigeot 
14881487f786SFrançois Tigeot 	if (OVERLAY_NEEDS_PHYSICAL(dev_priv))
1489e3440f96SFrançois Tigeot 		/* Cast to make sparse happy, but it's wc memory anyway, so
1490e3440f96SFrançois Tigeot 		 * equivalent to the wc io mapping on X86. */
1491e3440f96SFrançois Tigeot 		regs = (struct overlay_registers __iomem *)
14922c9916cdSFrançois Tigeot 			overlay->reg_bo->phys_handle->vaddr;
1493e3440f96SFrançois Tigeot 	else
1494*1e12ee3bSFrançois Tigeot 		regs = io_mapping_map_atomic_wc(&dev_priv->ggtt.mappable,
14951487f786SFrançois Tigeot 						overlay->flip_addr);
1496e3440f96SFrançois Tigeot 
1497e3440f96SFrançois Tigeot 	return regs;
1498e3440f96SFrançois Tigeot }
1499e3440f96SFrançois Tigeot 
1500e3440f96SFrançois Tigeot static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay,
1501e3440f96SFrançois Tigeot 					struct overlay_registers __iomem *regs)
1502e3440f96SFrançois Tigeot {
15031487f786SFrançois Tigeot 	if (!OVERLAY_NEEDS_PHYSICAL(overlay->i915))
1504e3440f96SFrançois Tigeot 		io_mapping_unmap_atomic(regs);
1505e3440f96SFrançois Tigeot }
1506e3440f96SFrançois Tigeot 
1507e3adcf8fSFrançois Tigeot struct intel_overlay_error_state *
15081487f786SFrançois Tigeot intel_overlay_capture_error_state(struct drm_i915_private *dev_priv)
1509e3adcf8fSFrançois Tigeot {
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 
1517bf017597SFrançois Tigeot 	error = kmalloc(sizeof(*error), M_DRM, 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);
15231487f786SFrançois Tigeot 	error->base = overlay->flip_addr;
1524e3adcf8fSFrançois Tigeot 
1525e3440f96SFrançois Tigeot 	regs = intel_overlay_map_regs_atomic(overlay);
1526e3adcf8fSFrançois Tigeot 	if (!regs)
1527e3adcf8fSFrançois Tigeot 		goto err;
1528e3adcf8fSFrançois Tigeot 
1529e3440f96SFrançois Tigeot 	memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers));
1530e3440f96SFrançois Tigeot 	intel_overlay_unmap_regs_atomic(overlay, regs);
1531e3adcf8fSFrançois Tigeot 
1532e3440f96SFrançois Tigeot 	return error;
1533e3adcf8fSFrançois Tigeot 
1534e3adcf8fSFrançois Tigeot err:
1535158486a6SFrançois Tigeot 	kfree(error);
1536e3440f96SFrançois Tigeot 	return NULL;
1537e3adcf8fSFrançois Tigeot }
1538e3adcf8fSFrançois Tigeot 
1539e3adcf8fSFrançois Tigeot void
15405d0b1887SFrançois Tigeot intel_overlay_print_error_state(struct drm_i915_error_state_buf *m,
15415d0b1887SFrançois Tigeot 				struct intel_overlay_error_state *error)
1542e3adcf8fSFrançois Tigeot {
15435d0b1887SFrançois Tigeot 	i915_error_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",
1544e3adcf8fSFrançois Tigeot 			  error->dovsta, error->isr);
15455d0b1887SFrançois Tigeot 	i915_error_printf(m, "  Register file at 0x%08lx:\n",
1546e3adcf8fSFrançois Tigeot 			  error->base);
1547e3adcf8fSFrançois Tigeot 
15485d0b1887SFrançois Tigeot #define P(x) i915_error_printf(m, "    " #x ":	0x%08x\n", error->regs.x)
1549e3adcf8fSFrançois Tigeot 	P(OBUF_0Y);
1550e3adcf8fSFrançois Tigeot 	P(OBUF_1Y);
1551e3adcf8fSFrançois Tigeot 	P(OBUF_0U);
1552e3adcf8fSFrançois Tigeot 	P(OBUF_0V);
1553e3adcf8fSFrançois Tigeot 	P(OBUF_1U);
1554e3adcf8fSFrançois Tigeot 	P(OBUF_1V);
1555e3adcf8fSFrançois Tigeot 	P(OSTRIDE);
1556e3adcf8fSFrançois Tigeot 	P(YRGB_VPH);
1557e3adcf8fSFrançois Tigeot 	P(UV_VPH);
1558e3adcf8fSFrançois Tigeot 	P(HORZ_PH);
1559e3adcf8fSFrançois Tigeot 	P(INIT_PHS);
1560e3adcf8fSFrançois Tigeot 	P(DWINPOS);
1561e3adcf8fSFrançois Tigeot 	P(DWINSZ);
1562e3adcf8fSFrançois Tigeot 	P(SWIDTH);
1563e3adcf8fSFrançois Tigeot 	P(SWIDTHSW);
1564e3adcf8fSFrançois Tigeot 	P(SHEIGHT);
1565e3adcf8fSFrançois Tigeot 	P(YRGBSCALE);
1566e3adcf8fSFrançois Tigeot 	P(UVSCALE);
1567e3adcf8fSFrançois Tigeot 	P(OCLRC0);
1568e3adcf8fSFrançois Tigeot 	P(OCLRC1);
1569e3adcf8fSFrançois Tigeot 	P(DCLRKV);
1570e3adcf8fSFrançois Tigeot 	P(DCLRKM);
1571e3adcf8fSFrançois Tigeot 	P(SCLRKVH);
1572e3adcf8fSFrançois Tigeot 	P(SCLRKVL);
1573e3adcf8fSFrançois Tigeot 	P(SCLRKEN);
1574e3adcf8fSFrançois Tigeot 	P(OCONFIG);
1575e3adcf8fSFrançois Tigeot 	P(OCMD);
1576e3adcf8fSFrançois Tigeot 	P(OSTART_0Y);
1577e3adcf8fSFrançois Tigeot 	P(OSTART_1Y);
1578e3adcf8fSFrançois Tigeot 	P(OSTART_0U);
1579e3adcf8fSFrançois Tigeot 	P(OSTART_0V);
1580e3adcf8fSFrançois Tigeot 	P(OSTART_1U);
1581e3adcf8fSFrançois Tigeot 	P(OSTART_1V);
1582e3adcf8fSFrançois Tigeot 	P(OTILEOFF_0Y);
1583e3adcf8fSFrançois Tigeot 	P(OTILEOFF_1Y);
1584e3adcf8fSFrançois Tigeot 	P(OTILEOFF_0U);
1585e3adcf8fSFrançois Tigeot 	P(OTILEOFF_0V);
1586e3adcf8fSFrançois Tigeot 	P(OTILEOFF_1U);
1587e3adcf8fSFrançois Tigeot 	P(OTILEOFF_1V);
1588e3adcf8fSFrançois Tigeot 	P(FASTHSCALE);
1589e3adcf8fSFrançois Tigeot 	P(UVSCALEV);
1590e3adcf8fSFrançois Tigeot #undef P
1591e3adcf8fSFrançois Tigeot }
1592*1e12ee3bSFrançois Tigeot 
1593*1e12ee3bSFrançois Tigeot #endif
1594