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