Module Name:    src
Committed By:   martin
Date:           Mon Dec  1 13:23:49 UTC 2014

Modified Files:
        src/sys/arch/arm/allwinner [netbsd-7]: awin_debe.c awin_fb.c awin_reg.h
Added Files:
        src/sys/arch/arm/allwinner [netbsd-7]: awin_mp.c

Log Message:
Pull up following revision(s) (requested by jmcneill in ticket #284):
        sys/arch/arm/allwinner/awin_reg.h: revision 1.56
        sys/arch/arm/allwinner/awin_debe.c: revision 1.9-1.10
        sys/arch/arm/allwinner/awin_mp.c: revision 1.1
        sys/arch/arm/allwinner/awin_fb.c: revision 1.7
hardware cursor support
hide the hw cursor when blanking the screen


To generate a diff of this commit:
cvs rdiff -u -r1.6.2.4 -r1.6.2.5 src/sys/arch/arm/allwinner/awin_debe.c
cvs rdiff -u -r1.4.2.4 -r1.4.2.5 src/sys/arch/arm/allwinner/awin_fb.c
cvs rdiff -u -r0 -r1.1.2.2 src/sys/arch/arm/allwinner/awin_mp.c
cvs rdiff -u -r1.14.2.7 -r1.14.2.8 src/sys/arch/arm/allwinner/awin_reg.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/allwinner/awin_debe.c
diff -u src/sys/arch/arm/allwinner/awin_debe.c:1.6.2.4 src/sys/arch/arm/allwinner/awin_debe.c:1.6.2.5
--- src/sys/arch/arm/allwinner/awin_debe.c:1.6.2.4	Sat Nov 15 11:31:40 2014
+++ src/sys/arch/arm/allwinner/awin_debe.c	Mon Dec  1 13:23:49 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: awin_debe.c,v 1.6.2.4 2014/11/15 11:31:40 martin Exp $ */
+/* $NetBSD: awin_debe.c,v 1.6.2.5 2014/12/01 13:23:49 martin Exp $ */
 
 /*-
  * Copyright (c) 2014 Jared D. McNeill <jmcne...@invisible.ca>
@@ -33,8 +33,10 @@
 #define AWIN_DEBE_VIDEOMEM	(16 * 1024 * 1024)
 #endif
 
+#define AWIN_DEBE_CURMAX	64
+
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: awin_debe.c,v 1.6.2.4 2014/11/15 11:31:40 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: awin_debe.c,v 1.6.2.5 2014/12/01 13:23:49 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -66,6 +68,12 @@ struct awin_debe_softc {
 	void *sc_dmap;
 
 	uint16_t sc_margin;
+
+	bool sc_cursor_enable;
+	int sc_cursor_x, sc_cursor_y;
+	int sc_hot_x, sc_hot_y;
+	uint8_t sc_cursor_bitmap[8 * AWIN_DEBE_CURMAX];
+	uint8_t sc_cursor_mask[8 * AWIN_DEBE_CURMAX];
 };
 
 #define DEBE_READ(sc, reg) \
@@ -80,6 +88,10 @@ static int	awin_debe_alloc_videomem(stru
 static void	awin_debe_setup_fbdev(struct awin_debe_softc *,
 				      const struct videomode *);
 
+static int	awin_debe_set_curpos(struct awin_debe_softc *, int, int);
+static int	awin_debe_set_cursor(struct awin_debe_softc *,
+				     struct wsdisplay_cursor *);
+
 CFATTACH_DECL_NEW(awin_debe, sizeof(struct awin_debe_softc),
 	awin_debe_match, awin_debe_attach, NULL, NULL);
 
@@ -177,6 +189,8 @@ awin_debe_attach(device_t parent, device
 
 	DEBE_WRITE(sc, AWIN_DEBE_MODCTL_REG, AWIN_DEBE_MODCTL_EN);
 
+	DEBE_WRITE(sc, AWIN_DEBE_HWC_PALETTE_TABLE, 0);
+
 	error = awin_debe_alloc_videomem(sc);
 	if (error) {
 		aprint_error_dev(sc->sc_dev,
@@ -255,6 +269,125 @@ awin_debe_setup_fbdev(struct awin_debe_s
 #endif
 }
 
+static int
+awin_debe_set_curpos(struct awin_debe_softc *sc, int x, int y)
+{
+	int xx, yy;
+	u_int yoff, xoff;
+
+	xoff = yoff = 0;
+	xx = x - sc->sc_hot_x + sc->sc_margin;
+	yy = y - sc->sc_hot_y + sc->sc_margin;
+	if (xx < 0) {
+		xoff -= xx;
+		xx = 0;
+	}
+	if (yy < 0) {
+		yoff -= yy;
+		yy = 0;
+	}
+
+	DEBE_WRITE(sc, AWIN_DEBE_HWCCTL_REG,
+	    __SHIFTIN(yy, AWIN_DEBE_HWCCTL_YCOOR) |
+	    __SHIFTIN(xx, AWIN_DEBE_HWCCTL_XCOOR));
+	DEBE_WRITE(sc, AWIN_DEBE_HWCFBCTL_REG,
+#if AWIN_DEBE_CURMAX == 32
+	    __SHIFTIN(AWIN_DEBE_HWCFBCTL_YSIZE_32, AWIN_DEBE_HWCFBCTL_YSIZE) |
+	    __SHIFTIN(AWIN_DEBE_HWCFBCTL_XSIZE_32, AWIN_DEBE_HWCFBCTL_XSIZE) |
+#else
+	    __SHIFTIN(AWIN_DEBE_HWCFBCTL_YSIZE_64, AWIN_DEBE_HWCFBCTL_YSIZE) |
+	    __SHIFTIN(AWIN_DEBE_HWCFBCTL_XSIZE_64, AWIN_DEBE_HWCFBCTL_XSIZE) |
+#endif
+	    __SHIFTIN(AWIN_DEBE_HWCFBCTL_FBFMT_2BPP, AWIN_DEBE_HWCFBCTL_FBFMT) |
+	    __SHIFTIN(yoff, AWIN_DEBE_HWCFBCTL_YCOOROFF) |
+	    __SHIFTIN(xoff, AWIN_DEBE_HWCFBCTL_XCOOROFF));
+
+	return 0;
+}
+
+static int
+awin_debe_set_cursor(struct awin_debe_softc *sc, struct wsdisplay_cursor *cur)
+{
+	uint32_t val;
+	uint8_t r[4], g[4], b[4];
+	u_int index, count, shift, off, pcnt;
+	int i, j, idx, error;
+	uint8_t mask;
+
+	if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
+		val = DEBE_READ(sc, AWIN_DEBE_MODCTL_REG);
+		if (cur->enable)
+			val |= AWIN_DEBE_MODCTL_HWC_EN;
+		else
+			val &= ~AWIN_DEBE_MODCTL_HWC_EN;
+		DEBE_WRITE(sc, AWIN_DEBE_MODCTL_REG, val);
+
+		sc->sc_cursor_enable = cur->enable;
+	}
+
+	if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
+		sc->sc_hot_x = cur->hot.x;
+		sc->sc_hot_y = cur->hot.y;
+		cur->which |= WSDISPLAY_CURSOR_DOPOS;
+	}
+
+	if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
+		awin_debe_set_curpos(sc, cur->pos.x, cur->pos.y);
+	}
+
+	if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
+		index = cur->cmap.index;
+		count = cur->cmap.count;
+		if (index >= 2 || (index + count) > 2)
+			return EINVAL;
+		error = copyin(cur->cmap.red, &r[index], count);
+		if (error)
+			return error;
+		error = copyin(cur->cmap.green, &g[index], count);
+		if (error)
+			return error;
+		error = copyin(cur->cmap.blue, &b[index], count);
+		if (error)
+			return error;
+
+		for (i = index; i < (index + count); i++) {
+			DEBE_WRITE(sc,
+			    AWIN_DEBE_HWC_PALETTE_TABLE + (4 * (i + 2)),
+			    (r[i] << 16) | (g[i] << 8) | b[i] | 0xff000000);
+		}
+	}
+
+	if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
+		error = copyin(cur->mask, sc->sc_cursor_mask,
+		    AWIN_DEBE_CURMAX * 8);
+		if (error)
+			return error;
+		error = copyin(cur->image, sc->sc_cursor_bitmap,
+		    AWIN_DEBE_CURMAX * 8);
+		if (error)
+			return error;
+	}
+
+	if (cur->which & (WSDISPLAY_CURSOR_DOCMAP|WSDISPLAY_CURSOR_DOSHAPE)) {
+		for (i = 0, pcnt = 0; i < AWIN_DEBE_CURMAX * 8; i++) {
+			for (j = 0, mask = 1; j < 8; j++, mask <<= 1, pcnt++) {
+				idx = ((sc->sc_cursor_mask[i] & mask) ? 2 : 0) |
+				    ((sc->sc_cursor_bitmap[i] & mask) ? 1 : 0);
+				off = (pcnt >> 4) * 4;
+				shift = (pcnt & 0xf) * 2;
+				val = DEBE_READ(sc,
+				    AWIN_DEBE_HWC_PATTERN_BLOCK + off);
+				val &= ~(3 << shift);
+				val |= (idx << shift);
+				DEBE_WRITE(sc,
+				    AWIN_DEBE_HWC_PATTERN_BLOCK + off, val);
+			}
+		}
+	}
+
+	return 0;
+}
+
 void
 awin_debe_enable(bool enable)
 {
@@ -366,6 +499,7 @@ int
 awin_debe_ioctl(device_t self, u_long cmd, void *data)
 {
 	struct awin_debe_softc *sc = device_private(self);
+	struct wsdisplay_curpos *cp;
 	uint32_t val;
 	int enable;
 
@@ -373,16 +507,38 @@ awin_debe_ioctl(device_t self, u_long cm
 	case WSDISPLAYIO_SVIDEO:
 		enable = *(int *)data;
 		val = DEBE_READ(sc, AWIN_DEBE_MODCTL_REG);
-		if (enable)
+		if (enable) {
 			val |= AWIN_DEBE_MODCTL_LAY0_EN;
-		else
+			if (sc->sc_cursor_enable) {
+				val |= AWIN_DEBE_MODCTL_HWC_EN;
+			} else {
+				val &= ~AWIN_DEBE_MODCTL_HWC_EN;
+			}
+		} else {
 			val &= ~AWIN_DEBE_MODCTL_LAY0_EN;
+			val &= ~AWIN_DEBE_MODCTL_HWC_EN;
+		}
 		DEBE_WRITE(sc, AWIN_DEBE_MODCTL_REG, val);
 		return 0;
 	case WSDISPLAYIO_GVIDEO:
 		val = DEBE_READ(sc, AWIN_DEBE_MODCTL_REG);
 		*(int *)data = !!(val & AWIN_DEBE_MODCTL_LAY0_EN);
 		return 0;
+	case WSDISPLAYIO_GCURPOS:
+		cp = data;
+		cp->x = sc->sc_cursor_x;
+		cp->y = sc->sc_cursor_y;
+		return 0;
+	case WSDISPLAYIO_SCURPOS:
+		cp = data;
+		return awin_debe_set_curpos(sc, cp->x, cp->y);
+	case WSDISPLAYIO_GCURMAX:
+		cp = data;
+		cp->x = AWIN_DEBE_CURMAX;
+		cp->y = AWIN_DEBE_CURMAX;
+		return 0;
+	case WSDISPLAYIO_SCURSOR:
+		return awin_debe_set_cursor(sc, data);
 	}
 
 	return EPASSTHROUGH;

Index: src/sys/arch/arm/allwinner/awin_fb.c
diff -u src/sys/arch/arm/allwinner/awin_fb.c:1.4.2.4 src/sys/arch/arm/allwinner/awin_fb.c:1.4.2.5
--- src/sys/arch/arm/allwinner/awin_fb.c:1.4.2.4	Sat Nov 15 11:31:40 2014
+++ src/sys/arch/arm/allwinner/awin_fb.c	Mon Dec  1 13:23:49 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: awin_fb.c,v 1.4.2.4 2014/11/15 11:31:40 martin Exp $ */
+/* $NetBSD: awin_fb.c,v 1.4.2.5 2014/12/01 13:23:49 martin Exp $ */
 
 /*-
  * Copyright (c) 2014 Jared D. McNeill <jmcne...@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: awin_fb.c,v 1.4.2.4 2014/11/15 11:31:40 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: awin_fb.c,v 1.4.2.5 2014/12/01 13:23:49 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -148,6 +148,10 @@ awin_fb_ioctl(void *v, void *vs, u_long 
 		return error;
 	case WSDISPLAYIO_SVIDEO:
 	case WSDISPLAYIO_GVIDEO:
+	case WSDISPLAYIO_GCURPOS:
+	case WSDISPLAYIO_SCURPOS:
+	case WSDISPLAYIO_GCURMAX:
+	case WSDISPLAYIO_SCURSOR:
 		return awin_debe_ioctl(sc->sc_debedev, cmd, data);
 	default:
 		return EPASSTHROUGH;

Index: src/sys/arch/arm/allwinner/awin_reg.h
diff -u src/sys/arch/arm/allwinner/awin_reg.h:1.14.2.7 src/sys/arch/arm/allwinner/awin_reg.h:1.14.2.8
--- src/sys/arch/arm/allwinner/awin_reg.h:1.14.2.7	Tue Nov 25 08:08:10 2014
+++ src/sys/arch/arm/allwinner/awin_reg.h	Mon Dec  1 13:23:49 2014
@@ -1653,6 +1653,8 @@ struct awin_mmc_idma_descriptor {
 #define AWIN_DEBE_OCGCONS_REG		0x09EC
 #define AWIN_DEBE_OCBCOEF_REG		0x09F0
 #define AWIN_DEBE_OCBCONS_REG		0x09FC
+#define AWIN_DEBE_HWC_PATTERN_BLOCK	0x4800
+#define AWIN_DEBE_HWC_PALETTE_TABLE	0x4C00
 
 #define AWIN_DEBE_MODCTL_LINE_SEL	__BIT(29)
 #define AWIN_DEBE_MODCTL_ITLMOD_EN	__BIT(28)
@@ -1703,6 +1705,23 @@ struct awin_mmc_idma_descriptor {
 #define AWIN_DEBE_REGBUFFCTL_REGAUTOLOAD_DIS __BIT(1)
 #define AWIN_DEBE_REGBUFFCTL_REGLOADCTL	__BIT(0)
 
+#define AWIN_DEBE_HWCCTL_YCOOR		__BITS(31,16)
+#define AWIN_DEBE_HWCCTL_XCOOR		__BITS(15,0)
+
+#define AWIN_DEBE_HWCFBCTL_YCOOROFF	__BITS(31,24)
+#define AWIN_DEBE_HWCFBCTL_XCOOROFF	__BITS(23,16)
+#define AWIN_DEBE_HWCFBCTL_YSIZE	__BITS(5,4)
+#define AWIN_DEBE_HWCFBCTL_YSIZE_32	0
+#define AWIN_DEBE_HWCFBCTL_YSIZE_64	1
+#define AWIN_DEBE_HWCFBCTL_XSIZE	__BITS(3,2)
+#define AWIN_DEBE_HWCFBCTL_XSIZE_32	0
+#define AWIN_DEBE_HWCFBCTL_XSIZE_64	1
+#define AWIN_DEBE_HWCFBCTL_FBFMT	__BITS(1,0)
+#define AWIN_DEBE_HWCFBCTL_FBFMT_1BPP	0
+#define AWIN_DEBE_HWCFBCTL_FBFMT_2BPP	1
+#define AWIN_DEBE_HWCFBCTL_FBFMT_4BPP	2
+#define AWIN_DEBE_HWCFBCTL_FBFMT_8BPP	3
+
 /* TCON */
 #define AWIN_TCON_GCTL_REG		0x0000
 #define AWIN_TCON_GINT0_REG		0x0004

Added files:

Index: src/sys/arch/arm/allwinner/awin_mp.c
diff -u /dev/null src/sys/arch/arm/allwinner/awin_mp.c:1.1.2.2
--- /dev/null	Mon Dec  1 13:23:49 2014
+++ src/sys/arch/arm/allwinner/awin_mp.c	Mon Dec  1 13:23:49 2014
@@ -0,0 +1,398 @@
+/* $NetBSD: awin_mp.c,v 1.1.2.2 2014/12/01 13:23:49 martin Exp $ */
+
+/*-
+ * Copyright (c) 2014 Jared D. McNeill <jmcne...@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "opt_ddb.h"
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: awin_mp.c,v 1.1.2.2 2014/12/01 13:23:49 martin Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+
+#include <arm/allwinner/awin_reg.h>
+#include <arm/allwinner/awin_var.h>
+
+#include <dev/wscons/wsconsio.h>
+
+struct awin_mp_softc {
+	device_t sc_dev;
+	bus_space_tag_t sc_bst;
+	bus_space_handle_t sc_bsh;
+	kmutex_t sc_lock;
+	kcondvar_t sc_cv;
+	void *sc_ih;
+
+	paddr_t sc_membase;
+	size_t sc_memsize;
+
+	uint32_t sc_intr_sts;
+};
+
+#define MP_READ(sc, reg) \
+    bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define MP_WRITE(sc, reg, val) \
+    bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+static int	awin_mp_match(device_t, cfdata_t, void *);
+static void	awin_mp_attach(device_t, device_t, void *);
+static void	awin_mp_clkinit(struct awin_mp_softc *, bus_space_handle_t);
+
+static int	awin_mp_intr(void *);
+static int	awin_mp_wait(struct awin_mp_softc *);
+static uint64_t	awin_mp_addr(struct awin_mp_softc *, uint32_t, uint32_t,
+		    uint32_t, uint32_t);
+static int	awin_mp_exec(struct awin_mp_softc *);
+
+static int	awin_mp_fill(struct awin_mp_softc *,
+		    const struct wsdisplayio_fill *);
+static int	awin_mp_copy(struct awin_mp_softc *,
+		    const struct wsdisplayio_copy *);
+
+#ifdef DDB
+void		awin_mp_dump_regs(void);
+#endif
+
+CFATTACH_DECL_NEW(awin_mp, sizeof(struct awin_mp_softc),
+	awin_mp_match, awin_mp_attach, NULL, NULL);
+
+static int
+awin_mp_match(device_t parent, cfdata_t cf, void *aux)
+{
+	struct awinio_attach_args * const aio = aux;
+	const struct awin_locators * const loc = &aio->aio_loc;
+
+	if (strcmp(cf->cf_name, loc->loc_name))
+		return 0;
+
+	return 1;
+}
+
+static void
+awin_mp_attach(device_t parent, device_t self, void *aux)
+{
+	struct awin_mp_softc *sc = device_private(self);
+	struct awinio_attach_args * const aio = aux;
+	const struct awin_locators * const loc = &aio->aio_loc;
+
+	sc->sc_dev = self;
+	sc->sc_bst = aio->aio_core_bst;
+	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SCHED);
+	cv_init(&sc->sc_cv, "awinmp");
+	bus_space_subregion(sc->sc_bst, aio->aio_core_bsh,
+	    loc->loc_offset, loc->loc_size, &sc->sc_bsh);
+
+	aprint_naive("\n");
+	aprint_normal(": Mixer processor\n");
+
+	awin_mp_clkinit(sc, aio->aio_ccm_bsh);
+
+	sc->sc_ih = intr_establish(loc->loc_intr, IPL_SCHED, IST_LEVEL,
+	    awin_mp_intr, sc);
+	if (sc->sc_ih == NULL) {
+		aprint_error_dev(self, "couldn't establish interrupt %d\n",
+		    loc->loc_intr);
+		return;
+	}
+	aprint_normal_dev(self, "interrupting at irq %d\n", loc->loc_intr);
+}
+
+static void
+awin_mp_clkinit(struct awin_mp_softc *sc, bus_space_handle_t ccm_bsh)
+{
+	/* Set PLL7 to 297 MHz */
+	awin_pll7_enable();
+
+	switch (awin_chip_id()) {
+	case AWIN_CHIP_ID_A31:
+		/* Soft reset */
+		awin_reg_set_clear(sc->sc_bst, ccm_bsh, AWIN_A31_AHB_RESET1_REG,
+		    AWIN_A31_AHB_RESET1_MP_RST, 0);
+		/* DRAM clock gating */
+		awin_reg_set_clear(sc->sc_bst, ccm_bsh, AWIN_DRAM_CLK_REG,
+		    AWIN_DRAM_CLK_DE_MP_DCLK_ENABLE, 0);
+		/* MP clock source PLL7, 99 MHz, enable */
+		awin_reg_set_clear(sc->sc_bst, ccm_bsh, AWIN_MP_CLK_REG,
+		    __SHIFTIN(AWIN_CLK_SRC_SEL_MP_PLL7, AWIN_CLK_SRC_SEL) |
+		    __SHIFTIN(2, AWIN_CLK_DIV_RATIO_M) |
+		    AWIN_CLK_ENABLE,
+		    AWIN_CLK_SRC_SEL | AWIN_CLK_DIV_RATIO_M);
+		break;
+	}
+
+	/* Enable */
+	awin_reg_set_clear(sc->sc_bst, ccm_bsh, AWIN_AHB_GATING1_REG,
+	    AWIN_AHB_GATING1_MP, 0);
+}
+
+static int
+awin_mp_intr(void *priv)
+{
+	struct awin_mp_softc *sc = priv;
+	uint32_t sts;
+
+	sts = MP_READ(sc, AWIN_MP_STS_REG);
+	if (!sts)
+		return 0;
+
+	MP_WRITE(sc, AWIN_MP_STS_REG, sts);
+
+	mutex_enter(&sc->sc_lock);
+	sc->sc_intr_sts |= sts;
+	cv_broadcast(&sc->sc_cv);
+	mutex_exit(&sc->sc_lock);
+
+	return 1;
+}
+
+static int
+awin_mp_wait(struct awin_mp_softc *sc)
+{
+	int error = EINVAL;
+
+	KASSERT(mutex_owned(&sc->sc_lock));
+
+	sc->sc_intr_sts |= MP_READ(sc, AWIN_MP_STS_REG);
+
+	for (;;) {
+		if (sc->sc_intr_sts & AWIN_MP_STS_FINISHIRQ_FLAG)
+			return 0;
+
+		error = cv_timedwait(&sc->sc_cv, &sc->sc_lock, mstohz(200));
+		if (error)
+			break;
+	}
+
+	return error;
+}
+
+static uint64_t
+awin_mp_addr(struct awin_mp_softc *sc, uint32_t offset, uint32_t stride,
+    uint32_t x, uint32_t y)
+{
+	return (sc->sc_membase + (uint64_t)offset + stride * y + (x * 4)) * 8;
+}
+
+static int
+awin_mp_exec(struct awin_mp_softc *sc)
+{
+	KASSERT(mutex_owned(&sc->sc_lock));
+
+	sc->sc_intr_sts = 0;
+
+	MP_WRITE(sc, AWIN_MP_STS_REG, MP_READ(sc, AWIN_MP_STS_REG));
+	MP_WRITE(sc, AWIN_MP_CTL_REG, 0);
+	MP_WRITE(sc, AWIN_MP_CTL_REG,
+	    AWIN_MP_CTL_HWERRIRQ_EN |
+	    AWIN_MP_CTL_FINISHIRQ_EN |
+	    AWIN_MP_CTL_START_CTL |
+	    AWIN_MP_CTL_MP_EN);
+
+	return awin_mp_wait(sc);
+}
+
+static int
+awin_mp_fill(struct awin_mp_softc *sc, const struct wsdisplayio_fill *fill)
+{
+	uint64_t outaddr;
+	uint32_t w, h;
+
+	KASSERT(mutex_owned(&sc->sc_lock));
+
+	w = fill->x2 - fill->x1;
+	h = fill->y2 - fill->y1;
+	outaddr = awin_mp_addr(sc, fill->dst.offset, fill->dst.stride,
+	    fill->x1, fill->y1);
+
+	MP_WRITE(sc, AWIN_MP_IDMAGLBCTL_REG,
+	    __SHIFTIN(AWIN_MP_IDMAGLBCTL_MEMSCANORDER_TD_LR,
+		      AWIN_MP_IDMAGLBCTL_MEMSCANORDER));
+
+	MP_WRITE(sc, AWIN_MP_IDMASIZE_REG(0),
+	    __SHIFTIN(h - 1, AWIN_MP_IDMASIZE_HEIGHT) |
+	    __SHIFTIN(w - 1, AWIN_MP_IDMASIZE_WIDTH));
+	MP_WRITE(sc, AWIN_MP_IDMACOOR_REG(0), 0);
+	MP_WRITE(sc, AWIN_MP_IDMASET_REG(0),
+	    __SHIFTIN(AWIN_MP_IDMASET_IDMA_FMT_ARGB8888,
+		      AWIN_MP_IDMASET_IDMA_FMT) |
+	    __SHIFTIN(AWIN_MP_IDMASET_IDMA_ROPMIRCTL_NORMAL,
+		      AWIN_MP_IDMASET_IDMA_ROPMIRCTL) |
+	    AWIN_MP_IDMASET_IDMA_FCMODEN |
+	    AWIN_MP_IDMASET_IDMA_EN);
+	MP_WRITE(sc, AWIN_MP_IDMAFILLCOLOR_REG(0), fill->fg);
+
+	MP_WRITE(sc, AWIN_MP_ROPIDX0CTL_REG,
+	    __SHIFTIN(1, AWIN_MP_ROPIDXxCTL_NOD6_CTL) |
+	    __SHIFTIN(1, AWIN_MP_ROPIDXxCTL_NOD4_CTL));
+
+	MP_WRITE(sc, AWIN_MP_OUTSIZE_REG,
+	    __SHIFTIN(h - 1, AWIN_MP_OUTSIZE_OUT_HEIGHT) |
+	    __SHIFTIN(w - 1, AWIN_MP_OUTSIZE_OUT_WIDTH));
+	MP_WRITE(sc, AWIN_MP_OUTH4ADD_REG,
+	    __SHIFTIN((outaddr >> 32) & 0xf, AWIN_MP_OUTH4ADD_OUTCH0_H4ADD));
+	MP_WRITE(sc, AWIN_MP_OUTL32ADD_REG(0), outaddr & 0xffffffff);
+	MP_WRITE(sc, AWIN_MP_OUTLINEWIDTH_REG(0), fill->dst.stride * NBBY);
+	MP_WRITE(sc, AWIN_MP_OUTCTL_REG,
+	    AWIN_MP_OUTCTL_RND_EN |
+	    __SHIFTIN(AWIN_MP_OUTCTL_OUT_FMT_ARGB8888, AWIN_MP_OUTCTL_OUT_FMT));
+
+	return awin_mp_exec(sc);
+}
+
+static int
+awin_mp_copy(struct awin_mp_softc *sc, const struct wsdisplayio_copy *copy)
+{
+	uint64_t inaddr, outaddr;
+	uint32_t xoff, yoff;
+	u_int mso;
+
+	KASSERT(mutex_owned(&sc->sc_lock));
+
+	xoff = yoff = 0;
+	mso = AWIN_MP_IDMAGLBCTL_MEMSCANORDER_TD_LR;
+
+	if (copy->src.offset == copy->dst.offset) {
+		if (copy->dsty > copy->srcy) {
+			mso = AWIN_MP_IDMAGLBCTL_MEMSCANORDER_DT_LR;
+			yoff += (copy->height - 1);
+		} else if (copy->dsty == copy->srcy) {
+			if (copy->dstx > copy->srcx) {
+				mso = AWIN_MP_IDMAGLBCTL_MEMSCANORDER_TD_RL;
+				xoff += (copy->width - 1);
+			}
+		}
+	}
+
+	MP_WRITE(sc, AWIN_MP_IDMAGLBCTL_REG,
+	    __SHIFTIN(mso, AWIN_MP_IDMAGLBCTL_MEMSCANORDER));
+
+	inaddr = awin_mp_addr(sc, copy->src.offset, copy->src.stride,
+	    copy->srcx, copy->srcy);
+	outaddr = awin_mp_addr(sc, copy->dst.offset, copy->dst.stride,
+	    copy->dstx + xoff, copy->dsty + yoff);
+
+	MP_WRITE(sc, AWIN_MP_IDMA_H4ADD_REG,
+	    __SHIFTIN((inaddr >> 32) & 0xf, AWIN_MP_IDMA_H4ADD_IDMA0_H4ADD));
+	MP_WRITE(sc, AWIN_MP_IDMA_L32ADD_REG(0), inaddr & 0xffffffff);
+
+	MP_WRITE(sc, AWIN_MP_IDMALINEWIDTH_REG(0), copy->src.stride * NBBY);
+	MP_WRITE(sc, AWIN_MP_IDMASIZE_REG(0),
+	    __SHIFTIN(copy->height - 1, AWIN_MP_IDMASIZE_HEIGHT) |
+	    __SHIFTIN(copy->width - 1, AWIN_MP_IDMASIZE_WIDTH));
+	MP_WRITE(sc, AWIN_MP_IDMACOOR_REG(0), 0);
+	MP_WRITE(sc, AWIN_MP_IDMASET_REG(0),
+	    __SHIFTIN(AWIN_MP_IDMASET_IDMA_FMT_ARGB8888,
+		      AWIN_MP_IDMASET_IDMA_FMT) |
+	    __SHIFTIN(AWIN_MP_IDMASET_IDMA_ROPMIRCTL_NORMAL,
+		      AWIN_MP_IDMASET_IDMA_ROPMIRCTL) |
+	    __SHIFTIN(0xff, AWIN_MP_IDMASET_IDMA_GLBALPHA) |
+	    __SHIFTIN(1, AWIN_MP_IDMASET_IDMA_ALPHACTL) |
+	    AWIN_MP_IDMASET_IDMA_EN);
+
+	MP_WRITE(sc, AWIN_MP_ROPIDX0CTL_REG,
+	    __SHIFTIN(1, AWIN_MP_ROPIDXxCTL_NOD6_CTL) |
+	    __SHIFTIN(1, AWIN_MP_ROPIDXxCTL_NOD4_CTL));
+
+	MP_WRITE(sc, AWIN_MP_OUTSIZE_REG,
+	    __SHIFTIN(copy->height - 1, AWIN_MP_OUTSIZE_OUT_HEIGHT) |
+	    __SHIFTIN(copy->width - 1, AWIN_MP_OUTSIZE_OUT_WIDTH));
+	MP_WRITE(sc, AWIN_MP_OUTH4ADD_REG,
+	    __SHIFTIN((outaddr >> 32) & 0xf, AWIN_MP_OUTH4ADD_OUTCH0_H4ADD));
+	MP_WRITE(sc, AWIN_MP_OUTL32ADD_REG(0), outaddr & 0xffffffff);
+	MP_WRITE(sc, AWIN_MP_OUTLINEWIDTH_REG(0), copy->dst.stride * NBBY);
+	MP_WRITE(sc, AWIN_MP_OUTCTL_REG,
+	    AWIN_MP_OUTCTL_RND_EN |
+	    __SHIFTIN(AWIN_MP_OUTCTL_OUT_FMT_ARGB8888, AWIN_MP_OUTCTL_OUT_FMT));
+
+	return awin_mp_exec(sc);
+}
+
+void
+awin_mp_setbase(device_t dev, paddr_t base, size_t size)
+{
+	struct awin_mp_softc *sc = device_private(dev);
+
+	sc->sc_membase = base;
+	sc->sc_memsize = size;
+}
+
+int
+awin_mp_ioctl(device_t dev, u_long cmd, void *data)
+{
+	struct awin_mp_softc *sc = device_private(dev);
+	int error;
+
+	if (sc->sc_membase == 0)
+		return EPASSTHROUGH;
+
+	mutex_enter(&sc->sc_lock);
+
+	switch (cmd) {
+	case WSDISPLAYIO_FILL:
+		error = awin_mp_fill(sc, data);
+		break;
+	case WSDISPLAYIO_COPY:
+		error = awin_mp_copy(sc, data);
+		break;
+	case WSDISPLAYIO_SYNC:
+		error = awin_mp_wait(sc);
+		break;
+	default:
+		error = EPASSTHROUGH;
+		break;
+	}
+
+	mutex_exit(&sc->sc_lock);
+
+	return error;
+}
+
+#ifdef DDB
+void
+awin_mp_dump_regs(void)
+{
+	struct awin_mp_softc *sc;
+	device_t dev;
+	uint32_t v;
+
+	dev = device_find_by_driver_unit("awinmp", 0);
+	if (dev == NULL)
+		return;
+	sc = device_private(dev);
+
+	for (int i = 0; i <= AWIN_MP_CMDQUEADD_REG; i += 4) {
+		v = MP_READ(sc, i);
+		printf("MP: 0x%04x = 0x%08x\n", i, v);
+	}
+}
+#endif

Reply via email to