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