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