diff options
author | ian <ian@FreeBSD.org> | 2014-05-15 18:38:19 +0000 |
---|---|---|
committer | ian <ian@FreeBSD.org> | 2014-05-15 18:38:19 +0000 |
commit | c287c5d5301219fe2fabc25222edae29e314c213 (patch) | |
tree | 6279c6bac201dbed9f74b5d6ff7052423f603994 /sys/arm | |
parent | aa8cf0356302220da5d26bb149e6a0f5061fae7b (diff) | |
download | FreeBSD-src-c287c5d5301219fe2fabc25222edae29e314c213.zip FreeBSD-src-c287c5d5301219fe2fabc25222edae29e314c213.tar.gz |
MFC r261616, r261639
Remove FreeBSD 6 support from atmel usb controllers.
Add Vybrid drivers for:
- Enhanced Direct Memory Access Controller (eDMA)
- Direct Memory Access Multiplexer (DMAMUX)
Diffstat (limited to 'sys/arm')
-rw-r--r-- | sys/arm/freescale/vybrid/files.vybrid | 2 | ||||
-rw-r--r-- | sys/arm/freescale/vybrid/vf_dmamux.c | 155 | ||||
-rw-r--r-- | sys/arm/freescale/vybrid/vf_dmamux.h | 48 | ||||
-rw-r--r-- | sys/arm/freescale/vybrid/vf_edma.c | 338 | ||||
-rw-r--r-- | sys/arm/freescale/vybrid/vf_edma.h | 186 |
5 files changed, 729 insertions, 0 deletions
diff --git a/sys/arm/freescale/vybrid/files.vybrid b/sys/arm/freescale/vybrid/files.vybrid index 6b77ff2..756beb9 100644 --- a/sys/arm/freescale/vybrid/files.vybrid +++ b/sys/arm/freescale/vybrid/files.vybrid @@ -21,6 +21,8 @@ arm/freescale/vybrid/vf_anadig.c standard arm/freescale/vybrid/vf_iomuxc.c standard arm/freescale/vybrid/vf_mscm.c standard arm/freescale/vybrid/vf_src.c standard +arm/freescale/vybrid/vf_edma.c standard +arm/freescale/vybrid/vf_dmamux.c standard arm/freescale/vybrid/vf_tcon.c optional vt arm/freescale/vybrid/vf_dcu4.c optional vt arm/freescale/vybrid/vf_nfc.c optional nand diff --git a/sys/arm/freescale/vybrid/vf_dmamux.c b/sys/arm/freescale/vybrid/vf_dmamux.c new file mode 100644 index 0000000..1909621 --- /dev/null +++ b/sys/arm/freescale/vybrid/vf_dmamux.c @@ -0,0 +1,155 @@ +/*- + * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> + * 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. + */ + +/* + * Vybrid Family Direct Memory Access Multiplexer (DMAMUX) + * Chapter 22, Vybrid Reference Manual, Rev. 5, 07/2013 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/malloc.h> +#include <sys/rman.h> +#include <sys/timeet.h> +#include <sys/timetc.h> +#include <sys/watchdog.h> + +#include <dev/fdt/fdt_common.h> +#include <dev/ofw/openfirm.h> +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> + +#include <machine/bus.h> +#include <machine/fdt.h> +#include <machine/cpu.h> +#include <machine/intr.h> + +#include <arm/freescale/vybrid/vf_common.h> +#include <arm/freescale/vybrid/vf_dmamux.h> + +#define DMAMUX_CHCFG(n) (0x1 * n) /* Channels 0-15 Cfg Reg */ +#define CHCFG_ENBL (1 << 7) /* Channel Enable */ +#define CHCFG_TRIG (1 << 6) /* Channel Trigger Enable */ +#define CHCFG_SOURCE_MASK 0x3f /* Channel Source (Slot) */ +#define CHCFG_SOURCE_SHIFT 0 + +struct dmamux_softc { + struct resource *res[4]; + bus_space_tag_t bst[4]; + bus_space_handle_t bsh[4]; +}; + +struct dmamux_softc *dmamux_sc; + +static struct resource_spec dmamux_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* DMAMUX0 */ + { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* DMAMUX1 */ + { SYS_RES_MEMORY, 2, RF_ACTIVE }, /* DMAMUX2 */ + { SYS_RES_MEMORY, 3, RF_ACTIVE }, /* DMAMUX3 */ + { -1, 0 } +}; + +static int +dmamux_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "fsl,mvf600-dmamux")) + return (ENXIO); + + device_set_desc(dev, "Vybrid Family Direct Memory Access Multiplexer"); + return (BUS_PROBE_DEFAULT); +} + +int +dmamux_configure(int mux, int source, int channel, int enable) +{ + struct dmamux_softc *sc; + int reg; + + sc = dmamux_sc; + + MUX_WRITE1(sc, mux, DMAMUX_CHCFG(channel), 0x0); + + reg = 0; + if (enable) + reg |= (CHCFG_ENBL); + + reg &= ~(CHCFG_SOURCE_MASK << CHCFG_SOURCE_SHIFT); + reg |= (source << CHCFG_SOURCE_SHIFT); + + MUX_WRITE1(sc, mux, DMAMUX_CHCFG(channel), reg); + + return (0); +} + +static int +dmamux_attach(device_t dev) +{ + struct dmamux_softc *sc; + int i; + + sc = device_get_softc(dev); + + if (bus_alloc_resources(dev, dmamux_spec, sc->res)) { + device_printf(dev, "could not allocate resources\n"); + return (ENXIO); + } + + /* Memory interface */ + for (i = 0; i < 4; i++) { + sc->bst[i] = rman_get_bustag(sc->res[i]); + sc->bsh[i] = rman_get_bushandle(sc->res[i]); + } + + dmamux_sc = sc; + + return (0); +} + +static device_method_t dmamux_methods[] = { + DEVMETHOD(device_probe, dmamux_probe), + DEVMETHOD(device_attach, dmamux_attach), + { 0, 0 } +}; + +static driver_t dmamux_driver = { + "dmamux", + dmamux_methods, + sizeof(struct dmamux_softc), +}; + +static devclass_t dmamux_devclass; + +DRIVER_MODULE(dmamux, simplebus, dmamux_driver, dmamux_devclass, 0, 0); diff --git a/sys/arm/freescale/vybrid/vf_dmamux.h b/sys/arm/freescale/vybrid/vf_dmamux.h new file mode 100644 index 0000000..92fa076 --- /dev/null +++ b/sys/arm/freescale/vybrid/vf_dmamux.h @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> + * 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$ + */ + +int dmamux_configure(int mux, int source, int channel, int enable); + +enum mux_num { + MUX0, + MUX1, + MUX2, + MUX3, +}; + +enum mux_grp { + MUXGRP0, /* MUX[0,3] */ + MUXGRP1, /* MUX[1,2] */ +}; + +/* DMAMUX */ +#define MUX_READ1(_sc, _mux, _reg) \ + bus_space_read_1(_sc->bst[_mux], _sc->bsh[_mux], _reg) + +#define MUX_WRITE1(_sc, _mux, _reg, _val) \ + bus_space_write_1(_sc->bst[_mux], _sc->bsh[_mux], _reg, _val) diff --git a/sys/arm/freescale/vybrid/vf_edma.c b/sys/arm/freescale/vybrid/vf_edma.c new file mode 100644 index 0000000..c5df919 --- /dev/null +++ b/sys/arm/freescale/vybrid/vf_edma.c @@ -0,0 +1,338 @@ +/*- + * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> + * 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. + */ + +/* + * Vybrid Family Enhanced Direct Memory Access Controller (eDMA) + * Chapter 21, Vybrid Reference Manual, Rev. 5, 07/2013 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/malloc.h> +#include <sys/rman.h> +#include <sys/timeet.h> +#include <sys/timetc.h> +#include <sys/watchdog.h> + +#include <dev/fdt/fdt_common.h> +#include <dev/ofw/openfirm.h> +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> + +#include <machine/bus.h> +#include <machine/fdt.h> +#include <machine/cpu.h> +#include <machine/intr.h> + +#include <arm/freescale/vybrid/vf_edma.h> +#include <arm/freescale/vybrid/vf_dmamux.h> +#include <arm/freescale/vybrid/vf_common.h> + +struct edma_channel { + uint32_t enabled; + uint32_t mux_num; + uint32_t mux_src; + uint32_t mux_chn; + uint32_t (*ih) (void *, int); + void *ih_user; +}; + +static struct edma_channel edma_map[EDMA_NUM_CHANNELS]; + +static struct resource_spec edma_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* TCD */ + { SYS_RES_IRQ, 0, RF_ACTIVE }, /* Transfer complete */ + { SYS_RES_IRQ, 1, RF_ACTIVE }, /* Error Interrupt */ + { -1, 0 } +}; + +static int +edma_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "fsl,mvf600-edma")) + return (ENXIO); + + device_set_desc(dev, "Vybrid Family eDMA Controller"); + return (BUS_PROBE_DEFAULT); +} + +static void +edma_transfer_complete_intr(void *arg) +{ + struct edma_channel *ch; + struct edma_softc *sc; + int interrupts; + int i; + + sc = arg; + + interrupts = READ4(sc, DMA_INT); + WRITE1(sc, DMA_CINT, CINT_CAIR); + + for (i = 0; i < EDMA_NUM_CHANNELS; i++) { + if (interrupts & (0x1 << i)) { + ch = &edma_map[i]; + if (ch->enabled == 1) { + if (ch->ih != NULL) { + ch->ih(ch->ih_user, i); + } + } + } + } +} + +static void +edma_err_intr(void *arg) +{ + struct edma_softc *sc; + int reg; + + sc = arg; + + reg = READ4(sc, DMA_ERR); + +#if 0 + device_printf(sc->dev, "DMA_ERR 0x%08x, ES 0x%08x\n", + reg, READ4(sc, DMA_ES)); +#endif + + WRITE1(sc, DMA_CERR, CERR_CAEI); +} + +static int +channel_free(struct edma_softc *sc, int chnum) +{ + struct edma_channel *ch; + + ch = &edma_map[chnum]; + ch->enabled = 0; + + dmamux_configure(ch->mux_num, ch->mux_src, ch->mux_chn, 0); + + return (0); +} + +static int +channel_configure(struct edma_softc *sc, int mux_grp, int mux_src) +{ + struct edma_channel *ch; + int channel_first; + int mux_num; + int chnum; + int i; + + if ((sc->device_id == 0 && mux_grp == 1) || \ + (sc->device_id == 1 && mux_grp == 0)) { + channel_first = NCHAN_PER_MUX; + mux_num = (sc->device_id * 2) + 1; + } else { + channel_first = 0; + mux_num = sc->device_id * 2; + }; + + /* Take first unused eDMA channel */ + ch = NULL; + for (i = channel_first; i < (channel_first + NCHAN_PER_MUX); i++) { + ch = &edma_map[i]; + if (ch->enabled == 0) { + break; + } + ch = NULL; + }; + + if (ch == NULL) { + /* Can't find free channel */ + return (-1); + }; + + chnum = i; + + ch->enabled = 1; + ch->mux_num = mux_num; + ch->mux_src = mux_src; + ch->mux_chn = (chnum - channel_first); /* 0 to 15 */ + + dmamux_configure(ch->mux_num, ch->mux_src, ch->mux_chn, 1); + + return (chnum); +} + +static int +dma_stop(struct edma_softc *sc, int chnum) +{ + int reg; + + reg = READ4(sc, DMA_ERQ); + reg &= ~(0x1 << chnum); + WRITE4(sc, DMA_ERQ, reg); + + return (0); +} + +static int +dma_setup(struct edma_softc *sc, struct tcd_conf *tcd) +{ + struct edma_channel *ch; + int chnum; + int reg; + + chnum = tcd->channel; + + ch = &edma_map[chnum]; + ch->ih = tcd->ih; + ch->ih_user = tcd->ih_user; + + TCD_WRITE4(sc, DMA_TCDn_SADDR(chnum), tcd->saddr); + TCD_WRITE4(sc, DMA_TCDn_DADDR(chnum), tcd->daddr); + + reg = (tcd->smod << TCD_ATTR_SMOD_SHIFT); + reg |= (tcd->dmod << TCD_ATTR_DMOD_SHIFT); + reg |= (tcd->ssize << TCD_ATTR_SSIZE_SHIFT); + reg |= (tcd->dsize << TCD_ATTR_DSIZE_SHIFT); + TCD_WRITE2(sc, DMA_TCDn_ATTR(chnum), reg); + + TCD_WRITE2(sc, DMA_TCDn_SOFF(chnum), tcd->soff); + TCD_WRITE2(sc, DMA_TCDn_DOFF(chnum), tcd->doff); + TCD_WRITE4(sc, DMA_TCDn_SLAST(chnum), tcd->slast); + TCD_WRITE4(sc, DMA_TCDn_DLASTSGA(chnum), tcd->dlast_sga); + TCD_WRITE4(sc, DMA_TCDn_NBYTES_MLOFFYES(chnum), tcd->nbytes); + + reg = tcd->nmajor; /* Current Major Iteration Count */ + TCD_WRITE2(sc, DMA_TCDn_CITER_ELINKNO(chnum), reg); + TCD_WRITE2(sc, DMA_TCDn_BITER_ELINKNO(chnum), reg); + + reg = (TCD_CSR_INTMAJOR); + if(tcd->majorelink == 1) { + reg |= TCD_CSR_MAJORELINK; + reg |= (tcd->majorelinkch << TCD_CSR_MAJORELINKCH_SHIFT); + } + TCD_WRITE2(sc, DMA_TCDn_CSR(chnum), reg); + + /* Enable requests */ + reg = READ4(sc, DMA_ERQ); + reg |= (0x1 << chnum); + WRITE4(sc, DMA_ERQ, reg); + + /* Enable error interrupts */ + reg = READ4(sc, DMA_EEI); + reg |= (0x1 << chnum); + WRITE4(sc, DMA_EEI, reg); + + return (0); +} + +static int +dma_request(struct edma_softc *sc, int chnum) +{ + int reg; + + /* Start */ + reg = TCD_READ2(sc, DMA_TCDn_CSR(chnum)); + reg |= TCD_CSR_START; + TCD_WRITE2(sc, DMA_TCDn_CSR(chnum), reg); + + return (0); +} + +static int +edma_attach(device_t dev) +{ + struct edma_softc *sc; + phandle_t node; + int dts_value; + int len; + + sc = device_get_softc(dev); + sc->dev = dev; + + if ((node = ofw_bus_get_node(sc->dev)) == -1) + return (ENXIO); + + if ((len = OF_getproplen(node, "device-id")) <= 0) + return (ENXIO); + + OF_getprop(node, "device-id", &dts_value, len); + sc->device_id = fdt32_to_cpu(dts_value); + + sc->dma_stop = dma_stop; + sc->dma_setup = dma_setup; + sc->dma_request = dma_request; + sc->channel_configure = channel_configure; + sc->channel_free = channel_free; + + if (bus_alloc_resources(dev, edma_spec, sc->res)) { + device_printf(dev, "could not allocate resources\n"); + return (ENXIO); + } + + /* Memory interface */ + sc->bst = rman_get_bustag(sc->res[0]); + sc->bsh = rman_get_bushandle(sc->res[0]); + sc->bst_tcd = rman_get_bustag(sc->res[1]); + sc->bsh_tcd = rman_get_bushandle(sc->res[1]); + + /* Setup interrupt handlers */ + if (bus_setup_intr(dev, sc->res[2], INTR_TYPE_BIO | INTR_MPSAFE, + NULL, edma_transfer_complete_intr, sc, &sc->tc_ih)) { + device_printf(dev, "Unable to alloc DMA intr resource.\n"); + return (ENXIO); + } + + if (bus_setup_intr(dev, sc->res[3], INTR_TYPE_BIO | INTR_MPSAFE, + NULL, edma_err_intr, sc, &sc->err_ih)) { + device_printf(dev, "Unable to alloc DMA Err intr resource.\n"); + return (ENXIO); + } + + return (0); +} + +static device_method_t edma_methods[] = { + DEVMETHOD(device_probe, edma_probe), + DEVMETHOD(device_attach, edma_attach), + { 0, 0 } +}; + +static driver_t edma_driver = { + "edma", + edma_methods, + sizeof(struct edma_softc), +}; + +static devclass_t edma_devclass; + +DRIVER_MODULE(edma, simplebus, edma_driver, edma_devclass, 0, 0); diff --git a/sys/arm/freescale/vybrid/vf_edma.h b/sys/arm/freescale/vybrid/vf_edma.h new file mode 100644 index 0000000..5f77eacc --- /dev/null +++ b/sys/arm/freescale/vybrid/vf_edma.h @@ -0,0 +1,186 @@ +/*- + * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> + * 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$ + */ + +#define DMA_CR 0x000 /* Control */ +#define DMA_ES 0x004 /* Error Status */ +#define DMA_ERQ 0x00C /* Enable Request */ +#define DMA_EEI 0x014 /* Enable Error Interrupt */ +#define DMA_CEEI 0x018 /* Clear Enable Error Interrupt */ +#define DMA_SEEI 0x019 /* Set Enable Error Interrupt */ +#define DMA_CERQ 0x01A /* Clear Enable Request */ +#define DMA_SERQ 0x01B /* Set Enable Request */ +#define DMA_CDNE 0x01C /* Clear DONE Status Bit */ +#define DMA_SSRT 0x01D /* Set START Bit */ +#define DMA_CERR 0x01E /* Clear Error */ +#define CERR_CAEI (1 << 6) /* Clear All Error Indicators */ +#define DMA_CINT 0x01F /* Clear Interrupt Request */ +#define CINT_CAIR (1 << 6) /* Clear All Interrupt Requests */ +#define DMA_INT 0x024 /* Interrupt Request */ +#define DMA_ERR 0x02C /* Error */ +#define DMA_HRS 0x034 /* Hardware Request Status */ +#define DMA_EARS 0x044 /* Enable Asynchronous Request in Stop */ +#define DMA_DCHPRI3 0x100 /* Channel n Priority */ +#define DMA_DCHPRI2 0x101 /* Channel n Priority */ +#define DMA_DCHPRI1 0x102 /* Channel n Priority */ +#define DMA_DCHPRI0 0x103 /* Channel n Priority */ +#define DMA_DCHPRI7 0x104 /* Channel n Priority */ +#define DMA_DCHPRI6 0x105 /* Channel n Priority */ +#define DMA_DCHPRI5 0x106 /* Channel n Priority */ +#define DMA_DCHPRI4 0x107 /* Channel n Priority */ +#define DMA_DCHPRI11 0x108 /* Channel n Priority */ +#define DMA_DCHPRI10 0x109 /* Channel n Priority */ +#define DMA_DCHPRI9 0x10A /* Channel n Priority */ +#define DMA_DCHPRI8 0x10B /* Channel n Priority */ +#define DMA_DCHPRI15 0x10C /* Channel n Priority */ +#define DMA_DCHPRI14 0x10D /* Channel n Priority */ +#define DMA_DCHPRI13 0x10E /* Channel n Priority */ +#define DMA_DCHPRI12 0x10F /* Channel n Priority */ +#define DMA_DCHPRI19 0x110 /* Channel n Priority */ +#define DMA_DCHPRI18 0x111 /* Channel n Priority */ +#define DMA_DCHPRI17 0x112 /* Channel n Priority */ +#define DMA_DCHPRI16 0x113 /* Channel n Priority */ +#define DMA_DCHPRI23 0x114 /* Channel n Priority */ +#define DMA_DCHPRI22 0x115 /* Channel n Priority */ +#define DMA_DCHPRI21 0x116 /* Channel n Priority */ +#define DMA_DCHPRI20 0x117 /* Channel n Priority */ +#define DMA_DCHPRI27 0x118 /* Channel n Priority */ +#define DMA_DCHPRI26 0x119 /* Channel n Priority */ +#define DMA_DCHPRI25 0x11A /* Channel n Priority */ +#define DMA_DCHPRI24 0x11B /* Channel n Priority */ +#define DMA_DCHPRI31 0x11C /* Channel n Priority */ +#define DMA_DCHPRI30 0x11D /* Channel n Priority */ +#define DMA_DCHPRI29 0x11E /* Channel n Priority */ +#define DMA_DCHPRI28 0x11F /* Channel n Priority */ + +#define DMA_TCDn_SADDR(n) (0x00 + 0x20 * n) /* Source Address */ +#define DMA_TCDn_SOFF(n) (0x04 + 0x20 * n) /* Signed Source Address Offset */ +#define DMA_TCDn_ATTR(n) (0x06 + 0x20 * n) /* Transfer Attributes */ +#define DMA_TCDn_NBYTES_MLNO(n) (0x08 + 0x20 * n) /* Minor Byte Count */ +#define DMA_TCDn_NBYTES_MLOFFNO(n) (0x08 + 0x20 * n) /* Signed Minor Loop Offset */ +#define DMA_TCDn_NBYTES_MLOFFYES(n) (0x08 + 0x20 * n) /* Signed Minor Loop Offset */ +#define DMA_TCDn_SLAST(n) (0x0C + 0x20 * n) /* Last Source Address Adjustment */ +#define DMA_TCDn_DADDR(n) (0x10 + 0x20 * n) /* Destination Address */ +#define DMA_TCDn_DOFF(n) (0x14 + 0x20 * n) /* Signed Destination Address Offset */ +#define DMA_TCDn_CITER_ELINKYES(n) (0x16 + 0x20 * n) /* Current Minor Loop Link, Major Loop Count */ +#define DMA_TCDn_CITER_ELINKNO(n) (0x16 + 0x20 * n) +#define DMA_TCDn_DLASTSGA(n) (0x18 + 0x20 * n) /* Last Dst Addr Adjustment/Scatter Gather Address */ +#define DMA_TCDn_CSR(n) (0x1C + 0x20 * n) /* Control and Status */ +#define DMA_TCDn_BITER_ELINKYES(n) (0x1E + 0x20 * n) /* Beginning Minor Loop Link, Major Loop Count */ +#define DMA_TCDn_BITER_ELINKNO(n) (0x1E + 0x20 * n) /* Beginning Minor Loop Link, Major Loop Count */ + +#define TCD_CSR_START (1 << 0) +#define TCD_CSR_INTMAJOR (1 << 1) +#define TCD_CSR_INTHALF (1 << 2) +#define TCD_CSR_DREQ (1 << 3) +#define TCD_CSR_ESG (1 << 4) +#define TCD_CSR_MAJORELINK (1 << 5) +#define TCD_CSR_ACTIVE (1 << 6) +#define TCD_CSR_DONE (1 << 7) +#define TCD_CSR_MAJORELINKCH_SHIFT 8 + +#define TCD_ATTR_SMOD_SHIFT 11 /* Source Address Modulo */ +#define TCD_ATTR_SSIZE_SHIFT 8 /* Source Data Transfer Size */ +#define TCD_ATTR_DMOD_SHIFT 3 /* Dst Address Modulo */ +#define TCD_ATTR_DSIZE_SHIFT 0 /* Dst Data Transfer Size */ + +#define TCD_READ4(_sc, _reg) \ + bus_space_read_4(_sc->bst_tcd, _sc->bsh_tcd, _reg) +#define TCD_WRITE4(_sc, _reg, _val) \ + bus_space_write_4(_sc->bst_tcd, _sc->bsh_tcd, _reg, _val) +#define TCD_READ2(_sc, _reg) \ + bus_space_read_2(_sc->bst_tcd, _sc->bsh_tcd, _reg) +#define TCD_WRITE2(_sc, _reg, _val) \ + bus_space_write_2(_sc->bst_tcd, _sc->bsh_tcd, _reg, _val) +#define TCD_READ1(_sc, _reg) \ + bus_space_read_1(_sc->bst_tcd, _sc->bsh_tcd, _reg) +#define TCD_WRITE1(_sc, _reg, _val) \ + bus_space_write_1(_sc->bst_tcd, _sc->bsh_tcd, _reg, _val) + +#define EDMA_NUM_DEVICES 2 +#define EDMA_NUM_CHANNELS 32 +#define NCHAN_PER_MUX 16 + +struct tcd_conf { + bus_addr_t saddr; + bus_addr_t daddr; + uint32_t nbytes; + uint32_t nmajor; + uint32_t majorelink; + uint32_t majorelinkch; + uint32_t esg; + uint32_t smod; + uint32_t dmod; + uint32_t soff; + uint32_t doff; + uint32_t ssize; + uint32_t dsize; + uint32_t slast; + uint32_t dlast_sga; + uint32_t channel; + uint32_t (*ih)(void *, int); + void *ih_user; +}; + +/* + * TCD struct is described at + * Vybrid Reference Manual, Rev. 5, 07/2013 + * + * Should be used for Scatter/Gathering feature. + */ + +struct TCD { + uint32_t saddr; + uint16_t attr; + uint16_t soff; + uint32_t nbytes; + uint32_t slast; + uint32_t daddr; + uint16_t citer; + uint16_t doff; + uint32_t dlast_sga; + uint16_t biter; + uint16_t csr; +} __packed; + +struct edma_softc { + device_t dev; + struct resource *res[4]; + bus_space_tag_t bst; + bus_space_handle_t bsh; + bus_space_tag_t bst_tcd; + bus_space_handle_t bsh_tcd; + void *tc_ih; + void *err_ih; + uint32_t device_id; + + int (*channel_configure) (struct edma_softc *, int, int); + int (*channel_free) (struct edma_softc *, int); + int (*dma_request) (struct edma_softc *, int); + int (*dma_setup) (struct edma_softc *, struct tcd_conf *); + int (*dma_stop) (struct edma_softc *, int); +}; |