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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
+ * 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