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