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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[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.
+ */
+
+#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 <[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_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 <[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_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