xref: /netbsd-src/sys/arch/arm/sunxi/sunxi_mixer.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /* $NetBSD: sunxi_mixer.c,v 1.16 2021/01/27 03:10:20 thorpej Exp $ */
2 
3 /*-
4  * Copyright (c) 2019 Jared D. McNeill <jmcneill@invisible.ca>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: sunxi_mixer.c,v 1.16 2021/01/27 03:10:20 thorpej Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/bus.h>
34 #include <sys/device.h>
35 #include <sys/intr.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/conf.h>
39 #include <sys/sysctl.h>
40 
41 #include <drm/drmP.h>
42 #include <drm/drm_crtc.h>
43 #include <drm/drm_crtc_helper.h>
44 #include <drm/drm_plane_helper.h>
45 
46 #include <dev/fdt/fdtvar.h>
47 #include <dev/fdt/fdt_port.h>
48 
49 #include <arm/sunxi/sunxi_drm.h>
50 
51 #define	MIXER_CURSOR_MAXWIDTH	256
52 #define	MIXER_CURSOR_MAXHEIGHT	256
53 
54 #define	SUNXI_MIXER_FREQ	432000000
55 
56 #define	GLB_BASE		0x00000
57 #define	BLD_BASE		0x01000
58 #define	OVL_BASE(n)		(0x02000 + (n) * 0x1000)
59 #define	VSU_BASE		0x20000
60 #define	CSC_BASE(n)		((n) == 0 ? 0xaa050 : 0xa0000)
61 
62 /* GLB registers */
63 #define	GLB_CTL			0x000
64 #define	 GLB_CTL_EN				__BIT(0)
65 #define	GLB_STS			0x004
66 #define	GLB_DBUFFER		0x008
67 #define	 GLB_DBUFFER_DOUBLE_BUFFER_RDY		__BIT(0)
68 #define	GLB_SIZE		0x00c
69 
70 /* BLD registers */
71 #define	BLD_FILL_COLOR_CTL	0x000
72 #define	 BLD_FILL_COLOR_CTL_P3_EN		__BIT(11)
73 #define	 BLD_FILL_COLOR_CTL_P2_EN		__BIT(10)
74 #define	 BLD_FILL_COLOR_CTL_P1_EN		__BIT(9)
75 #define	 BLD_FILL_COLOR_CTL_P0_EN		__BIT(8)
76 #define	 BLD_FILL_COLOR_CTL_P3_FCEN		__BIT(3)
77 #define	 BLD_FILL_COLOR_CTL_P2_FCEN		__BIT(2)
78 #define	 BLD_FILL_COLOR_CTL_P1_FCEN		__BIT(1)
79 #define	 BLD_FILL_COLOR_CTL_P0_FCEN		__BIT(0)
80 #define	BLD_FILL_COLOR(n)	(0x004 + (n) * 0x10)
81 #define	BLD_CH_ISIZE(n)		(0x008 + (n) * 0x10)
82 #define	BLD_CH_OFFSET(n)	(0x00c + (n) * 0x10)
83 #define	BLD_CH_RTCTL		0x080
84 #define	 BLD_CH_RTCTL_P3			__BITS(15,12)
85 #define	 BLD_CH_RTCTL_P2			__BITS(11,8)
86 #define	 BLD_CH_RTCTL_P1			__BITS(7,4)
87 #define	 BLD_CH_RTCTL_P0			__BITS(3,0)
88 #define	BLD_SIZE		0x08c
89 #define	BLD_CTL(n)		(0x090 + (n) * 0x04)
90 
91 /* OVL_V registers */
92 #define	OVL_V_ATTCTL(n)		(0x000 + (n) * 0x30)
93 #define	 OVL_V_ATTCTL_VIDEO_UI_SEL		__BIT(15)
94 #define	 OVL_V_ATTCTL_LAY_FBFMT			__BITS(12,8)
95 #define	  OVL_V_ATTCTL_LAY_FBFMT_VYUY		0x00
96 #define	  OVL_V_ATTCTL_LAY_FBFMT_YVYU		0x01
97 #define	  OVL_V_ATTCTL_LAY_FBFMT_UYVY		0x02
98 #define	  OVL_V_ATTCTL_LAY_FBFMT_YUYV		0x03
99 #define	  OVL_V_ATTCTL_LAY_FBFMT_YUV422		0x06
100 #define	  OVL_V_ATTCTL_LAY_FBFMT_YUV420		0x0a
101 #define	  OVL_V_ATTCTL_LAY_FBFMT_YUV411		0x0e
102 #if BYTE_ORDER == BIG_ENDIAN
103 #define	  OVL_V_ATTCTL_LAY_FBFMT_ARGB_8888	0x03
104 #define	  OVL_V_ATTCTL_LAY_FBFMT_XRGB_8888	0x07
105 #else
106 #define	  OVL_V_ATTCTL_LAY_FBFMT_ARGB_8888	0x00
107 #define	  OVL_V_ATTCTL_LAY_FBFMT_XRGB_8888	0x04
108 #endif
109 #define	 OVL_V_ATTCTL_LAY0_EN			__BIT(0)
110 #define	OVL_V_MBSIZE(n)		(0x004 + (n) * 0x30)
111 #define	OVL_V_COOR(n)		(0x008 + (n) * 0x30)
112 #define	OVL_V_PITCH0(n)		(0x00c + (n) * 0x30)
113 #define	OVL_V_PITCH1(n)		(0x010 + (n) * 0x30)
114 #define	OVL_V_PITCH2(n)		(0x014 + (n) * 0x30)
115 #define	OVL_V_TOP_LADD0(n)	(0x018 + (n) * 0x30)
116 #define	OVL_V_TOP_LADD1(n)	(0x01c + (n) * 0x30)
117 #define	OVL_V_TOP_LADD2(n)	(0x020 + (n) * 0x30)
118 #define	OVL_V_FILL_COLOR(n)	(0x0c0 + (n) * 0x4)
119 #define	OVL_V_TOP_HADD0		0x0d0
120 #define	OVL_V_TOP_HADD1		0x0d4
121 #define	OVL_V_TOP_HADD2		0x0d8
122 #define	 OVL_V_TOP_HADD_LAYER0	__BITS(7,0)
123 #define	OVL_V_SIZE		0x0e8
124 #define	OVL_V_HDS_CTL0		0x0f0
125 #define	OVL_V_HDS_CTL1		0x0f4
126 #define	OVL_V_VDS_CTL0		0x0f8
127 #define	OVL_V_VDS_CTL1		0x0fc
128 
129 /* OVL_UI registers */
130 #define	OVL_UI_ATTR_CTL(n)	(0x000 + (n) * 0x20)
131 #define	 OVL_UI_ATTR_CTL_LAY_FBFMT		__BITS(12,8)
132 #if BYTE_ORDER == BIG_ENDIAN
133 #define	  OVL_UI_ATTR_CTL_LAY_FBFMT_ARGB_8888	0x03
134 #define	  OVL_UI_ATTR_CTL_LAY_FBFMT_XRGB_8888	0x07
135 #else
136 #define	  OVL_UI_ATTR_CTL_LAY_FBFMT_ARGB_8888	0x00
137 #define	  OVL_UI_ATTR_CTL_LAY_FBFMT_XRGB_8888	0x04
138 #endif
139 #define	 OVL_UI_ATTR_CTL_LAY_EN			__BIT(0)
140 #define	OVL_UI_MBSIZE(n)	(0x004 + (n) * 0x20)
141 #define	OVL_UI_COOR(n)		(0x008 + (n) * 0x20)
142 #define	OVL_UI_PITCH(n)		(0x00c + (n) * 0x20)
143 #define	OVL_UI_TOP_LADD(n)	(0x010 + (n) * 0x20)
144 #define	OVL_UI_FILL_COLOR(n)	(0x018 + (n) * 0x20)
145 #define	OVL_UI_TOP_HADD		0x080
146 #define	 OVL_UI_TOP_HADD_LAYER1	__BITS(15,8)
147 #define	 OVL_UI_TOP_HADD_LAYER0	__BITS(7,0)
148 #define	OVL_UI_SIZE		0x088
149 
150 /* VSU registers */
151 #define	VS_CTRL_REG		0x000
152 #define	 VS_CTRL_COEF_SWITCH_EN			__BIT(4)
153 #define	 VS_CTRL_EN				__BIT(0)
154 #define	VS_STATUS_REG		0x008
155 #define	VS_FIELD_CTRL_REG	0x00c
156 #define	VS_OUT_SIZE_REG		0x040
157 #define	VS_Y_SIZE_REG		0x080
158 #define	VS_Y_HSTEP_REG		0x088
159 #define	VS_Y_VSTEP_REG		0x08c
160 #define	VS_Y_HPHASE_REG		0x090
161 #define	VS_Y_VPHASE0_REG	0x098
162 #define	VS_Y_VPHASE1_REG	0x09c
163 #define	VS_C_SIZE_REG		0x0c0
164 #define	VS_C_HSTEP_REG		0x0c8
165 #define	VS_C_VSTEP_REG		0x0cc
166 #define	VS_C_HPHASE_REG		0x0d0
167 #define	VS_C_VPHASE0_REG	0x0d8
168 #define	VS_C_VPHASE1_REG	0x0dc
169 #define	VS_Y_HCOEF0_REG(n)	(0x200 + (n) * 0x4)
170 #define	VS_Y_HCOEF1_REG(n)	(0x300 + (n) * 0x4)
171 #define	VS_Y_VCOEF_REG(n)	(0x400 + (n) * 0x4)
172 #define	VS_C_HCOEF0_REG(n)	(0x600 + (n) * 0x4)
173 #define	VS_C_HCOEF1_REG(n)	(0x700 + (n) * 0x4)
174 #define	VS_C_VCOEF_REG(n)	(0x800 + (n) * 0x4)
175 
176 /* CSC registers */
177 #define	CSC_BYPASS_REG		0x000
178 #define	 CSC_BYPASS_DISABLE			__BIT(0)
179 #define	CSC_COEFF0_REG(n)	(0x10 + 0x10 * (n))
180 #define	GLB_ALPHA_REG		0x040
181 
182 enum {
183 	MIXER_PORT_OUTPUT = 1,
184 };
185 
186 struct sunxi_mixer_compat_data {
187 	uint8_t ovl_ui_count;
188 	uint8_t mixer_index;
189 };
190 
191 struct sunxi_mixer_compat_data mixer0_data = {
192 	.ovl_ui_count = 3,
193 	.mixer_index = 0,
194 };
195 
196 struct sunxi_mixer_compat_data mixer1_data = {
197 	.ovl_ui_count = 1,
198 	.mixer_index = 1,
199 };
200 
201 static const struct device_compatible_entry compat_data[] = {
202 	{ .compat = "allwinner,sun8i-h3-de2-mixer-0",
203 	  .data = &mixer0_data },
204 	{ .compat = "allwinner,sun50i-a64-de2-mixer-0",
205 	  .data = &mixer0_data },
206 	{ .compat = "allwinner,sun50i-a64-de2-mixer-1",
207 	  .data = &mixer1_data },
208 
209 	DEVICE_COMPAT_EOL
210 };
211 
212 struct sunxi_mixer_softc;
213 
214 struct sunxi_mixer_crtc {
215 	struct drm_crtc		base;
216 	struct sunxi_mixer_softc *sc;
217 };
218 
219 struct sunxi_mixer_plane {
220 	struct drm_plane	base;
221 	struct sunxi_mixer_softc *sc;
222 };
223 
224 struct sunxi_mixer_softc {
225 	device_t		sc_dev;
226 	bus_space_tag_t		sc_bst;
227 	bus_space_handle_t	sc_bsh;
228 	int			sc_phandle;
229 
230 	u_int			sc_ovl_ui_count;
231 
232 	struct sunxi_mixer_crtc	sc_crtc;
233 	struct sunxi_mixer_plane sc_overlay;
234 
235 	struct fdt_device_ports	sc_ports;
236 };
237 
238 #define	GLB_READ(sc, reg)				\
239 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, GLB_BASE + (reg))
240 #define	GLB_WRITE(sc, reg, val)				\
241 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, GLB_BASE + (reg), (val))
242 
243 #define	BLD_READ(sc, reg)				\
244 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, BLD_BASE + (reg))
245 #define	BLD_WRITE(sc, reg, val)				\
246 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, BLD_BASE + (reg), (val))
247 
248 #define	OVL_V_READ(sc, reg)				\
249 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, OVL_BASE(0) + (reg))
250 #define	OVL_V_WRITE(sc, reg, val)			\
251 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, OVL_BASE(0) + (reg), (val))
252 
253 #define	OVL_UI_READ(sc, n, reg)				\
254 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, OVL_BASE((n) + 1) + (reg))
255 #define	OVL_UI_WRITE(sc, n, reg, val)			\
256 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, OVL_BASE((n) + 1) + (reg), (val))
257 
258 #define	VSU_READ(sc, reg)				\
259 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, VSU_BASE + (reg))
260 #define	VSU_WRITE(sc, reg, val)			\
261 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, VSU_BASE + (reg), (val))
262 
263 #define	CSC_READ(sc, n, reg)				\
264 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, CSC_BASE(n) + (reg))
265 #define	CSC_WRITE(sc, n, reg, val)			\
266 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, CSC_BASE(n) + (reg), (val))
267 
268 #define	to_sunxi_mixer_crtc(x)		container_of(x, struct sunxi_mixer_crtc, base)
269 #define	to_sunxi_mixer_plane(x)	container_of(x, struct sunxi_mixer_plane, base)
270 
271 static int
272 sunxi_mixer_mode_do_set_base(struct drm_crtc *crtc, struct drm_framebuffer *fb,
273     int x, int y, int atomic)
274 {
275 	struct sunxi_mixer_crtc *mixer_crtc = to_sunxi_mixer_crtc(crtc);
276 	struct sunxi_mixer_softc * const sc = mixer_crtc->sc;
277 	struct sunxi_drm_framebuffer *sfb = atomic?
278 	    to_sunxi_drm_framebuffer(fb) :
279 	    to_sunxi_drm_framebuffer(crtc->primary->fb);
280 	uint32_t val;
281 
282 	uint64_t paddr = (uint64_t)sfb->obj->dmamap->dm_segs[0].ds_addr;
283 
284 	paddr += y * sfb->base.pitches[0];
285 	paddr += x * drm_format_plane_cpp(sfb->base.pixel_format, 0);
286 
287 	uint32_t haddr = (paddr >> 32) & OVL_UI_TOP_HADD_LAYER0;
288 	uint32_t laddr = paddr & 0xffffffff;
289 
290 	/* Set UI overlay line size */
291 	OVL_UI_WRITE(sc, 0, OVL_UI_PITCH(0), sfb->base.pitches[0]);
292 
293 	/* Framebuffer start address */
294 	val = OVL_UI_READ(sc, 0, OVL_UI_TOP_HADD);
295 	val &= ~OVL_UI_TOP_HADD_LAYER0;
296 	val |= __SHIFTIN(haddr, OVL_UI_TOP_HADD_LAYER0);
297 	OVL_UI_WRITE(sc, 0, OVL_UI_TOP_HADD, val);
298 	OVL_UI_WRITE(sc, 0, OVL_UI_TOP_LADD(0), laddr);
299 
300 	return 0;
301 }
302 
303 static void
304 sunxi_mixer_destroy(struct drm_crtc *crtc)
305 {
306 	drm_crtc_cleanup(crtc);
307 }
308 
309 static int
310 sunxi_mixer_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
311     struct drm_pending_vblank_event *event, uint32_t flags)
312 {
313 	struct sunxi_mixer_crtc *mixer_crtc = to_sunxi_mixer_crtc(crtc);
314 	struct sunxi_mixer_softc * const sc = mixer_crtc->sc;
315 	unsigned long irqflags;
316 
317 	drm_crtc_wait_one_vblank(crtc);
318 
319 	sunxi_mixer_mode_do_set_base(crtc, fb, 0, 0, true);
320 
321 	/* Commit settings */
322 	GLB_WRITE(sc, GLB_DBUFFER, GLB_DBUFFER_DOUBLE_BUFFER_RDY);
323 
324 	if (event) {
325 		spin_lock_irqsave(&crtc->dev->event_lock, irqflags);
326 		drm_send_vblank_event(crtc->dev, drm_crtc_index(crtc), event);
327 		spin_unlock_irqrestore(&crtc->dev->event_lock, irqflags);
328 	}
329 
330 	return 0;
331 }
332 
333 static int
334 sunxi_mixer_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
335     uint32_t handle, uint32_t width, uint32_t height)
336 {
337 	struct sunxi_mixer_crtc *mixer_crtc = to_sunxi_mixer_crtc(crtc);
338 	struct sunxi_mixer_softc * const sc = mixer_crtc->sc;
339 	struct drm_gem_object *gem_obj = NULL;
340 	struct drm_gem_cma_object *obj;
341 	uint32_t val;
342 	int error;
343 
344 	/* Only mixers with more than one UI layer can support hardware cursors */
345 	if (sc->sc_ovl_ui_count <= 1)
346 		return -EINVAL;
347 
348 	if (handle == 0) {
349 		val = BLD_READ(sc, BLD_FILL_COLOR_CTL);
350 		val &= ~BLD_FILL_COLOR_CTL_P2_EN;
351 		val |= BLD_FILL_COLOR_CTL_P2_FCEN;
352 		BLD_WRITE(sc, BLD_FILL_COLOR_CTL, val);
353 
354 		error = 0;
355 		goto done;
356 	}
357 
358 	/* Arbitrary limits, the hardware layer can do 8192x8192 */
359 	if (width > MIXER_CURSOR_MAXWIDTH || height > MIXER_CURSOR_MAXHEIGHT) {
360 		DRM_ERROR("Cursor dimension %ux%u not supported\n", width, height);
361 		error = -EINVAL;
362 		goto done;
363 	}
364 
365 	gem_obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
366 	if (gem_obj == NULL) {
367 		DRM_ERROR("Cannot find cursor object %#x for crtc %d\n",
368 		    handle, drm_crtc_index(crtc));
369 		error = -ENOENT;
370 		goto done;
371 	}
372 	obj = to_drm_gem_cma_obj(gem_obj);
373 
374 	if (obj->base.size < width * height * 4) {
375 		DRM_ERROR("Cursor buffer is too small\n");
376 		error = -ENOMEM;
377 		goto done;
378 	}
379 
380 	uint64_t paddr = (uint64_t)obj->dmamap->dm_segs[0].ds_addr;
381 	uint32_t haddr = (paddr >> 32) & OVL_UI_TOP_HADD_LAYER0;
382 	uint32_t laddr = paddr & 0xffffffff;
383 
384 	/* Framebuffer start address */
385 	val = OVL_UI_READ(sc, 1, OVL_UI_TOP_HADD);
386 	val &= ~OVL_UI_TOP_HADD_LAYER0;
387 	val |= __SHIFTIN(haddr, OVL_UI_TOP_HADD_LAYER0);
388 	OVL_UI_WRITE(sc, 1, OVL_UI_TOP_HADD, val);
389 	OVL_UI_WRITE(sc, 1, OVL_UI_TOP_LADD(0), laddr);
390 
391 	const uint32_t size = ((height - 1) << 16) | (width - 1);
392 	const uint32_t offset = (crtc->cursor_y << 16) | crtc->cursor_x;
393 	const uint32_t crtc_size = ((crtc->primary->fb->height - 1) << 16) |
394 	    (crtc->primary->fb->width - 1);
395 
396 	/* Enable cursor in ARGB8888 mode */
397 	val = OVL_UI_ATTR_CTL_LAY_EN |
398 	      __SHIFTIN(OVL_UI_ATTR_CTL_LAY_FBFMT_ARGB_8888, OVL_UI_ATTR_CTL_LAY_FBFMT);
399 	OVL_UI_WRITE(sc, 1, OVL_UI_ATTR_CTL(0), val);
400 	/* Set UI overlay layer size */
401 	OVL_UI_WRITE(sc, 1, OVL_UI_MBSIZE(0), size);
402 	/* Set UI overlay offset */
403 	OVL_UI_WRITE(sc, 1, OVL_UI_COOR(0), offset);
404 	/* Set UI overlay line size */
405 	OVL_UI_WRITE(sc, 1, OVL_UI_PITCH(0), width * 4);
406 	/* Set UI overlay window size */
407 	OVL_UI_WRITE(sc, 1, OVL_UI_SIZE, crtc_size);
408 
409 	/* Set blender 2 input size */
410 	BLD_WRITE(sc, BLD_CH_ISIZE(2), crtc_size);
411 	/* Set blender 2 offset */
412 	BLD_WRITE(sc, BLD_CH_OFFSET(2), 0);
413 	/* Route channel 2 to pipe 2 */
414 	val = BLD_READ(sc, BLD_CH_RTCTL);
415 	val &= ~BLD_CH_RTCTL_P2;
416 	val |= __SHIFTIN(2, BLD_CH_RTCTL_P2);
417 	BLD_WRITE(sc, BLD_CH_RTCTL, val);
418 
419 	/* Enable pipe 2 */
420 	val = BLD_READ(sc, BLD_FILL_COLOR_CTL);
421 	val |= BLD_FILL_COLOR_CTL_P2_EN;
422 	val &= ~BLD_FILL_COLOR_CTL_P2_FCEN;
423 	BLD_WRITE(sc, BLD_FILL_COLOR_CTL, val);
424 
425 	error = 0;
426 
427 done:
428 	if (error == 0) {
429 		/* Commit settings */
430 		GLB_WRITE(sc, GLB_DBUFFER, GLB_DBUFFER_DOUBLE_BUFFER_RDY);
431 	}
432 
433 	if (gem_obj != NULL)
434 		drm_gem_object_unreference_unlocked(gem_obj);
435 
436 	return error;
437 }
438 
439 static int
440 sunxi_mixer_cursor_move(struct drm_crtc *crtc, int x, int y)
441 {
442 	struct sunxi_mixer_crtc *mixer_crtc = to_sunxi_mixer_crtc(crtc);
443 	struct sunxi_mixer_softc * const sc = mixer_crtc->sc;
444 
445 	crtc->cursor_x = x & 0xffff;
446 	crtc->cursor_y = y & 0xffff;
447 
448 	const uint32_t offset = (crtc->cursor_y << 16) | crtc->cursor_x;
449 
450 	OVL_UI_WRITE(sc, 1, OVL_UI_COOR(0), offset);
451 
452 	/* Commit settings */
453 	GLB_WRITE(sc, GLB_DBUFFER, GLB_DBUFFER_DOUBLE_BUFFER_RDY);
454 
455 	return 0;
456 }
457 
458 static const struct drm_crtc_funcs sunxi_mixer0_crtc_funcs = {
459 	.set_config = drm_crtc_helper_set_config,
460 	.destroy = sunxi_mixer_destroy,
461 	.page_flip = sunxi_mixer_page_flip,
462 	.cursor_set = sunxi_mixer_cursor_set,
463 	.cursor_move = sunxi_mixer_cursor_move,
464 };
465 
466 static const struct drm_crtc_funcs sunxi_mixer1_crtc_funcs = {
467 	.set_config = drm_crtc_helper_set_config,
468 	.destroy = sunxi_mixer_destroy,
469 	.page_flip = sunxi_mixer_page_flip,
470 };
471 
472 static void
473 sunxi_mixer_dpms(struct drm_crtc *crtc, int mode)
474 {
475 }
476 
477 static bool
478 sunxi_mixer_mode_fixup(struct drm_crtc *crtc,
479     const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode)
480 {
481 	return true;
482 }
483 
484 static int
485 sunxi_mixer_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
486     struct drm_display_mode *adjusted_mode, int x, int y,
487     struct drm_framebuffer *old_fb)
488 {
489 	struct sunxi_mixer_crtc *mixer_crtc = to_sunxi_mixer_crtc(crtc);
490 	struct sunxi_mixer_softc * const sc = mixer_crtc->sc;
491 	uint32_t val;
492 	u_int fbfmt;
493 
494 	const uint32_t size = ((adjusted_mode->vdisplay - 1) << 16) |
495 			      (adjusted_mode->hdisplay - 1);
496 
497 	/* Set global size */
498 	GLB_WRITE(sc, GLB_SIZE, size);
499 
500 	/* Enable pipe 0 */
501 	val = BLD_READ(sc, BLD_FILL_COLOR_CTL);
502 	val |= BLD_FILL_COLOR_CTL_P0_EN;
503 	BLD_WRITE(sc, BLD_FILL_COLOR_CTL, val);
504 
505 	/* Set blender 0 input size */
506 	BLD_WRITE(sc, BLD_CH_ISIZE(0), size);
507 	/* Set blender 0 offset */
508 	BLD_WRITE(sc, BLD_CH_OFFSET(0), 0);
509 	/* Route channel 1 to pipe 0 */
510 	val = BLD_READ(sc, BLD_CH_RTCTL);
511 	val &= ~BLD_CH_RTCTL_P0;
512 	val |= __SHIFTIN(1, BLD_CH_RTCTL_P0);
513 	BLD_WRITE(sc, BLD_CH_RTCTL, val);
514 	/* Set blender output size */
515 	BLD_WRITE(sc, BLD_SIZE, size);
516 
517 	/* Enable UI overlay */
518 	if (crtc->primary->fb->pixel_format == DRM_FORMAT_XRGB8888)
519 		fbfmt = OVL_UI_ATTR_CTL_LAY_FBFMT_XRGB_8888;
520 	else
521 		fbfmt = OVL_UI_ATTR_CTL_LAY_FBFMT_ARGB_8888;
522 	val = OVL_UI_ATTR_CTL_LAY_EN | __SHIFTIN(fbfmt, OVL_UI_ATTR_CTL_LAY_FBFMT);
523 	OVL_UI_WRITE(sc, 0, OVL_UI_ATTR_CTL(0), val);
524 	/* Set UI overlay layer size */
525 	OVL_UI_WRITE(sc, 0, OVL_UI_MBSIZE(0), size);
526 	/* Set UI overlay offset */
527 	OVL_UI_WRITE(sc, 0, OVL_UI_COOR(0), 0);
528 	/* Set UI overlay window size */
529 	OVL_UI_WRITE(sc, 0, OVL_UI_SIZE, size);
530 
531 	sunxi_mixer_mode_do_set_base(crtc, old_fb, x, y, 0);
532 
533 	return 0;
534 }
535 
536 static int
537 sunxi_mixer_mode_set_base(struct drm_crtc *crtc, int x, int y,
538     struct drm_framebuffer *old_fb)
539 {
540 	struct sunxi_mixer_crtc *mixer_crtc = to_sunxi_mixer_crtc(crtc);
541 	struct sunxi_mixer_softc * const sc = mixer_crtc->sc;
542 
543 	sunxi_mixer_mode_do_set_base(crtc, old_fb, x, y, 0);
544 
545 	/* Commit settings */
546 	GLB_WRITE(sc, GLB_DBUFFER, GLB_DBUFFER_DOUBLE_BUFFER_RDY);
547 
548 	return 0;
549 }
550 
551 static int
552 sunxi_mixer_mode_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
553     int x, int y, enum mode_set_atomic state)
554 {
555 	struct sunxi_mixer_crtc *mixer_crtc = to_sunxi_mixer_crtc(crtc);
556 	struct sunxi_mixer_softc * const sc = mixer_crtc->sc;
557 
558 	sunxi_mixer_mode_do_set_base(crtc, fb, x, y, 1);
559 
560 	/* Commit settings */
561 	GLB_WRITE(sc, GLB_DBUFFER, GLB_DBUFFER_DOUBLE_BUFFER_RDY);
562 
563 	return 0;
564 }
565 
566 static void
567 sunxi_mixer_disable(struct drm_crtc *crtc)
568 {
569 }
570 
571 static void
572 sunxi_mixer_prepare(struct drm_crtc *crtc)
573 {
574 	struct sunxi_mixer_crtc *mixer_crtc = to_sunxi_mixer_crtc(crtc);
575 	struct sunxi_mixer_softc * const sc = mixer_crtc->sc;
576 
577 	/* RT enable */
578 	GLB_WRITE(sc, GLB_CTL, GLB_CTL_EN);
579 }
580 
581 static void
582 sunxi_mixer_commit(struct drm_crtc *crtc)
583 {
584 	struct sunxi_mixer_crtc *mixer_crtc = to_sunxi_mixer_crtc(crtc);
585 	struct sunxi_mixer_softc * const sc = mixer_crtc->sc;
586 
587 	/* Commit settings */
588 	GLB_WRITE(sc, GLB_DBUFFER, GLB_DBUFFER_DOUBLE_BUFFER_RDY);
589 }
590 
591 static const struct drm_crtc_helper_funcs sunxi_mixer_crtc_helper_funcs = {
592 	.dpms = sunxi_mixer_dpms,
593 	.mode_fixup = sunxi_mixer_mode_fixup,
594 	.mode_set = sunxi_mixer_mode_set,
595 	.mode_set_base = sunxi_mixer_mode_set_base,
596 	.mode_set_base_atomic = sunxi_mixer_mode_set_base_atomic,
597 	.disable = sunxi_mixer_disable,
598 	.prepare = sunxi_mixer_prepare,
599 	.commit = sunxi_mixer_commit,
600 };
601 
602 static void
603 sunxi_mixer_overlay_destroy(struct drm_plane *plane)
604 {
605 }
606 
607 static bool
608 sunxi_mixer_overlay_rgb(uint32_t drm_format)
609 {
610 	switch (drm_format) {
611 	case DRM_FORMAT_ARGB8888:
612 	case DRM_FORMAT_XRGB8888:
613 		return true;
614 	default:
615 		return false;
616 	}
617 }
618 
619 static u_int
620 sunxi_mixer_overlay_format(uint32_t drm_format)
621 {
622 	switch (drm_format) {
623 	case DRM_FORMAT_ARGB8888:	return OVL_V_ATTCTL_LAY_FBFMT_ARGB_8888;
624 	case DRM_FORMAT_XRGB8888:	return OVL_V_ATTCTL_LAY_FBFMT_XRGB_8888;
625 	case DRM_FORMAT_VYUY:		return OVL_V_ATTCTL_LAY_FBFMT_VYUY;
626 	case DRM_FORMAT_YVYU:		return OVL_V_ATTCTL_LAY_FBFMT_YVYU;
627 	case DRM_FORMAT_UYVY:		return OVL_V_ATTCTL_LAY_FBFMT_UYVY;
628 	case DRM_FORMAT_YUYV:		return OVL_V_ATTCTL_LAY_FBFMT_YUYV;
629 	case DRM_FORMAT_YUV422:		return OVL_V_ATTCTL_LAY_FBFMT_YUV422;
630 	case DRM_FORMAT_YUV420:		return OVL_V_ATTCTL_LAY_FBFMT_YUV420;
631 	case DRM_FORMAT_YUV411:		return OVL_V_ATTCTL_LAY_FBFMT_YUV411;
632 	default:			return 0;	/* shouldn't happen */
633 	}
634 }
635 
636 static const uint32_t lan3coefftab32_left[512] = {
637 	0x40000000, 0x40fe0000, 0x3ffd0100, 0x3efc0100,
638 	0x3efb0100, 0x3dfa0200, 0x3cf90200, 0x3bf80200,
639 	0x39f70200, 0x37f70200, 0x35f70200, 0x33f70200,
640 	0x31f70200, 0x2ef70200, 0x2cf70200, 0x2af70200,
641 	0x27f70200, 0x24f80100, 0x22f80100, 0x1ef90100,
642 	0x1cf90100, 0x19fa0100, 0x17fa0100, 0x14fb0100,
643 	0x11fc0000, 0x0ffc0000, 0x0cfd0000, 0x0afd0000,
644 	0x08fe0000, 0x05ff0000, 0x03ff0000, 0x02000000,
645 
646 	0x40000000, 0x40fe0000, 0x3ffd0100, 0x3efc0100,
647 	0x3efb0100, 0x3dfa0200, 0x3cf90200, 0x3bf80200,
648 	0x39f70200, 0x37f70200, 0x35f70200, 0x33f70200,
649 	0x31f70200, 0x2ef70200, 0x2cf70200, 0x2af70200,
650 	0x27f70200, 0x24f80100, 0x22f80100, 0x1ef90100,
651 	0x1cf90100, 0x19fa0100, 0x17fa0100, 0x14fb0100,
652 	0x11fc0000, 0x0ffc0000, 0x0cfd0000, 0x0afd0000,
653 	0x08fe0000, 0x05ff0000, 0x03ff0000, 0x02000000,
654 
655 	0x3806fc02, 0x3805fc02, 0x3803fd01, 0x3801fe01,
656 	0x3700fe01, 0x35ffff01, 0x35fdff01, 0x34fc0001,
657 	0x34fb0000, 0x33fa0000, 0x31fa0100, 0x2ff90100,
658 	0x2df80200, 0x2bf80200, 0x2af70200, 0x28f70200,
659 	0x27f70200, 0x24f70300, 0x22f70300, 0x1ff70300,
660 	0x1ef70300, 0x1cf70300, 0x1af70300, 0x18f70300,
661 	0x16f80300, 0x13f80300, 0x11f90300, 0x0ef90300,
662 	0x0efa0200, 0x0cfa0200, 0x0afb0200, 0x08fb0200,
663 
664 	0x320bfa02, 0x3309fa02, 0x3208fb02, 0x3206fb02,
665 	0x3205fb02, 0x3104fc02, 0x3102fc01, 0x3001fd01,
666 	0x3000fd01, 0x2ffffd01, 0x2efefe01, 0x2dfdfe01,
667 	0x2bfcff01, 0x29fcff01, 0x28fbff01, 0x27fa0001,
668 	0x26fa0000, 0x24f90000, 0x22f90100, 0x20f90100,
669 	0x1ff80100, 0x1ef80100, 0x1cf80100, 0x1af80200,
670 	0x18f80200, 0x17f80200, 0x15f80200, 0x12f80200,
671 	0x11f90200, 0x0ff90200, 0x0df90200, 0x0cfa0200,
672 
673 	0x2e0efa01, 0x2f0dfa01, 0x2f0bfa01, 0x2e0afa01,
674 	0x2e09fa01, 0x2e07fb01, 0x2d06fb01, 0x2d05fb01,
675 	0x2c04fb01, 0x2b03fc01, 0x2a02fc01, 0x2a01fc01,
676 	0x2800fd01, 0x28fffd01, 0x26fefd01, 0x25fefe01,
677 	0x24fdfe01, 0x23fcfe01, 0x21fcff01, 0x20fbff01,
678 	0x1efbff01, 0x1efbff00, 0x1cfa0000, 0x1bfa0000,
679 	0x19fa0000, 0x18fa0000, 0x17f90000, 0x15f90100,
680 	0x14f90100, 0x12f90100, 0x11f90100, 0x0ff90100,
681 
682 	0x2b10fa00, 0x2b0ffa00, 0x2b0efa00, 0x2b0cfa00,
683 	0x2b0bfa00, 0x2a0afb01, 0x2a09fb01, 0x2908fb01,
684 	0x2807fb01, 0x2806fb01, 0x2805fb01, 0x2604fc01,
685 	0x2503fc01, 0x2502fc01, 0x2401fc01, 0x2301fc01,
686 	0x2100fd01, 0x21fffd01, 0x21fffd01, 0x20fefd01,
687 	0x1dfefe01, 0x1cfdfe01, 0x1cfdfe00, 0x1bfcfe00,
688 	0x19fcff00, 0x19fbff00, 0x17fbff00, 0x16fbff00,
689 	0x15fbff00, 0x14fb0000, 0x13fa0000, 0x11fa0000,
690 
691 	0x2811fcff, 0x2810fcff, 0x280ffbff, 0x280efbff,
692 	0x270dfb00, 0x270cfb00, 0x270bfb00, 0x260afb00,
693 	0x2609fb00, 0x2508fb00, 0x2507fb00, 0x2407fb00,
694 	0x2406fc00, 0x2305fc00, 0x2204fc00, 0x2203fc00,
695 	0x2103fc00, 0x2002fc00, 0x1f01fd00, 0x1e01fd00,
696 	0x1d00fd00, 0x1dfffd00, 0x1cfffd00, 0x1bfefd00,
697 	0x1afefe00, 0x19fefe00, 0x18fdfe00, 0x17fdfe00,
698 	0x16fdfe00, 0x15fcff00, 0x13fcff00, 0x12fcff00,
699 
700 	0x2512fdfe, 0x2511fdff, 0x2410fdff, 0x240ffdff,
701 	0x240efcff, 0x240dfcff, 0x240dfcff, 0x240cfcff,
702 	0x230bfcff, 0x230afc00, 0x2209fc00, 0x2108fc00,
703 	0x2108fc00, 0x2007fc00, 0x2006fc00, 0x2005fc00,
704 	0x1f05fc00, 0x1e04fc00, 0x1e03fc00, 0x1c03fd00,
705 	0x1c02fd00, 0x1b02fd00, 0x1b01fd00, 0x1a00fd00,
706 	0x1900fd00, 0x1800fd00, 0x17fffe00, 0x16fffe00,
707 	0x16fefe00, 0x14fefe00, 0x13fefe00, 0x13fdfe00,
708 
709 	0x2212fffe, 0x2211fefe, 0x2211fefe, 0x2110fefe,
710 	0x210ffeff, 0x220efdff, 0x210dfdff, 0x210dfdff,
711 	0x210cfdff, 0x210bfdff, 0x200afdff, 0x200afdff,
712 	0x1f09fdff, 0x1f08fdff, 0x1d08fd00, 0x1c07fd00,
713 	0x1d06fd00, 0x1b06fd00, 0x1b05fd00, 0x1c04fd00,
714 	0x1b04fd00, 0x1a03fd00, 0x1a03fd00, 0x1902fd00,
715 	0x1802fd00, 0x1801fd00, 0x1701fd00, 0x1600fd00,
716 	0x1400fe00, 0x1400fe00, 0x14fffe00, 0x13fffe00,
717 
718 	0x201200fe, 0x201100fe, 0x1f11fffe, 0x2010fffe,
719 	0x1f0ffffe, 0x1e0ffffe, 0x1f0efeff, 0x1f0dfeff,
720 	0x1f0dfeff, 0x1e0cfeff, 0x1e0bfeff, 0x1d0bfeff,
721 	0x1d0afeff, 0x1d09fdff, 0x1d09fdff, 0x1c08fdff,
722 	0x1c07fdff, 0x1b07fd00, 0x1b06fd00, 0x1a06fd00,
723 	0x1a05fd00, 0x1805fd00, 0x1904fd00, 0x1804fd00,
724 	0x1703fd00, 0x1703fd00, 0x1602fe00, 0x1502fe00,
725 	0x1501fe00, 0x1401fe00, 0x1301fe00, 0x1300fe00,
726 
727 	0x1c1202fe, 0x1c1102fe, 0x1b1102fe, 0x1c1001fe,
728 	0x1b1001fe, 0x1b0f01ff, 0x1b0e00ff, 0x1b0e00ff,
729 	0x1b0d00ff, 0x1a0d00ff, 0x1a0c00ff, 0x1a0cffff,
730 	0x1a0bffff, 0x1a0bffff, 0x1a0affff, 0x180affff,
731 	0x1909ffff, 0x1809ffff, 0x1808ffff, 0x1808feff,
732 	0x1807feff, 0x1707fe00, 0x1606fe00, 0x1506fe00,
733 	0x1605fe00, 0x1505fe00, 0x1504fe00, 0x1304fe00,
734 	0x1304fe00, 0x1303fe00, 0x1203fe00, 0x1203fe00,
735 
736 	0x181104ff, 0x191103ff, 0x191003ff, 0x181003ff,
737 	0x180f03ff, 0x190f02ff, 0x190e02ff, 0x180e02ff,
738 	0x180d02ff, 0x180d01ff, 0x180d01ff, 0x180c01ff,
739 	0x180c01ff, 0x180b00ff, 0x170b00ff, 0x170a00ff,
740 	0x170a00ff, 0x170900ff, 0x160900ff, 0x160900ff,
741 	0x1608ffff, 0x1508ffff, 0x1507ff00, 0x1507ff00,
742 	0x1407ff00, 0x1306ff00, 0x1306ff00, 0x1305ff00,
743 	0x1205ff00, 0x1105ff00, 0x1204ff00, 0x1104ff00,
744 
745 	0x171005ff, 0x171005ff, 0x171004ff, 0x170f04ff,
746 	0x160f04ff, 0x170f03ff, 0x170e03ff, 0x160e03ff,
747 	0x160d03ff, 0x160d02ff, 0x160d02ff, 0x160c02ff,
748 	0x160c02ff, 0x160c02ff, 0x160b01ff, 0x150b01ff,
749 	0x150a01ff, 0x150a01ff, 0x150a01ff, 0x140901ff,
750 	0x14090000, 0x14090000, 0x14080000, 0x13080000,
751 	0x13070000, 0x12070000, 0x12070000, 0x12060000,
752 	0x11060000, 0x11060000, 0x11050000, 0x1105ff00,
753 
754 	0x14100600, 0x15100500, 0x150f0500, 0x150f0500,
755 	0x140f0500, 0x150e0400, 0x140e0400, 0x130e0400,
756 	0x140d0400, 0x150d0300, 0x130d0300, 0x140c0300,
757 	0x140c0300, 0x140c0200, 0x140b0200, 0x130b0200,
758 	0x120b0200, 0x130a0200, 0x130a0200, 0x130a0100,
759 	0x13090100, 0x12090100, 0x11090100, 0x12080100,
760 	0x11080100, 0x10080100, 0x11070100, 0x11070000,
761 	0x10070000, 0x11060000, 0x10060000, 0x10060000,
762 
763 	0x140f0600, 0x140f0600, 0x130f0600, 0x140f0500,
764 	0x140e0500, 0x130e0500, 0x130e0500, 0x140d0400,
765 	0x140d0400, 0x130d0400, 0x120d0400, 0x130c0400,
766 	0x130c0300, 0x130c0300, 0x130b0300, 0x130b0300,
767 	0x110b0300, 0x130a0200, 0x120a0200, 0x120a0200,
768 	0x120a0200, 0x12090200, 0x10090200, 0x11090100,
769 	0x11080100, 0x11080100, 0x10080100, 0x10080100,
770 	0x10070100, 0x10070100, 0x0f070100, 0x10060100,
771 
772 	0x120f0701, 0x130f0601, 0x130e0601, 0x130e0601,
773 	0x120e0601, 0x130e0501, 0x130e0500, 0x130d0500,
774 	0x120d0500, 0x120d0500, 0x130c0400, 0x130c0400,
775 	0x120c0400, 0x110c0400, 0x120b0400, 0x120b0300,
776 	0x120b0300, 0x120b0300, 0x120a0300, 0x110a0300,
777 	0x110a0200, 0x11090200, 0x11090200, 0x10090200,
778 	0x10090200, 0x10080200, 0x10080200, 0x10080100,
779 	0x0f080100, 0x10070100, 0x0f070100, 0x0f070100
780 };
781 
782 static const uint32_t lan3coefftab32_right[512] = {
783 	0x00000000, 0x00000002, 0x0000ff04, 0x0000ff06,
784 	0x0000fe08, 0x0000fd0a, 0x0000fd0c, 0x0000fc0f,
785 	0x0000fc12, 0x0001fb14, 0x0001fa17, 0x0001fa19,
786 	0x0001f91c, 0x0001f91f, 0x0001f822, 0x0001f824,
787 	0x0002f727, 0x0002f72a, 0x0002f72c, 0x0002f72f,
788 	0x0002f731, 0x0002f733, 0x0002f735, 0x0002f737,
789 	0x0002f73a, 0x0002f83b, 0x0002f93c, 0x0002fa3d,
790 	0x0001fb3e, 0x0001fc3f, 0x0001fd40, 0x0000fe40,
791 
792 	0x00000000, 0x00000002, 0x0000ff04, 0x0000ff06,
793 	0x0000fe08, 0x0000fd0a, 0x0000fd0c, 0x0000fc0f,
794 	0x0000fc12, 0x0001fb14, 0x0001fa17, 0x0001fa19,
795 	0x0001f91c, 0x0001f91f, 0x0001f822, 0x0001f824,
796 	0x0002f727, 0x0002f72a, 0x0002f72c, 0x0002f72f,
797 	0x0002f731, 0x0002f733, 0x0002f735, 0x0002f737,
798 	0x0002f73a, 0x0002f83b, 0x0002f93c, 0x0002fa3d,
799 	0x0001fb3e, 0x0001fc3f, 0x0001fd40, 0x0000fe40,
800 
801 	0x0002fc06, 0x0002fb08, 0x0002fb0a, 0x0002fa0c,
802 	0x0002fa0e, 0x0003f910, 0x0003f912, 0x0003f814,
803 	0x0003f816, 0x0003f719, 0x0003f71a, 0x0003f71d,
804 	0x0003f71f, 0x0003f721, 0x0003f723, 0x0003f725,
805 	0x0002f727, 0x0002f729, 0x0002f72b, 0x0002f82d,
806 	0x0002f82e, 0x0001f930, 0x0001fa31, 0x0000fa34,
807 	0x0000fb34, 0x0100fc35, 0x01fffd36, 0x01ffff37,
808 	0x01fe0037, 0x01fe0138, 0x01fd0338, 0x02fc0538,
809 
810 	0x0002fa0b, 0x0002fa0c, 0x0002f90e, 0x0002f910,
811 	0x0002f911, 0x0002f813, 0x0002f816, 0x0002f817,
812 	0x0002f818, 0x0002f81a, 0x0001f81c, 0x0001f81e,
813 	0x0001f820, 0x0001f921, 0x0001f923, 0x0000f925,
814 	0x0000fa26, 0x0100fa28, 0x01fffb29, 0x01fffc2a,
815 	0x01fffc2c, 0x01fefd2d, 0x01fefe2e, 0x01fdff2f,
816 	0x01fd0030, 0x01fd0130, 0x01fc0232, 0x02fc0432,
817 	0x02fb0532, 0x02fb0633, 0x02fb0833, 0x02fa0933,
818 
819 	0x0001fa0e, 0x0001f90f, 0x0001f911, 0x0001f913,
820 	0x0001f914, 0x0001f915, 0x0000f918, 0x0000fa18,
821 	0x0000fa1a, 0x0000fa1b, 0x0000fa1d, 0x00fffb1e,
822 	0x01fffb1f, 0x01fffb20, 0x01fffc22, 0x01fefc23,
823 	0x01fefd24, 0x01fefe25, 0x01fdfe27, 0x01fdff28,
824 	0x01fd0029, 0x01fc012a, 0x01fc022b, 0x01fc032b,
825 	0x01fb042d, 0x01fb052d, 0x01fb062e, 0x01fb072e,
826 	0x01fa092e, 0x01fa0a2f, 0x01fa0b2f, 0x01fa0d2f,
827 
828 	0x0000fa11, 0x0000fa12, 0x0000fa13, 0x0000fb14,
829 	0x00fffb16, 0x00fffb16, 0x00fffb17, 0x00fffb19,
830 	0x00fffc1a, 0x00fefc1c, 0x00fefd1c, 0x01fefd1d,
831 	0x01fefe1e, 0x01fdfe20, 0x01fdff21, 0x01fdff22,
832 	0x01fd0023, 0x01fc0124, 0x01fc0124, 0x01fc0225,
833 	0x01fc0326, 0x01fc0427, 0x01fb0528, 0x01fb0629,
834 	0x01fb0729, 0x01fb0829, 0x01fb092a, 0x01fb0a2a,
835 	0x00fa0b2c, 0x00fa0c2b, 0x00fa0e2b, 0x00fa0f2c,
836 
837 	0x00fffc11, 0x00fffc12, 0x00fffc14, 0x00fffc15,
838 	0x00fefd16, 0x00fefd17, 0x00fefd18, 0x00fefe19,
839 	0x00fefe1a, 0x00fdfe1d, 0x00fdff1d, 0x00fdff1e,
840 	0x00fd001d, 0x00fd011e, 0x00fd0120, 0x00fc0221,
841 	0x00fc0321, 0x00fc0323, 0x00fc0423, 0x00fc0523,
842 	0x00fc0624, 0x00fb0725, 0x00fb0726, 0x00fb0827,
843 	0x00fb0926, 0x00fb0a26, 0x00fb0b27, 0x00fb0c27,
844 	0x00fb0d27, 0xfffb0e28, 0xfffb0f29, 0xfffc1028,
845 
846 	0x00fefd13, 0x00fefd13, 0x00fefe14, 0x00fefe15,
847 	0x00fefe17, 0x00feff17, 0x00feff17, 0x00fd0018,
848 	0x00fd001a, 0x00fd001a, 0x00fd011b, 0x00fd021c,
849 	0x00fd021c, 0x00fd031d, 0x00fc031f, 0x00fc041f,
850 	0x00fc051f, 0x00fc0521, 0x00fc0621, 0x00fc0721,
851 	0x00fc0821, 0x00fc0822, 0x00fc0922, 0x00fc0a23,
852 	0xfffc0b24, 0xfffc0c24, 0xfffc0d24, 0xfffc0d25,
853 	0xfffc0e25, 0xfffd0f25, 0xfffd1025, 0xfffd1125,
854 
855 	0x00feff12, 0x00feff14, 0x00feff14, 0x00fe0015,
856 	0x00fe0015, 0x00fd0017, 0x00fd0118, 0x00fd0118,
857 	0x00fd0218, 0x00fd0219, 0x00fd031a, 0x00fd031a,
858 	0x00fd041b, 0x00fd041c, 0x00fd051c, 0x00fd061d,
859 	0x00fd061d, 0x00fd071e, 0x00fd081e, 0xfffd081f,
860 	0xfffd091f, 0xfffd0a20, 0xfffd0a20, 0xfffd0b21,
861 	0xfffd0c21, 0xfffd0d21, 0xfffd0d22, 0xfffd0e23,
862 	0xfffe0f22, 0xfefe1022, 0xfefe1122, 0xfefe1123,
863 
864 	0x00fe0012, 0x00fe0013, 0x00fe0114, 0x00fe0114,
865 	0x00fe0116, 0x00fe0216, 0x00fe0216, 0x00fd0317,
866 	0x00fd0317, 0x00fd0418, 0x00fd0419, 0x00fd0519,
867 	0x00fd051a, 0x00fd061b, 0x00fd061b, 0x00fd071c,
868 	0xfffd071e, 0xfffd081d, 0xfffd091d, 0xfffd091e,
869 	0xfffe0a1d, 0xfffe0b1e, 0xfffe0b1e, 0xfffe0c1e,
870 	0xfffe0d1f, 0xfffe0d1f, 0xfffe0e1f, 0xfeff0f1f,
871 	0xfeff0f20, 0xfeff1020, 0xfeff1120, 0xfe001120,
872 
873 	0x00fe0212, 0x00fe0312, 0x00fe0313, 0x00fe0314,
874 	0x00fe0414, 0x00fe0414, 0x00fe0416, 0x00fe0515,
875 	0x00fe0516, 0x00fe0616, 0x00fe0617, 0x00fe0717,
876 	0xfffe0719, 0xfffe0818, 0xffff0818, 0xffff0919,
877 	0xffff0919, 0xffff0a19, 0xffff0a1a, 0xffff0b1a,
878 	0xffff0b1b, 0xffff0c1a, 0xff000c1b, 0xff000d1b,
879 	0xff000d1b, 0xff000e1b, 0xff000e1c, 0xff010f1c,
880 	0xfe01101c, 0xfe01101d, 0xfe02111c, 0xfe02111c,
881 
882 	0x00ff0411, 0x00ff0411, 0x00ff0412, 0x00ff0512,
883 	0x00ff0513, 0x00ff0513, 0x00ff0613, 0x00ff0614,
884 	0x00ff0714, 0x00ff0715, 0x00ff0715, 0xffff0816,
885 	0xffff0816, 0xff000916, 0xff000917, 0xff000918,
886 	0xff000a17, 0xff000a18, 0xff000b18, 0xff000b18,
887 	0xff010c18, 0xff010c19, 0xff010d18, 0xff010d18,
888 	0xff020d18, 0xff020e19, 0xff020e19, 0xff020f19,
889 	0xff030f19, 0xff031019, 0xff031019, 0xff031119,
890 
891 	0x00ff0511, 0x00ff0511, 0x00000511, 0x00000611,
892 	0x00000612, 0x00000612, 0x00000712, 0x00000713,
893 	0x00000714, 0x00000814, 0x00000814, 0x00000914,
894 	0x00000914, 0xff010914, 0xff010a15, 0xff010a16,
895 	0xff010a17, 0xff010b16, 0xff010b16, 0xff020c16,
896 	0xff020c16, 0xff020c16, 0xff020d16, 0xff020d17,
897 	0xff030d17, 0xff030e17, 0xff030e17, 0xff030f17,
898 	0xff040f17, 0xff040f17, 0xff041017, 0xff051017,
899 
900 	0x00000610, 0x00000610, 0x00000611, 0x00000611,
901 	0x00000711, 0x00000712, 0x00010712, 0x00010812,
902 	0x00010812, 0x00010812, 0x00010913, 0x00010913,
903 	0x00010913, 0x00010a13, 0x00020a13, 0x00020a14,
904 	0x00020b14, 0x00020b14, 0x00020b14, 0x00020c14,
905 	0x00030c14, 0x00030c15, 0x00030d15, 0x00030d15,
906 	0x00040d15, 0x00040e15, 0x00040e15, 0x00040e16,
907 	0x00050f15, 0x00050f15, 0x00050f16, 0x00051015,
908 
909 	0x00000611, 0x00010610, 0x00010710, 0x00010710,
910 	0x00010711, 0x00010811, 0x00010811, 0x00010812,
911 	0x00010812, 0x00010912, 0x00020912, 0x00020912,
912 	0x00020a12, 0x00020a12, 0x00020a13, 0x00020a13,
913 	0x00030b13, 0x00030b13, 0x00030b14, 0x00030c13,
914 	0x00030c13, 0x00040c13, 0x00040d14, 0x00040d14,
915 	0x00040d15, 0x00040d15, 0x00050e14, 0x00050e14,
916 	0x00050e15, 0x00050f14, 0x00060f14, 0x00060f14,
917 
918 	0x0001070f, 0x0001070f, 0x00010710, 0x00010710,
919 	0x00010810, 0x00010810, 0x00020810, 0x00020811,
920 	0x00020911, 0x00020911, 0x00020912, 0x00020912,
921 	0x00020a12, 0x00030a12, 0x00030a12, 0x00030b12,
922 	0x00030b12, 0x00030b12, 0x00040b12, 0x00040c12,
923 	0x00040c13, 0x00040c14, 0x00040c14, 0x00050d13,
924 	0x00050d13, 0x00050d14, 0x00050e13, 0x01050e13,
925 	0x01060e13, 0x01060e13, 0x01060e14, 0x01060f13
926 };
927 
928 static const uint32_t lan2coefftab32[512] = {
929 	0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd, 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
930 	0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb, 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
931 	0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd, 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
932 	0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff, 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
933 
934 	0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd, 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
935 	0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb, 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
936 	0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd, 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
937 	0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff, 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
938 
939 	0xff053804, 0xff063803, 0xff083801, 0xff093701, 0xff0a3700, 0xff0c3500, 0xff0e34ff, 0xff1033fe,
940 	0xff1232fd, 0xfe1431fd, 0xfe162ffd, 0xfe182dfd, 0xfd1b2cfc, 0xfd1d2afc, 0xfd1f28fc, 0xfd2126fc,
941 	0xfd2323fd, 0xfc2621fd, 0xfc281ffd, 0xfc2a1dfd, 0xfc2c1bfd, 0xfd2d18fe, 0xfd2f16fe, 0xfd3114fe,
942 	0xfd3212ff, 0xfe3310ff, 0xff340eff, 0x00350cff, 0x00360a00, 0x01360900, 0x02370700, 0x03370600,
943 
944 	0xff083207, 0xff093206, 0xff0a3205, 0xff0c3203, 0xff0d3103, 0xff0e3102, 0xfe113001, 0xfe132f00,
945 	0xfe142e00, 0xfe162dff, 0xfe182bff, 0xfe192aff, 0xfe1b29fe, 0xfe1d27fe, 0xfe1f25fe, 0xfd2124fe,
946 	0xfe2222fe, 0xfe2421fd, 0xfe251ffe, 0xfe271dfe, 0xfe291bfe, 0xff2a19fe, 0xff2b18fe, 0xff2d16fe,
947 	0x002e14fe, 0x002f12ff, 0x013010ff, 0x02300fff, 0x03310dff, 0x04310cff, 0x05310a00, 0x06310900,
948 
949 	0xff0a2e09, 0xff0b2e08, 0xff0c2e07, 0xff0e2d06, 0xff0f2d05, 0xff102d04, 0xff122c03, 0xfe142c02,
950 	0xfe152b02, 0xfe172a01, 0xfe182901, 0xfe1a2800, 0xfe1b2700, 0xfe1d2500, 0xff1e24ff, 0xfe2023ff,
951 	0xff2121ff, 0xff2320fe, 0xff241eff, 0x00251dfe, 0x00261bff, 0x00281afe, 0x012818ff, 0x012a16ff,
952 	0x022a15ff, 0x032b13ff, 0x032c12ff, 0x052c10ff, 0x052d0fff, 0x062d0d00, 0x072d0c00, 0x082d0b00,
953 
954 	0xff0c2a0b, 0xff0d2a0a, 0xff0e2a09, 0xff0f2a08, 0xff102a07, 0xff112a06, 0xff132905, 0xff142904,
955 	0xff162803, 0xff172703, 0xff182702, 0xff1a2601, 0xff1b2501, 0xff1c2401, 0xff1e2300, 0xff1f2200,
956 	0x00202000, 0x00211f00, 0x01221d00, 0x01231c00, 0x01251bff, 0x02251aff, 0x032618ff, 0x032717ff,
957 	0x042815ff, 0x052814ff, 0x052913ff, 0x06291100, 0x072a10ff, 0x082a0e00, 0x092a0d00, 0x0a2a0c00,
958 
959 	0xff0d280c, 0xff0e280b, 0xff0f280a, 0xff102809, 0xff112808, 0xff122708, 0xff142706, 0xff152705,
960 	0xff162605, 0xff172604, 0xff192503, 0xff1a2403, 0x001b2302, 0x001c2202, 0x001d2201, 0x001e2101,
961 	0x011f1f01, 0x01211e00, 0x01221d00, 0x02221c00, 0x02231b00, 0x03241900, 0x04241800, 0x04251700,
962 	0x052616ff, 0x06261400, 0x072713ff, 0x08271100, 0x08271100, 0x09271000, 0x0a280e00, 0x0b280d00,
963 
964 	0xff0e260d, 0xff0f260c, 0xff10260b, 0xff11260a, 0xff122609, 0xff132608, 0xff142508, 0xff152507,
965 	0x00152506, 0x00172405, 0x00182305, 0x00192304, 0x001b2203, 0x001c2103, 0x011d2002, 0x011d2002,
966 	0x011f1f01, 0x021f1e01, 0x02201d01, 0x03211c00, 0x03221b00, 0x04221a00, 0x04231801, 0x05241700,
967 	0x06241600, 0x07241500, 0x08251300, 0x09251200, 0x09261100, 0x0a261000, 0x0b260f00, 0x0c260e00,
968 
969 	0xff0e250e, 0xff0f250d, 0xff10250c, 0xff11250b, 0x0011250a, 0x00132409, 0x00142408, 0x00152407,
970 	0x00162307, 0x00172306, 0x00182206, 0x00192205, 0x011a2104, 0x011b2004, 0x011c2003, 0x021c1f03,
971 	0x021e1e02, 0x031e1d02, 0x03201c01, 0x04201b01, 0x04211a01, 0x05221900, 0x05221801, 0x06231700,
972 	0x07231600, 0x07241500, 0x08241400, 0x09241300, 0x0a241200, 0x0b241100, 0x0c241000, 0x0d240f00,
973 
974 	0x000e240e, 0x000f240d, 0x0010240c, 0x0011240b, 0x0013230a, 0x0013230a, 0x00142309, 0x00152308,
975 	0x00162208, 0x00172207, 0x01182106, 0x01192105, 0x011a2005, 0x021b1f04, 0x021b1f04, 0x021d1e03,
976 	0x031d1d03, 0x031e1d02, 0x041e1c02, 0x041f1b02, 0x05201a01, 0x05211901, 0x06211801, 0x07221700,
977 	0x07221601, 0x08231500, 0x09231400, 0x0a231300, 0x0a231300, 0x0b231200, 0x0c231100, 0x0d231000,
978 
979 	0x000f220f, 0x0010220e, 0x0011220d, 0x0012220c, 0x0013220b, 0x0013220b, 0x0015210a, 0x0015210a,
980 	0x01162108, 0x01172008, 0x01182007, 0x02191f06, 0x02191f06, 0x021a1e06, 0x031a1e05, 0x031c1d04,
981 	0x041c1c04, 0x041d1c03, 0x051d1b03, 0x051e1a03, 0x061f1902, 0x061f1902, 0x07201801, 0x08201701,
982 	0x08211601, 0x09211501, 0x0a211500, 0x0b211400, 0x0b221300, 0x0c221200, 0x0d221100, 0x0e221000,
983 
984 	0x0010210f, 0x0011210e, 0x0011210e, 0x0012210d, 0x0013210c, 0x0014200c, 0x0114200b, 0x0115200a,
985 	0x01161f0a, 0x01171f09, 0x02171f08, 0x02181e08, 0x03181e07, 0x031a1d06, 0x031a1d06, 0x041b1c05,
986 	0x041c1c04, 0x051c1b04, 0x051d1a04, 0x061d1a03, 0x071d1903, 0x071e1803, 0x081e1802, 0x081f1702,
987 	0x091f1602, 0x0a201501, 0x0b1f1501, 0x0b201401, 0x0c211300, 0x0d211200, 0x0e201200, 0x0e211100,
988 
989 	0x00102010, 0x0011200f, 0x0012200e, 0x0013200d, 0x0013200d, 0x01141f0c, 0x01151f0b, 0x01151f0b,
990 	0x01161f0a, 0x02171e09, 0x02171e09, 0x03181d08, 0x03191d07, 0x03191d07, 0x041a1c06, 0x041b1c05,
991 	0x051b1b05, 0x051c1b04, 0x061c1a04, 0x071d1903, 0x071d1903, 0x081d1803, 0x081e1703, 0x091e1702,
992 	0x0a1f1601, 0x0a1f1502, 0x0b1f1501, 0x0c1f1401, 0x0d201300, 0x0d201300, 0x0e201200, 0x0f201100,
993 
994 	0x00102010, 0x0011200f, 0x00121f0f, 0x00131f0e, 0x00141f0d, 0x01141f0c, 0x01141f0c, 0x01151e0c,
995 	0x02161e0a, 0x02171e09, 0x03171d09, 0x03181d08, 0x03181d08, 0x04191c07, 0x041a1c06, 0x051a1b06,
996 	0x051b1b05, 0x061b1a05, 0x061c1a04, 0x071c1904, 0x081c1903, 0x081d1803, 0x091d1703, 0x091e1702,
997 	0x0a1e1602, 0x0b1e1502, 0x0c1e1501, 0x0c1f1401, 0x0d1f1400, 0x0e1f1300, 0x0e1f1201, 0x0f1f1200,
998 
999 	0x00111e11, 0x00121e10, 0x00131e0f, 0x00131e0f, 0x01131e0e, 0x01141d0e, 0x02151d0c, 0x02151d0c,
1000 	0x02161d0b, 0x03161c0b, 0x03171c0a, 0x04171c09, 0x04181b09, 0x05181b08, 0x05191b07, 0x06191a07,
1001 	0x061a1a06, 0x071a1906, 0x071b1905, 0x081b1805, 0x091b1804, 0x091c1704, 0x0a1c1703, 0x0a1c1604,
1002 	0x0b1d1602, 0x0c1d1502, 0x0c1d1502, 0x0d1d1402, 0x0e1d1401, 0x0e1e1301, 0x0f1e1300, 0x101e1200,
1003 
1004 	0x00111e11, 0x00121e10, 0x00131d10, 0x01131d0f, 0x01141d0e, 0x01141d0e, 0x02151c0d, 0x02151c0d,
1005 	0x03161c0b, 0x03161c0b, 0x04171b0a, 0x04171b0a, 0x05171b09, 0x05181a09, 0x06181a08, 0x06191a07,
1006 	0x07191907, 0x071a1906, 0x081a1806, 0x081a1806, 0x091a1805, 0x0a1b1704, 0x0a1b1704, 0x0b1c1603,
1007 	0x0b1c1603, 0x0c1c1503, 0x0d1c1502, 0x0d1d1402, 0x0e1d1401, 0x0f1d1301, 0x0f1d1301, 0x101e1200,
1008 };
1009 
1010 static void
1011 sunxi_mixer_vsu_init(struct sunxi_mixer_softc *sc, u_int src_w, u_int src_h,
1012     u_int crtc_w, u_int crtc_h, uint32_t pixel_format)
1013 {
1014 	const u_int hstep = (src_w << 16) / crtc_w;
1015 	const u_int vstep = (src_h << 16) / crtc_h;
1016 
1017 	const int hsub = drm_format_horz_chroma_subsampling(pixel_format);
1018 	const int vsub = drm_format_vert_chroma_subsampling(pixel_format);
1019 
1020 	const u_int src_cw = src_w / hsub;
1021 	const u_int src_ch = src_h / vsub;
1022 
1023 	VSU_WRITE(sc, VS_OUT_SIZE_REG, ((crtc_h - 1) << 16) | (crtc_w - 1));
1024 	VSU_WRITE(sc, VS_Y_SIZE_REG, ((src_h - 1) << 16) | (src_w - 1));
1025 	VSU_WRITE(sc, VS_Y_HSTEP_REG, hstep << 4);
1026 	VSU_WRITE(sc, VS_Y_VSTEP_REG, vstep << 4);
1027 	VSU_WRITE(sc, VS_Y_HPHASE_REG, 0);
1028 	VSU_WRITE(sc, VS_Y_VPHASE0_REG, 0);
1029 	VSU_WRITE(sc, VS_Y_VPHASE1_REG, 0);
1030 	VSU_WRITE(sc, VS_C_SIZE_REG, ((src_ch - 1) << 16) | (src_cw - 1));
1031 	VSU_WRITE(sc, VS_C_HSTEP_REG, (hstep / hsub) << 4);
1032 	VSU_WRITE(sc, VS_C_VSTEP_REG, (vstep / vsub) << 4);
1033 	VSU_WRITE(sc, VS_C_HPHASE_REG, 0);
1034 	VSU_WRITE(sc, VS_C_VPHASE0_REG, 0);
1035 	VSU_WRITE(sc, VS_C_VPHASE1_REG, 0);
1036 
1037 	/* XXX */
1038 	const u_int coef_base = 0;
1039 
1040 	for (int i = 0; i < 32; i++) {
1041 		VSU_WRITE(sc, VS_Y_HCOEF0_REG(i), lan3coefftab32_left[coef_base + i]);
1042 		VSU_WRITE(sc, VS_Y_HCOEF1_REG(i), lan3coefftab32_right[coef_base + i]);
1043 		VSU_WRITE(sc, VS_Y_VCOEF_REG(i), lan2coefftab32[coef_base + i]);
1044 		VSU_WRITE(sc, VS_C_HCOEF0_REG(i), lan3coefftab32_left[coef_base + i]);
1045 		VSU_WRITE(sc, VS_C_HCOEF1_REG(i), lan3coefftab32_right[coef_base + i]);
1046 		VSU_WRITE(sc, VS_C_VCOEF_REG(i), lan2coefftab32[coef_base + i]);
1047 	}
1048 
1049 	/* Commit settings and enable scaler */
1050 	VSU_WRITE(sc, VS_CTRL_REG, VS_CTRL_COEF_SWITCH_EN | VS_CTRL_EN);
1051 }
1052 
1053 static const u32 yuv2rgb[] = {
1054 	0x000004A8, 0x00000000, 0x00000662, 0xFFFC865A,
1055 	0x000004A8, 0xFFFFFE6F, 0xFFFFFCBF, 0x00021FF4,
1056 	0x000004A8, 0x00000813, 0x00000000, 0xFFFBAE4A,
1057 };
1058 
1059 static void
1060 sunxi_mixer_csc_init(struct sunxi_mixer_softc *sc, uint32_t pixel_format)
1061 {
1062 	const u_int crtc_index = drm_crtc_index(&sc->sc_crtc.base);
1063 
1064 	for (int i = 0; i < __arraycount(yuv2rgb); i++)
1065 		CSC_WRITE(sc, crtc_index, CSC_COEFF0_REG(0) + i * 4, yuv2rgb[i]);
1066 
1067 	CSC_WRITE(sc, crtc_index, CSC_BYPASS_REG, CSC_BYPASS_DISABLE);
1068 }
1069 
1070 static void
1071 sunxi_mixer_csc_disable(struct sunxi_mixer_softc *sc)
1072 {
1073 	const u_int crtc_index = drm_crtc_index(&sc->sc_crtc.base);
1074 
1075 	CSC_WRITE(sc, crtc_index, CSC_BYPASS_REG, 0);
1076 }
1077 
1078 static int
1079 sunxi_mixer_overlay_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
1080     struct drm_framebuffer *fb, int crtc_x, int crtc_y, u_int crtc_w, u_int crtc_h,
1081     uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h)
1082 {
1083 	struct sunxi_mixer_plane *overlay = to_sunxi_mixer_plane(plane);
1084 	struct sunxi_mixer_softc * const sc = overlay->sc;
1085 	struct sunxi_drm_framebuffer *sfb = to_sunxi_drm_framebuffer(fb);
1086 	uint32_t val;
1087 
1088 	const u_int fbfmt = sunxi_mixer_overlay_format(fb->pixel_format);
1089 	const uint64_t paddr = (uint64_t)sfb->obj->dmamap->dm_segs[0].ds_addr;
1090 
1091 	const uint32_t input_size = (((src_h >> 16) - 1) << 16) | ((src_w >> 16) - 1);
1092 	const uint32_t input_pos = ((src_y >> 16) << 16) | (src_x >> 16);
1093 
1094 	OVL_V_WRITE(sc, OVL_V_MBSIZE(0), input_size);
1095 	OVL_V_WRITE(sc, OVL_V_COOR(0), input_pos);
1096 
1097 	/* Note: DRM and hardware's ideas of pitch 1 and 2 are swapped */
1098 
1099 	OVL_V_WRITE(sc, OVL_V_PITCH0(0), fb->pitches[0]);
1100 	OVL_V_WRITE(sc, OVL_V_PITCH1(0), fb->pitches[2]);
1101 	OVL_V_WRITE(sc, OVL_V_PITCH2(0), fb->pitches[1]);
1102 
1103 	const uint64_t paddr0 = paddr + fb->offsets[0] +
1104 	    (src_x >> 16) * drm_format_plane_cpp(fb->pixel_format, 0) +
1105 	    (src_y >> 16) * fb->pitches[0];
1106 	const uint64_t paddr1 = paddr + fb->offsets[2] +
1107 	    (src_x >> 16) * drm_format_plane_cpp(fb->pixel_format, 2) +
1108 	    (src_y >> 16) * fb->pitches[2];
1109 	const uint64_t paddr2 = paddr + fb->offsets[1] +
1110 	    (src_x >> 16) * drm_format_plane_cpp(fb->pixel_format, 1) +
1111 	    (src_y >> 16) * fb->pitches[1];
1112 
1113 	OVL_V_WRITE(sc, OVL_V_TOP_HADD0, (paddr0 >> 32) & OVL_V_TOP_HADD_LAYER0);
1114 	OVL_V_WRITE(sc, OVL_V_TOP_HADD1, (paddr1 >> 32) & OVL_V_TOP_HADD_LAYER0);
1115 	OVL_V_WRITE(sc, OVL_V_TOP_HADD2, (paddr2 >> 32) & OVL_V_TOP_HADD_LAYER0);
1116 
1117 	OVL_V_WRITE(sc, OVL_V_TOP_LADD0(0), paddr0 & 0xffffffff);
1118 	OVL_V_WRITE(sc, OVL_V_TOP_LADD1(0), paddr1 & 0xffffffff);
1119 	OVL_V_WRITE(sc, OVL_V_TOP_LADD2(0), paddr2 & 0xffffffff);
1120 
1121 	OVL_V_WRITE(sc, OVL_V_SIZE, input_size);
1122 
1123 	val = OVL_V_ATTCTL_LAY0_EN;
1124 	val |= __SHIFTIN(fbfmt, OVL_V_ATTCTL_LAY_FBFMT);
1125 	if (sunxi_mixer_overlay_rgb(fb->pixel_format) == true)
1126 		val |= OVL_V_ATTCTL_VIDEO_UI_SEL;
1127 	OVL_V_WRITE(sc, OVL_V_ATTCTL(0), val);
1128 
1129 	/* Enable video scaler */
1130 	sunxi_mixer_vsu_init(sc, src_w >> 16, src_h >> 16, crtc_w, crtc_h, fb->pixel_format);
1131 
1132 	/* Enable colour space conversion for non-RGB formats */
1133 	if (sunxi_mixer_overlay_rgb(fb->pixel_format) == false)
1134 		sunxi_mixer_csc_init(sc, fb->pixel_format);
1135 	else
1136 		sunxi_mixer_csc_disable(sc);
1137 
1138 	/* Set blender 1 input size */
1139 	BLD_WRITE(sc, BLD_CH_ISIZE(1), ((crtc_h - 1) << 16) | (crtc_w - 1));
1140 	/* Set blender 1 offset */
1141 	BLD_WRITE(sc, BLD_CH_OFFSET(1), (crtc_y << 16) | crtc_x);
1142 	/* Route channel 0 to pipe 1 */
1143 	val = BLD_READ(sc, BLD_CH_RTCTL);
1144 	val &= ~BLD_CH_RTCTL_P1;
1145 	val |= __SHIFTIN(0, BLD_CH_RTCTL_P1);
1146 	BLD_WRITE(sc, BLD_CH_RTCTL, val);
1147 
1148         /* Enable pipe 1 */
1149 	val = BLD_READ(sc, BLD_FILL_COLOR_CTL);
1150 	val |= BLD_FILL_COLOR_CTL_P1_EN;
1151 	BLD_WRITE(sc, BLD_FILL_COLOR_CTL, val);
1152 
1153 	/* Commit settings */
1154 	GLB_WRITE(sc, GLB_DBUFFER, GLB_DBUFFER_DOUBLE_BUFFER_RDY);
1155 
1156 	return 0;
1157 }
1158 
1159 static int
1160 sunxi_mixer_overlay_disable_plane(struct drm_plane *plane)
1161 {
1162 	struct sunxi_mixer_plane *overlay = to_sunxi_mixer_plane(plane);
1163 	struct sunxi_mixer_softc * const sc = overlay->sc;
1164 	uint32_t val;
1165 
1166 	sunxi_mixer_csc_disable(sc);
1167 
1168 	val = BLD_READ(sc, BLD_FILL_COLOR_CTL);
1169 	val &= ~BLD_FILL_COLOR_CTL_P1_EN;
1170 	BLD_WRITE(sc, BLD_FILL_COLOR_CTL, val);
1171 
1172 	/* Commit settings */
1173 	GLB_WRITE(sc, GLB_DBUFFER, GLB_DBUFFER_DOUBLE_BUFFER_RDY);
1174 
1175 	return 0;
1176 }
1177 
1178 static const struct drm_plane_funcs sunxi_mixer_overlay_funcs = {
1179 	.update_plane = sunxi_mixer_overlay_update_plane,
1180 	.disable_plane = sunxi_mixer_overlay_disable_plane,
1181 	.destroy = sunxi_mixer_overlay_destroy,
1182 };
1183 
1184 static uint32_t sunxi_mixer_overlay_formats[] = {
1185 	DRM_FORMAT_ARGB8888,
1186 	DRM_FORMAT_XRGB8888,
1187 #if notyet
1188 	DRM_FORMAT_VYUY,
1189 	DRM_FORMAT_YVYU,
1190 	DRM_FORMAT_UYVY,
1191 	DRM_FORMAT_YUYV,
1192 #endif
1193 	DRM_FORMAT_YUV422,
1194 	DRM_FORMAT_YUV420,
1195 	DRM_FORMAT_YUV411,
1196 };
1197 
1198 static int
1199 sunxi_mixer_ep_activate(device_t dev, struct fdt_endpoint *ep, bool activate)
1200 {
1201 	struct sunxi_mixer_softc * const sc = device_private(dev);
1202 	struct drm_device *ddev;
1203 	bus_size_t reg;
1204 
1205 	if (!activate)
1206 		return EINVAL;
1207 
1208 	ddev = sunxi_drm_endpoint_device(ep);
1209 	if (ddev == NULL) {
1210 		DRM_ERROR("couldn't find DRM device\n");
1211 		return ENXIO;
1212 	}
1213 
1214 	sc->sc_crtc.sc = sc;
1215 	sc->sc_overlay.sc = sc;
1216 
1217 	/* Initialize registers */
1218 	for (reg = 0; reg < 0xc000; reg += 4)
1219 		bus_space_write_4(sc->sc_bst, sc->sc_bsh, reg, 0);
1220 	BLD_WRITE(sc, BLD_CTL(0), 0x03010301);
1221 	BLD_WRITE(sc, BLD_CTL(1), 0x03010301);
1222 	BLD_WRITE(sc, BLD_CTL(2), 0x03010301);
1223 	BLD_WRITE(sc, BLD_CTL(3), 0x03010301);
1224 
1225 	if (sc->sc_ovl_ui_count > 1)
1226 		drm_crtc_init(ddev, &sc->sc_crtc.base, &sunxi_mixer0_crtc_funcs);
1227 	else
1228 		drm_crtc_init(ddev, &sc->sc_crtc.base, &sunxi_mixer1_crtc_funcs);
1229 	drm_crtc_helper_add(&sc->sc_crtc.base, &sunxi_mixer_crtc_helper_funcs);
1230 
1231 	drm_universal_plane_init(ddev, &sc->sc_overlay.base,
1232 	    1 << drm_crtc_index(&sc->sc_crtc.base), &sunxi_mixer_overlay_funcs,
1233 	    sunxi_mixer_overlay_formats, __arraycount(sunxi_mixer_overlay_formats),
1234 	    DRM_PLANE_TYPE_OVERLAY);
1235 
1236 	return fdt_endpoint_activate(ep, activate);
1237 }
1238 
1239 static void *
1240 sunxi_mixer_ep_get_data(device_t dev, struct fdt_endpoint *ep)
1241 {
1242 	struct sunxi_mixer_softc * const sc = device_private(dev);
1243 
1244 	return &sc->sc_crtc;
1245 }
1246 
1247 static int
1248 sunxi_mixer_match(device_t parent, cfdata_t cf, void *aux)
1249 {
1250 	struct fdt_attach_args * const faa = aux;
1251 
1252 	return of_compatible_match(faa->faa_phandle, compat_data);
1253 }
1254 
1255 static void
1256 sunxi_mixer_attach(device_t parent, device_t self, void *aux)
1257 {
1258 	struct sunxi_mixer_softc * const sc = device_private(self);
1259 	struct fdt_attach_args * const faa = aux;
1260 	struct fdt_endpoint *out_ep;
1261 	const int phandle = faa->faa_phandle;
1262 	const struct sunxi_mixer_compat_data * const cd =
1263 	    of_compatible_lookup(phandle, compat_data)->data;
1264 	struct clk *clk_bus, *clk_mod;
1265 	struct fdtbus_reset *rst;
1266 	bus_addr_t addr;
1267 	bus_size_t size;
1268 
1269 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
1270 		aprint_error(": couldn't get registers\n");
1271 		return;
1272 	}
1273 
1274 	rst = fdtbus_reset_get_index(phandle, 0);
1275 	if (rst == NULL || fdtbus_reset_deassert(rst) != 0) {
1276 		aprint_error(": couldn't de-assert reset\n");
1277 		return;
1278 	}
1279 
1280 	clk_bus = fdtbus_clock_get(phandle, "bus");
1281 	if (clk_bus == NULL || clk_enable(clk_bus) != 0) {
1282 		aprint_error(": couldn't enable bus clock\n");
1283 		return;
1284 	}
1285 
1286 	clk_mod = fdtbus_clock_get(phandle, "mod");
1287 	if (clk_mod == NULL ||
1288 	    clk_set_rate(clk_mod, SUNXI_MIXER_FREQ) != 0 ||
1289 	    clk_enable(clk_mod) != 0) {
1290 		aprint_error(": couldn't enable mod clock\n");
1291 		return;
1292 	}
1293 
1294 	sc->sc_dev = self;
1295 	sc->sc_bst = faa->faa_bst;
1296 	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
1297 		aprint_error(": couldn't map registers\n");
1298 		return;
1299 	}
1300 	sc->sc_phandle = faa->faa_phandle;
1301 	sc->sc_ovl_ui_count = cd->ovl_ui_count;
1302 
1303 	aprint_naive("\n");
1304 	aprint_normal(": Display Engine Mixer\n");
1305 
1306 	sc->sc_ports.dp_ep_activate = sunxi_mixer_ep_activate;
1307 	sc->sc_ports.dp_ep_get_data = sunxi_mixer_ep_get_data;
1308 	fdt_ports_register(&sc->sc_ports, self, phandle, EP_DRM_CRTC);
1309 
1310 	out_ep = fdt_endpoint_get_from_index(&sc->sc_ports,
1311 	    MIXER_PORT_OUTPUT, cd->mixer_index);
1312 	if (out_ep == NULL) {
1313 		/* Couldn't find new-style DE2 endpoint, try old style. */
1314 		out_ep = fdt_endpoint_get_from_index(&sc->sc_ports,
1315 		    MIXER_PORT_OUTPUT, 0);
1316 	}
1317 
1318 	if (out_ep != NULL)
1319 		sunxi_drm_register_endpoint(phandle, out_ep);
1320 }
1321 
1322 CFATTACH_DECL_NEW(sunxi_mixer, sizeof(struct sunxi_mixer_softc),
1323 	sunxi_mixer_match, sunxi_mixer_attach, NULL, NULL);
1324