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