Module Name:    src
Committed By:   jmcneill
Date:           Mon Oct 13 12:34:00 UTC 2014

Modified Files:
        src/sys/arch/arm/allwinner: awin_ac.c awin_dma.c awin_reg.h awin_var.h
            files.awin
Added Files:
        src/sys/arch/arm/allwinner: awin_dma.h awin_dma_a10.c awin_dma_a31.c

Log Message:
Split awindma into a frontend and A10/A20 backend; add an A31 DMA backend.


To generate a diff of this commit:
cvs rdiff -u -r1.13 -r1.14 src/sys/arch/arm/allwinner/awin_ac.c
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/arm/allwinner/awin_dma.c
cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/allwinner/awin_dma.h \
    src/sys/arch/arm/allwinner/awin_dma_a10.c \
    src/sys/arch/arm/allwinner/awin_dma_a31.c
cvs rdiff -u -r1.33 -r1.34 src/sys/arch/arm/allwinner/awin_reg.h
cvs rdiff -u -r1.17 -r1.18 src/sys/arch/arm/allwinner/awin_var.h
cvs rdiff -u -r1.16 -r1.17 src/sys/arch/arm/allwinner/files.awin

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_ac.c
diff -u src/sys/arch/arm/allwinner/awin_ac.c:1.13 src/sys/arch/arm/allwinner/awin_ac.c:1.14
--- src/sys/arch/arm/allwinner/awin_ac.c:1.13	Sun Oct 12 17:25:35 2014
+++ src/sys/arch/arm/allwinner/awin_ac.c	Mon Oct 13 12:34:00 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: awin_ac.c,v 1.13 2014/10/12 17:25:35 jmcneill Exp $ */
+/* $NetBSD: awin_ac.c,v 1.14 2014/10/13 12:34:00 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2014 Jared D. McNeill <jmcne...@invisible.ca>
@@ -30,7 +30,7 @@
 #include "opt_ddb.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: awin_ac.c,v 1.13 2014/10/12 17:25:35 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: awin_ac.c,v 1.14 2014/10/13 12:34:00 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -179,6 +179,9 @@ struct awinac_softc {
 
 	LIST_HEAD(, awinac_dma)	sc_dmalist;
 
+	uint8_t			sc_drqtype_codec;
+	uint8_t			sc_drqtype_sdram;
+
 	kmutex_t		sc_lock;
 	kmutex_t		sc_intr_lock;
 
@@ -361,12 +364,19 @@ awinac_attach(device_t parent, device_t 
 
 	awinac_init(sc);
 
-	sc->sc_pdma = awin_dma_alloc(AWIN_DMA_TYPE_NDMA, awinac_pint, sc);
+	sc->sc_drqtype_codec = awin_chip_id() == AWIN_CHIP_ID_A31 ?
+	    AWIN_A31_DMA_DRQ_TYPE_AUDIOCODEC :
+	    AWIN_NDMA_CTL_DRQ_CODEC;
+	sc->sc_drqtype_sdram = awin_chip_id() == AWIN_CHIP_ID_A31 ?
+	    AWIN_A31_DMA_DRQ_TYPE_SDRAM :
+	    AWIN_NDMA_CTL_DRQ_SDRAM;
+
+	sc->sc_pdma = awin_dma_alloc("codec-play", awinac_pint, sc);
 	if (sc->sc_pdma == NULL) {
 		aprint_error_dev(self, "couldn't allocate play DMA channel\n");
 		return;
 	}
-	sc->sc_rdma = awin_dma_alloc(AWIN_DMA_TYPE_NDMA, awinac_rint, sc);
+	sc->sc_rdma = awin_dma_alloc("codec-rec", awinac_rint, sc);
 	if (sc->sc_rdma == NULL) {
 		aprint_error_dev(self, "couldn't allocate rec DMA channel\n");
 		return;
@@ -967,9 +977,9 @@ awinac_trigger_output(void *priv, void *
 			    AWIN_DMA_CTL_SRC_BURST_LEN);
 	dmacfg |= AWIN_DMA_CTL_BC_REMAINING;
 	dmacfg |= AWIN_NDMA_CTL_DST_ADDR_NOINCR;
-	dmacfg |= __SHIFTIN(AWIN_NDMA_CTL_DRQ_CODEC,
+	dmacfg |= __SHIFTIN(sc->sc_drqtype_codec,
 			    AWIN_DMA_CTL_DST_DRQ_TYPE);
-	dmacfg |= __SHIFTIN(AWIN_NDMA_CTL_DRQ_SDRAM,
+	dmacfg |= __SHIFTIN(sc->sc_drqtype_sdram,
 			    AWIN_DMA_CTL_SRC_DRQ_TYPE);
 	awin_dma_set_config(sc->sc_pdma, dmacfg);
 
@@ -1035,9 +1045,9 @@ awinac_trigger_input(void *priv, void *s
 			    AWIN_DMA_CTL_SRC_BURST_LEN);
 	dmacfg |= AWIN_DMA_CTL_BC_REMAINING;
 	dmacfg |= AWIN_NDMA_CTL_SRC_ADDR_NOINCR;
-	dmacfg |= __SHIFTIN(AWIN_NDMA_CTL_DRQ_SDRAM,
+	dmacfg |= __SHIFTIN(sc->sc_drqtype_sdram,
 			    AWIN_DMA_CTL_DST_DRQ_TYPE);
-	dmacfg |= __SHIFTIN(AWIN_NDMA_CTL_DRQ_CODEC,
+	dmacfg |= __SHIFTIN(sc->sc_drqtype_codec,
 			    AWIN_DMA_CTL_SRC_DRQ_TYPE);
 	awin_dma_set_config(sc->sc_rdma, dmacfg);
 

Index: src/sys/arch/arm/allwinner/awin_dma.c
diff -u src/sys/arch/arm/allwinner/awin_dma.c:1.4 src/sys/arch/arm/allwinner/awin_dma.c:1.5
--- src/sys/arch/arm/allwinner/awin_dma.c:1.4	Sat Sep  6 17:10:17 2014
+++ src/sys/arch/arm/allwinner/awin_dma.c	Mon Oct 13 12:34:00 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: awin_dma.c,v 1.4 2014/09/06 17:10:17 jmcneill Exp $ */
+/* $NetBSD: awin_dma.c,v 1.5 2014/10/13 12:34:00 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2014 Jared D. McNeill <jmcne...@invisible.ca>
@@ -27,9 +27,10 @@
  */
 
 #include "opt_ddb.h"
+#include "opt_allwinner.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: awin_dma.c,v 1.4 2014/09/06 17:10:17 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: awin_dma.c,v 1.5 2014/10/13 12:34:00 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -40,44 +41,13 @@ __KERNEL_RCSID(0, "$NetBSD: awin_dma.c,v
 
 #include <arm/allwinner/awin_reg.h>
 #include <arm/allwinner/awin_var.h>
-
-#define NDMA_CHANNELS	8
-#define DDMA_CHANNELS	8
-
-struct awin_dma_channel {
-	uint8_t ch_index;
-	enum awin_dma_type ch_type;
-	void (*ch_callback)(void *);
-	void *ch_callbackarg;
-	uint32_t ch_regoff;
-};
-
-struct awin_dma_softc {
-	device_t sc_dev;
-	bus_space_tag_t sc_bst;
-	bus_space_handle_t sc_bsh;
-	void *sc_ih;
-};
-
-#define DMA_READ(reg)			\
-    bus_space_read_4(awin_dma_sc->sc_bst, awin_dma_sc->sc_bsh, (reg))
-#define DMA_WRITE(reg, val)		\
-    bus_space_write_4(awin_dma_sc->sc_bst, awin_dma_sc->sc_bsh, (reg), (val))
-#define DMACH_READ(ch, reg)		\
-    DMA_READ((reg) + (ch)->ch_regoff)
-#define DMACH_WRITE(ch, reg, val)	\
-    DMA_WRITE((reg) + (ch)->ch_regoff, (val))
+#include <arm/allwinner/awin_dma.h>
 
 static struct awin_dma_softc *awin_dma_sc;
