xref: /dflybsd-src/sys/dev/drm/i915/intel_overlay.c (revision 24edb8848e2499ece59b84a04f554a7a897feeab)
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;
175e3adcf8fSFrançois Tigeot 	int active;
176e3adcf8fSFrançois Tigeot 	int pfit_active;
177e3adcf8fSFrançois Tigeot 	u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
178e3adcf8fSFrançois Tigeot 	u32 color_key;
179e3adcf8fSFrançois Tigeot 	u32 brightness, contrast, saturation;
180e3adcf8fSFrançois Tigeot 	u32 old_xscale, old_yscale;
181e3adcf8fSFrançois Tigeot 	/* register access */
182e3adcf8fSFrançois Tigeot 	u32 flip_addr;
183e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *reg_bo;
184e3adcf8fSFrançois Tigeot 	/* flip handling */
185e3adcf8fSFrançois Tigeot 	uint32_t last_flip_req;
186e3adcf8fSFrançois Tigeot 	void (*flip_tail)(struct intel_overlay *);
187e3adcf8fSFrançois Tigeot };
188e3adcf8fSFrançois Tigeot 
189e3440f96SFrançois Tigeot static struct overlay_registers __iomem *
190e3adcf8fSFrançois Tigeot intel_overlay_map_regs(struct intel_overlay *overlay)
191e3adcf8fSFrançois Tigeot {
192e3440f96SFrançois Tigeot 	struct overlay_registers __iomem *regs;
193e3adcf8fSFrançois Tigeot 
194e3440f96SFrançois Tigeot 	if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
195ba55f2f5SFrançois Tigeot 		regs = (struct overlay_registers __iomem *)overlay->reg_bo->phys_handle->vaddr;
196e3440f96SFrançois Tigeot 	else
197e3adcf8fSFrançois Tigeot 		regs = pmap_mapdev_attr(overlay->dev->agp->base +
1989edbd4a0SFrançois Tigeot 		    i915_gem_obj_ggtt_offset(overlay->reg_bo), PAGE_SIZE,
199e3adcf8fSFrançois Tigeot 		    PAT_WRITE_COMBINING);
200e3440f96SFrançois Tigeot 
201e3440f96SFrançois Tigeot 	return regs;
202e3adcf8fSFrançois Tigeot }
203e3adcf8fSFrançois Tigeot 
204e3adcf8fSFrançois Tigeot static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
205e3440f96SFrançois Tigeot 				     struct overlay_registers __iomem *regs)
206e3adcf8fSFrançois Tigeot {
207e3adcf8fSFrançois Tigeot 	if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
208e3adcf8fSFrançois Tigeot 		pmap_unmapdev((vm_offset_t)regs, PAGE_SIZE);
209e3adcf8fSFrançois Tigeot }
210e3adcf8fSFrançois Tigeot 
211e3adcf8fSFrançois Tigeot static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
212e3adcf8fSFrançois Tigeot 					 void (*tail)(struct intel_overlay *))
213e3adcf8fSFrançois Tigeot {
214e3adcf8fSFrançois Tigeot 	struct drm_device *dev = overlay->dev;
215ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
216ba55f2f5SFrançois Tigeot 	struct intel_engine_cs *ring = &dev_priv->ring[RCS];
217e3adcf8fSFrançois Tigeot 	int ret;
218e3adcf8fSFrançois Tigeot 
219b030f26bSFrançois Tigeot 	BUG_ON(overlay->last_flip_req);
2205d0b1887SFrançois Tigeot 	ret = i915_add_request(ring, &overlay->last_flip_req);
221f192107fSFrançois Tigeot 	if (ret)
222e3adcf8fSFrançois Tigeot 		return ret;
223f192107fSFrançois Tigeot 
224e3adcf8fSFrançois Tigeot 	overlay->flip_tail = tail;
225f192107fSFrançois Tigeot 	ret = i915_wait_seqno(ring, overlay->last_flip_req);
226e3adcf8fSFrançois Tigeot 	if (ret)
227e3adcf8fSFrançois Tigeot 		return ret;
228686a02f1SFrançois Tigeot 	i915_gem_retire_requests(dev);
229e3adcf8fSFrançois Tigeot 
230e3adcf8fSFrançois Tigeot 	overlay->last_flip_req = 0;
231e3adcf8fSFrançois Tigeot 	return 0;
232e3adcf8fSFrançois Tigeot }
233e3adcf8fSFrançois Tigeot 
234e3adcf8fSFrançois Tigeot /* overlay needs to be disable in OCMD reg */
235e3adcf8fSFrançois Tigeot static int intel_overlay_on(struct intel_overlay *overlay)
236e3adcf8fSFrançois Tigeot {
237e3adcf8fSFrançois Tigeot 	struct drm_device *dev = overlay->dev;
238e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
239ba55f2f5SFrançois Tigeot 	struct intel_engine_cs *ring = &dev_priv->ring[RCS];
240e3adcf8fSFrançois Tigeot 	int ret;
241e3adcf8fSFrançois Tigeot 
2427cbd1a46SFrançois Tigeot 	BUG_ON(overlay->active);
243e3adcf8fSFrançois Tigeot 	overlay->active = 1;
244e3adcf8fSFrançois Tigeot 
2457cbd1a46SFrançois Tigeot 	WARN_ON(IS_I830(dev) && !(dev_priv->quirks & QUIRK_PIPEA_FORCE));
246e3adcf8fSFrançois Tigeot 
247f192107fSFrançois Tigeot 	ret = intel_ring_begin(ring, 4);
248f192107fSFrançois Tigeot 	if (ret)
249e3adcf8fSFrançois Tigeot 		return ret;
250f192107fSFrançois Tigeot 
251f192107fSFrançois Tigeot 	intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_ON);
252f192107fSFrançois Tigeot 	intel_ring_emit(ring, overlay->flip_addr | OFC_UPDATE);
253f192107fSFrançois Tigeot 	intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
254f192107fSFrançois Tigeot 	intel_ring_emit(ring, MI_NOOP);
255f192107fSFrançois Tigeot 	intel_ring_advance(ring);
256f192107fSFrançois Tigeot 
257f192107fSFrançois Tigeot 	return intel_overlay_do_wait_request(overlay, NULL);
258e3adcf8fSFrançois Tigeot }
259e3adcf8fSFrançois Tigeot 
260e3adcf8fSFrançois Tigeot /* overlay needs to be enabled in OCMD reg */
261e3adcf8fSFrançois Tigeot static int intel_overlay_continue(struct intel_overlay *overlay,
262e3adcf8fSFrançois Tigeot 				  bool load_polyphase_filter)
263e3adcf8fSFrançois Tigeot {
264e3adcf8fSFrançois Tigeot 	struct drm_device *dev = overlay->dev;
265ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
266ba55f2f5SFrançois Tigeot 	struct intel_engine_cs *ring = &dev_priv->ring[RCS];
267e3adcf8fSFrançois Tigeot 	u32 flip_addr = overlay->flip_addr;
268e3adcf8fSFrançois Tigeot 	u32 tmp;
269e3adcf8fSFrançois Tigeot 	int ret;
270e3adcf8fSFrançois Tigeot 
271f192107fSFrançois Tigeot 	BUG_ON(!overlay->active);
272e3adcf8fSFrançois Tigeot 
273e3adcf8fSFrançois Tigeot 	if (load_polyphase_filter)
274e3adcf8fSFrançois Tigeot 		flip_addr |= OFC_UPDATE;
275e3adcf8fSFrançois Tigeot 
276e3adcf8fSFrançois Tigeot 	/* check for underruns */
277e3adcf8fSFrançois Tigeot 	tmp = I915_READ(DOVSTA);
278e3adcf8fSFrançois Tigeot 	if (tmp & (1 << 17))
279e3adcf8fSFrançois Tigeot 		DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
280e3adcf8fSFrançois Tigeot 
281f192107fSFrançois Tigeot 	ret = intel_ring_begin(ring, 2);
282f192107fSFrançois Tigeot 	if (ret)
283e3adcf8fSFrançois Tigeot 		return ret;
284e3adcf8fSFrançois Tigeot 
285f192107fSFrançois Tigeot 	intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
286f192107fSFrançois Tigeot 	intel_ring_emit(ring, flip_addr);
287f192107fSFrançois Tigeot 	intel_ring_advance(ring);
288e3adcf8fSFrançois Tigeot 
2895d0b1887SFrançois Tigeot 	return i915_add_request(ring, &overlay->last_flip_req);
290e3adcf8fSFrançois Tigeot }
291e3adcf8fSFrançois Tigeot 
292e3adcf8fSFrançois Tigeot static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
293e3adcf8fSFrançois Tigeot {
294e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *obj = overlay->old_vid_bo;
295e3adcf8fSFrançois Tigeot 
296ba55f2f5SFrançois Tigeot 	i915_gem_object_ggtt_unpin(obj);
297e3adcf8fSFrançois Tigeot 	drm_gem_object_unreference(&obj->base);
298e3adcf8fSFrançois Tigeot 
299e3adcf8fSFrançois Tigeot 	overlay->old_vid_bo = NULL;
300e3adcf8fSFrançois Tigeot }
301e3adcf8fSFrançois Tigeot 
302e3adcf8fSFrançois Tigeot static void intel_overlay_off_tail(struct intel_overlay *overlay)
303e3adcf8fSFrançois Tigeot {
304e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *obj = overlay->vid_bo;
305e3adcf8fSFrançois Tigeot 
306e3adcf8fSFrançois Tigeot 	/* never have the overlay hw on without showing a frame */
307e3440f96SFrançois Tigeot 	BUG_ON(!overlay->vid_bo);
308e3adcf8fSFrançois Tigeot 
309ba55f2f5SFrançois Tigeot 	i915_gem_object_ggtt_unpin(obj);
310e3adcf8fSFrançois Tigeot 	drm_gem_object_unreference(&obj->base);
311e3adcf8fSFrançois Tigeot 	overlay->vid_bo = NULL;
312e3adcf8fSFrançois Tigeot 
313e3adcf8fSFrançois Tigeot 	overlay->crtc->overlay = NULL;
314e3adcf8fSFrançois Tigeot 	overlay->crtc = NULL;
315e3adcf8fSFrançois Tigeot 	overlay->active = 0;
316e3adcf8fSFrançois Tigeot }
317e3adcf8fSFrançois Tigeot 
318e3adcf8fSFrançois Tigeot /* overlay needs to be disabled in OCMD reg */
319e3adcf8fSFrançois Tigeot static int intel_overlay_off(struct intel_overlay *overlay)
320e3adcf8fSFrançois Tigeot {
321e3adcf8fSFrançois Tigeot 	struct drm_device *dev = overlay->dev;
322e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
323ba55f2f5SFrançois Tigeot 	struct intel_engine_cs *ring = &dev_priv->ring[RCS];
324e3adcf8fSFrançois Tigeot 	u32 flip_addr = overlay->flip_addr;
325e3adcf8fSFrançois Tigeot 	int ret;
326e3adcf8fSFrançois Tigeot 
327f192107fSFrançois Tigeot 	BUG_ON(!overlay->active);
328e3adcf8fSFrançois Tigeot 
329e3adcf8fSFrançois Tigeot 	/* According to intel docs the overlay hw may hang (when switching
330e3adcf8fSFrançois Tigeot 	 * off) without loading the filter coeffs. It is however unclear whether
331e3adcf8fSFrançois Tigeot 	 * this applies to the disabling of the overlay or to the switching off
332e3adcf8fSFrançois Tigeot 	 * of the hw. Do it in both cases */
333e3adcf8fSFrançois Tigeot 	flip_addr |= OFC_UPDATE;
334e3adcf8fSFrançois Tigeot 
335f192107fSFrançois Tigeot 	ret = intel_ring_begin(ring, 6);
336f192107fSFrançois Tigeot 	if (ret)
337e3adcf8fSFrançois Tigeot 		return ret;
338e3adcf8fSFrançois Tigeot 
339f192107fSFrançois Tigeot 	/* wait for overlay to go idle */
340f192107fSFrançois Tigeot 	intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
341f192107fSFrançois Tigeot 	intel_ring_emit(ring, flip_addr);
342f192107fSFrançois Tigeot 	intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
343f192107fSFrançois Tigeot 	/* turn overlay off */
34419df918dSFrançois Tigeot 	if (IS_I830(dev)) {
34519df918dSFrançois Tigeot 		/* Workaround: Don't disable the overlay fully, since otherwise
34619df918dSFrançois Tigeot 		 * it dies on the next OVERLAY_ON cmd. */
34719df918dSFrançois Tigeot 		intel_ring_emit(ring, MI_NOOP);
34819df918dSFrançois Tigeot 		intel_ring_emit(ring, MI_NOOP);
34919df918dSFrançois Tigeot 		intel_ring_emit(ring, MI_NOOP);
35019df918dSFrançois Tigeot 	} else {
351f192107fSFrançois Tigeot 		intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
352f192107fSFrançois Tigeot 		intel_ring_emit(ring, flip_addr);
353f192107fSFrançois Tigeot 		intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
35419df918dSFrançois Tigeot 	}
355f192107fSFrançois Tigeot 	intel_ring_advance(ring);
356f192107fSFrançois Tigeot 
357f192107fSFrançois Tigeot 	return intel_overlay_do_wait_request(overlay, intel_overlay_off_tail);
358e3adcf8fSFrançois Tigeot }
359e3adcf8fSFrançois Tigeot 
360e3adcf8fSFrançois Tigeot /* recover from an interruption due to a signal
361e3adcf8fSFrançois Tigeot  * We have to be careful not to repeat work forever an make forward progess. */
362e3adcf8fSFrançois Tigeot static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
363e3adcf8fSFrançois Tigeot {
364e3adcf8fSFrançois Tigeot 	struct drm_device *dev = overlay->dev;
365ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
366ba55f2f5SFrançois Tigeot 	struct intel_engine_cs *ring = &dev_priv->ring[RCS];
367e3adcf8fSFrançois Tigeot 	int ret;
368e3adcf8fSFrançois Tigeot 
369e3adcf8fSFrançois Tigeot 	if (overlay->last_flip_req == 0)
370e3adcf8fSFrançois Tigeot 		return 0;
371e3adcf8fSFrançois Tigeot 
372b030f26bSFrançois Tigeot 	ret = i915_wait_seqno(ring, overlay->last_flip_req);
373e3adcf8fSFrançois Tigeot 	if (ret)
374e3adcf8fSFrançois Tigeot 		return ret;
375b030f26bSFrançois Tigeot 	i915_gem_retire_requests(dev);
376e3adcf8fSFrançois Tigeot 
377e3adcf8fSFrançois Tigeot 	if (overlay->flip_tail)
378e3adcf8fSFrançois Tigeot 		overlay->flip_tail(overlay);
379e3adcf8fSFrançois Tigeot 
380e3adcf8fSFrançois Tigeot 	overlay->last_flip_req = 0;
381e3adcf8fSFrançois Tigeot 	return 0;
382e3adcf8fSFrançois Tigeot }
383e3adcf8fSFrançois Tigeot 
384e3adcf8fSFrançois Tigeot /* Wait for pending overlay flip and release old frame.
385e3adcf8fSFrançois Tigeot  * Needs to be called before the overlay register are changed
386e3adcf8fSFrançois Tigeot  * via intel_overlay_(un)map_regs
387e3adcf8fSFrançois Tigeot  */
388e3adcf8fSFrançois Tigeot static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
389e3adcf8fSFrançois Tigeot {
390e3adcf8fSFrançois Tigeot 	struct drm_device *dev = overlay->dev;
391ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
392ba55f2f5SFrançois Tigeot 	struct intel_engine_cs *ring = &dev_priv->ring[RCS];
393e3adcf8fSFrançois Tigeot 	int ret;
394e3adcf8fSFrançois Tigeot 
395e3adcf8fSFrançois Tigeot 	/* Only wait if there is actually an old frame to release to
396e3adcf8fSFrançois Tigeot 	 * guarantee forward progress.
397e3adcf8fSFrançois Tigeot 	 */
398e3adcf8fSFrançois Tigeot 	if (!overlay->old_vid_bo)
399e3adcf8fSFrançois Tigeot 		return 0;
400e3adcf8fSFrançois Tigeot 
401e3adcf8fSFrançois Tigeot 	if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) {
402e3adcf8fSFrançois Tigeot 		/* synchronous slowpath */
403f192107fSFrançois Tigeot 		ret = intel_ring_begin(ring, 2);
404f192107fSFrançois Tigeot 		if (ret)
405e3adcf8fSFrançois Tigeot 			return ret;
406e3adcf8fSFrançois Tigeot 
407f192107fSFrançois Tigeot 		intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
408f192107fSFrançois Tigeot 		intel_ring_emit(ring, MI_NOOP);
409f192107fSFrançois Tigeot 		intel_ring_advance(ring);
410e3adcf8fSFrançois Tigeot 
411f192107fSFrançois Tigeot 		ret = intel_overlay_do_wait_request(overlay,
412e3adcf8fSFrançois Tigeot 						    intel_overlay_release_old_vid_tail);
413e3adcf8fSFrançois Tigeot 		if (ret)
414e3adcf8fSFrançois Tigeot 			return ret;
415e3adcf8fSFrançois Tigeot 	}
416e3adcf8fSFrançois Tigeot 
417e3adcf8fSFrançois Tigeot 	intel_overlay_release_old_vid_tail(overlay);
418*24edb884SFrançois Tigeot 
419*24edb884SFrançois Tigeot 
420*24edb884SFrançois Tigeot 	i915_gem_track_fb(overlay->old_vid_bo, NULL,
421*24edb884SFrançois Tigeot 			  INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe));
422e3adcf8fSFrançois Tigeot 	return 0;
423e3adcf8fSFrançois Tigeot }
424e3adcf8fSFrançois Tigeot 
425e3adcf8fSFrançois Tigeot struct put_image_params {
426e3adcf8fSFrançois Tigeot 	int format;
427e3adcf8fSFrançois Tigeot 	short dst_x;
428e3adcf8fSFrançois Tigeot 	short dst_y;
429e3adcf8fSFrançois Tigeot 	short dst_w;
430e3adcf8fSFrançois Tigeot 	short dst_h;
431e3adcf8fSFrançois Tigeot 	short src_w;
432e3adcf8fSFrançois Tigeot 	short src_scan_h;
433e3adcf8fSFrançois Tigeot 	short src_scan_w;
434e3adcf8fSFrançois Tigeot 	short src_h;
435e3adcf8fSFrançois Tigeot 	short stride_Y;
436e3adcf8fSFrançois Tigeot 	short stride_UV;
437e3adcf8fSFrançois Tigeot 	int offset_Y;
438e3adcf8fSFrançois Tigeot 	int offset_U;
439e3adcf8fSFrançois Tigeot 	int offset_V;
440e3adcf8fSFrançois Tigeot };
441e3adcf8fSFrançois Tigeot 
442e3adcf8fSFrançois Tigeot static int packed_depth_bytes(u32 format)
443e3adcf8fSFrançois Tigeot {
444e3adcf8fSFrançois Tigeot 	switch (format & I915_OVERLAY_DEPTH_MASK) {
445e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV422:
446e3adcf8fSFrançois Tigeot 		return 4;
447e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV411:
448e3adcf8fSFrançois Tigeot 		/* return 6; not implemented */
449e3adcf8fSFrançois Tigeot 	default:
450e3adcf8fSFrançois Tigeot 		return -EINVAL;
451e3adcf8fSFrançois Tigeot 	}
452e3adcf8fSFrançois Tigeot }
453e3adcf8fSFrançois Tigeot 
454e3adcf8fSFrançois Tigeot static int packed_width_bytes(u32 format, short width)
455e3adcf8fSFrançois Tigeot {
456e3adcf8fSFrançois Tigeot 	switch (format & I915_OVERLAY_DEPTH_MASK) {
457e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV422:
458e3adcf8fSFrançois Tigeot 		return width << 1;
459e3adcf8fSFrançois Tigeot 	default:
460e3adcf8fSFrançois Tigeot 		return -EINVAL;
461e3adcf8fSFrançois Tigeot 	}
462e3adcf8fSFrançois Tigeot }
463e3adcf8fSFrançois Tigeot 
464e3adcf8fSFrançois Tigeot static int uv_hsubsampling(u32 format)
465e3adcf8fSFrançois Tigeot {
466e3adcf8fSFrançois Tigeot 	switch (format & I915_OVERLAY_DEPTH_MASK) {
467e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV422:
468e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV420:
469e3adcf8fSFrançois Tigeot 		return 2;
470e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV411:
471e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV410:
472e3adcf8fSFrançois Tigeot 		return 4;
473e3adcf8fSFrançois Tigeot 	default:
474e3adcf8fSFrançois Tigeot 		return -EINVAL;
475e3adcf8fSFrançois Tigeot 	}
476e3adcf8fSFrançois Tigeot }
477e3adcf8fSFrançois Tigeot 
478e3adcf8fSFrançois Tigeot static int uv_vsubsampling(u32 format)
479e3adcf8fSFrançois Tigeot {
480e3adcf8fSFrançois Tigeot 	switch (format & I915_OVERLAY_DEPTH_MASK) {
481e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV420:
482e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV410:
483e3adcf8fSFrançois Tigeot 		return 2;
484e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV422:
485e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV411:
486e3adcf8fSFrançois Tigeot 		return 1;
487e3adcf8fSFrançois Tigeot 	default:
488e3adcf8fSFrançois Tigeot 		return -EINVAL;
489e3adcf8fSFrançois Tigeot 	}
490e3adcf8fSFrançois Tigeot }
491e3adcf8fSFrançois Tigeot 
492e3adcf8fSFrançois Tigeot static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width)
493e3adcf8fSFrançois Tigeot {
494e3adcf8fSFrançois Tigeot 	u32 mask, shift, ret;
495e3adcf8fSFrançois Tigeot 	if (IS_GEN2(dev)) {
496e3adcf8fSFrançois Tigeot 		mask = 0x1f;
497e3adcf8fSFrançois Tigeot 		shift = 5;
498e3adcf8fSFrançois Tigeot 	} else {
499e3adcf8fSFrançois Tigeot 		mask = 0x3f;
500e3adcf8fSFrançois Tigeot 		shift = 6;
501e3adcf8fSFrançois Tigeot 	}
502e3adcf8fSFrançois Tigeot 	ret = ((offset + width + mask) >> shift) - (offset >> shift);
503e3adcf8fSFrançois Tigeot 	if (!IS_GEN2(dev))
504e3adcf8fSFrançois Tigeot 		ret <<= 1;
505e3adcf8fSFrançois Tigeot 	ret -= 1;
506e3adcf8fSFrançois Tigeot 	return ret << 2;
507e3adcf8fSFrançois Tigeot }
508e3adcf8fSFrançois Tigeot 
509e3adcf8fSFrançois Tigeot static const u16 y_static_hcoeffs[N_HORIZ_Y_TAPS * N_PHASES] = {
510e3adcf8fSFrançois Tigeot 	0x3000, 0xb4a0, 0x1930, 0x1920, 0xb4a0,
511e3adcf8fSFrançois Tigeot 	0x3000, 0xb500, 0x19d0, 0x1880, 0xb440,
512e3adcf8fSFrançois Tigeot 	0x3000, 0xb540, 0x1a88, 0x2f80, 0xb3e0,
513e3adcf8fSFrançois Tigeot 	0x3000, 0xb580, 0x1b30, 0x2e20, 0xb380,
514e3adcf8fSFrançois Tigeot 	0x3000, 0xb5c0, 0x1bd8, 0x2cc0, 0xb320,
515e3adcf8fSFrançois Tigeot 	0x3020, 0xb5e0, 0x1c60, 0x2b80, 0xb2c0,
516e3adcf8fSFrançois Tigeot 	0x3020, 0xb5e0, 0x1cf8, 0x2a20, 0xb260,
517e3adcf8fSFrançois Tigeot 	0x3020, 0xb5e0, 0x1d80, 0x28e0, 0xb200,
518e3adcf8fSFrançois Tigeot 	0x3020, 0xb5c0, 0x1e08, 0x3f40, 0xb1c0,
519e3adcf8fSFrançois Tigeot 	0x3020, 0xb580, 0x1e78, 0x3ce0, 0xb160,
520e3adcf8fSFrançois Tigeot 	0x3040, 0xb520, 0x1ed8, 0x3aa0, 0xb120,
521e3adcf8fSFrançois Tigeot 	0x3040, 0xb4a0, 0x1f30, 0x3880, 0xb0e0,
522e3adcf8fSFrançois Tigeot 	0x3040, 0xb400, 0x1f78, 0x3680, 0xb0a0,
523e3adcf8fSFrançois Tigeot 	0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060,
524e3adcf8fSFrançois Tigeot 	0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040,
525e3adcf8fSFrançois Tigeot 	0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020,
526e3adcf8fSFrançois Tigeot 	0xb000, 0x3000, 0x0800, 0x3000, 0xb000
527e3adcf8fSFrançois Tigeot };
528e3adcf8fSFrançois Tigeot 
529e3adcf8fSFrançois Tigeot static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
530e3adcf8fSFrançois Tigeot 	0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60,
531e3adcf8fSFrançois Tigeot 	0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40,
532e3adcf8fSFrançois Tigeot 	0xb040, 0x1b20, 0x29e0, 0xb060, 0x1bd8, 0x2880,
533e3adcf8fSFrançois Tigeot 	0xb080, 0x1c88, 0x3e60, 0xb0a0, 0x1d28, 0x3c00,
534e3adcf8fSFrançois Tigeot 	0xb0c0, 0x1db8, 0x39e0, 0xb0e0, 0x1e40, 0x37e0,
535e3adcf8fSFrançois Tigeot 	0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0,
536e3adcf8fSFrançois Tigeot 	0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240,
537e3adcf8fSFrançois Tigeot 	0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0,
538e3adcf8fSFrançois Tigeot 	0x3000, 0x0800, 0x3000
539e3adcf8fSFrançois Tigeot };
540e3adcf8fSFrançois Tigeot 
541e3440f96SFrançois Tigeot static void update_polyphase_filter(struct overlay_registers __iomem *regs)
542e3adcf8fSFrançois Tigeot {
543e3440f96SFrançois Tigeot 	memcpy_toio(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs));
544e3440f96SFrançois Tigeot 	memcpy_toio(regs->UV_HCOEFS, uv_static_hcoeffs,
545e3440f96SFrançois Tigeot 		    sizeof(uv_static_hcoeffs));
546e3adcf8fSFrançois Tigeot }
547e3adcf8fSFrançois Tigeot 
548e3adcf8fSFrançois Tigeot static bool update_scaling_factors(struct intel_overlay *overlay,
549e3440f96SFrançois Tigeot 				   struct overlay_registers __iomem *regs,
550e3adcf8fSFrançois Tigeot 				   struct put_image_params *params)
551e3adcf8fSFrançois Tigeot {
552e3adcf8fSFrançois Tigeot 	/* fixed point with a 12 bit shift */
553e3adcf8fSFrançois Tigeot 	u32 xscale, yscale, xscale_UV, yscale_UV;
554e3adcf8fSFrançois Tigeot #define FP_SHIFT 12
555e3adcf8fSFrançois Tigeot #define FRACT_MASK 0xfff
556e3adcf8fSFrançois Tigeot 	bool scale_changed = false;
557e3adcf8fSFrançois Tigeot 	int uv_hscale = uv_hsubsampling(params->format);
558e3adcf8fSFrançois Tigeot 	int uv_vscale = uv_vsubsampling(params->format);
559e3adcf8fSFrançois Tigeot 
560e3adcf8fSFrançois Tigeot 	if (params->dst_w > 1)
561e3adcf8fSFrançois Tigeot 		xscale = ((params->src_scan_w - 1) << FP_SHIFT)
562e3adcf8fSFrançois Tigeot 			/(params->dst_w);
563e3adcf8fSFrançois Tigeot 	else
564e3adcf8fSFrançois Tigeot 		xscale = 1 << FP_SHIFT;
565e3adcf8fSFrançois Tigeot 
566e3adcf8fSFrançois Tigeot 	if (params->dst_h > 1)
567e3adcf8fSFrançois Tigeot 		yscale = ((params->src_scan_h - 1) << FP_SHIFT)
568e3adcf8fSFrançois Tigeot 			/(params->dst_h);
569e3adcf8fSFrançois Tigeot 	else
570e3adcf8fSFrançois Tigeot 		yscale = 1 << FP_SHIFT;
571e3adcf8fSFrançois Tigeot 
572e3adcf8fSFrançois Tigeot 	/*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
573e3adcf8fSFrançois Tigeot 	xscale_UV = xscale/uv_hscale;
574e3adcf8fSFrançois Tigeot 	yscale_UV = yscale/uv_vscale;
575e3adcf8fSFrançois Tigeot 	/* make the Y scale to UV scale ratio an exact multiply */
576e3adcf8fSFrançois Tigeot 	xscale = xscale_UV * uv_hscale;
577e3adcf8fSFrançois Tigeot 	yscale = yscale_UV * uv_vscale;
578e3adcf8fSFrançois Tigeot 	/*} else {
579e3adcf8fSFrançois Tigeot 	  xscale_UV = 0;
580e3adcf8fSFrançois Tigeot 	  yscale_UV = 0;
581e3adcf8fSFrançois Tigeot 	  }*/
582e3adcf8fSFrançois Tigeot 
583e3adcf8fSFrançois Tigeot 	if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)
584e3adcf8fSFrançois Tigeot 		scale_changed = true;
585e3adcf8fSFrançois Tigeot 	overlay->old_xscale = xscale;
586e3adcf8fSFrançois Tigeot 	overlay->old_yscale = yscale;
587e3adcf8fSFrançois Tigeot 
588e3440f96SFrançois Tigeot 	iowrite32(((yscale & FRACT_MASK) << 20) |
589e3adcf8fSFrançois Tigeot 		  ((xscale >> FP_SHIFT)  << 16) |
590e3440f96SFrançois Tigeot 		  ((xscale & FRACT_MASK) << 3),
591e3440f96SFrançois Tigeot 		 &regs->YRGBSCALE);
592e3adcf8fSFrançois Tigeot 
593e3440f96SFrançois Tigeot 	iowrite32(((yscale_UV & FRACT_MASK) << 20) |
594e3adcf8fSFrançois Tigeot 		  ((xscale_UV >> FP_SHIFT)  << 16) |
595e3440f96SFrançois Tigeot 		  ((xscale_UV & FRACT_MASK) << 3),
596e3440f96SFrançois Tigeot 		 &regs->UVSCALE);
597e3adcf8fSFrançois Tigeot 
598e3440f96SFrançois Tigeot 	iowrite32((((yscale    >> FP_SHIFT) << 16) |
599e3440f96SFrançois Tigeot 		   ((yscale_UV >> FP_SHIFT) << 0)),
600e3440f96SFrançois Tigeot 		 &regs->UVSCALEV);
601e3adcf8fSFrançois Tigeot 
602e3adcf8fSFrançois Tigeot 	if (scale_changed)
603e3adcf8fSFrançois Tigeot 		update_polyphase_filter(regs);
604e3adcf8fSFrançois Tigeot 
605e3adcf8fSFrançois Tigeot 	return scale_changed;
606e3adcf8fSFrançois Tigeot }
607e3adcf8fSFrançois Tigeot 
608e3adcf8fSFrançois Tigeot static void update_colorkey(struct intel_overlay *overlay,
609e3440f96SFrançois Tigeot 			    struct overlay_registers __iomem *regs)
610e3adcf8fSFrançois Tigeot {
611e3adcf8fSFrançois Tigeot 	u32 key = overlay->color_key;
612e3adcf8fSFrançois Tigeot 
613ba55f2f5SFrançois Tigeot 	switch (overlay->crtc->base.primary->fb->bits_per_pixel) {
614e3adcf8fSFrançois Tigeot 	case 8:
615e3440f96SFrançois Tigeot 		iowrite32(0, &regs->DCLRKV);
616e3440f96SFrançois Tigeot 		iowrite32(CLK_RGB8I_MASK | DST_KEY_ENABLE, &regs->DCLRKM);
617e3adcf8fSFrançois Tigeot 		break;
618e3adcf8fSFrançois Tigeot 
619e3adcf8fSFrançois Tigeot 	case 16:
620ba55f2f5SFrançois Tigeot 		if (overlay->crtc->base.primary->fb->depth == 15) {
621e3440f96SFrançois Tigeot 			iowrite32(RGB15_TO_COLORKEY(key), &regs->DCLRKV);
622e3440f96SFrançois Tigeot 			iowrite32(CLK_RGB15_MASK | DST_KEY_ENABLE,
623e3440f96SFrançois Tigeot 				  &regs->DCLRKM);
624e3adcf8fSFrançois Tigeot 		} else {
625e3440f96SFrançois Tigeot 			iowrite32(RGB16_TO_COLORKEY(key), &regs->DCLRKV);
626e3440f96SFrançois Tigeot 			iowrite32(CLK_RGB16_MASK | DST_KEY_ENABLE,
627e3440f96SFrançois Tigeot 				  &regs->DCLRKM);
628e3adcf8fSFrançois Tigeot 		}
629e3adcf8fSFrançois Tigeot 		break;
630e3adcf8fSFrançois Tigeot 
631e3adcf8fSFrançois Tigeot 	case 24:
632e3adcf8fSFrançois Tigeot 	case 32:
633e3440f96SFrançois Tigeot 		iowrite32(key, &regs->DCLRKV);
634e3440f96SFrançois Tigeot 		iowrite32(CLK_RGB24_MASK | DST_KEY_ENABLE, &regs->DCLRKM);
635e3adcf8fSFrançois Tigeot 		break;
636e3adcf8fSFrançois Tigeot 	}
637e3adcf8fSFrançois Tigeot }
638e3adcf8fSFrançois Tigeot 
639e3adcf8fSFrançois Tigeot static u32 overlay_cmd_reg(struct put_image_params *params)
640e3adcf8fSFrançois Tigeot {
641e3adcf8fSFrançois Tigeot 	u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0;
642e3adcf8fSFrançois Tigeot 
643e3adcf8fSFrançois Tigeot 	if (params->format & I915_OVERLAY_YUV_PLANAR) {
644e3adcf8fSFrançois Tigeot 		switch (params->format & I915_OVERLAY_DEPTH_MASK) {
645e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_YUV422:
646e3adcf8fSFrançois Tigeot 			cmd |= OCMD_YUV_422_PLANAR;
647e3adcf8fSFrançois Tigeot 			break;
648e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_YUV420:
649e3adcf8fSFrançois Tigeot 			cmd |= OCMD_YUV_420_PLANAR;
650e3adcf8fSFrançois Tigeot 			break;
651e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_YUV411:
652e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_YUV410:
653e3adcf8fSFrançois Tigeot 			cmd |= OCMD_YUV_410_PLANAR;
654e3adcf8fSFrançois Tigeot 			break;
655e3adcf8fSFrançois Tigeot 		}
656e3adcf8fSFrançois Tigeot 	} else { /* YUV packed */
657e3adcf8fSFrançois Tigeot 		switch (params->format & I915_OVERLAY_DEPTH_MASK) {
658e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_YUV422:
659e3adcf8fSFrançois Tigeot 			cmd |= OCMD_YUV_422_PACKED;
660e3adcf8fSFrançois Tigeot 			break;
661e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_YUV411:
662e3adcf8fSFrançois Tigeot 			cmd |= OCMD_YUV_411_PACKED;
663e3adcf8fSFrançois Tigeot 			break;
664e3adcf8fSFrançois Tigeot 		}
665e3adcf8fSFrançois Tigeot 
666e3adcf8fSFrançois Tigeot 		switch (params->format & I915_OVERLAY_SWAP_MASK) {
667e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_NO_SWAP:
668e3adcf8fSFrançois Tigeot 			break;
669e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_UV_SWAP:
670e3adcf8fSFrançois Tigeot 			cmd |= OCMD_UV_SWAP;
671e3adcf8fSFrançois Tigeot 			break;
672e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_Y_SWAP:
673e3adcf8fSFrançois Tigeot 			cmd |= OCMD_Y_SWAP;
674e3adcf8fSFrançois Tigeot 			break;
675e3adcf8fSFrançois Tigeot 		case I915_OVERLAY_Y_AND_UV_SWAP:
676e3adcf8fSFrançois Tigeot 			cmd |= OCMD_Y_AND_UV_SWAP;
677e3adcf8fSFrançois Tigeot 			break;
678e3adcf8fSFrançois Tigeot 		}
679e3adcf8fSFrançois Tigeot 	}
680e3adcf8fSFrançois Tigeot 
681e3adcf8fSFrançois Tigeot 	return cmd;
682e3adcf8fSFrançois Tigeot }
683e3adcf8fSFrançois Tigeot 
684e3adcf8fSFrançois Tigeot static int intel_overlay_do_put_image(struct intel_overlay *overlay,
685e3adcf8fSFrançois Tigeot 				      struct drm_i915_gem_object *new_bo,
686e3adcf8fSFrançois Tigeot 				      struct put_image_params *params)
687e3adcf8fSFrançois Tigeot {
688e3adcf8fSFrançois Tigeot 	int ret, tmp_width;
689e3440f96SFrançois Tigeot 	struct overlay_registers __iomem *regs;
690e3adcf8fSFrançois Tigeot 	bool scale_changed = false;
691e3440f96SFrançois Tigeot 	struct drm_device *dev = overlay->dev;
692e3440f96SFrançois Tigeot 	u32 swidth, swidthsw, sheight, ostride;
693*24edb884SFrançois Tigeot 	enum i915_pipe pipe = overlay->crtc->pipe;
694e3adcf8fSFrançois Tigeot 
695e3440f96SFrançois Tigeot 	BUG_ON(!mutex_is_locked(&dev->struct_mutex));
696ba55f2f5SFrançois Tigeot 	BUG_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
697e3440f96SFrançois Tigeot 	BUG_ON(!overlay);
698e3adcf8fSFrançois Tigeot 
699e3adcf8fSFrançois Tigeot 	ret = intel_overlay_release_old_vid(overlay);
700e3adcf8fSFrançois Tigeot 	if (ret != 0)
701e3adcf8fSFrançois Tigeot 		return ret;
702e3adcf8fSFrançois Tigeot 
703e3adcf8fSFrançois Tigeot 	ret = i915_gem_object_pin_to_display_plane(new_bo, 0, NULL);
704e3adcf8fSFrançois Tigeot 	if (ret != 0)
705e3440f96SFrançois Tigeot 		return ret;
706e3adcf8fSFrançois Tigeot 
707e3adcf8fSFrançois Tigeot 	ret = i915_gem_object_put_fence(new_bo);
708e3adcf8fSFrançois Tigeot 	if (ret)
709e3adcf8fSFrançois Tigeot 		goto out_unpin;
710e3adcf8fSFrançois Tigeot 
711e3adcf8fSFrançois Tigeot 	if (!overlay->active) {
712e3440f96SFrançois Tigeot 		u32 oconfig;
713e3adcf8fSFrançois Tigeot 		regs = intel_overlay_map_regs(overlay);
714e3adcf8fSFrançois Tigeot 		if (!regs) {
715e3adcf8fSFrançois Tigeot 			ret = -ENOMEM;
716e3adcf8fSFrançois Tigeot 			goto out_unpin;
717e3adcf8fSFrançois Tigeot 		}
718e3440f96SFrançois Tigeot 		oconfig = OCONF_CC_OUT_8BIT;
719e3adcf8fSFrançois Tigeot 		if (IS_GEN4(overlay->dev))
720e3440f96SFrançois Tigeot 			oconfig |= OCONF_CSC_MODE_BT709;
721*24edb884SFrançois Tigeot 		oconfig |= pipe == 0 ?
722e3adcf8fSFrançois Tigeot 			OCONF_PIPE_A : OCONF_PIPE_B;
723e3440f96SFrançois Tigeot 		iowrite32(oconfig, &regs->OCONFIG);
724e3adcf8fSFrançois Tigeot 		intel_overlay_unmap_regs(overlay, regs);
725e3adcf8fSFrançois Tigeot 
726e3adcf8fSFrançois Tigeot 		ret = intel_overlay_on(overlay);
727e3adcf8fSFrançois Tigeot 		if (ret != 0)
728e3adcf8fSFrançois Tigeot 			goto out_unpin;
729e3adcf8fSFrançois Tigeot 	}
730e3adcf8fSFrançois Tigeot 
731e3adcf8fSFrançois Tigeot 	regs = intel_overlay_map_regs(overlay);
732e3adcf8fSFrançois Tigeot 	if (!regs) {
733e3adcf8fSFrançois Tigeot 		ret = -ENOMEM;
734e3adcf8fSFrançois Tigeot 		goto out_unpin;
735e3adcf8fSFrançois Tigeot 	}
736e3adcf8fSFrançois Tigeot 
737e3440f96SFrançois Tigeot 	iowrite32((params->dst_y << 16) | params->dst_x, &regs->DWINPOS);
738e3440f96SFrançois Tigeot 	iowrite32((params->dst_h << 16) | params->dst_w, &regs->DWINSZ);
739e3adcf8fSFrançois Tigeot 
740e3adcf8fSFrançois Tigeot 	if (params->format & I915_OVERLAY_YUV_PACKED)
741e3adcf8fSFrançois Tigeot 		tmp_width = packed_width_bytes(params->format, params->src_w);
742e3adcf8fSFrançois Tigeot 	else
743e3adcf8fSFrançois Tigeot 		tmp_width = params->src_w;
744e3adcf8fSFrançois Tigeot 
745e3440f96SFrançois Tigeot 	swidth = params->src_w;
746e3440f96SFrançois Tigeot 	swidthsw = calc_swidthsw(overlay->dev, params->offset_Y, tmp_width);
747e3440f96SFrançois Tigeot 	sheight = params->src_h;
7489edbd4a0SFrançois Tigeot 	iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_Y, &regs->OBUF_0Y);
749e3440f96SFrançois Tigeot 	ostride = params->stride_Y;
750e3adcf8fSFrançois Tigeot 
751e3adcf8fSFrançois Tigeot 	if (params->format & I915_OVERLAY_YUV_PLANAR) {
752e3adcf8fSFrançois Tigeot 		int uv_hscale = uv_hsubsampling(params->format);
753e3adcf8fSFrançois Tigeot 		int uv_vscale = uv_vsubsampling(params->format);
754e3adcf8fSFrançois Tigeot 		u32 tmp_U, tmp_V;
755e3440f96SFrançois Tigeot 		swidth |= (params->src_w/uv_hscale) << 16;
756e3adcf8fSFrançois Tigeot 		tmp_U = calc_swidthsw(overlay->dev, params->offset_U,
757e3adcf8fSFrançois Tigeot 				      params->src_w/uv_hscale);
758e3adcf8fSFrançois Tigeot 		tmp_V = calc_swidthsw(overlay->dev, params->offset_V,
759e3adcf8fSFrançois Tigeot 				      params->src_w/uv_hscale);
760e3440f96SFrançois Tigeot 		swidthsw |= max_t(u32, tmp_U, tmp_V) << 16;
761e3440f96SFrançois Tigeot 		sheight |= (params->src_h/uv_vscale) << 16;
7629edbd4a0SFrançois Tigeot 		iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_U, &regs->OBUF_0U);
7639edbd4a0SFrançois Tigeot 		iowrite32(i915_gem_obj_ggtt_offset(new_bo) + params->offset_V, &regs->OBUF_0V);
764e3440f96SFrançois Tigeot 		ostride |= params->stride_UV << 16;
765e3adcf8fSFrançois Tigeot 	}
766e3adcf8fSFrançois Tigeot 
767e3440f96SFrançois Tigeot 	iowrite32(swidth, &regs->SWIDTH);
768e3440f96SFrançois Tigeot 	iowrite32(swidthsw, &regs->SWIDTHSW);
769e3440f96SFrançois Tigeot 	iowrite32(sheight, &regs->SHEIGHT);
770e3440f96SFrançois Tigeot 	iowrite32(ostride, &regs->OSTRIDE);
771e3440f96SFrançois Tigeot 
772e3adcf8fSFrançois Tigeot 	scale_changed = update_scaling_factors(overlay, regs, params);
773e3adcf8fSFrançois Tigeot 
774e3adcf8fSFrançois Tigeot 	update_colorkey(overlay, regs);
775e3adcf8fSFrançois Tigeot 
776e3440f96SFrançois Tigeot 	iowrite32(overlay_cmd_reg(params), &regs->OCMD);
777e3adcf8fSFrançois Tigeot 
778e3adcf8fSFrançois Tigeot 	intel_overlay_unmap_regs(overlay, regs);
779e3adcf8fSFrançois Tigeot 
780e3adcf8fSFrançois Tigeot 	ret = intel_overlay_continue(overlay, scale_changed);
781e3adcf8fSFrançois Tigeot 	if (ret)
782e3adcf8fSFrançois Tigeot 		goto out_unpin;
783e3adcf8fSFrançois Tigeot 
784*24edb884SFrançois Tigeot 	i915_gem_track_fb(overlay->vid_bo, new_bo,
785*24edb884SFrançois Tigeot 			  INTEL_FRONTBUFFER_OVERLAY(pipe));
786*24edb884SFrançois Tigeot 
787e3adcf8fSFrançois Tigeot 	overlay->old_vid_bo = overlay->vid_bo;
788e3adcf8fSFrançois Tigeot 	overlay->vid_bo = new_bo;
789e3adcf8fSFrançois Tigeot 
790*24edb884SFrançois Tigeot 	intel_frontbuffer_flip(dev,
791*24edb884SFrançois Tigeot 			       INTEL_FRONTBUFFER_OVERLAY(pipe));
792*24edb884SFrançois Tigeot 
793e3adcf8fSFrançois Tigeot 	return 0;
794e3adcf8fSFrançois Tigeot 
795e3adcf8fSFrançois Tigeot out_unpin:
796ba55f2f5SFrançois Tigeot 	i915_gem_object_ggtt_unpin(new_bo);
797e3adcf8fSFrançois Tigeot 	return ret;
798e3adcf8fSFrançois Tigeot }
799e3adcf8fSFrançois Tigeot 
800e3adcf8fSFrançois Tigeot int intel_overlay_switch_off(struct intel_overlay *overlay)
801e3adcf8fSFrançois Tigeot {
802e3440f96SFrançois Tigeot 	struct overlay_registers __iomem *regs;
803e3440f96SFrançois Tigeot 	struct drm_device *dev = overlay->dev;
804e3adcf8fSFrançois Tigeot 	int ret;
805e3adcf8fSFrançois Tigeot 
806e3440f96SFrançois Tigeot 	BUG_ON(!mutex_is_locked(&dev->struct_mutex));
807ba55f2f5SFrançois Tigeot 	BUG_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
808e3adcf8fSFrançois Tigeot 
809e3adcf8fSFrançois Tigeot 	ret = intel_overlay_recover_from_interrupt(overlay);
810e3adcf8fSFrançois Tigeot 	if (ret != 0)
811e3adcf8fSFrançois Tigeot 		return ret;
812e3adcf8fSFrançois Tigeot 
813e3adcf8fSFrançois Tigeot 	if (!overlay->active)
814e3adcf8fSFrançois Tigeot 		return 0;
815e3adcf8fSFrançois Tigeot 
816e3adcf8fSFrançois Tigeot 	ret = intel_overlay_release_old_vid(overlay);
817e3adcf8fSFrançois Tigeot 	if (ret != 0)
818e3adcf8fSFrançois Tigeot 		return ret;
819e3adcf8fSFrançois Tigeot 
820e3adcf8fSFrançois Tigeot 	regs = intel_overlay_map_regs(overlay);
821e3440f96SFrançois Tigeot 	iowrite32(0, &regs->OCMD);
822e3adcf8fSFrançois Tigeot 	intel_overlay_unmap_regs(overlay, regs);
823e3adcf8fSFrançois Tigeot 
824e3adcf8fSFrançois Tigeot 	ret = intel_overlay_off(overlay);
825e3adcf8fSFrançois Tigeot 	if (ret != 0)
826e3adcf8fSFrançois Tigeot 		return ret;
827e3adcf8fSFrançois Tigeot 
828e3adcf8fSFrançois Tigeot 	intel_overlay_off_tail(overlay);
829e3adcf8fSFrançois Tigeot 	return 0;
830e3adcf8fSFrançois Tigeot }
831e3adcf8fSFrançois Tigeot 
832e3adcf8fSFrançois Tigeot static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
833e3adcf8fSFrançois Tigeot 					  struct intel_crtc *crtc)
834e3adcf8fSFrançois Tigeot {
835e3adcf8fSFrançois Tigeot 	if (!crtc->active)
836e3adcf8fSFrançois Tigeot 		return -EINVAL;
837e3adcf8fSFrançois Tigeot 
838e3adcf8fSFrançois Tigeot 	/* can't use the overlay with double wide pipe */
8399edbd4a0SFrançois Tigeot 	if (crtc->config.double_wide)
840e3adcf8fSFrançois Tigeot 		return -EINVAL;
841e3adcf8fSFrançois Tigeot 
842e3adcf8fSFrançois Tigeot 	return 0;
843e3adcf8fSFrançois Tigeot }
844e3adcf8fSFrançois Tigeot 
845e3adcf8fSFrançois Tigeot static void update_pfit_vscale_ratio(struct intel_overlay *overlay)
846e3adcf8fSFrançois Tigeot {
847e3adcf8fSFrançois Tigeot 	struct drm_device *dev = overlay->dev;
848ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
849e3adcf8fSFrançois Tigeot 	u32 pfit_control = I915_READ(PFIT_CONTROL);
850e3adcf8fSFrançois Tigeot 	u32 ratio;
851e3adcf8fSFrançois Tigeot 
852e3adcf8fSFrançois Tigeot 	/* XXX: This is not the same logic as in the xorg driver, but more in
853e3adcf8fSFrançois Tigeot 	 * line with the intel documentation for the i965
854e3adcf8fSFrançois Tigeot 	 */
855e3adcf8fSFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 4) {
856e3adcf8fSFrançois Tigeot 		/* on i965 use the PGM reg to read out the autoscaler values */
857e3adcf8fSFrançois Tigeot 		ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965;
858e3adcf8fSFrançois Tigeot 	} else {
859e3adcf8fSFrançois Tigeot 		if (pfit_control & VERT_AUTO_SCALE)
860e3adcf8fSFrançois Tigeot 			ratio = I915_READ(PFIT_AUTO_RATIOS);
861e3adcf8fSFrançois Tigeot 		else
862e3adcf8fSFrançois Tigeot 			ratio = I915_READ(PFIT_PGM_RATIOS);
863e3adcf8fSFrançois Tigeot 		ratio >>= PFIT_VERT_SCALE_SHIFT;
864e3adcf8fSFrançois Tigeot 	}
865e3adcf8fSFrançois Tigeot 
866e3adcf8fSFrançois Tigeot 	overlay->pfit_vscale_ratio = ratio;
867e3adcf8fSFrançois Tigeot }
868e3adcf8fSFrançois Tigeot 
869e3adcf8fSFrançois Tigeot static int check_overlay_dst(struct intel_overlay *overlay,
870e3adcf8fSFrançois Tigeot 			     struct drm_intel_overlay_put_image *rec)
871e3adcf8fSFrançois Tigeot {
872e3adcf8fSFrançois Tigeot 	struct drm_display_mode *mode = &overlay->crtc->base.mode;
873e3adcf8fSFrançois Tigeot 
874e3adcf8fSFrançois Tigeot 	if (rec->dst_x < mode->hdisplay &&
875e3adcf8fSFrançois Tigeot 	    rec->dst_x + rec->dst_width <= mode->hdisplay &&
876e3adcf8fSFrançois Tigeot 	    rec->dst_y < mode->vdisplay &&
877e3adcf8fSFrançois Tigeot 	    rec->dst_y + rec->dst_height <= mode->vdisplay)
878e3adcf8fSFrançois Tigeot 		return 0;
879e3adcf8fSFrançois Tigeot 	else
880e3adcf8fSFrançois Tigeot 		return -EINVAL;
881e3adcf8fSFrançois Tigeot }
882e3adcf8fSFrançois Tigeot 
883e3adcf8fSFrançois Tigeot static int check_overlay_scaling(struct put_image_params *rec)
884e3adcf8fSFrançois Tigeot {
885e3adcf8fSFrançois Tigeot 	u32 tmp;
886e3adcf8fSFrançois Tigeot 
887e3adcf8fSFrançois Tigeot 	/* downscaling limit is 8.0 */
888e3adcf8fSFrançois Tigeot 	tmp = ((rec->src_scan_h << 16) / rec->dst_h) >> 16;
889e3adcf8fSFrançois Tigeot 	if (tmp > 7)
890e3adcf8fSFrançois Tigeot 		return -EINVAL;
891e3adcf8fSFrançois Tigeot 	tmp = ((rec->src_scan_w << 16) / rec->dst_w) >> 16;
892e3adcf8fSFrançois Tigeot 	if (tmp > 7)
893e3adcf8fSFrançois Tigeot 		return -EINVAL;
894e3adcf8fSFrançois Tigeot 
895e3adcf8fSFrançois Tigeot 	return 0;
896e3adcf8fSFrançois Tigeot }
897e3adcf8fSFrançois Tigeot 
898e3adcf8fSFrançois Tigeot static int check_overlay_src(struct drm_device *dev,
899e3adcf8fSFrançois Tigeot 			     struct drm_intel_overlay_put_image *rec,
900e3adcf8fSFrançois Tigeot 			     struct drm_i915_gem_object *new_bo)
901e3adcf8fSFrançois Tigeot {
902e3adcf8fSFrançois Tigeot 	int uv_hscale = uv_hsubsampling(rec->flags);
903e3adcf8fSFrançois Tigeot 	int uv_vscale = uv_vsubsampling(rec->flags);
904e3adcf8fSFrançois Tigeot 	u32 stride_mask;
905e3adcf8fSFrançois Tigeot 	int depth;
906e3adcf8fSFrançois Tigeot 	u32 tmp;
907e3adcf8fSFrançois Tigeot 
908e3adcf8fSFrançois Tigeot 	/* check src dimensions */
909e3adcf8fSFrançois Tigeot 	if (IS_845G(dev) || IS_I830(dev)) {
910e3adcf8fSFrançois Tigeot 		if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY ||
911e3adcf8fSFrançois Tigeot 		    rec->src_width  > IMAGE_MAX_WIDTH_LEGACY)
912e3adcf8fSFrançois Tigeot 			return -EINVAL;
913e3adcf8fSFrançois Tigeot 	} else {
914e3adcf8fSFrançois Tigeot 		if (rec->src_height > IMAGE_MAX_HEIGHT ||
915e3adcf8fSFrançois Tigeot 		    rec->src_width  > IMAGE_MAX_WIDTH)
916e3adcf8fSFrançois Tigeot 			return -EINVAL;
917e3adcf8fSFrançois Tigeot 	}
918e3adcf8fSFrançois Tigeot 
919e3adcf8fSFrançois Tigeot 	/* better safe than sorry, use 4 as the maximal subsampling ratio */
920e3adcf8fSFrançois Tigeot 	if (rec->src_height < N_VERT_Y_TAPS*4 ||
921e3adcf8fSFrançois Tigeot 	    rec->src_width  < N_HORIZ_Y_TAPS*4)
922e3adcf8fSFrançois Tigeot 		return -EINVAL;
923e3adcf8fSFrançois Tigeot 
924e3adcf8fSFrançois Tigeot 	/* check alignment constraints */
925e3adcf8fSFrançois Tigeot 	switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
926e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_RGB:
927e3adcf8fSFrançois Tigeot 		/* not implemented */
928e3adcf8fSFrançois Tigeot 		return -EINVAL;
929e3adcf8fSFrançois Tigeot 
930e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV_PACKED:
931e3adcf8fSFrançois Tigeot 		if (uv_vscale != 1)
932e3adcf8fSFrançois Tigeot 			return -EINVAL;
933e3adcf8fSFrançois Tigeot 
934e3adcf8fSFrançois Tigeot 		depth = packed_depth_bytes(rec->flags);
935e3adcf8fSFrançois Tigeot 		if (depth < 0)
936e3adcf8fSFrançois Tigeot 			return depth;
937e3adcf8fSFrançois Tigeot 
938e3adcf8fSFrançois Tigeot 		/* ignore UV planes */
939e3adcf8fSFrançois Tigeot 		rec->stride_UV = 0;
940e3adcf8fSFrançois Tigeot 		rec->offset_U = 0;
941e3adcf8fSFrançois Tigeot 		rec->offset_V = 0;
942e3adcf8fSFrançois Tigeot 		/* check pixel alignment */
943e3adcf8fSFrançois Tigeot 		if (rec->offset_Y % depth)
944e3adcf8fSFrançois Tigeot 			return -EINVAL;
945e3adcf8fSFrançois Tigeot 		break;
946e3adcf8fSFrançois Tigeot 
947e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV_PLANAR:
948e3adcf8fSFrançois Tigeot 		if (uv_vscale < 0 || uv_hscale < 0)
949e3adcf8fSFrançois Tigeot 			return -EINVAL;
950e3adcf8fSFrançois Tigeot 		/* no offset restrictions for planar formats */
951e3adcf8fSFrançois Tigeot 		break;
952e3adcf8fSFrançois Tigeot 
953e3adcf8fSFrançois Tigeot 	default:
954e3adcf8fSFrançois Tigeot 		return -EINVAL;
955e3adcf8fSFrançois Tigeot 	}
956e3adcf8fSFrançois Tigeot 
957e3adcf8fSFrançois Tigeot 	if (rec->src_width % uv_hscale)
958e3adcf8fSFrançois Tigeot 		return -EINVAL;
959e3adcf8fSFrançois Tigeot 
960e3adcf8fSFrançois Tigeot 	/* stride checking */
961e3adcf8fSFrançois Tigeot 	if (IS_I830(dev) || IS_845G(dev))
962e3adcf8fSFrançois Tigeot 		stride_mask = 255;
963e3adcf8fSFrançois Tigeot 	else
964e3adcf8fSFrançois Tigeot 		stride_mask = 63;
965e3adcf8fSFrançois Tigeot 
966e3adcf8fSFrançois Tigeot 	if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
967e3adcf8fSFrançois Tigeot 		return -EINVAL;
968e3adcf8fSFrançois Tigeot 	if (IS_GEN4(dev) && rec->stride_Y < 512)
969e3adcf8fSFrançois Tigeot 		return -EINVAL;
970e3adcf8fSFrançois Tigeot 
971e3adcf8fSFrançois Tigeot 	tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ?
972e3adcf8fSFrançois Tigeot 		4096 : 8192;
973e3adcf8fSFrançois Tigeot 	if (rec->stride_Y > tmp || rec->stride_UV > 2*1024)
974e3adcf8fSFrançois Tigeot 		return -EINVAL;
975e3adcf8fSFrançois Tigeot 
976e3adcf8fSFrançois Tigeot 	/* check buffer dimensions */
977e3adcf8fSFrançois Tigeot 	switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
978e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_RGB:
979e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV_PACKED:
980e3adcf8fSFrançois Tigeot 		/* always 4 Y values per depth pixels */
981e3adcf8fSFrançois Tigeot 		if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y)
982e3adcf8fSFrançois Tigeot 			return -EINVAL;
983e3adcf8fSFrançois Tigeot 
984e3adcf8fSFrançois Tigeot 		tmp = rec->stride_Y*rec->src_height;
985e3adcf8fSFrançois Tigeot 		if (rec->offset_Y + tmp > new_bo->base.size)
986e3adcf8fSFrançois Tigeot 			return -EINVAL;
987e3adcf8fSFrançois Tigeot 		break;
988e3adcf8fSFrançois Tigeot 
989e3adcf8fSFrançois Tigeot 	case I915_OVERLAY_YUV_PLANAR:
990e3adcf8fSFrançois Tigeot 		if (rec->src_width > rec->stride_Y)
991e3adcf8fSFrançois Tigeot 			return -EINVAL;
992e3adcf8fSFrançois Tigeot 		if (rec->src_width/uv_hscale > rec->stride_UV)
993e3adcf8fSFrançois Tigeot 			return -EINVAL;
994e3adcf8fSFrançois Tigeot 
995e3adcf8fSFrançois Tigeot 		tmp = rec->stride_Y * rec->src_height;
996e3adcf8fSFrançois Tigeot 		if (rec->offset_Y + tmp > new_bo->base.size)
997e3adcf8fSFrançois Tigeot 			return -EINVAL;
998e3adcf8fSFrançois Tigeot 
999e3adcf8fSFrançois Tigeot 		tmp = rec->stride_UV * (rec->src_height / uv_vscale);
1000e3adcf8fSFrançois Tigeot 		if (rec->offset_U + tmp > new_bo->base.size ||
1001e3adcf8fSFrançois Tigeot 		    rec->offset_V + tmp > new_bo->base.size)
1002e3adcf8fSFrançois Tigeot 			return -EINVAL;
1003e3adcf8fSFrançois Tigeot 		break;
1004e3adcf8fSFrançois Tigeot 	}
1005e3adcf8fSFrançois Tigeot 
1006e3adcf8fSFrançois Tigeot 	return 0;
1007e3adcf8fSFrançois Tigeot }
1008e3adcf8fSFrançois Tigeot 
1009e3adcf8fSFrançois Tigeot /**
1010e3adcf8fSFrançois Tigeot  * Return the pipe currently connected to the panel fitter,
1011e3adcf8fSFrançois Tigeot  * or -1 if the panel fitter is not present or not in use
1012e3adcf8fSFrançois Tigeot  */
1013e3adcf8fSFrançois Tigeot static int intel_panel_fitter_pipe(struct drm_device *dev)
1014e3adcf8fSFrançois Tigeot {
1015e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1016e3adcf8fSFrançois Tigeot 	u32  pfit_control;
1017e3adcf8fSFrançois Tigeot 
1018e3adcf8fSFrançois Tigeot 	/* i830 doesn't have a panel fitter */
10199edbd4a0SFrançois Tigeot 	if (INTEL_INFO(dev)->gen <= 3 && (IS_I830(dev) || !IS_MOBILE(dev)))
1020e3adcf8fSFrançois Tigeot 		return -1;
1021e3adcf8fSFrançois Tigeot 
1022e3adcf8fSFrançois Tigeot 	pfit_control = I915_READ(PFIT_CONTROL);
1023e3adcf8fSFrançois Tigeot 
1024e3adcf8fSFrançois Tigeot 	/* See if the panel fitter is in use */
1025e3adcf8fSFrançois Tigeot 	if ((pfit_control & PFIT_ENABLE) == 0)
1026e3adcf8fSFrançois Tigeot 		return -1;
1027e3adcf8fSFrançois Tigeot 
1028e3adcf8fSFrançois Tigeot 	/* 965 can place panel fitter on either pipe */
1029e3adcf8fSFrançois Tigeot 	if (IS_GEN4(dev))
1030e3adcf8fSFrançois Tigeot 		return (pfit_control >> 29) & 0x3;
1031e3adcf8fSFrançois Tigeot 
1032e3adcf8fSFrançois Tigeot 	/* older chips can only use pipe 1 */
1033e3adcf8fSFrançois Tigeot 	return 1;
1034e3adcf8fSFrançois Tigeot }
1035e3adcf8fSFrançois Tigeot 
1036e3adcf8fSFrançois Tigeot int intel_overlay_put_image(struct drm_device *dev, void *data,
1037e3adcf8fSFrançois Tigeot 			    struct drm_file *file_priv)
1038e3adcf8fSFrançois Tigeot {
1039e3adcf8fSFrançois Tigeot 	struct drm_intel_overlay_put_image *put_image_rec = data;
1040ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1041e3adcf8fSFrançois Tigeot 	struct intel_overlay *overlay;
1042*24edb884SFrançois Tigeot 	struct drm_crtc *drmmode_crtc;
1043e3adcf8fSFrançois Tigeot 	struct intel_crtc *crtc;
1044e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *new_bo;
1045e3adcf8fSFrançois Tigeot 	struct put_image_params *params;
1046e3adcf8fSFrançois Tigeot 	int ret;
1047e3adcf8fSFrançois Tigeot 
1048e3440f96SFrançois Tigeot 	/* No need to check for DRIVER_MODESET - we don't set it up then. */
1049e3adcf8fSFrançois Tigeot 	overlay = dev_priv->overlay;
1050e3adcf8fSFrançois Tigeot 	if (!overlay) {
1051e3adcf8fSFrançois Tigeot 		DRM_DEBUG("userspace bug: no overlay\n");
1052e3adcf8fSFrançois Tigeot 		return -ENODEV;
1053e3adcf8fSFrançois Tigeot 	}
1054e3adcf8fSFrançois Tigeot 
1055e3adcf8fSFrançois Tigeot 	if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) {
1056a2fdbec6SFrançois Tigeot 		drm_modeset_lock_all(dev);
1057a2fdbec6SFrançois Tigeot 		mutex_lock(&dev->struct_mutex);
1058e3adcf8fSFrançois Tigeot 
1059e3adcf8fSFrançois Tigeot 		ret = intel_overlay_switch_off(overlay);
1060e3adcf8fSFrançois Tigeot 
1061a2fdbec6SFrançois Tigeot 		mutex_unlock(&dev->struct_mutex);
1062a2fdbec6SFrançois Tigeot 		drm_modeset_unlock_all(dev);
1063e3adcf8fSFrançois Tigeot 
1064e3adcf8fSFrançois Tigeot 		return ret;
1065e3adcf8fSFrançois Tigeot 	}
1066e3adcf8fSFrançois Tigeot 
10679edbd4a0SFrançois Tigeot 	params = kmalloc(sizeof(*params), M_DRM, M_WAITOK);
1068e3440f96SFrançois Tigeot 	if (!params)
1069e3440f96SFrançois Tigeot 		return -ENOMEM;
1070e3adcf8fSFrançois Tigeot 
1071*24edb884SFrançois Tigeot 	drmmode_crtc = drm_crtc_find(dev, put_image_rec->crtc_id);
1072*24edb884SFrançois Tigeot 	if (!drmmode_crtc) {
1073e3adcf8fSFrançois Tigeot 		ret = -ENOENT;
1074e3adcf8fSFrançois Tigeot 		goto out_free;
1075e3adcf8fSFrançois Tigeot 	}
1076*24edb884SFrançois Tigeot 	crtc = to_intel_crtc(drmmode_crtc);
1077e3adcf8fSFrançois Tigeot 
1078e3adcf8fSFrançois Tigeot 	new_bo = to_intel_bo(drm_gem_object_lookup(dev, file_priv,
1079e3adcf8fSFrançois Tigeot 						   put_image_rec->bo_handle));
1080e3adcf8fSFrançois Tigeot 	if (&new_bo->base == NULL) {
1081e3adcf8fSFrançois Tigeot 		ret = -ENOENT;
1082e3adcf8fSFrançois Tigeot 		goto out_free;
1083e3adcf8fSFrançois Tigeot 	}
1084e3adcf8fSFrançois Tigeot 
1085a2fdbec6SFrançois Tigeot 	drm_modeset_lock_all(dev);
1086a2fdbec6SFrançois Tigeot 	mutex_lock(&dev->struct_mutex);
1087e3adcf8fSFrançois Tigeot 
1088e3adcf8fSFrançois Tigeot 	if (new_bo->tiling_mode) {
1089ba55f2f5SFrançois Tigeot 		DRM_DEBUG_KMS("buffer used for overlay image can not be tiled\n");
1090e3adcf8fSFrançois Tigeot 		ret = -EINVAL;
1091e3adcf8fSFrançois Tigeot 		goto out_unlock;
1092e3adcf8fSFrançois Tigeot 	}
1093e3adcf8fSFrançois Tigeot 
1094e3adcf8fSFrançois Tigeot 	ret = intel_overlay_recover_from_interrupt(overlay);
1095e3adcf8fSFrançois Tigeot 	if (ret != 0)
1096e3adcf8fSFrançois Tigeot 		goto out_unlock;
1097e3adcf8fSFrançois Tigeot 
1098e3adcf8fSFrançois Tigeot 	if (overlay->crtc != crtc) {
1099e3adcf8fSFrançois Tigeot 		struct drm_display_mode *mode = &crtc->base.mode;
1100e3adcf8fSFrançois Tigeot 		ret = intel_overlay_switch_off(overlay);
1101e3adcf8fSFrançois Tigeot 		if (ret != 0)
1102e3adcf8fSFrançois Tigeot 			goto out_unlock;
1103e3adcf8fSFrançois Tigeot 
1104e3adcf8fSFrançois Tigeot 		ret = check_overlay_possible_on_crtc(overlay, crtc);
1105e3adcf8fSFrançois Tigeot 		if (ret != 0)
1106e3adcf8fSFrançois Tigeot 			goto out_unlock;
1107e3adcf8fSFrançois Tigeot 
1108e3adcf8fSFrançois Tigeot 		overlay->crtc = crtc;
1109e3adcf8fSFrançois Tigeot 		crtc->overlay = overlay;
1110e3adcf8fSFrançois Tigeot 
1111e3adcf8fSFrançois Tigeot 		/* line too wide, i.e. one-line-mode */
1112e3adcf8fSFrançois Tigeot 		if (mode->hdisplay > 1024 &&
1113e3adcf8fSFrançois Tigeot 		    intel_panel_fitter_pipe(dev) == crtc->pipe) {
1114e3adcf8fSFrançois Tigeot 			overlay->pfit_active = 1;
1115e3adcf8fSFrançois Tigeot 			update_pfit_vscale_ratio(overlay);
1116e3adcf8fSFrançois Tigeot 		} else
1117e3adcf8fSFrançois Tigeot 			overlay->pfit_active = 0;
1118e3adcf8fSFrançois Tigeot 	}
1119e3adcf8fSFrançois Tigeot 
1120e3adcf8fSFrançois Tigeot 	ret = check_overlay_dst(overlay, put_image_rec);
1121e3adcf8fSFrançois Tigeot 	if (ret != 0)
1122e3adcf8fSFrançois Tigeot 		goto out_unlock;
1123e3adcf8fSFrançois Tigeot 
1124e3adcf8fSFrançois Tigeot 	if (overlay->pfit_active) {
1125e3adcf8fSFrançois Tigeot 		params->dst_y = ((((u32)put_image_rec->dst_y) << 12) /
1126e3adcf8fSFrançois Tigeot 				 overlay->pfit_vscale_ratio);
1127e3adcf8fSFrançois Tigeot 		/* shifting right rounds downwards, so add 1 */
1128e3adcf8fSFrançois Tigeot 		params->dst_h = ((((u32)put_image_rec->dst_height) << 12) /
1129e3adcf8fSFrançois Tigeot 				 overlay->pfit_vscale_ratio) + 1;
1130e3adcf8fSFrançois Tigeot 	} else {
1131e3adcf8fSFrançois Tigeot 		params->dst_y = put_image_rec->dst_y;
1132e3adcf8fSFrançois Tigeot 		params->dst_h = put_image_rec->dst_height;
1133e3adcf8fSFrançois Tigeot 	}
1134e3adcf8fSFrançois Tigeot 	params->dst_x = put_image_rec->dst_x;
1135e3adcf8fSFrançois Tigeot 	params->dst_w = put_image_rec->dst_width;
1136e3adcf8fSFrançois Tigeot 
1137e3adcf8fSFrançois Tigeot 	params->src_w = put_image_rec->src_width;
1138e3adcf8fSFrançois Tigeot 	params->src_h = put_image_rec->src_height;
1139e3adcf8fSFrançois Tigeot 	params->src_scan_w = put_image_rec->src_scan_width;
1140e3adcf8fSFrançois Tigeot 	params->src_scan_h = put_image_rec->src_scan_height;
1141e3adcf8fSFrançois Tigeot 	if (params->src_scan_h > params->src_h ||
1142e3adcf8fSFrançois Tigeot 	    params->src_scan_w > params->src_w) {
1143e3adcf8fSFrançois Tigeot 		ret = -EINVAL;
1144e3adcf8fSFrançois Tigeot 		goto out_unlock;
1145e3adcf8fSFrançois Tigeot 	}
1146e3adcf8fSFrançois Tigeot 
1147e3adcf8fSFrançois Tigeot 	ret = check_overlay_src(dev, put_image_rec, new_bo);
1148e3adcf8fSFrançois Tigeot 	if (ret != 0)
1149e3adcf8fSFrançois Tigeot 		goto out_unlock;
1150e3adcf8fSFrançois Tigeot 	params->format = put_image_rec->flags & ~I915_OVERLAY_FLAGS_MASK;
1151e3adcf8fSFrançois Tigeot 	params->stride_Y = put_image_rec->stride_Y;
1152e3adcf8fSFrançois Tigeot 	params->stride_UV = put_image_rec->stride_UV;
1153e3adcf8fSFrançois Tigeot 	params->offset_Y = put_image_rec->offset_Y;
1154e3adcf8fSFrançois Tigeot 	params->offset_U = put_image_rec->offset_U;
1155e3adcf8fSFrançois Tigeot 	params->offset_V = put_image_rec->offset_V;
1156e3adcf8fSFrançois Tigeot 
1157e3adcf8fSFrançois Tigeot 	/* Check scaling after src size to prevent a divide-by-zero. */
1158e3adcf8fSFrançois Tigeot 	ret = check_overlay_scaling(params);
1159e3adcf8fSFrançois Tigeot 	if (ret != 0)
1160e3adcf8fSFrançois Tigeot 		goto out_unlock;
1161e3adcf8fSFrançois Tigeot 
1162e3adcf8fSFrançois Tigeot 	ret = intel_overlay_do_put_image(overlay, new_bo, params);
1163e3adcf8fSFrançois Tigeot 	if (ret != 0)
1164e3adcf8fSFrançois Tigeot 		goto out_unlock;
1165e3adcf8fSFrançois Tigeot 
1166a2fdbec6SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
1167a2fdbec6SFrançois Tigeot 	drm_modeset_unlock_all(dev);
1168e3adcf8fSFrançois Tigeot 
1169158486a6SFrançois Tigeot 	kfree(params);
1170e3adcf8fSFrançois Tigeot 
1171e3adcf8fSFrançois Tigeot 	return 0;
1172e3adcf8fSFrançois Tigeot 
1173e3adcf8fSFrançois Tigeot out_unlock:
1174a2fdbec6SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
1175a2fdbec6SFrançois Tigeot 	drm_modeset_unlock_all(dev);
1176e3adcf8fSFrançois Tigeot 	drm_gem_object_unreference_unlocked(&new_bo->base);
1177e3adcf8fSFrançois Tigeot out_free:
1178158486a6SFrançois Tigeot 	kfree(params);
1179e3adcf8fSFrançois Tigeot 
1180e3adcf8fSFrançois Tigeot 	return ret;
1181e3adcf8fSFrançois Tigeot }
1182e3adcf8fSFrançois Tigeot 
1183e3adcf8fSFrançois Tigeot static void update_reg_attrs(struct intel_overlay *overlay,
1184e3440f96SFrançois Tigeot 			     struct overlay_registers __iomem *regs)
1185e3adcf8fSFrançois Tigeot {
1186e3440f96SFrançois Tigeot 	iowrite32((overlay->contrast << 18) | (overlay->brightness & 0xff),
1187e3440f96SFrançois Tigeot 		  &regs->OCLRC0);
1188e3440f96SFrançois Tigeot 	iowrite32(overlay->saturation, &regs->OCLRC1);
1189e3adcf8fSFrançois Tigeot }
1190e3adcf8fSFrançois Tigeot 
1191e3adcf8fSFrançois Tigeot static bool check_gamma_bounds(u32 gamma1, u32 gamma2)
1192e3adcf8fSFrançois Tigeot {
1193e3adcf8fSFrançois Tigeot 	int i;
1194e3adcf8fSFrançois Tigeot 
1195e3adcf8fSFrançois Tigeot 	if (gamma1 & 0xff000000 || gamma2 & 0xff000000)
1196e3adcf8fSFrançois Tigeot 		return false;
1197e3adcf8fSFrançois Tigeot 
1198e3adcf8fSFrançois Tigeot 	for (i = 0; i < 3; i++) {
1199e3adcf8fSFrançois Tigeot 		if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
1200e3adcf8fSFrançois Tigeot 			return false;
1201e3adcf8fSFrançois Tigeot 	}
1202e3adcf8fSFrançois Tigeot 
1203e3adcf8fSFrançois Tigeot 	return true;
1204e3adcf8fSFrançois Tigeot }
1205e3adcf8fSFrançois Tigeot 
1206e3adcf8fSFrançois Tigeot static bool check_gamma5_errata(u32 gamma5)
1207e3adcf8fSFrançois Tigeot {
1208e3adcf8fSFrançois Tigeot 	int i;
1209e3adcf8fSFrançois Tigeot 
1210e3adcf8fSFrançois Tigeot 	for (i = 0; i < 3; i++) {
1211e3adcf8fSFrançois Tigeot 		if (((gamma5 >> i*8) & 0xff) == 0x80)
1212e3adcf8fSFrançois Tigeot 			return false;
1213e3adcf8fSFrançois Tigeot 	}
1214e3adcf8fSFrançois Tigeot 
1215e3adcf8fSFrançois Tigeot 	return true;
1216e3adcf8fSFrançois Tigeot }
1217e3adcf8fSFrançois Tigeot 
1218e3adcf8fSFrançois Tigeot static int check_gamma(struct drm_intel_overlay_attrs *attrs)
1219e3adcf8fSFrançois Tigeot {
1220e3adcf8fSFrançois Tigeot 	if (!check_gamma_bounds(0, attrs->gamma0) ||
1221e3adcf8fSFrançois Tigeot 	    !check_gamma_bounds(attrs->gamma0, attrs->gamma1) ||
1222e3adcf8fSFrançois Tigeot 	    !check_gamma_bounds(attrs->gamma1, attrs->gamma2) ||
1223e3adcf8fSFrançois Tigeot 	    !check_gamma_bounds(attrs->gamma2, attrs->gamma3) ||
1224e3adcf8fSFrançois Tigeot 	    !check_gamma_bounds(attrs->gamma3, attrs->gamma4) ||
1225e3adcf8fSFrançois Tigeot 	    !check_gamma_bounds(attrs->gamma4, attrs->gamma5) ||
1226e3adcf8fSFrançois Tigeot 	    !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
1227e3adcf8fSFrançois Tigeot 		return -EINVAL;
1228e3adcf8fSFrançois Tigeot 
1229e3adcf8fSFrançois Tigeot 	if (!check_gamma5_errata(attrs->gamma5))
1230e3adcf8fSFrançois Tigeot 		return -EINVAL;
1231e3adcf8fSFrançois Tigeot 
1232e3adcf8fSFrançois Tigeot 	return 0;
1233e3adcf8fSFrançois Tigeot }
1234e3adcf8fSFrançois Tigeot 
1235e3adcf8fSFrançois Tigeot int intel_overlay_attrs(struct drm_device *dev, void *data,
1236e3adcf8fSFrançois Tigeot 			struct drm_file *file_priv)
1237e3adcf8fSFrançois Tigeot {
1238e3adcf8fSFrançois Tigeot 	struct drm_intel_overlay_attrs *attrs = data;
1239ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1240e3adcf8fSFrançois Tigeot 	struct intel_overlay *overlay;
1241e3440f96SFrançois Tigeot 	struct overlay_registers __iomem *regs;
1242e3adcf8fSFrançois Tigeot 	int ret;
1243e3adcf8fSFrançois Tigeot 
1244e3440f96SFrançois Tigeot 	/* No need to check for DRIVER_MODESET - we don't set it up then. */
1245e3adcf8fSFrançois Tigeot 	overlay = dev_priv->overlay;
1246e3adcf8fSFrançois Tigeot 	if (!overlay) {
1247e3adcf8fSFrançois Tigeot 		DRM_DEBUG("userspace bug: no overlay\n");
1248e3adcf8fSFrançois Tigeot 		return -ENODEV;
1249e3adcf8fSFrançois Tigeot 	}
1250e3adcf8fSFrançois Tigeot 
1251a2fdbec6SFrançois Tigeot 	drm_modeset_lock_all(dev);
1252a2fdbec6SFrançois Tigeot 	mutex_lock(&dev->struct_mutex);
1253e3adcf8fSFrançois Tigeot 
1254e3adcf8fSFrançois Tigeot 	ret = -EINVAL;
1255e3adcf8fSFrançois Tigeot 	if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) {
1256e3adcf8fSFrançois Tigeot 		attrs->color_key  = overlay->color_key;
1257e3adcf8fSFrançois Tigeot 		attrs->brightness = overlay->brightness;
1258e3adcf8fSFrançois Tigeot 		attrs->contrast   = overlay->contrast;
1259e3adcf8fSFrançois Tigeot 		attrs->saturation = overlay->saturation;
1260e3adcf8fSFrançois Tigeot 
1261e3adcf8fSFrançois Tigeot 		if (!IS_GEN2(dev)) {
1262e3adcf8fSFrançois Tigeot 			attrs->gamma0 = I915_READ(OGAMC0);
1263e3adcf8fSFrançois Tigeot 			attrs->gamma1 = I915_READ(OGAMC1);
1264e3adcf8fSFrançois Tigeot 			attrs->gamma2 = I915_READ(OGAMC2);
1265e3adcf8fSFrançois Tigeot 			attrs->gamma3 = I915_READ(OGAMC3);
1266e3adcf8fSFrançois Tigeot 			attrs->gamma4 = I915_READ(OGAMC4);
1267e3adcf8fSFrançois Tigeot 			attrs->gamma5 = I915_READ(OGAMC5);
1268e3adcf8fSFrançois Tigeot 		}
1269e3adcf8fSFrançois Tigeot 	} else {
1270e3adcf8fSFrançois Tigeot 		if (attrs->brightness < -128 || attrs->brightness > 127)
1271e3adcf8fSFrançois Tigeot 			goto out_unlock;
1272e3adcf8fSFrançois Tigeot 		if (attrs->contrast > 255)
1273e3adcf8fSFrançois Tigeot 			goto out_unlock;
1274e3adcf8fSFrançois Tigeot 		if (attrs->saturation > 1023)
1275e3adcf8fSFrançois Tigeot 			goto out_unlock;
1276e3adcf8fSFrançois Tigeot 
1277e3adcf8fSFrançois Tigeot 		overlay->color_key  = attrs->color_key;
1278e3adcf8fSFrançois Tigeot 		overlay->brightness = attrs->brightness;
1279e3adcf8fSFrançois Tigeot 		overlay->contrast   = attrs->contrast;
1280e3adcf8fSFrançois Tigeot 		overlay->saturation = attrs->saturation;
1281e3adcf8fSFrançois Tigeot 
1282e3adcf8fSFrançois Tigeot 		regs = intel_overlay_map_regs(overlay);
1283e3adcf8fSFrançois Tigeot 		if (!regs) {
1284e3adcf8fSFrançois Tigeot 			ret = -ENOMEM;
1285e3adcf8fSFrançois Tigeot 			goto out_unlock;
1286e3adcf8fSFrançois Tigeot 		}
1287e3adcf8fSFrançois Tigeot 
1288e3adcf8fSFrançois Tigeot 		update_reg_attrs(overlay, regs);
1289e3adcf8fSFrançois Tigeot 
1290e3adcf8fSFrançois Tigeot 		intel_overlay_unmap_regs(overlay, regs);
1291e3adcf8fSFrançois Tigeot 
1292e3adcf8fSFrançois Tigeot 		if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) {
1293e3adcf8fSFrançois Tigeot 			if (IS_GEN2(dev))
1294e3adcf8fSFrançois Tigeot 				goto out_unlock;
1295e3adcf8fSFrançois Tigeot 
1296e3adcf8fSFrançois Tigeot 			if (overlay->active) {
1297e3adcf8fSFrançois Tigeot 				ret = -EBUSY;
1298e3adcf8fSFrançois Tigeot 				goto out_unlock;
1299e3adcf8fSFrançois Tigeot 			}
1300e3adcf8fSFrançois Tigeot 
1301e3adcf8fSFrançois Tigeot 			ret = check_gamma(attrs);
1302e3adcf8fSFrançois Tigeot 			if (ret)
1303e3adcf8fSFrançois Tigeot 				goto out_unlock;
1304e3adcf8fSFrançois Tigeot 
1305e3adcf8fSFrançois Tigeot 			I915_WRITE(OGAMC0, attrs->gamma0);
1306e3adcf8fSFrançois Tigeot 			I915_WRITE(OGAMC1, attrs->gamma1);
1307e3adcf8fSFrançois Tigeot 			I915_WRITE(OGAMC2, attrs->gamma2);
1308e3adcf8fSFrançois Tigeot 			I915_WRITE(OGAMC3, attrs->gamma3);
1309e3adcf8fSFrançois Tigeot 			I915_WRITE(OGAMC4, attrs->gamma4);
1310e3adcf8fSFrançois Tigeot 			I915_WRITE(OGAMC5, attrs->gamma5);
1311e3adcf8fSFrançois Tigeot 		}
1312e3adcf8fSFrançois Tigeot 	}
1313e3adcf8fSFrançois Tigeot 
1314e3adcf8fSFrançois Tigeot 	ret = 0;
1315e3adcf8fSFrançois Tigeot out_unlock:
1316a2fdbec6SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
1317a2fdbec6SFrançois Tigeot 	drm_modeset_unlock_all(dev);
1318e3adcf8fSFrançois Tigeot 
1319e3adcf8fSFrançois Tigeot 	return ret;
1320e3adcf8fSFrançois Tigeot }
1321e3adcf8fSFrançois Tigeot 
1322e3adcf8fSFrançois Tigeot void intel_setup_overlay(struct drm_device *dev)
1323e3adcf8fSFrançois Tigeot {
1324ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1325e3adcf8fSFrançois Tigeot 	struct intel_overlay *overlay;
1326e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *reg_bo;
1327e3440f96SFrançois Tigeot 	struct overlay_registers __iomem *regs;
1328e3adcf8fSFrançois Tigeot 	int ret;
1329e3adcf8fSFrançois Tigeot 
1330e3adcf8fSFrançois Tigeot 	if (!HAS_OVERLAY(dev))
1331e3adcf8fSFrançois Tigeot 		return;
1332e3adcf8fSFrançois Tigeot 
13339edbd4a0SFrançois Tigeot 	overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
1334e3440f96SFrançois Tigeot 	if (!overlay)
1335e3440f96SFrançois Tigeot 		return;
1336e3440f96SFrançois Tigeot 
1337a2fdbec6SFrançois Tigeot 	mutex_lock(&dev->struct_mutex);
1338e3440f96SFrançois Tigeot 	if (WARN_ON(dev_priv->overlay))
1339e3adcf8fSFrançois Tigeot 		goto out_free;
1340e3440f96SFrançois Tigeot 
1341e3adcf8fSFrançois Tigeot 	overlay->dev = dev;
1342e3adcf8fSFrançois Tigeot 
13439edbd4a0SFrançois Tigeot 	reg_bo = NULL;
13449edbd4a0SFrançois Tigeot 	if (!OVERLAY_NEEDS_PHYSICAL(dev))
13459edbd4a0SFrançois Tigeot 		reg_bo = i915_gem_object_create_stolen(dev, PAGE_SIZE);
13469edbd4a0SFrançois Tigeot 	if (reg_bo == NULL)
1347e3adcf8fSFrançois Tigeot 		reg_bo = i915_gem_alloc_object(dev, PAGE_SIZE);
13489edbd4a0SFrançois Tigeot 	if (reg_bo == NULL)
1349e3adcf8fSFrançois Tigeot 		goto out_free;
1350e3adcf8fSFrançois Tigeot 	overlay->reg_bo = reg_bo;
1351e3adcf8fSFrançois Tigeot 
1352e3adcf8fSFrançois Tigeot 	if (OVERLAY_NEEDS_PHYSICAL(dev)) {
1353ba55f2f5SFrançois Tigeot 		ret = i915_gem_object_attach_phys(reg_bo, PAGE_SIZE);
1354e3adcf8fSFrançois Tigeot 		if (ret) {
1355e3adcf8fSFrançois Tigeot 			DRM_ERROR("failed to attach phys overlay regs\n");
1356e3adcf8fSFrançois Tigeot 			goto out_free_bo;
1357e3adcf8fSFrançois Tigeot 		}
1358ba55f2f5SFrançois Tigeot 		overlay->flip_addr = reg_bo->phys_handle->busaddr;
1359e3adcf8fSFrançois Tigeot 	} else {
1360ba55f2f5SFrançois Tigeot 		ret = i915_gem_obj_ggtt_pin(reg_bo, PAGE_SIZE, PIN_MAPPABLE);
1361e3adcf8fSFrançois Tigeot 		if (ret) {
1362e3adcf8fSFrançois Tigeot 			DRM_ERROR("failed to pin overlay register bo\n");
1363e3adcf8fSFrançois Tigeot 			goto out_free_bo;
1364e3adcf8fSFrançois Tigeot 		}
13659edbd4a0SFrançois Tigeot 		overlay->flip_addr = i915_gem_obj_ggtt_offset(reg_bo);
1366e3adcf8fSFrançois Tigeot 
1367e3adcf8fSFrançois Tigeot 		ret = i915_gem_object_set_to_gtt_domain(reg_bo, true);
1368e3adcf8fSFrançois Tigeot 		if (ret) {
1369e3adcf8fSFrançois Tigeot 			DRM_ERROR("failed to move overlay register bo into the GTT\n");
1370e3adcf8fSFrançois Tigeot 			goto out_unpin_bo;
1371e3adcf8fSFrançois Tigeot 		}
1372e3adcf8fSFrançois Tigeot 	}
1373e3adcf8fSFrançois Tigeot 
1374e3adcf8fSFrançois Tigeot 	/* init all values */
1375e3adcf8fSFrançois Tigeot 	overlay->color_key = 0x0101fe;
1376e3adcf8fSFrançois Tigeot 	overlay->brightness = -19;
1377e3adcf8fSFrançois Tigeot 	overlay->contrast = 75;
1378e3adcf8fSFrançois Tigeot 	overlay->saturation = 146;
1379e3adcf8fSFrançois Tigeot 
1380e3adcf8fSFrançois Tigeot 	regs = intel_overlay_map_regs(overlay);
1381e3adcf8fSFrançois Tigeot 	if (!regs)
1382e3adcf8fSFrançois Tigeot 		goto out_unpin_bo;
1383e3adcf8fSFrançois Tigeot 
1384e3440f96SFrançois Tigeot 	memset_io(regs, 0, sizeof(struct overlay_registers));
1385e3adcf8fSFrançois Tigeot 	update_polyphase_filter(regs);
1386e3adcf8fSFrançois Tigeot 	update_reg_attrs(overlay, regs);
1387e3adcf8fSFrançois Tigeot 
1388e3adcf8fSFrançois Tigeot 	intel_overlay_unmap_regs(overlay, regs);
1389e3adcf8fSFrançois Tigeot 
1390e3adcf8fSFrançois Tigeot 	dev_priv->overlay = overlay;
1391a2fdbec6SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
1392e3440f96SFrançois Tigeot 	DRM_INFO("initialized overlay support\n");
1393e3adcf8fSFrançois Tigeot 	return;
1394e3adcf8fSFrançois Tigeot 
1395e3adcf8fSFrançois Tigeot out_unpin_bo:
1396e3adcf8fSFrançois Tigeot 	if (!OVERLAY_NEEDS_PHYSICAL(dev))
1397ba55f2f5SFrançois Tigeot 		i915_gem_object_ggtt_unpin(reg_bo);
1398e3adcf8fSFrançois Tigeot out_free_bo:
1399e3adcf8fSFrançois Tigeot 	drm_gem_object_unreference(&reg_bo->base);
1400e3adcf8fSFrançois Tigeot out_free:
1401a2fdbec6SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
1402158486a6SFrançois Tigeot 	kfree(overlay);
1403e3adcf8fSFrançois Tigeot 	return;
1404e3adcf8fSFrançois Tigeot }
1405e3adcf8fSFrançois Tigeot 
1406e3adcf8fSFrançois Tigeot void intel_cleanup_overlay(struct drm_device *dev)
1407e3adcf8fSFrançois Tigeot {
1408ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1409e3adcf8fSFrançois Tigeot 
1410e3adcf8fSFrançois Tigeot 	if (!dev_priv->overlay)
1411e3adcf8fSFrançois Tigeot 		return;
1412e3adcf8fSFrançois Tigeot 
1413e3adcf8fSFrançois Tigeot 	/* The bo's should be free'd by the generic code already.
1414e3adcf8fSFrançois Tigeot 	 * Furthermore modesetting teardown happens beforehand so the
1415e3adcf8fSFrançois Tigeot 	 * hardware should be off already */
1416e3440f96SFrançois Tigeot 	BUG_ON(dev_priv->overlay->active);
1417e3adcf8fSFrançois Tigeot 
1418e3adcf8fSFrançois Tigeot 	drm_gem_object_unreference_unlocked(&dev_priv->overlay->reg_bo->base);
1419158486a6SFrançois Tigeot 	kfree(dev_priv->overlay);
1420e3adcf8fSFrançois Tigeot }
1421e3adcf8fSFrançois Tigeot 
1422e3adcf8fSFrançois Tigeot struct intel_overlay_error_state {
1423e3adcf8fSFrançois Tigeot 	struct overlay_registers regs;
1424e3adcf8fSFrançois Tigeot 	unsigned long base;
1425e3adcf8fSFrançois Tigeot 	u32 dovsta;
1426e3adcf8fSFrançois Tigeot 	u32 isr;
1427e3adcf8fSFrançois Tigeot };
1428e3adcf8fSFrançois Tigeot 
14299edbd4a0SFrançois Tigeot #if 0
1430e3440f96SFrançois Tigeot static struct overlay_registers __iomem *
1431e3440f96SFrançois Tigeot intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
1432e3440f96SFrançois Tigeot {
1433ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = overlay->dev->dev_private;
1434e3440f96SFrançois Tigeot 	struct overlay_registers __iomem *regs;
1435e3440f96SFrançois Tigeot 
1436e3440f96SFrançois Tigeot 	if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
1437e3440f96SFrançois Tigeot 		/* Cast to make sparse happy, but it's wc memory anyway, so
1438e3440f96SFrançois Tigeot 		 * equivalent to the wc io mapping on X86. */
1439e3440f96SFrançois Tigeot 		regs = (struct overlay_registers __iomem *)
1440e3440f96SFrançois Tigeot 			overlay->reg_bo->phys_obj->handle->vaddr;
1441e3440f96SFrançois Tigeot 	else
1442a2fdbec6SFrançois Tigeot 		regs = io_mapping_map_atomic_wc(dev_priv->gtt.mappable,
14439edbd4a0SFrançois Tigeot 						i915_gem_obj_ggtt_offset(overlay->reg_bo));
1444e3440f96SFrançois Tigeot 
1445e3440f96SFrançois Tigeot 	return regs;
1446e3440f96SFrançois Tigeot }
1447e3440f96SFrançois Tigeot 
1448e3440f96SFrançois Tigeot static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay,
1449e3440f96SFrançois Tigeot 					struct overlay_registers __iomem *regs)
1450e3440f96SFrançois Tigeot {
1451e3440f96SFrançois Tigeot 	if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
1452e3440f96SFrançois Tigeot 		io_mapping_unmap_atomic(regs);
1453e3440f96SFrançois Tigeot }
1454e3440f96SFrançois Tigeot 
1455ba55f2f5SFrançois Tigeot 
1456e3adcf8fSFrançois Tigeot struct intel_overlay_error_state *
1457e3adcf8fSFrançois Tigeot intel_overlay_capture_error_state(struct drm_device *dev)
1458e3adcf8fSFrançois Tigeot {
1459ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1460e3adcf8fSFrançois Tigeot 	struct intel_overlay *overlay = dev_priv->overlay;
1461e3adcf8fSFrançois Tigeot 	struct intel_overlay_error_state *error;
1462e3adcf8fSFrançois Tigeot 	struct overlay_registers __iomem *regs;
1463e3adcf8fSFrançois Tigeot 
1464e3adcf8fSFrançois Tigeot 	if (!overlay || !overlay->active)
1465e3adcf8fSFrançois Tigeot 		return NULL;
1466e3adcf8fSFrançois Tigeot 
1467ba55f2f5SFrançois Tigeot 	error = kmalloc(sizeof(*error), GFP_ATOMIC);
1468e3adcf8fSFrançois Tigeot 	if (error == NULL)
1469e3adcf8fSFrançois Tigeot 		return NULL;
1470e3adcf8fSFrançois Tigeot 
1471e3adcf8fSFrançois Tigeot 	error->dovsta = I915_READ(DOVSTA);
1472e3adcf8fSFrançois Tigeot 	error->isr = I915_READ(ISR);
1473e3adcf8fSFrançois Tigeot 	if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
1474e3440f96SFrançois Tigeot 		error->base = (__force long)overlay->reg_bo->phys_obj->handle->vaddr;
1475e3adcf8fSFrançois Tigeot 	else
14769edbd4a0SFrançois Tigeot 		error->base = i915_gem_obj_ggtt_offset(overlay->reg_bo);
1477e3adcf8fSFrançois Tigeot 
1478e3440f96SFrançois Tigeot 	regs = intel_overlay_map_regs_atomic(overlay);
1479e3adcf8fSFrançois Tigeot 	if (!regs)
1480e3adcf8fSFrançois Tigeot 		goto err;
1481e3adcf8fSFrançois Tigeot 
1482e3440f96SFrançois Tigeot 	memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers));
1483e3440f96SFrançois Tigeot 	intel_overlay_unmap_regs_atomic(overlay, regs);
1484e3adcf8fSFrançois Tigeot 
1485e3440f96SFrançois Tigeot 	return error;
1486e3adcf8fSFrançois Tigeot 
1487e3adcf8fSFrançois Tigeot err:
1488158486a6SFrançois Tigeot 	kfree(error);
1489e3440f96SFrançois Tigeot 	return NULL;
1490e3adcf8fSFrançois Tigeot }
1491e3adcf8fSFrançois Tigeot 
1492e3adcf8fSFrançois Tigeot void
14935d0b1887SFrançois Tigeot intel_overlay_print_error_state(struct drm_i915_error_state_buf *m,
14945d0b1887SFrançois Tigeot 				struct intel_overlay_error_state *error)
1495e3adcf8fSFrançois Tigeot {
14965d0b1887SFrançois Tigeot 	i915_error_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",
1497e3adcf8fSFrançois Tigeot 			  error->dovsta, error->isr);
14985d0b1887SFrançois Tigeot 	i915_error_printf(m, "  Register file at 0x%08lx:\n",
1499e3adcf8fSFrançois Tigeot 			  error->base);
1500e3adcf8fSFrançois Tigeot 
15015d0b1887SFrançois Tigeot #define P(x) i915_error_printf(m, "    " #x ":	0x%08x\n", error->regs.x)
1502e3adcf8fSFrançois Tigeot 	P(OBUF_0Y);
1503e3adcf8fSFrançois Tigeot 	P(OBUF_1Y);
1504e3adcf8fSFrançois Tigeot 	P(OBUF_0U);
1505e3adcf8fSFrançois Tigeot 	P(OBUF_0V);
1506e3adcf8fSFrançois Tigeot 	P(OBUF_1U);
1507e3adcf8fSFrançois Tigeot 	P(OBUF_1V);
1508e3adcf8fSFrançois Tigeot 	P(OSTRIDE);
1509e3adcf8fSFrançois Tigeot 	P(YRGB_VPH);
1510e3adcf8fSFrançois Tigeot 	P(UV_VPH);
1511e3adcf8fSFrançois Tigeot 	P(HORZ_PH);
1512e3adcf8fSFrançois Tigeot 	P(INIT_PHS);
1513e3adcf8fSFrançois Tigeot 	P(DWINPOS);
1514e3adcf8fSFrançois Tigeot 	P(DWINSZ);
1515e3adcf8fSFrançois Tigeot 	P(SWIDTH);
1516e3adcf8fSFrançois Tigeot 	P(SWIDTHSW);
1517e3adcf8fSFrançois Tigeot 	P(SHEIGHT);
1518e3adcf8fSFrançois Tigeot 	P(YRGBSCALE);
1519e3adcf8fSFrançois Tigeot 	P(UVSCALE);
1520e3adcf8fSFrançois Tigeot 	P(OCLRC0);
1521e3adcf8fSFrançois Tigeot 	P(OCLRC1);
1522e3adcf8fSFrançois Tigeot 	P(DCLRKV);
1523e3adcf8fSFrançois Tigeot 	P(DCLRKM);
1524e3adcf8fSFrançois Tigeot 	P(SCLRKVH);
1525e3adcf8fSFrançois Tigeot 	P(SCLRKVL);
1526e3adcf8fSFrançois Tigeot 	P(SCLRKEN);
1527e3adcf8fSFrançois Tigeot 	P(OCONFIG);
1528e3adcf8fSFrançois Tigeot 	P(OCMD);
1529e3adcf8fSFrançois Tigeot 	P(OSTART_0Y);
1530e3adcf8fSFrançois Tigeot 	P(OSTART_1Y);
1531e3adcf8fSFrançois Tigeot 	P(OSTART_0U);
1532e3adcf8fSFrançois Tigeot 	P(OSTART_0V);
1533e3adcf8fSFrançois Tigeot 	P(OSTART_1U);
1534e3adcf8fSFrançois Tigeot 	P(OSTART_1V);
1535e3adcf8fSFrançois Tigeot 	P(OTILEOFF_0Y);
1536e3adcf8fSFrançois Tigeot 	P(OTILEOFF_1Y);
1537e3adcf8fSFrançois Tigeot 	P(OTILEOFF_0U);
1538e3adcf8fSFrançois Tigeot 	P(OTILEOFF_0V);
1539e3adcf8fSFrançois Tigeot 	P(OTILEOFF_1U);
1540e3adcf8fSFrançois Tigeot 	P(OTILEOFF_1V);
1541e3adcf8fSFrançois Tigeot 	P(FASTHSCALE);
1542e3adcf8fSFrançois Tigeot 	P(UVSCALEV);
1543e3adcf8fSFrançois Tigeot #undef P
1544e3adcf8fSFrançois Tigeot }
15453f2f609dSFrançois Tigeot #endif
1546