Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144545502
D5050.1775347897.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
23 KB
Referenced Files
None
Subscribers
None
D5050.1775347897.diff
View Options
Index: sys/arm/allwinner/a10_dmac.h
===================================================================
--- /dev/null
+++ sys/arm/allwinner/a10_dmac.h
@@ -0,0 +1,158 @@
+/*-
+ * Copyright (c) 2014-2016 Jared D. McNeill <jmcneill@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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _A10_DMAC_H_
+#define _A10_DMAC_H_
+
+#define AWIN_DMA_IRQ_EN_REG 0x0000
+#define AWIN_DMA_IRQ_PEND_STA_REG 0x0004
+#define AWIN_NDMA_AUTO_GATE_REG 0x0008
+#define AWIN_NDMA_REG(n) (0x100+0x20*(n))
+#define AWIN_NDMA_CTL_REG 0x0000
+#define AWIN_NDMA_SRC_ADDR_REG 0x0004
+#define AWIN_NDMA_DEST_ADDR_REG 0x0008
+#define AWIN_NDMA_BC_REG 0x000c
+#define AWIN_DDMA_REG(n) (0x300+0x20*(n))
+#define AWIN_DDMA_CTL_REG 0x0000
+#define AWIN_DDMA_SRC_START_ADDR_REG 0x0004
+#define AWIN_DDMA_DEST_START_ADDR_REG 0x0008
+#define AWIN_DDMA_BC_REG 0x000c
+#define AWIN_DDMA_PARA_REG 0x0018
+#define AWIN_DMA_IRQ_END_MASK 0xaaaaaaaa
+#define AWIN_DMA_IRQ_HF_MASK 0x55555555
+#define AWIN_DMA_IRQ_DDMA 0xffff0000
+#define AWIN_DMA_IRQ_DDMA_END(n) (1U << (17+2*(n)))
+#define AWIN_DMA_IRQ_DDMA_HF(n) (1U << (16+2*(n)))
+#define AWIN_DMA_IRQ_NDMA 0x0000ffff
+#define AWIN_DMA_IRQ_NDMA_END(n) (1U << (1+2*(n)))
+#define AWIN_DMA_IRQ_NDMA_HF(n) (1U << (0+2*(n)))
+#define AWIN_NDMA_AUTO_GATING_DIS (1U << 16)
+#define AWIN_DMA_CTL_DST_DATA_WIDTH_SHIFT 25
+#define AWIN_DMA_CTL_DST_DATA_WIDTH_MASK (3U << AWIN_DMA_CTL_DST_DATA_WIDTH_SHIFT)
+#define AWIN_DMA_CTL_DATA_WIDTH_8 0
+#define AWIN_DMA_CTL_DATA_WIDTH_16 1
+#define AWIN_DMA_CTL_DATA_WIDTH_32 2
+#define AWIN_DMA_CTL_DST_BURST_LEN_SHIFT 23
+#define AWIN_DMA_CTL_DST_BURST_LEN_MASK (3 << AWIN_DMA_CTL_DST_BURST_LEN_SHIFT)
+#define AWIN_DMA_CTL_BURST_LEN_1 0
+#define AWIN_DMA_CTL_BURST_LEN_4 1
+#define AWIN_DMA_CTL_BURST_LEN_8 2
+#define AWIN_DMA_CTL_DST_DRQ_TYPE_SHIFT 16
+#define AWIN_DMA_CTL_DST_DRQ_TYPE_MASK (0x1f << AWIN_DMA_CTL_DST_DRQ_TYPE_SHIFT)
+#define AWIN_DMA_CTL_BC_REMAINING (1U << 15)
+#define AWIN_DMA_CTL_SRC_DATA_WIDTH_SHIFT 9
+#define AWIN_DMA_CTL_SRC_DATA_WIDTH_MASK (3U << AWIN_DMA_CTL_SRC_DATA_WIDTH_SHIFT)
+#define AWIN_DMA_CTL_SRC_BURST_LEN_SHIFT 7
+#define AWIN_DMA_CTL_SRC_BURST_LEN_MASK (3U << AWIN_DMA_CTL_SRC_BURST_LEN_SHIFT)
+#define AWIN_DMA_CTL_SRC_DRQ_TYPE_SHIFT 0
+#define AWIN_DMA_CTL_SRC_DRQ_TYPE_MASK (0x1f << AWIN_DMA_CTL_SRC_DRQ_TYPE_SHIFT)
+#define AWIN_NDMA_CTL_DMA_LOADING (1U << 31)
+#define AWIN_NDMA_CTL_DMA_CONTIN_MODE (1U << 30)
+#define AWIN_NDMA_CTL_WAIT_STATE_LOG2_SHIFT 27
+#define AWIN_NDMA_CTL_WAIT_STATE_LOG2_MASK (7U << AWIN_NDMA_CTL_WAIT_STATE_LOG2_SHIFT)
+#define AWIN_NDMA_CTL_DST_NON_SECURE (1U << 22)
+#define AWIN_NDMA_CTL_DST_ADDR_NOINCR (1U << 21)
+#define AWIN_NDMA_CTL_DRQ_IRO 0
+#define AWIN_NDMA_CTL_DRQ_IR1 1
+#define AWIN_NDMA_CTL_DRQ_SPDIF 2
+#define AWIN_NDMA_CTL_DRQ_IISO 3
+#define AWIN_NDMA_CTL_DRQ_IIS1 4
+#define AWIN_NDMA_CTL_DRQ_AC97 5
+#define AWIN_NDMA_CTL_DRQ_IIS2 6
+#define AWIN_NDMA_CTL_DRQ_UARTO 8
+#define AWIN_NDMA_CTL_DRQ_UART1 9
+#define AWIN_NDMA_CTL_DRQ_UART2 10
+#define AWIN_NDMA_CTL_DRQ_UART3 11
+#define AWIN_NDMA_CTL_DRQ_UART4 12
+#define AWIN_NDMA_CTL_DRQ_UART5 13
+#define AWIN_NDMA_CTL_DRQ_UART6 14
+#define AWIN_NDMA_CTL_DRQ_UART7 15
+#define AWIN_NDMA_CTL_DRQ_DDC 16
+#define AWIN_NDMA_CTL_DRQ_USB_EP1 17
+#define AWIN_NDMA_CTL_DRQ_CODEC 19
+#define AWIN_NDMA_CTL_DRQ_SRAM 21
+#define AWIN_NDMA_CTL_DRQ_SDRAM 22
+#define AWIN_NDMA_CTL_DRQ_TP_AD 23
+#define AWIN_NDMA_CTL_DRQ_SPI0 24
+#define AWIN_NDMA_CTL_DRQ_SPI1 25
+#define AWIN_NDMA_CTL_DRQ_SPI2 26
+#define AWIN_NDMA_CTL_DRQ_SPI3 27
+#define AWIN_NDMA_CTL_DRQ_USB_EP2 28
+#define AWIN_NDMA_CTL_DRQ_USB_EP3 29
+#define AWIN_NDMA_CTL_DRQ_USB_EP4 30
+#define AWIN_NDMA_CTL_DRQ_USB_EP5 31
+#define AWIN_NDMA_CTL_SRC_NON_SECURE (1U << 6)
+#define AWIN_NDMA_CTL_SRC_ADDR_NOINCR (1U << 5)
+#define AWIN_NDMA_BC_COUNT 0x0003ffff
+#define AWIN_DDMA_CTL_DMA_LOADING (1U << 31)
+#define AWIN_DDMA_CTL_BUSY (1U << 30)
+#define AWIN_DDMA_CTL_DMA_CONTIN_MODE (1U << 29)
+#define AWIN_DDMA_CTL_DST_NON_SECURE (1U << 28)
+#define AWIN_DDMA_CTL_DST_ADDR_MODE_SHIFT 21
+#define AWIN_DDMA_CTL_DST_ADDR_MODE_MASK (3U << AWIN_DDMA_CTL_DST_ADDR_MODE_SHIFT)
+#define AWIN_DDMA_CTL_DMA_ADDR_LINEAR 0
+#define AWIN_DDMA_CTL_DMA_ADDR_IO 1
+#define AWIN_DDMA_CTL_DMA_ADDR_HPAGE 2
+#define AWIN_DDMA_CTL_DMA_ADDR_VPAGE 3
+#define AWIN_DDMA_CTL_DST_DRQ_TYPE_SHIFT 16
+#define AWIN_DDMA_CTL_DST_DRQ_TYPE_MASK (0x1f << AWIN_DDMA_CTL_DST_DRQ_TYPE_SHIFT)
+#define AWIN_DDMA_CTL_DRQ_SRAM 0
+#define AWIN_DDMA_CTL_DRQ_SDRAM 1
+#define AWIN_DDMA_CTL_DRQ_NFC 3
+#define AWIN_DDMA_CTL_DRQ_USB0 4
+#define AWIN_DDMA_CTL_DRQ_EMAC_TX 6
+#define AWIN_DDMA_CTL_DRQ_EMAC_RX 7
+#define AWIN_DDMA_CTL_DRQ_SPI1_TX 8
+#define AWIN_DDMA_CTL_DRQ_SPI1_RX 9
+#define AWIN_DDMA_CTL_DRQ_SS_TX 10
+#define AWIN_DDMA_CTL_DRQ_SS_RX 11
+#define AWIN_DDMA_CTL_DRQ_TCON0 14
+#define AWIN_DDMA_CTL_DRQ_TCON1 15
+#define AWIN_DDMA_CTL_DRQ_MS_TX 23
+#define AWIN_DDMA_CTL_DRQ_MS_RX 23
+#define AWIN_DDMA_CTL_DRQ_HDMI_AUDIO 24
+#define AWIN_DDMA_CTL_DRQ_SPI0_TX 26
+#define AWIN_DDMA_CTL_DRQ_SPI0_RX 27
+#define AWIN_DDMA_CTL_DRQ_SPI2_TX 28
+#define AWIN_DDMA_CTL_DRQ_SPI2_RX 29
+#define AWIN_DDMA_CTL_DRQ_SPI3_TX 30
+#define AWIN_DDMA_CTL_DRQ_SPI3_RX 31
+#define AWIN_DDMA_CTL_SRC_NON_SECURE (1U << 12)
+#define AWIN_DDMA_CTL_SRC_ADDR_MODE_SHIFT 5
+#define AWIN_DDMA_CTL_SRC_ADDR_MODE_MASK (3U << AWIN_DDMA_CTL_SRC_ADDR_MODE_SHIFT)
+#define AWIN_DDMA_BC_COUNT 0x00003fff
+#define AWIN_DDMA_PARA_DST_DATA_BLK_SIZ_SHIFT 24
+#define AWIN_DDMA_PARA_DST_DATA_BLK_SIZ_MASK (0xff << AWIN_DDMA_PARA_DST_DATA_BLK_SIZ_SHIFT)
+#define AWIN_DDMA_PARA_DST_WAIT_CYC_SHIFT 16
+#define AWIN_DDMA_PARA_DST_WAIT_CYC_MASK (0xff << AWIN_DDMA_PARA_DST_WAIT_CYC_SHIFT)
+#define AWIN_DDMA_PARA_SRC_DATA_BLK_SIZ_SHIFT 8
+#define AWIN_DDMA_PARA_SRC_DATA_BLK_SIZ_MASK (0xff << AWIN_DDMA_PARA_SRC_DATA_BLK_SIZ_SHIFT)
+#define AWIN_DDMA_PARA_SRC_WAIT_CYC_SHIFT 0
+#define AWIN_DDMA_PARA_SRC_WAIT_CYC_MASK (0xff << AWIN_DDMA_PARA_SRC_WAIT_CYC_SHIFT)
+
+#endif /* !_A10_DMAC_H_ */
Index: sys/arm/allwinner/a10_dmac.c
===================================================================
--- /dev/null
+++ sys/arm/allwinner/a10_dmac.c
@@ -0,0 +1,466 @@
+/*-
+ * Copyright (c) 2014-2016 Jared D. McNeill <jmcneill@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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Allwinner A10/A20 DMA controller
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_bus.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/condvar.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <machine/bus.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "sunxi_dma_if.h"
+
+#include "a10_dmac.h"
+#include "a10_clk.h"
+
+#define NDMA_CHANNELS 8
+#define DDMA_CHANNELS 8
+
+enum a10dmac_type {
+ CH_NDMA,
+ CH_DDMA
+};
+
+struct a10dmac_softc;
+
+struct a10dmac_channel {
+ struct a10dmac_softc * ch_sc;
+ uint8_t ch_index;
+ enum a10dmac_type ch_type;
+ void (*ch_callback)(void *);
+ void * ch_callbackarg;
+ uint32_t ch_regoff;
+};
+
+struct a10dmac_softc {
+ device_t sc_dev;
+ struct resource * sc_res;
+ struct resource * sc_irq;
+ struct mtx sc_mtx;
+ void * sc_ih;
+
+ struct a10dmac_channel sc_ndma_channels[NDMA_CHANNELS];
+ struct a10dmac_channel sc_ddma_channels[DDMA_CHANNELS];
+};
+
+#define DMA_READ(sc, reg) bus_read_4((sc)->sc_res, (reg))
+#define DMA_WRITE(sc, reg, val) bus_write_4((sc)->sc_res, (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 void a10dmac_intr(void *);
+
+static int
+a10dmac_probe(device_t dev)
+{
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-dma"))
+ return (ENXIO);
+
+ device_set_desc(dev, "Allwinner DMA controller");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+a10dmac_attach(device_t dev)
+{
+ struct a10dmac_softc *sc;
+ unsigned int index;
+ int rid, error;
+
+ sc = device_get_softc(dev);
+ sc->sc_dev = dev;
+
+ mtx_init(&sc->sc_mtx, "a10 dmac", NULL, MTX_SPIN);
+
+ rid = 0;
+ sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->sc_res == NULL) {
+ device_printf(dev, "unable to map memory\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ rid = 0;
+ sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_SHAREABLE | RF_ACTIVE);
+ if (sc->sc_irq == NULL) {
+ device_printf(dev, "cannot allocate IRQ resources\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* Activate DMA controller clock */
+ a10_clk_dmac_activate();
+
+ /* Disable all interrupts and clear pending status */
+ DMA_WRITE(sc, AWIN_DMA_IRQ_EN_REG, 0);
+ DMA_WRITE(sc, AWIN_DMA_IRQ_PEND_STA_REG, ~0);
+
+ /* Initialize channels */
+ for (index = 0; index < NDMA_CHANNELS; index++) {
+ sc->sc_ndma_channels[index].ch_sc = sc;
+ sc->sc_ndma_channels[index].ch_index = index;
+ sc->sc_ndma_channels[index].ch_type = CH_NDMA;
+ sc->sc_ndma_channels[index].ch_callback = NULL;
+ sc->sc_ndma_channels[index].ch_callbackarg = NULL;
+ sc->sc_ndma_channels[index].ch_regoff = AWIN_NDMA_REG(index);
+ DMACH_WRITE(&sc->sc_ndma_channels[index], AWIN_NDMA_CTL_REG, 0);
+ }
+ for (index = 0; index < DDMA_CHANNELS; index++) {
+ sc->sc_ddma_channels[index].ch_sc = sc;
+ sc->sc_ddma_channels[index].ch_index = index;
+ sc->sc_ddma_channels[index].ch_type = CH_DDMA;
+ sc->sc_ddma_channels[index].ch_callback = NULL;
+ sc->sc_ddma_channels[index].ch_callbackarg = NULL;
+ sc->sc_ddma_channels[index].ch_regoff = AWIN_DDMA_REG(index);
+ DMACH_WRITE(&sc->sc_ddma_channels[index], AWIN_DDMA_CTL_REG, 0);
+ }
+
+ error = bus_setup_intr(dev, sc->sc_irq, INTR_MPSAFE | INTR_TYPE_MISC,
+ NULL, a10dmac_intr, sc, &sc->sc_ih);
+ if (error != 0) {
+ device_printf(dev, "could not setup interrupt handler\n");
+ goto fail;
+ }
+
+ return (0);
+
+fail:
+ if (sc->sc_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_res);
+ if (sc->sc_irq != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq);
+
+ return (error);
+}
+
+static void
+a10dmac_intr(void *priv)
+{
+ struct a10dmac_softc *sc = priv;
+ uint32_t sta, bit, mask;
+ uint8_t index;
+
+ sta = DMA_READ(sc, AWIN_DMA_IRQ_PEND_STA_REG);
+ DMA_WRITE(sc, AWIN_DMA_IRQ_PEND_STA_REG, sta);
+
+ while ((bit = ffs(sta & AWIN_DMA_IRQ_END_MASK)) != 0) {
+ mask = (1U << (bit - 1));
+ sta &= ~mask;
+ /*
+ * Map status bit to channel number. The status register is
+ * encoded with two bits of status per channel (lowest bit
+ * is half transfer pending, highest bit is end transfer
+ * pending). The 8 normal DMA channel status are in the lower
+ * 16 bits and the 8 dedicated DMA channel status are in
+ * the upper 16 bits. The output is a channel number from 0-7.
+ */
+ index = ((bit - 1) / 2) & 7;
+ if (mask & AWIN_DMA_IRQ_NDMA) {
+ if (sc->sc_ndma_channels[index].ch_callback == NULL)
+ continue;
+ sc->sc_ndma_channels[index].ch_callback(
+ sc->sc_ndma_channels[index].ch_callbackarg);
+ } else {
+ if (sc->sc_ddma_channels[index].ch_callback == NULL)
+ continue;
+ sc->sc_ddma_channels[index].ch_callback(
+ sc->sc_ddma_channels[index].ch_callbackarg);
+ }
+ }
+}
+
+static uint32_t
+a10dmac_read_ctl(struct a10dmac_channel *ch)
+{
+ if (ch->ch_type == CH_NDMA) {
+ return (DMACH_READ(ch, AWIN_NDMA_CTL_REG));
+ } else {
+ return (DMACH_READ(ch, AWIN_DDMA_CTL_REG));
+ }
+}
+
+static void
+a10dmac_write_ctl(struct a10dmac_channel *ch, uint32_t val)
+{
+ if (ch->ch_type == CH_NDMA) {
+ DMACH_WRITE(ch, AWIN_NDMA_CTL_REG, val);
+ } else {
+ DMACH_WRITE(ch, AWIN_DDMA_CTL_REG, val);
+ }
+}
+
+static int
+a10dmac_set_config(device_t dev, void *priv, const struct sunxi_dma_config *cfg)
+{
+ struct a10dmac_channel *ch = priv;
+ uint32_t val;
+ unsigned int dst_dw, dst_bl, src_dw, src_bl;
+
+ switch (cfg->dst_width) {
+ case 8:
+ dst_dw = AWIN_DMA_CTL_DATA_WIDTH_8;
+ break;
+ case 16:
+ dst_dw = AWIN_DMA_CTL_DATA_WIDTH_16;
+ break;
+ case 32:
+ dst_dw = AWIN_DMA_CTL_DATA_WIDTH_32;
+ break;
+ default:
+ return (EINVAL);
+ }
+ switch (cfg->dst_burst_len) {
+ case 1:
+ dst_bl = AWIN_DMA_CTL_BURST_LEN_1;
+ break;
+ case 4:
+ dst_bl = AWIN_DMA_CTL_BURST_LEN_4;
+ break;
+ case 8:
+ dst_bl = AWIN_DMA_CTL_BURST_LEN_8;
+ break;
+ default:
+ return (EINVAL);
+ }
+ switch (cfg->src_width) {
+ case 8:
+ src_dw = AWIN_DMA_CTL_DATA_WIDTH_8;
+ break;
+ case 16:
+ src_dw = AWIN_DMA_CTL_DATA_WIDTH_16;
+ break;
+ case 32:
+ src_dw = AWIN_DMA_CTL_DATA_WIDTH_32;
+ break;
+ default:
+ return (EINVAL);
+ }
+ switch (cfg->src_burst_len) {
+ case 1:
+ src_bl = AWIN_DMA_CTL_BURST_LEN_1;
+ break;
+ case 4:
+ src_bl = AWIN_DMA_CTL_BURST_LEN_4;
+ break;
+ case 8:
+ src_bl = AWIN_DMA_CTL_BURST_LEN_8;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ val = (dst_dw << AWIN_DMA_CTL_DST_DATA_WIDTH_SHIFT) |
+ (dst_bl << AWIN_DMA_CTL_DST_BURST_LEN_SHIFT) |
+ (cfg->dst_drqtype << AWIN_DMA_CTL_DST_DRQ_TYPE_SHIFT) |
+ (src_dw << AWIN_DMA_CTL_SRC_DATA_WIDTH_SHIFT) |
+ (src_bl << AWIN_DMA_CTL_SRC_BURST_LEN_SHIFT) |
+ (cfg->src_drqtype << AWIN_DMA_CTL_SRC_DRQ_TYPE_SHIFT);
+ if (cfg->dst_noincr) {
+ val |= AWIN_NDMA_CTL_DST_ADDR_NOINCR;
+ }
+ if (cfg->src_noincr) {
+ val |= AWIN_NDMA_CTL_SRC_ADDR_NOINCR;
+ }
+
+ if (ch->ch_type == CH_NDMA) {
+ DMACH_WRITE(ch, AWIN_NDMA_CTL_REG, val);
+ } else {
+ DMACH_WRITE(ch, AWIN_DDMA_CTL_REG, val);
+ }
+
+ return (0);
+}
+
+static void *
+a10dmac_alloc(device_t dev, bool dedicated, void (*cb)(void *), void *cbarg)
+{
+ struct a10dmac_softc *sc = device_get_softc(dev);
+ struct a10dmac_channel *ch_list;
+ struct a10dmac_channel *ch = NULL;
+ uint32_t irqen;
+ uint8_t ch_count, index;
+
+ if (dedicated) {
+ ch_list = sc->sc_ddma_channels;
+ ch_count = DDMA_CHANNELS;
+ } else {
+ ch_list = sc->sc_ndma_channels;
+ ch_count = NDMA_CHANNELS;
+ }
+
+ mtx_lock_spin(&sc->sc_mtx);
+ 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 (ch->ch_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;
+ }
+ }
+ mtx_unlock_spin(&sc->sc_mtx);
+
+ return (ch);
+}
+
+static void
+a10dmac_free(device_t dev, void *priv)
+{
+ struct a10dmac_channel *ch = priv;
+ struct a10dmac_softc *sc = ch->ch_sc;
+ uint32_t irqen, sta, cfg;
+
+ mtx_lock_spin(&sc->sc_mtx);
+
+ irqen = DMA_READ(sc, AWIN_DMA_IRQ_EN_REG);
+ cfg = a10dmac_read_ctl(ch);
+ if (ch->ch_type == CH_NDMA) {
+ sta = AWIN_DMA_IRQ_NDMA_END(ch->ch_index);
+ cfg &= ~AWIN_NDMA_CTL_DMA_LOADING;
+ } else {
+ sta = AWIN_DMA_IRQ_DDMA_END(ch->ch_index);
+ cfg &= ~AWIN_DDMA_CTL_DMA_LOADING;
+ }
+ irqen &= ~sta;
+ a10dmac_write_ctl(ch, cfg);
+ DMA_WRITE(sc, AWIN_DMA_IRQ_EN_REG, irqen);
+ DMA_WRITE(sc, AWIN_DMA_IRQ_PEND_STA_REG, sta);
+
+ ch->ch_callback = NULL;
+ ch->ch_callbackarg = NULL;
+
+ mtx_unlock_spin(&sc->sc_mtx);
+}
+
+static int
+a10dmac_transfer(device_t dev, void *priv, bus_addr_t src, bus_addr_t dst,
+ size_t nbytes)
+{
+ struct a10dmac_channel *ch = priv;
+ uint32_t cfg;
+
+ cfg = a10dmac_read_ctl(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;
+ a10dmac_write_ctl(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);
+ DMACH_WRITE(ch, AWIN_DDMA_PARA_REG,
+ (31 << AWIN_DDMA_PARA_DST_DATA_BLK_SIZ_SHIFT) |
+ (7 << AWIN_DDMA_PARA_DST_WAIT_CYC_SHIFT) |
+ (31 << AWIN_DDMA_PARA_SRC_DATA_BLK_SIZ_SHIFT) |
+ (7 << AWIN_DDMA_PARA_SRC_WAIT_CYC_SHIFT));
+
+ cfg |= AWIN_DDMA_CTL_DMA_LOADING;
+ a10dmac_write_ctl(ch, cfg);
+ }
+
+ return (0);
+}
+
+static void
+a10dmac_halt(device_t dev, void *priv)
+{
+ struct a10dmac_channel *ch = priv;
+ uint32_t cfg;
+
+ cfg = a10dmac_read_ctl(ch);
+ if (ch->ch_type == CH_NDMA) {
+ cfg &= ~AWIN_NDMA_CTL_DMA_LOADING;
+ } else {
+ cfg &= ~AWIN_DDMA_CTL_DMA_LOADING;
+ }
+ a10dmac_write_ctl(ch, cfg);
+}
+
+static device_method_t a10dmac_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, a10dmac_probe),
+ DEVMETHOD(device_attach, a10dmac_attach),
+
+ /* sunxi DMA interface */
+ DEVMETHOD(sunxi_dma_alloc, a10dmac_alloc),
+ DEVMETHOD(sunxi_dma_free, a10dmac_free),
+ DEVMETHOD(sunxi_dma_set_config, a10dmac_set_config),
+ DEVMETHOD(sunxi_dma_transfer, a10dmac_transfer),
+ DEVMETHOD(sunxi_dma_halt, a10dmac_halt),
+
+ DEVMETHOD_END
+};
+
+static driver_t a10dmac_driver = {
+ "a10dmac",
+ a10dmac_methods,
+ sizeof(struct a10dmac_softc)
+};
+
+static devclass_t a10dmac_devclass;
+
+DRIVER_MODULE(a10dmac, simplebus, a10dmac_driver, a10dmac_devclass, 0, 0);
Index: sys/arm/allwinner/files.allwinner
===================================================================
--- sys/arm/allwinner/files.allwinner
+++ sys/arm/allwinner/files.allwinner
@@ -4,6 +4,7 @@
arm/allwinner/a10_ahci.c optional ahci
arm/allwinner/a10_clk.c standard
arm/allwinner/a10_common.c standard
+arm/allwinner/a10_dmac.c standard
arm/allwinner/a10_ehci.c optional ehci
arm/allwinner/a10_gpio.c optional gpio
arm/allwinner/a10_machdep.c standard
@@ -12,5 +13,6 @@
arm/allwinner/a10_wdog.c standard
arm/allwinner/a20/a20_cpu_cfg.c standard
arm/allwinner/if_emac.c optional emac
+arm/allwinner/sunxi_dma_if.m standard
arm/allwinner/timer.c standard
#arm/allwinner/console.c standard
Index: sys/arm/allwinner/sunxi_dma_if.m
===================================================================
--- /dev/null
+++ sys/arm/allwinner/sunxi_dma_if.m
@@ -0,0 +1,94 @@
+#-
+# Copyright (c) 2016 Jared D. McNeill <jmcneill@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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+#
+# $FreeBSD$
+#
+
+#include <sys/bus.h>
+
+INTERFACE sunxi_dma;
+
+HEADER {
+ #include <machine/bus.h>
+
+ struct sunxi_dma_config {
+ unsigned int dst_width;
+ unsigned int dst_burst_len;
+ unsigned int dst_drqtype;
+ bool dst_noincr;
+ unsigned int src_width;
+ unsigned int src_burst_len;
+ unsigned int src_drqtype;
+ bool src_noincr;
+ };
+
+ typedef void (*sunxi_dma_callback)(void *);
+}
+
+#
+# Allocate DMA channel
+#
+METHOD void * alloc {
+ device_t dev;
+ bool dedicated;
+ sunxi_dma_callback callback;
+ void *callback_arg;
+};
+
+#
+# Free DMA channel
+#
+METHOD void free {
+ device_t dev;
+ void *dmachan;
+};
+
+#
+# Set DMA channel configuration
+#
+METHOD int set_config {
+ device_t dev;
+ void *dmachan;
+ const struct sunxi_dma_config *cfg;
+};
+
+#
+# Start DMA channel transfer
+#
+METHOD int transfer {
+ device_t dev;
+ void *dmachan;
+ bus_addr_t src;
+ bus_addr_t dst;
+ size_t nbytes;
+};
+
+#
+# Halt DMA channel transfer
+#
+METHOD void halt {
+ device_t dev;
+ void *dmachan;
+};
Index: sys/boot/fdt/dts/arm/sun7i-a20.dtsi
===================================================================
--- sys/boot/fdt/dts/arm/sun7i-a20.dtsi
+++ sys/boot/fdt/dts/arm/sun7i-a20.dtsi
@@ -156,6 +156,13 @@
#address-cells = <1>;
#size-cells = <0>;
};
+
+ dma: dma-controller@01c02000 {
+ compatible = "allwinner,sun4i-a10-dma";
+ reg = <0x01c02000 0x1000>;
+ interrupts = <27>;
+ interrupt-parent = <&GIC>;
+ };
};
};
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Apr 5, 12:11 AM (9 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28262460
Default Alt Text
D5050.1775347897.diff (23 KB)
Attached To
Mode
D5050: Allwinner A10/A20 DMA controller driver
Attached
Detach File
Event Timeline
Log In to Comment