-static kmutex_t awin_dma_lock;
-static struct awin_dma_channel awin_ndma_channels[NDMA_CHANNELS];
-static struct awin_dma_channel awin_ddma_channels[DDMA_CHANNELS];
 
 static int	awin_dma_match(device_t, cfdata_t, void *);
 static void	awin_dma_attach(device_t, device_t, void *);
 
-static int	awin_dma_intr(void *);
-
 #if defined(DDB)
 void		awin_dma_dump_regs(void);
 #endif
@@ -88,7 +58,11 @@ CFATTACH_DECL_NEW(awin_dma, sizeof(struc
 static int
 awin_dma_match(device_t parent, cfdata_t cf, void *aux)
 {
+#if defined(ALLWINNER_A10) || defined(ALLWINNER_A20) || defined(ALLWINNER_A31)
 	return awin_dma_sc == NULL;
+#else
+	return 0;
+#endif
 }
 
 static void
@@ -97,235 +71,106 @@ awin_dma_attach(device_t parent, device_
 	struct awin_dma_softc *sc = device_private(self);
 	struct awinio_attach_args * const aio = aux;
 	const struct awin_locators * const loc = &aio->aio_loc;
-	uint8_t index;
 
 	KASSERT(awin_dma_sc == NULL);
 	awin_dma_sc = sc;
 
 	sc->sc_dev = self;
 	sc->sc_bst = aio->aio_core_bst;
+	sc->sc_dmat = aio->aio_dmat;
 	bus_space_subregion(sc->sc_bst, aio->aio_core_bsh,
 	    loc->loc_offset, loc->loc_size, &sc->sc_bsh);
 
 	aprint_naive("\n");
 	aprint_normal(": DMA\n");
 
-	mutex_init(&awin_dma_lock, MUTEX_DEFAULT, IPL_SCHED);
-
-	awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh,
-	    AWIN_AHB_GATING0_REG, AWIN_AHB_GATING0_DMA, 0);
-
-	DMA_WRITE(AWIN_DMA_IRQ_EN_REG, 0);
-	DMA_WRITE(AWIN_DMA_IRQ_PEND_STA_REG, ~0);
-
-	for (index = 0; index < NDMA_CHANNELS; index++) {
-		awin_ndma_channels[index].ch_index = index;
-		awin_ndma_channels[index].ch_type = AWIN_DMA_TYPE_NDMA;
-		awin_ndma_channels[index].ch_callback = NULL;
-		awin_ndma_channels[index].ch_callbackarg = NULL;
-		awin_ndma_channels[index].ch_regoff = AWIN_NDMA_REG(index);
-		DMACH_WRITE(&awin_ndma_channels[index], AWIN_NDMA_CTL_REG, 0);
-	}
-	for (index = 0; index < DDMA_CHANNELS; index++) {
-		awin_ddma_channels[index].ch_index = index;
-		awin_ddma_channels[index].ch_type = AWIN_DMA_TYPE_DDMA;
-		awin_ddma_channels[index].ch_callback = NULL;
-		awin_ddma_channels[index].ch_callbackarg = NULL;
-		awin_ddma_channels[index].ch_regoff = AWIN_DDMA_REG(index);
-		DMACH_WRITE(&awin_ddma_channels[index], AWIN_DDMA_CTL_REG, 0);
-	}
-
-	sc->sc_ih = intr_establish(loc->loc_intr, IPL_SCHED, IST_LEVEL,
-	    awin_dma_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 on irq %d\n", loc->loc_intr);
-}
-
-static int
-awin_dma_intr(void *priv)
-{
-	uint32_t sta, bit, mask;
-	uint8_t index;
-
-	sta = DMA_READ(AWIN_DMA_IRQ_PEND_STA_REG);
-	if (!sta)
-		return 0;
-
-	DMA_WRITE(AWIN_DMA_IRQ_PEND_STA_REG, sta);
-
-	while ((bit = ffs(sta & AWIN_DMA_IRQ_END_MASK)) != 0) {
-		mask = __BIT(bit - 1);
-		sta &= ~mask;
-		index = ((bit - 1) / 2) & 7;
-		if (mask & AWIN_DMA_IRQ_NDMA) {
-			if (awin_ndma_channels[index].ch_callback == NULL)
-				continue;
-			awin_ndma_channels[index].ch_callback(
-			    awin_ndma_channels[index].ch_callbackarg);
-		} else {
-			if (awin_ddma_channels[index].ch_callback == NULL)
-				continue;
-			awin_ddma_channels[index].ch_callback(
-			    awin_ddma_channels[index].ch_callbackarg);
-		}
+	switch (awin_chip_id()) {
+#if defined(ALLWINNER_A10) || defined(ALLWINNER_A20)
+	case AWIN_CHIP_ID_A10:
+	case AWIN_CHIP_ID_A20:
+		awin_dma_a10_attach(sc, aio, loc);
+		break;
+#endif
+#if defined(ALLWINNER_A31)
+	case AWIN_CHIP_ID_A31:
+		awin_dma_a31_attach(sc, aio, loc);
+		break;
+#endif
 	}
 
-	return 1;
+	KASSERT(sc->sc_dc != NULL);
 }
 
-struct awin_dma_channel *
-awin_dma_alloc(enum awin_dma_type type, void (*cb)(void *), void *cbarg)
+void *
+awin_dma_alloc(const char *type, void (*cb)(void *), void *cbarg)
 {
-	struct awin_dma_channel *ch_list;
-	struct awin_dma_channel *ch = NULL;
-	uint32_t irqen;
-	uint8_t ch_count, index;
-
-	if (type == AWIN_DMA_TYPE_NDMA) {
-		ch_list = awin_ndma_channels;
-		ch_count = NDMA_CHANNELS;
-	} else {
-		ch_list = awin_ndma_channels;
-		ch_count = DDMA_CHANNELS;
-	}
+	struct awin_dma_softc *sc = awin_dma_sc;
 
-	mutex_enter(&awin_dma_lock);
-	for (index = 0; index < ch_count; index++) {
-		if (ch_list[index].ch_callback == NULL) {
-			ch = &ch_list[index];
-			ch->ch_callback = cb;
-			ch->ch_callbackarg = cbarg;
-
-			irqen = DMA_READ(AWIN_DMA_IRQ_EN_REG);
-			if (type == AWIN_DMA_TYPE_NDMA)
-				irqen |= AWIN_DMA_IRQ_NDMA_END(index);
-			else
-				irqen |= AWIN_DMA_IRQ_DDMA_END(index);
-			DMA_WRITE(AWIN_DMA_IRQ_EN_REG, irqen);
-
-			break;
-		}
-	}
-	mutex_exit(&awin_dma_lock);
+	if (sc == NULL)
+		return NULL;
 
-	return ch;
+	return sc->sc_dc->dma_alloc(sc, type, cb, cbarg);
 }
 
 void
-awin_dma_free(struct awin_dma_channel *ch)
+awin_dma_free(void *ch)
 {
-	uint32_t irqen, cfg;
+	struct awin_dma_softc *sc = awin_dma_sc;
 
-	irqen = DMA_READ(AWIN_DMA_IRQ_EN_REG);
-	cfg = awin_dma_get_config(ch);
-	if (ch->ch_type == AWIN_DMA_TYPE_NDMA) {
-		irqen &= ~AWIN_DMA_IRQ_NDMA_END(ch->ch_index);
-		cfg &= ~AWIN_NDMA_CTL_DMA_LOADING;
-	} else {
-		irqen &= ~AWIN_DMA_IRQ_DDMA_END(ch->ch_index);
-		cfg &= ~AWIN_DDMA_CTL_DMA_LOADING;
-	}
-	awin_dma_set_config(ch, cfg);
-	DMA_WRITE(AWIN_DMA_IRQ_EN_REG, irqen);
-
-	mutex_enter(&awin_dma_lock);
-	ch->ch_callback = NULL;
-	ch->ch_callbackarg = NULL;
-	mutex_exit(&awin_dma_lock);
+	return sc->sc_dc->dma_free(ch);
 }
 
 uint32_t
-awin_dma_get_config(struct awin_dma_channel *ch)
+awin_dma_get_config(void *ch)
 {
-	return DMACH_READ(ch, AWIN_NDMA_CTL_REG);
+	struct awin_dma_softc *sc = awin_dma_sc;
+
+	return sc->sc_dc->dma_get_config(ch);
 }
 
 void
-awin_dma_set_config(struct awin_dma_channel *ch, uint32_t val)
+awin_dma_set_config(void *ch, uint32_t val)
 {
-	DMACH_WRITE(ch, AWIN_NDMA_CTL_REG, val);
+	struct awin_dma_softc *sc = awin_dma_sc;
+
+	return sc->sc_dc->dma_set_config(ch, val);
 }
 
 int
-awin_dma_transfer(struct awin_dma_channel *ch, paddr_t src, paddr_t dst,
+awin_dma_transfer(void *ch, paddr_t src, paddr_t dst,
     size_t nbytes)
 {
-	uint32_t cfg;
+	struct awin_dma_softc *sc = awin_dma_sc;
 
-	cfg = awin_dma_get_config(ch);
-	if (ch->ch_type == AWIN_DMA_TYPE_NDMA) {
-		if (cfg & AWIN_NDMA_CTL_DMA_LOADING)
-			return EBUSY;
-
-		DMACH_WRITE(ch, AWIN_NDMA_SRC_ADDR_REG, src);
-		DMACH_WRITE(ch, AWIN_NDMA_DEST_ADDR_REG, dst);
-		DMACH_WRITE(ch, AWIN_NDMA_BC_REG, nbytes);
-
-		cfg |= AWIN_NDMA_CTL_DMA_LOADING;
-		awin_dma_set_config(ch, cfg);
-	} else {
-		if (cfg & AWIN_DDMA_CTL_DMA_LOADING)
-			return EBUSY;
-
-		DMACH_WRITE(ch, AWIN_DDMA_SRC_START_ADDR_REG, src);
-		DMACH_WRITE(ch, AWIN_DDMA_DEST_START_ADDR_REG, dst);
-		DMACH_WRITE(ch, AWIN_DDMA_BC_REG, nbytes);
-
-		cfg |= AWIN_DDMA_CTL_DMA_LOADING;
-		awin_dma_set_config(ch, cfg);
-	}
-
-	return 0;
+	return sc->sc_dc->dma_transfer(ch, src, dst, nbytes);
 }
 
 void
-awin_dma_halt(struct awin_dma_channel *ch)
+awin_dma_halt(void *ch)
 {
-	uint32_t cfg;
+	struct awin_dma_softc *sc = awin_dma_sc;
 
-	cfg = awin_dma_get_config(ch);
-	if (ch->ch_type == AWIN_DMA_TYPE_NDMA) {
-		cfg &= ~AWIN_NDMA_CTL_DMA_LOADING;
-	} else {
-		cfg &= ~AWIN_DDMA_CTL_DMA_LOADING;
-	}
-	awin_dma_set_config(ch, cfg);
+	return sc->sc_dc->dma_halt(ch);
 }
 
 #if defined(DDB)
 void
 awin_dma_dump_regs(void)
 {
-	int i;
+	struct awin_dma_softc *sc = awin_dma_sc;
 
-	printf("IRQ_EN:          %08X\n", DMA_READ(AWIN_DMA_IRQ_EN_REG));
-	printf("PEND_STA:        %08X\n",
-	    DMA_READ(AWIN_DMA_IRQ_PEND_STA_REG));
-	for (i = 0; i < NDMA_CHANNELS; i++) {
-		printf("NDMA%d CTL:       %08X\n", i,
-		    DMA_READ(AWIN_NDMA_REG(i) + AWIN_NDMA_CTL_REG));
-		printf("NDMA%d SRC_ADDR:  %08X\n", i,
-		    DMA_READ(AWIN_NDMA_REG(i) + AWIN_NDMA_SRC_ADDR_REG));
-		printf("NDMA%d DEST_ADDR: %08X\n", i,
-		    DMA_READ(AWIN_NDMA_REG(i) + AWIN_NDMA_DEST_ADDR_REG));
-		printf("NDMA%d BC:        %08X\n", i,
-		    DMA_READ(AWIN_NDMA_REG(i) + AWIN_NDMA_BC_REG));
-	}
-	for (i = 0; i < DDMA_CHANNELS; i++) {
-		printf("DDMA%d CTL:       %08X\n", i,
-		    DMA_READ(AWIN_DDMA_REG(i) + AWIN_DDMA_CTL_REG));
-		printf("DDMA%d SRC_ADDR:  %08X\n", i,
-		    DMA_READ(AWIN_DDMA_REG(i) + AWIN_DDMA_SRC_START_ADDR_REG));
-		printf("DDMA%d DEST_ADDR: %08X\n", i,
-		    DMA_READ(AWIN_DDMA_REG(i) + AWIN_DDMA_DEST_START_ADDR_REG));
-		printf("DDMA%d BC:        %08X\n", i,
-		    DMA_READ(AWIN_DDMA_REG(i) + AWIN_DDMA_BC_REG));
-		printf("DDMA%d PARA:      %08X\n", i,
-		    DMA_READ(AWIN_DDMA_REG(i) + AWIN_DDMA_PARA_REG));
+	switch (awin_chip_id()) {
+#if defined(ALLWINNER_A10) || defined(ALLWINNER_A20)
+	case AWIN_CHIP_ID_A10:
+	case AWIN_CHIP_ID_A20:
+		awin_dma_a10_dump_regs(sc);
+		break;
+#endif
+#if defined(ALLWINNER_A31)
+	case AWIN_CHIP_ID_A31:
+		awin_dma_a31_dump_regs(sc);
+		break;
+#endif
 	}
 }
 #endif

Index: src/sys/arch/arm/allwinner/awin_reg.h
diff -u src/sys/arch/arm/allwinner/awin_reg.h:1.33 src/sys/arch/arm/allwinner/awin_reg.h:1.34
--- src/sys/arch/arm/allwinner/awin_reg.h:1.33	Sun Oct 12 23:57:58 2014
+++ src/sys/arch/arm/allwinner/awin_reg.h	Mon Oct 13 12:34:00 2014
@@ -1848,6 +1848,96 @@ struct awin_mmc_idma_descriptor {
 #define AWIN_A31_P2WI_PMCR_PMU_MODE_CTRL_REG_ADDR __BITS(15,8)
 #define AWIN_A31_P2WI_PMCR_PMU_DEVICE_ADDR	__BITS(7,0)
 
+#define AWIN_A31_DMA_IRQ_EN_REG0_REG		0x0000
+#define AWIN_A31_DMA_IRQ_EN_REG1_REG		0x0004
+#define AWIN_A31_DMA_IRQ_PEND_REG0_REG		0x0010
+#define AWIN_A31_DMA_IRQ_PEND_REG1_REG		0x0014
+#define AWIN_A31_DMA_STA_REG			0x0030
+#define AWIN_A31_DMA_EN_REG(n)			(0x0100 + (n) * 0x40 + 0x00)
+#define AWIN_A31_DMA_PAU_REG(n)			(0x0100 + (n) * 0x40 + 0x04)
+#define AWIN_A31_DMA_START_ADDR_REG(n)		(0x0100 + (n) * 0x40 + 0x08)
+#define AWIN_A31_DMA_CFG_REG(n)			(0x0100 + (n) * 0x40 + 0x0C)
+#define AWIN_A31_DMA_CUR_SRC_REG(n)		(0x0100 + (n) * 0x40 + 0x10)
+#define AWIN_A31_DMA_CUR_DEST_REG(n)		(0x0100 + (n) * 0x40 + 0x14)
+#define AWIN_A31_DMA_BCNT_LEFT_REG(n)		(0x0100 + (n) * 0x40 + 0x18)
+#define AWIN_A31_DMA_PARA_REG(n)		(0x0100 + (n) * 0x40 + 0x1C)
+
+#define AWIN_A31_DMA_IRQ_EN_REG0_QUEUE_IRQ_EN(n) __BIT(n * 4 + 2)
+#define AWIN_A31_DMA_IRQ_EN_REG0_PKG_IRQ_EN(n)	__BIT(n * 4 + 1)
+#define AWIN_A31_DMA_IRQ_EN_REG0_HLAF_IRQ_EN(n)	__BIT(n * 4 + 0)
+
+#define AWIN_A31_DMA_IRQ_EN_REG1_QUEUE_IRQ_EN(n) __BIT((n - 8) * 4 + 2)
+#define AWIN_A31_DMA_IRQ_EN_REG1_PKG_IRQ_EN(n)	__BIT((n - 8) * 4 + 1)
+#define AWIN_A31_DMA_IRQ_EN_REG1_HLAF_IRQ_EN(n)	__BIT((n - 8) * 4 + 0)
+
+#define AWIN_A31_DMA_EN_EN			__BIT(0)
+
+#define AWIN_A31_DMA_PAU_PAUSE			__BIT(0)
+
+#define AWIN_A31_DMA_CFG_DEST_DATA_WIDTH	__BITS(26,25)
+#define AWIN_A31_DMA_CFG_DEST_BST_LEN		__BITS(24,23)
+#define AWIN_A31_DMA_CFG_DEST_ADDR_MODE		__BITS(22,21)
+#define AWIN_A31_DMA_CFG_DEST_DRQ_TYPE		__BITS(20,16)
+#define AWIN_A31_DMA_CFG_SRC_DATA_WIDTH		__BITS(10,9)
+#define AWIN_A31_DMA_CFG_SRC_BST_LEN		__BITS(8,7)
+#define AWIN_A31_DMA_CFG_SRC_ADDR_MODE		__BITS(6,5)
+#define AWIN_A31_DMA_CFG_SRC_DRQ_TYPE		__BITS(4,0)
+
+#define AWIN_A31_DMA_PARA_DATA_BLK_SIZE		__BITS(15,8)
+#define AWIN_A31_DMA_PARA_WAIT_CYC		__BITS(7,0)
+
+#define AWIN_A31_DMA_CFG_DATA_WIDTH_8		0
+#define AWIN_A31_DMA_CFG_DATA_WIDTH_16		1
+#define AWIN_A31_DMA_CFG_DATA_WIDTH_32		2
+
+#define AWIN_A31_DMA_CFG_BST_LEN_1		0
+#define AWIN_A31_DMA_CFG_BST_LEN_8		1
+
+#define AWIN_A31_DMA_CFG_ADDR_MODE_LINEAR	0
+#define AWIN_A31_DMA_CFG_ADDR_MODE_IO		1
+
+#define AWIN_A31_DMA_DRQ_TYPE_SRAM		0
+#define AWIN_A31_DMA_DRQ_TYPE_SDRAM		1
+#define AWIN_A31_DMA_DRQ_TYPE_DAUDIO0		3
+#define AWIN_A31_DMA_DRQ_TYPE_DAUDIO1		4
+#define AWIN_A31_DMA_DRQ_TYPE_NAND0		5
+#define AWIN_A31_DMA_DRQ_TYPE_UART0		6
+#define AWIN_A31_DMA_DRQ_TYPE_UART1		7
+#define AWIN_A31_DMA_DRQ_TYPE_UART2		8
+#define AWIN_A31_DMA_DRQ_TYPE_UART3		9
+#define AWIN_A31_DMA_DRQ_TYPE_UART4		10
+#define AWIN_A31_DMA_DRQ_TYPE_TCON0		11
+#define AWIN_A31_DMA_DRQ_TYPE_TCON1		12
+#define AWIN_A31_DMA_DRQ_TYPE_HDMIDDC		13
+#define AWIN_A31_DMA_DRQ_TYPE_HDMIAUDIO		14
+#define AWIN_A31_DMA_DRQ_TYPE_AUDIOCODEC	15
+#define AWIN_A31_DMA_DRQ_TYPE_SS		16
+#define AWIN_A31_DMA_DRQ_TYPE_OTG_EP1		17
+#define AWIN_A31_DMA_DRQ_TYPE_OTG_EP2		18
+#define AWIN_A31_DMA_DRQ_TYPE_OTG_EP3		19
+#define AWIN_A31_DMA_DRQ_TYPE_OTG_EP4		20
+#define AWIN_A31_DMA_DRQ_TYPE_OTG_EP5		21
+#define AWIN_A31_DMA_DRQ_TYPE_UART5		22
+#define AWIN_A31_DMA_DRQ_TYPE_SPI0		23
+#define AWIN_A31_DMA_DRQ_TYPE_SPI1		24
+#define AWIN_A31_DMA_DRQ_TYPE_SPI2		25
+#define AWIN_A31_DMA_DRQ_TYPE_SPI3		26
+#define AWIN_A31_DMA_DRQ_TYPE_TP		27
+#define AWIN_A31_DMA_DRQ_TYPE_NAND1		28
+#define AWIN_A31_DMA_DRQ_TYPE_DIGITALMIC	30
+
+#if !defined(_LOCORE)
+struct awin_a31_dma_desc {
+	uint32_t	dma_config;
+	uint32_t	dma_srcaddr;
+	uint32_t	dma_dstaddr;
+	uint32_t	dma_bcnt;
+	uint32_t	dma_para;
+	uint32_t	dma_next;
+#define AWIN_A31_DMA_NULL	0xfffff800
+};
+#endif
+
 #define AWIN_A31_PIO_PB_TWI3_FUNC	2
 #define AWIN_A31_PIO_PB_TWI3_PINS	0x00000060 /* PB pins 6-5 */
 

Index: src/sys/arch/arm/allwinner/awin_var.h
diff -u src/sys/arch/arm/allwinner/awin_var.h:1.17 src/sys/arch/arm/allwinner/awin_var.h:1.18
--- src/sys/arch/arm/allwinner/awin_var.h:1.17	Fri Oct 10 23:50:43 2014
+++ src/sys/arch/arm/allwinner/awin_var.h	Mon Oct 13 12:34:00 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: awin_var.h,v 1.17 2014/10/10 23:50:43 jmcneill Exp $ */
+/* $NetBSD: awin_var.h,v 1.18 2014/10/13 12:34:00 jmcneill Exp $ */
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -73,11 +73,6 @@ struct awin_gpio_pindata {
 	int pd_pin;
 };
 
-enum awin_dma_type {
-	AWIN_DMA_TYPE_NDMA,
-	AWIN_DMA_TYPE_DDMA,
-};
-
 struct awin_dma_channel;
 
 extern struct bus_space awin_bs_tag;
@@ -108,13 +103,12 @@ void	awin_gpio_pinset_acquire(const stru
 void	awin_gpio_pinset_release(const struct awin_gpio_pinset *);
 bool	awin_gpio_pin_reserve(const char *, struct awin_gpio_pindata *);
 
-struct awin_dma_channel *awin_dma_alloc(enum awin_dma_type,
-					      void (*)(void *), void *);
-void	awin_dma_free(struct awin_dma_channel *);
-uint32_t awin_dma_get_config(struct awin_dma_channel *);
-void	awin_dma_set_config(struct awin_dma_channel *, uint32_t);
-int	awin_dma_transfer(struct awin_dma_channel *, paddr_t, paddr_t, size_t);
-void	awin_dma_halt(struct awin_dma_channel *);
+void *	awin_dma_alloc(const char *, void (*)(void *), void *);
+void	awin_dma_free(void *);
+uint32_t awin_dma_get_config(void *);
+void	awin_dma_set_config(void *, uint32_t);
+int	awin_dma_transfer(void *, paddr_t, paddr_t, size_t);
+void	awin_dma_halt(void *);
 
 void	awin_wdog_reset(void);
 void	awin_tmr_cpu_init(struct cpu_info *);

Index: src/sys/arch/arm/allwinner/files.awin
diff -u src/sys/arch/arm/allwinner/files.awin:1.16 src/sys/arch/arm/allwinner/files.awin:1.17
--- src/sys/arch/arm/allwinner/files.awin:1.16	Sun Oct 12 23:57:58 2014
+++ src/sys/arch/arm/allwinner/files.awin	Mon Oct 13 12:34:00 2014
@@ -1,4 +1,4 @@
-#	$NetBSD: files.awin,v 1.16 2014/10/12 23:57:58 jmcneill Exp $
+#	$NetBSD: files.awin,v 1.17 2014/10/13 12:34:00 jmcneill Exp $
 #
 # Configuration info for Allwinner ARM Peripherals
 #
@@ -67,6 +67,8 @@ file	arch/arm/allwinner/awin_gpio.c		awi
 device	awindma
 attach	awindma at awinio with awin_dma
 file	arch/arm/allwinner/awin_dma.c		awin_dma
+file	arch/arm/allwinner/awin_dma_a10.c	awin_dma & (allwinner_a10 | allwinner_a20)
+file	arch/arm/allwinner/awin_dma_a31.c	awin_dma & allwinner_a31
 
 # A10/A20 TWI (IIC)
 device	awiniic : i2cbus, i2cexec, mvi2c

Added files:

Index: src/sys/arch/arm/allwinner/awin_dma.h
diff -u /dev/null src/sys/arch/arm/allwinner/awin_dma.h:1.1
--- /dev/null	Mon Oct 13 12:34:00 2014
+++ src/sys/arch/arm/allwinner/awin_dma.h	Mon Oct 13 12:34:00 2014
@@ -0,0 +1,85 @@
+/* $NetBSD: awin_dma.h,v 1.1 2014/10/13 12:34:00 jmcneill 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.
+ */
+
+#ifndef _ARM_ALLWINNER_AWIN_DMA_H
+#define _ARM_ALLWINNER_AWIN_DMA_H
+
+#include "opt_ddb.h"
+#include "opt_allwinner.h"
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: awin_dma.h,v 1.1 2014/10/13 12:34:00 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/mutex.h>
+
+#include <arm/allwinner/awin_reg.h>
+#include <arm/allwinner/awin_var.h>
+
+struct awin_dma_softc;
+
+struct awin_dma_controller {
+	void *(*dma_alloc)(struct awin_dma_softc *, const char *,
+			   void (*)(void *), void *);
+	void (*dma_free)(void *);
+	uint32_t (*dma_get_config)(void *);
+	void (*dma_set_config)(void *, uint32_t);
+	int (*dma_transfer)(void *, paddr_t, paddr_t, size_t);
+	void (*dma_halt)(void *);
+};
+
+struct awin_dma_softc {
+	device_t sc_dev;
+	bus_space_tag_t sc_bst;
+	bus_space_handle_t sc_bsh;
+	bus_dma_tag_t sc_dmat;
+	const struct awin_dma_controller *sc_dc;
+	void *sc_ih;
+};
+
+#if defined(ALLWINNER_A10) || defined(ALLWINNER_A20)
+void awin_dma_a10_attach(struct awin_dma_softc *, struct awinio_attach_args *,
+			 const struct awin_locators * const);
+#if defined(DDB)
+void awin_dma_a10_dump_regs(struct awin_dma_softc *);
+#endif
+
+#endif
+#if defined(ALLWINNER_A31)
+void awin_dma_a31_attach(struct awin_dma_softc *, struct awinio_attach_args *,
+			 const struct awin_locators * const);
+#if defined(DDB)
+void awin_dma_a31_dump_regs(struct awin_dma_softc *);
+#endif
+#endif
+
+#endif /* !_ARM_ALLWINNER_AWIN_DMA_H */
Index: src/sys/arch/arm/allwinner/awin_dma_a10.c
diff -u /dev/null src/sys/arch/arm/allwinner/awin_dma_a10.c:1.1
--- /dev/null	Mon Oct 13 12:34:00 2014
+++ src/sys/arch/arm/allwinner/awin_dma_a10.c	Mon Oct 13 12:34:00 2014
@@ -0,0 +1,333 @@
+/* $NetBSD: awin_dma_a10.c,v 1.1 2014/10/13 12:34:00 jmcneill 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_dma_a10.c,v 1.1 2014/10/13 12:34:00 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/mutex.h>
+
+#include <arm/allwinner/awin_reg.h>
+#include <arm/allwinner/awin_var.h>
+#include <arm/allwinner/awin_dma.h>
+
+#define NDMA_CHANNELS	8
+#define DDMA_CHANNELS	8
+
+enum awin_dma_a10_type {
+	CH_NDMA,
+	CH_DDMA
+};
+
+struct awin_dma_a10_channel {
+	struct awin_dma_softc *ch_sc;
+	uint8_t ch_index;
+	enum awin_dma_a10_type ch_type;
+	void (*ch_callback)(void *);
+	void *ch_callbackarg;
+	uint32_t ch_regoff;
+};
+
+#define DMA_READ(sc, reg)		\
+    bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define DMA_WRITE(sc, reg, val)		\
+    bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+#define DMACH_READ(ch, reg)		\
+    DMA_READ((ch)->ch_sc, (reg) + (ch)->ch_regoff)
+#define DMACH_WRITE(ch, reg, val)	\
+    DMA_WRITE((ch)->ch_sc, (reg) + (ch)->ch_regoff, (val))
+
+static kmutex_t awin_dma_a10_lock;
+static struct awin_dma_a10_channel awin_ndma_channels[NDMA_CHANNELS];
+static struct awin_dma_a10_channel awin_ddma_channels[DDMA_CHANNELS];
+
+static int awin_dma_a10_intr(void *);
+
+static void *awin_dma_a10_alloc(struct awin_dma_softc *, const char *,
+				void (*)(void *), void *);
+static void awin_dma_a10_free(void *);
+static uint32_t awin_dma_a10_get_config(void *);
+static void awin_dma_a10_set_config(void *, uint32_t);
+static int awin_dma_a10_transfer(void *, paddr_t, paddr_t, size_t);
+static void awin_dma_a10_halt(void *);
+
+static const struct awin_dma_controller awin_dma_a10_controller = {
+	.dma_alloc = awin_dma_a10_alloc,
+	.dma_free = awin_dma_a10_free,
+	.dma_get_config = awin_dma_a10_get_config,
+	.dma_set_config = awin_dma_a10_set_config,
+	.dma_transfer = awin_dma_a10_transfer,
+	.dma_halt = awin_dma_a10_halt,
+};
+
+void
+awin_dma_a10_attach(struct awin_dma_softc *sc, struct awinio_attach_args *aio,
+    const struct awin_locators * const loc)
+{
+	unsigned int index;
+
+	sc->sc_dc = &awin_dma_a10_controller;
+
+	mutex_init(&awin_dma_a10_lock, MUTEX_DEFAULT, IPL_SCHED);
+
+	awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh,
+	    AWIN_AHB_GATING0_REG, AWIN_AHB_GATING0_DMA, 0);
+
+	DMA_WRITE(sc, AWIN_DMA_IRQ_EN_REG, 0);
+	DMA_WRITE(sc, AWIN_DMA_IRQ_PEND_STA_REG, ~0);
+
+	for (index = 0; index < NDMA_CHANNELS; index++) {
+		awin_ndma_channels[index].ch_sc = sc;
+		awin_ndma_channels[index].ch_index = index;
+		awin_ndma_channels[index].ch_type = CH_NDMA;
+		awin_ndma_channels[index].ch_callback = NULL;
+		awin_ndma_channels[index].ch_callbackarg = NULL;
+		awin_ndma_channels[index].ch_regoff = AWIN_NDMA_REG(index);
+		DMACH_WRITE(&awin_ndma_channels[index], AWIN_NDMA_CTL_REG, 0);
+	}
+	for (index = 0; index < DDMA_CHANNELS; index++) {
+		awin_ddma_channels[index].ch_sc = sc;
+		awin_ddma_channels[index].ch_index = index;
+		awin_ddma_channels[index].ch_type = CH_DDMA;
+		awin_ddma_channels[index].ch_callback = NULL;
+		awin_ddma_channels[index].ch_callbackarg = NULL;
+		awin_ddma_channels[index].ch_regoff = AWIN_DDMA_REG(index);
+		DMACH_WRITE(&awin_ddma_channels[index], AWIN_DDMA_CTL_REG, 0);
+	}
+
+	sc->sc_ih = intr_establish(loc->loc_intr, IPL_SCHED, IST_LEVEL,
+	    awin_dma_a10_intr, sc);
+	if (sc->sc_ih == NULL) {
+		aprint_error_dev(sc->sc_dev,
+		    "couldn't establish interrupt %d\n", loc->loc_intr);
+		return;
+	}
+	aprint_normal_dev(sc->sc_dev, "interrupting on irq %d\n",
+	    loc->loc_intr);
+}
+
+static int
+awin_dma_a10_intr(void *priv)
+{
+	struct awin_dma_softc *sc = priv;
+	uint32_t sta, bit, mask;
+	uint8_t index;
+
+	sta = DMA_READ(sc, AWIN_DMA_IRQ_PEND_STA_REG);
+	if (!sta)
+		return 0;
+
+	DMA_WRITE(sc, AWIN_DMA_IRQ_PEND_STA_REG, sta);
+
+	while ((bit = ffs(sta & AWIN_DMA_IRQ_END_MASK)) != 0) {
+		mask = __BIT(bit - 1);
+		sta &= ~mask;
+		index = ((bit - 1) / 2) & 7;
+		if (mask & AWIN_DMA_IRQ_NDMA) {
+			if (awin_ndma_channels[index].ch_callback == NULL)
+				continue;
+			awin_ndma_channels[index].ch_callback(
+			    awin_ndma_channels[index].ch_callbackarg);
+		} else {
+			if (awin_ddma_channels[index].ch_callback == NULL)
+				continue;
+			awin_ddma_channels[index].ch_callback(
+			    awin_ddma_channels[index].ch_callbackarg);
+		}
+	}
+
+	return 1;
+}
+
+static void *
+awin_dma_a10_alloc(struct awin_dma_softc *sc, const char *type,
+    void (*cb)(void *), void *cbarg)
+{
+	struct awin_dma_a10_channel *ch_list;
+	struct awin_dma_a10_channel *ch = NULL;
+	uint32_t irqen;
+	uint8_t ch_count, index;
+
+	if (strcmp(type, "ddma") == 0) {
+		ch_list = awin_ddma_channels;
+		ch_count = DDMA_CHANNELS;
+	} else {
+		ch_list = awin_ndma_channels;
+		ch_count = NDMA_CHANNELS;
+	}
+
+	mutex_enter(&awin_dma_a10_lock);
+	for (index = 0; index < ch_count; index++) {
+		if (ch_list[index].ch_callback == NULL) {
+			ch = &ch_list[index];
+			ch->ch_callback = cb;
+			ch->ch_callbackarg = cbarg;
+
+			irqen = DMA_READ(sc, AWIN_DMA_IRQ_EN_REG);
+			if (type == CH_NDMA)
+				irqen |= AWIN_DMA_IRQ_NDMA_END(index);
+			else
+				irqen |= AWIN_DMA_IRQ_DDMA_END(index);
+			DMA_WRITE(sc, AWIN_DMA_IRQ_EN_REG, irqen);
+
+			break;
+		}
+	}
+	mutex_exit(&awin_dma_a10_lock);
+
+	return ch;
+}
+
+static void
+awin_dma_a10_free(void *priv)
+{
+	struct awin_dma_a10_channel *ch = priv;
+	struct awin_dma_softc *sc = ch->ch_sc;
+	uint32_t irqen, cfg;
+
+	irqen = DMA_READ(sc, AWIN_DMA_IRQ_EN_REG);
+	cfg = awin_dma_a10_get_config(ch);
+	if (ch->ch_type == CH_NDMA) {
+		irqen &= ~AWIN_DMA_IRQ_NDMA_END(ch->ch_index);
+		cfg &= ~AWIN_NDMA_CTL_DMA_LOADING;
+	} else {
+		irqen &= ~AWIN_DMA_IRQ_DDMA_END(ch->ch_index);
+		cfg &= ~AWIN_DDMA_CTL_DMA_LOADING;
+	}
+	awin_dma_a10_set_config(ch, cfg);
+	DMA_WRITE(sc, AWIN_DMA_IRQ_EN_REG, irqen);
+
+	mutex_enter(&awin_dma_a10_lock);
+	ch->ch_callback = NULL;
+	ch->ch_callbackarg = NULL;
+	mutex_exit(&awin_dma_a10_lock);
+}
+
+static uint32_t
+awin_dma_a10_get_config(void *priv)
+{
+	struct awin_dma_a10_channel *ch = priv;
+
+	return DMACH_READ(ch, AWIN_NDMA_CTL_REG);
+}
+
+static void
+awin_dma_a10_set_config(void *priv, uint32_t val)
+{
+	struct awin_dma_a10_channel *ch = priv;
+
+	DMACH_WRITE(ch, AWIN_NDMA_CTL_REG, val);
+}
+
+static int
+awin_dma_a10_transfer(void *priv, paddr_t src, paddr_t dst,
+    size_t nbytes)
+{
+	struct awin_dma_a10_channel *ch = priv;
+	uint32_t cfg;
+
+	cfg = awin_dma_a10_get_config(ch);
+	if (ch->ch_type == CH_NDMA) {
+		if (cfg & AWIN_NDMA_CTL_DMA_LOADING)
+			return EBUSY;
+
+		DMACH_WRITE(ch, AWIN_NDMA_SRC_ADDR_REG, src);
+		DMACH_WRITE(ch, AWIN_NDMA_DEST_ADDR_REG, dst);
+		DMACH_WRITE(ch, AWIN_NDMA_BC_REG, nbytes);
+
+		cfg |= AWIN_NDMA_CTL_DMA_LOADING;
+		awin_dma_a10_set_config(ch, cfg);
+	} else {
+		if (cfg & AWIN_DDMA_CTL_DMA_LOADING)
+			return EBUSY;
+
+		DMACH_WRITE(ch, AWIN_DDMA_SRC_START_ADDR_REG, src);
+		DMACH_WRITE(ch, AWIN_DDMA_DEST_START_ADDR_REG, dst);
+		DMACH_WRITE(ch, AWIN_DDMA_BC_REG, nbytes);
+
+		cfg |= AWIN_DDMA_CTL_DMA_LOADING;
+		awin_dma_a10_set_config(ch, cfg);
+	}
+
+	return 0;
+}
+
+static void
+awin_dma_a10_halt(void *priv)
+{
+	struct awin_dma_a10_channel *ch = priv;
+	uint32_t cfg;
+
+	cfg = awin_dma_a10_get_config(ch);
+	if (ch->ch_type == CH_NDMA) {
+		cfg &= ~AWIN_NDMA_CTL_DMA_LOADING;
+	} else {
+		cfg &= ~AWIN_DDMA_CTL_DMA_LOADING;
+	}
+	awin_dma_a10_set_config(ch, cfg);
+}
+
+#if defined(DDB)
+void
+awin_dma_a10_dump_regs(struct awin_dma_softc *sc)
+{
+	int i;
+
+	printf("IRQ_EN:          %08X\n", DMA_READ(sc, AWIN_DMA_IRQ_EN_REG));
+	printf("PEND_STA:        %08X\n",
+	    DMA_READ(sc, AWIN_DMA_IRQ_PEND_STA_REG));
+	for (i = 0; i < NDMA_CHANNELS; i++) {
+		printf("NDMA%d CTL:       %08X\n", i,
+		    DMA_READ(sc, AWIN_NDMA_REG(i) + AWIN_NDMA_CTL_REG));
+		printf("NDMA%d SRC_ADDR:  %08X\n", i,
+		    DMA_READ(sc, AWIN_NDMA_REG(i) + AWIN_NDMA_SRC_ADDR_REG));
+		printf("NDMA%d DEST_ADDR: %08X\n", i,
+		    DMA_READ(sc, AWIN_NDMA_REG(i) + AWIN_NDMA_DEST_ADDR_REG));
+		printf("NDMA%d BC:        %08X\n", i,
+		    DMA_READ(sc, AWIN_NDMA_REG(i) + AWIN_NDMA_BC_REG));
+	}
+	for (i = 0; i < DDMA_CHANNELS; i++) {
+		printf("DDMA%d CTL:       %08X\n", i,
+		    DMA_READ(sc, AWIN_DDMA_REG(i) + AWIN_DDMA_CTL_REG));
+		printf("DDMA%d SRC_ADDR:  %08X\n", i,
+		    DMA_READ(sc, AWIN_DDMA_REG(i) + AWIN_DDMA_SRC_START_ADDR_REG));
+		printf("DDMA%d DEST_ADDR: %08X\n", i,
+		    DMA_READ(sc, AWIN_DDMA_REG(i) + AWIN_DDMA_DEST_START_ADDR_REG));
+		printf("DDMA%d BC:        %08X\n", i,
+		    DMA_READ(sc, AWIN_DDMA_REG(i) + AWIN_DDMA_BC_REG));
+		printf("DDMA%d PARA:      %08X\n", i,
+		    DMA_READ(sc, AWIN_DDMA_REG(i) + AWIN_DDMA_PARA_REG));
+	}
+}
+#endif
Index: src/sys/arch/arm/allwinner/awin_dma_a31.c
diff -u /dev/null src/sys/arch/arm/allwinner/awin_dma_a31.c:1.1
--- /dev/null	Mon Oct 13 12:34:00 2014
+++ src/sys/arch/arm/allwinner/awin_dma_a31.c	Mon Oct 13 12:34:00 2014
@@ -0,0 +1,332 @@
+/* $NetBSD: awin_dma_a31.c,v 1.1 2014/10/13 12:34:00 jmcneill 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_dma_a31.c,v 1.1 2014/10/13 12:34:00 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/mutex.h>
+#include <sys/bitops.h>
+
+#include <arm/allwinner/awin_reg.h>
+#include <arm/allwinner/awin_var.h>
+#include <arm/allwinner/awin_dma.h>
+
+#define DMA_CHANNELS	16
+
+struct awin_dma_a31_channel {
+	struct awin_dma_softc *ch_sc;
+	uint8_t ch_index;
+	void (*ch_callback)(void *);
+	void *ch_callbackarg;
+
+	bus_dma_segment_t ch_dmasegs[1];
+	bus_dmamap_t ch_dmamap;
+	void *ch_dmadesc;
+	bus_size_t ch_dmadesclen;
+};
+
+#define DMA_READ(sc, reg)		\
+    bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define DMA_WRITE(sc, reg, val)		\
+    bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+static kmutex_t awin_dma_a31_lock;
+static struct awin_dma_a31_channel awin_dma_channels[DMA_CHANNELS];
+
+static int awin_dma_a31_intr(void *);
+
+static void *awin_dma_a31_alloc(struct awin_dma_softc *, const char *,
+				void (*)(void *), void *);
+static void awin_dma_a31_free(void *);
+static uint32_t awin_dma_a31_get_config(void *);
+static void awin_dma_a31_set_config(void *, uint32_t);
+static int awin_dma_a31_transfer(void *, paddr_t, paddr_t, size_t);
+static void awin_dma_a31_halt(void *);
+
+static const struct awin_dma_controller awin_dma_a31_controller = {
+	.dma_alloc = awin_dma_a31_alloc,
+	.dma_free = awin_dma_a31_free,
+	.dma_get_config = awin_dma_a31_get_config,
+	.dma_set_config = awin_dma_a31_set_config,
+	.dma_transfer = awin_dma_a31_transfer,
+	.dma_halt = awin_dma_a31_halt,
+};
+
+void
+awin_dma_a31_attach(struct awin_dma_softc *sc, struct awinio_attach_args *aio,
+    const struct awin_locators * const loc)
+{
+	unsigned int index;
+	bus_size_t desclen = sizeof(struct awin_a31_dma_desc);
+	int error, nsegs;
+
+	sc->sc_dc = &awin_dma_a31_controller;
+
+	mutex_init(&awin_dma_a31_lock, MUTEX_DEFAULT, IPL_SCHED);
+
+	awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh,
+	    AWIN_AHB_GATING0_REG, AWIN_AHB_GATING0_DMA, 0);
+
+	DMA_WRITE(sc, AWIN_A31_DMA_IRQ_EN_REG0_REG, 0);
+	DMA_WRITE(sc, AWIN_A31_DMA_IRQ_EN_REG1_REG, 0);
+	DMA_WRITE(sc, AWIN_A31_DMA_IRQ_PEND_REG0_REG, ~0);
+	DMA_WRITE(sc, AWIN_A31_DMA_IRQ_PEND_REG1_REG, ~0);
+
+	for (index = 0; index < DMA_CHANNELS; index++) {
+		struct awin_dma_a31_channel *ch = &awin_dma_channels[index];
+		ch->ch_sc = sc;
+		ch->ch_index = index;
+		ch->ch_callback = NULL;
+		ch->ch_callbackarg = NULL;
+		ch->ch_dmadesclen = desclen;
+
+		error = bus_dmamem_alloc(sc->sc_dmat, desclen, 0, 0,
+		    ch->ch_dmasegs, 1, &nsegs, BUS_DMA_WAITOK);
+		if (error)
+			panic("bus_dmamem_alloc failed: %d", error);
+		error = bus_dmamem_map(sc->sc_dmat, ch->ch_dmasegs, nsegs,
+		    desclen, &ch->ch_dmadesc, BUS_DMA_WAITOK);
+		if (error)
+			panic("bus_dmamem_map failed: %d", error);
+		error = bus_dmamap_create(sc->sc_dmat, desclen, 1, desclen, 0,
+		    BUS_DMA_WAITOK, &ch->ch_dmamap);
+		if (error)
+			panic("bus_dmamap_create failed: %d", error);
+		error = bus_dmamap_load(sc->sc_dmat, ch->ch_dmamap,
+		    ch->ch_dmadesc, desclen, NULL, BUS_DMA_WAITOK);
+		if (error)
+			panic("bus_dmamap_load failed: %d", error);
+
+		DMA_WRITE(sc, AWIN_A31_DMA_EN_REG(index), 0);
+	}
+
+	sc->sc_ih = intr_establish(loc->loc_intr, IPL_SCHED, IST_LEVEL,
+	    awin_dma_a31_intr, sc);
+	if (sc->sc_ih == NULL) {
+		aprint_error_dev(sc->sc_dev,
+		    "couldn't establish interrupt %d\n", loc->loc_intr);
+		return;
+	}
+	aprint_normal_dev(sc->sc_dev, "interrupting on irq %d\n",
+	    loc->loc_intr);
+}
+
+static int
+awin_dma_a31_intr(void *priv)
+{
+	struct awin_dma_softc *sc = priv;
+	uint32_t pend0, pend1, bit;
+	uint64_t pend, mask;
+	uint8_t index;
+
+	pend0 = DMA_READ(sc, AWIN_A31_DMA_IRQ_PEND_REG0_REG);
+	pend1 = DMA_READ(sc, AWIN_A31_DMA_IRQ_PEND_REG1_REG);
+	if (!pend0 && !pend1)
+		return 0;
+
+	DMA_WRITE(sc, AWIN_A31_DMA_IRQ_PEND_REG0_REG, pend0);
+	DMA_WRITE(sc, AWIN_A31_DMA_IRQ_PEND_REG1_REG, pend1);
+
+	pend = pend0 | ((uint64_t)pend1 << 32);
+
+	while ((bit = ffs64(pend)) != 0) {
+		mask = __BIT(bit - 1);
+		pend &= ~mask;
+		index = (bit - 1) / 4;
+		if (awin_dma_channels[index].ch_callback == NULL)
+			continue;
+		awin_dma_channels[index].ch_callback(
+		    awin_dma_channels[index].ch_callbackarg);
+	}
+
+	return 1;
+}
+
+static void *
+awin_dma_a31_alloc(struct awin_dma_softc *sc, const char *type,
+    void (*cb)(void *), void *cbarg)
+{
+	struct awin_dma_a31_channel *ch_list = awin_dma_channels;
+	struct awin_dma_a31_channel *ch = NULL;
+	uint32_t irqen;
+	uint8_t index;
+
+	mutex_enter(&awin_dma_a31_lock);
+	for (index = 0; index < DMA_CHANNELS; index++) {
+		if (ch_list[index].ch_callback == NULL) {
+			ch = &ch_list[index];
+			ch->ch_callback = cb;
+			ch->ch_callbackarg = cbarg;
+
+			irqen = DMA_READ(sc, index < 8 ?
+			    AWIN_A31_DMA_IRQ_EN_REG0_REG :
+			    AWIN_A31_DMA_IRQ_EN_REG1_REG);
+			irqen |= (index < 8 ?
+			    AWIN_A31_DMA_IRQ_EN_REG0_PKG_IRQ_EN(index) :
+			    AWIN_A31_DMA_IRQ_EN_REG1_PKG_IRQ_EN(index));
+			DMA_WRITE(sc, index < 8 ?
+			    AWIN_A31_DMA_IRQ_EN_REG0_REG :
+			    AWIN_A31_DMA_IRQ_EN_REG1_REG, irqen);
+
+			break;
+		}
+	}
+	mutex_exit(&awin_dma_a31_lock);
+
+	return ch;
+}
+
+static void
+awin_dma_a31_free(void *priv)
+{
+	struct awin_dma_a31_channel *ch = priv;
+	struct awin_dma_softc *sc = ch->ch_sc;
+	uint32_t irqen;
+	uint8_t index = ch->ch_index;
+
+	irqen = DMA_READ(sc, index < 8 ?
+	    AWIN_A31_DMA_IRQ_EN_REG0_REG :
+	    AWIN_A31_DMA_IRQ_EN_REG1_REG);
+	irqen &= ~(index < 8 ?
+	    AWIN_A31_DMA_IRQ_EN_REG0_PKG_IRQ_EN(index) :
+	    AWIN_A31_DMA_IRQ_EN_REG1_PKG_IRQ_EN(index));
+	DMA_WRITE(sc, index < 8 ?
+	    AWIN_A31_DMA_IRQ_EN_REG0_REG :
+	    AWIN_A31_DMA_IRQ_EN_REG1_REG, irqen);
+
+	mutex_enter(&awin_dma_a31_lock);
+	ch->ch_callback = NULL;
+	ch->ch_callbackarg = NULL;
+	mutex_exit(&awin_dma_a31_lock);
+}
+
+static uint32_t
+awin_dma_a31_get_config(void *priv)
+{
+	struct awin_dma_a31_channel *ch = priv;
+	struct awin_dma_softc *sc = ch->ch_sc;
+
+	return DMA_READ(sc, AWIN_A31_DMA_CFG_REG(ch->ch_index));
+}
+
+static void
+awin_dma_a31_set_config(void *priv, uint32_t val)
+{
+	struct awin_dma_a31_channel *ch = priv;
+	struct awin_dma_softc *sc = ch->ch_sc;
+	struct awin_a31_dma_desc *desc = ch->ch_dmadesc;
+
+	desc->dma_config = htole32(val);
+
+	bus_dmamap_sync(sc->sc_dmat, ch->ch_dmamap, 0, ch->ch_dmadesclen,
+	    BUS_DMASYNC_PREWRITE);
+}
+
+static int
+awin_dma_a31_transfer(void *priv, paddr_t src, paddr_t dst,
+    size_t nbytes)
+{
+	struct awin_dma_a31_channel *ch = priv;
+	struct awin_dma_softc *sc = ch->ch_sc;
+	struct awin_a31_dma_desc *desc = ch->ch_dmadesc;
+#if 0
+	uint32_t stat;
+
+	stat = DMA_READ(sc, AWIN_A31_DMA_STA_REG);
+	if (stat & __BIT(ch->ch_index))
+		return EBUSY;
+#endif
+
+	desc->dma_srcaddr = htole32(src);
+	desc->dma_dstaddr = htole32(dst);
+	desc->dma_bcnt = htole32(nbytes);
+	desc->dma_para = htole32(0);
+	desc->dma_next = htole32(AWIN_A31_DMA_NULL);
+
+	bus_dmamap_sync(sc->sc_dmat, ch->ch_dmamap, 0, ch->ch_dmadesclen,
+	    BUS_DMASYNC_PREWRITE);
+
+	DMA_WRITE(sc, AWIN_A31_DMA_START_ADDR_REG(ch->ch_index),
+	    ch->ch_dmamap->dm_segs[0].ds_addr);
+	DMA_WRITE(sc, AWIN_A31_DMA_EN_REG(ch->ch_index), AWIN_A31_DMA_EN_EN);
+
+	return 0;
+}
+
+static void
+awin_dma_a31_halt(void *priv)
+{
+	struct awin_dma_a31_channel *ch = priv;
+	struct awin_dma_softc *sc = ch->ch_sc;
+
+	DMA_WRITE(sc, AWIN_A31_DMA_EN_REG(ch->ch_index), 0);
+}
+
+#if defined(DDB)
+void
+awin_dma_a31_dump_regs(struct awin_dma_softc *sc)
+{
+	int i;
+
+	printf("IRQ_EN0          %08X\n",
+	    DMA_READ(sc, AWIN_A31_DMA_IRQ_EN_REG0_REG));
+	printf("IRQ_EN1          %08X\n",
+	    DMA_READ(sc, AWIN_A31_DMA_IRQ_EN_REG1_REG));
+	printf("PEND0:           %08X\n",
+	    DMA_READ(sc, AWIN_A31_DMA_IRQ_PEND_REG0_REG));
+	printf("PEND1:           %08X\n",
+	    DMA_READ(sc, AWIN_A31_DMA_IRQ_PEND_REG1_REG));
+	printf("STA:             %08X\n",
+	    DMA_READ(sc, AWIN_A31_DMA_STA_REG));
+	for (i = 0; i < DMA_CHANNELS; i++) {
+		printf("DMA%d EN:         %08X\n", i,
+		    DMA_READ(sc, AWIN_A31_DMA_EN_REG(i)));
+		printf("DMA%d PAU:        %08X\n", i,
+		    DMA_READ(sc, AWIN_A31_DMA_PAU_REG(i)));
+		printf("DMA%d START_ADDR: %08X\n", i,
+		    DMA_READ(sc, AWIN_A31_DMA_START_ADDR_REG(i)));
+		printf("DMA%d CFG:        %08X\n", i,
+		    DMA_READ(sc, AWIN_A31_DMA_CFG_REG(i)));
+		printf("DMA%d CUR_SRC:    %08X\n", i,
+		    DMA_READ(sc, AWIN_A31_DMA_CUR_SRC_REG(i)));
+		printf("DMA%d CUR_DEST:   %08X\n", i,
+		    DMA_READ(sc, AWIN_A31_DMA_CUR_DEST_REG(i)));
+		printf("DMA%d BCNT_LEFT:  %08X\n", i,
+		    DMA_READ(sc, AWIN_A31_DMA_BCNT_LEFT_REG(i)));
+		printf("DMA%d PARA:       %08X\n", i,
+		    DMA_READ(sc, AWIN_A31_DMA_PARA_REG(i)));
+	}
+}
+#endif

Reply via email to