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