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