1f3a72e40SRuslan Bukin /*- 2f3a72e40SRuslan Bukin * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> 3f3a72e40SRuslan Bukin * All rights reserved. 4f3a72e40SRuslan Bukin * 5f3a72e40SRuslan Bukin * Redistribution and use in source and binary forms, with or without 6f3a72e40SRuslan Bukin * modification, are permitted provided that the following conditions 7f3a72e40SRuslan Bukin * are met: 8f3a72e40SRuslan Bukin * 1. Redistributions of source code must retain the above copyright 9f3a72e40SRuslan Bukin * notice, this list of conditions and the following disclaimer. 10f3a72e40SRuslan Bukin * 2. Redistributions in binary form must reproduce the above copyright 11f3a72e40SRuslan Bukin * notice, this list of conditions and the following disclaimer in the 12f3a72e40SRuslan Bukin * documentation and/or other materials provided with the distribution. 13f3a72e40SRuslan Bukin * 14f3a72e40SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15f3a72e40SRuslan Bukin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16f3a72e40SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17f3a72e40SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18f3a72e40SRuslan Bukin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19f3a72e40SRuslan Bukin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20f3a72e40SRuslan Bukin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21f3a72e40SRuslan Bukin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22f3a72e40SRuslan Bukin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23f3a72e40SRuslan Bukin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24f3a72e40SRuslan Bukin * SUCH DAMAGE. 25f3a72e40SRuslan Bukin */ 26f3a72e40SRuslan Bukin 27f3a72e40SRuslan Bukin /* 28f3a72e40SRuslan Bukin * Vybrid Family Enhanced Direct Memory Access Controller (eDMA) 29f3a72e40SRuslan Bukin * Chapter 21, Vybrid Reference Manual, Rev. 5, 07/2013 30f3a72e40SRuslan Bukin */ 31f3a72e40SRuslan Bukin 32f3a72e40SRuslan Bukin #include <sys/cdefs.h> 33f3a72e40SRuslan Bukin __FBSDID("$FreeBSD$"); 34f3a72e40SRuslan Bukin 35f3a72e40SRuslan Bukin #include <sys/param.h> 36f3a72e40SRuslan Bukin #include <sys/systm.h> 37f3a72e40SRuslan Bukin #include <sys/bus.h> 38f3a72e40SRuslan Bukin #include <sys/kernel.h> 39f3a72e40SRuslan Bukin #include <sys/module.h> 40f3a72e40SRuslan Bukin #include <sys/malloc.h> 41f3a72e40SRuslan Bukin #include <sys/rman.h> 42f3a72e40SRuslan Bukin #include <sys/timeet.h> 43f3a72e40SRuslan Bukin #include <sys/timetc.h> 44f3a72e40SRuslan Bukin #include <sys/watchdog.h> 45f3a72e40SRuslan Bukin 46f3a72e40SRuslan Bukin #include <dev/ofw/openfirm.h> 47f3a72e40SRuslan Bukin #include <dev/ofw/ofw_bus.h> 48f3a72e40SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h> 49f3a72e40SRuslan Bukin 50f3a72e40SRuslan Bukin #include <machine/bus.h> 51f3a72e40SRuslan Bukin #include <machine/cpu.h> 52f3a72e40SRuslan Bukin #include <machine/intr.h> 53f3a72e40SRuslan Bukin 54f3a72e40SRuslan Bukin #include <arm/freescale/vybrid/vf_edma.h> 55f3a72e40SRuslan Bukin #include <arm/freescale/vybrid/vf_dmamux.h> 56f3a72e40SRuslan Bukin #include <arm/freescale/vybrid/vf_common.h> 57f3a72e40SRuslan Bukin 58f3a72e40SRuslan Bukin struct edma_channel { 59f3a72e40SRuslan Bukin uint32_t enabled; 60f3a72e40SRuslan Bukin uint32_t mux_num; 61f3a72e40SRuslan Bukin uint32_t mux_src; 62f3a72e40SRuslan Bukin uint32_t mux_chn; 63f3a72e40SRuslan Bukin uint32_t (*ih) (void *, int); 64f3a72e40SRuslan Bukin void *ih_user; 65f3a72e40SRuslan Bukin }; 66f3a72e40SRuslan Bukin 67f3a72e40SRuslan Bukin static struct edma_channel edma_map[EDMA_NUM_CHANNELS]; 68f3a72e40SRuslan Bukin 69f3a72e40SRuslan Bukin static struct resource_spec edma_spec[] = { 70f3a72e40SRuslan Bukin { SYS_RES_MEMORY, 0, RF_ACTIVE }, 71f3a72e40SRuslan Bukin { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* TCD */ 72f3a72e40SRuslan Bukin { SYS_RES_IRQ, 0, RF_ACTIVE }, /* Transfer complete */ 73f3a72e40SRuslan Bukin { SYS_RES_IRQ, 1, RF_ACTIVE }, /* Error Interrupt */ 74f3a72e40SRuslan Bukin { -1, 0 } 75f3a72e40SRuslan Bukin }; 76f3a72e40SRuslan Bukin 77f3a72e40SRuslan Bukin static int 78f3a72e40SRuslan Bukin edma_probe(device_t dev) 79f3a72e40SRuslan Bukin { 80f3a72e40SRuslan Bukin 81f3a72e40SRuslan Bukin if (!ofw_bus_status_okay(dev)) 82f3a72e40SRuslan Bukin return (ENXIO); 83f3a72e40SRuslan Bukin 84f3a72e40SRuslan Bukin if (!ofw_bus_is_compatible(dev, "fsl,mvf600-edma")) 85f3a72e40SRuslan Bukin return (ENXIO); 86f3a72e40SRuslan Bukin 87f3a72e40SRuslan Bukin device_set_desc(dev, "Vybrid Family eDMA Controller"); 88f3a72e40SRuslan Bukin return (BUS_PROBE_DEFAULT); 89f3a72e40SRuslan Bukin } 90f3a72e40SRuslan Bukin 91f3a72e40SRuslan Bukin static void 92f3a72e40SRuslan Bukin edma_transfer_complete_intr(void *arg) 93f3a72e40SRuslan Bukin { 94f3a72e40SRuslan Bukin struct edma_channel *ch; 95f3a72e40SRuslan Bukin struct edma_softc *sc; 96f3a72e40SRuslan Bukin int interrupts; 97f3a72e40SRuslan Bukin int i; 98f3a72e40SRuslan Bukin 99f3a72e40SRuslan Bukin sc = arg; 100f3a72e40SRuslan Bukin 101f3a72e40SRuslan Bukin interrupts = READ4(sc, DMA_INT); 102f3a72e40SRuslan Bukin WRITE1(sc, DMA_CINT, CINT_CAIR); 103f3a72e40SRuslan Bukin 104f3a72e40SRuslan Bukin for (i = 0; i < EDMA_NUM_CHANNELS; i++) { 105f3a72e40SRuslan Bukin if (interrupts & (0x1 << i)) { 106f3a72e40SRuslan Bukin ch = &edma_map[i]; 107f3a72e40SRuslan Bukin if (ch->enabled == 1) { 108f3a72e40SRuslan Bukin if (ch->ih != NULL) { 109f3a72e40SRuslan Bukin ch->ih(ch->ih_user, i); 110f3a72e40SRuslan Bukin } 111f3a72e40SRuslan Bukin } 112f3a72e40SRuslan Bukin } 113f3a72e40SRuslan Bukin } 114f3a72e40SRuslan Bukin } 115f3a72e40SRuslan Bukin 116f3a72e40SRuslan Bukin static void 117f3a72e40SRuslan Bukin edma_err_intr(void *arg) 118f3a72e40SRuslan Bukin { 119f3a72e40SRuslan Bukin struct edma_softc *sc; 120f3a72e40SRuslan Bukin int reg; 121f3a72e40SRuslan Bukin 122f3a72e40SRuslan Bukin sc = arg; 123f3a72e40SRuslan Bukin 124f3a72e40SRuslan Bukin reg = READ4(sc, DMA_ERR); 125f3a72e40SRuslan Bukin 126f3a72e40SRuslan Bukin #if 0 127f3a72e40SRuslan Bukin device_printf(sc->dev, "DMA_ERR 0x%08x, ES 0x%08x\n", 128f3a72e40SRuslan Bukin reg, READ4(sc, DMA_ES)); 129f3a72e40SRuslan Bukin #endif 130f3a72e40SRuslan Bukin 131f3a72e40SRuslan Bukin WRITE1(sc, DMA_CERR, CERR_CAEI); 132f3a72e40SRuslan Bukin } 133f3a72e40SRuslan Bukin 134f3a72e40SRuslan Bukin static int 135f3a72e40SRuslan Bukin channel_free(struct edma_softc *sc, int chnum) 136f3a72e40SRuslan Bukin { 137f3a72e40SRuslan Bukin struct edma_channel *ch; 138f3a72e40SRuslan Bukin 139f3a72e40SRuslan Bukin ch = &edma_map[chnum]; 140f3a72e40SRuslan Bukin ch->enabled = 0; 141f3a72e40SRuslan Bukin 142f3a72e40SRuslan Bukin dmamux_configure(ch->mux_num, ch->mux_src, ch->mux_chn, 0); 143f3a72e40SRuslan Bukin 144f3a72e40SRuslan Bukin return (0); 145f3a72e40SRuslan Bukin } 146f3a72e40SRuslan Bukin 147f3a72e40SRuslan Bukin static int 148f3a72e40SRuslan Bukin channel_configure(struct edma_softc *sc, int mux_grp, int mux_src) 149f3a72e40SRuslan Bukin { 150f3a72e40SRuslan Bukin struct edma_channel *ch; 151f3a72e40SRuslan Bukin int channel_first; 152f3a72e40SRuslan Bukin int mux_num; 153f3a72e40SRuslan Bukin int chnum; 154f3a72e40SRuslan Bukin int i; 155f3a72e40SRuslan Bukin 156f3a72e40SRuslan Bukin if ((sc->device_id == 0 && mux_grp == 1) || \ 157f3a72e40SRuslan Bukin (sc->device_id == 1 && mux_grp == 0)) { 158f3a72e40SRuslan Bukin channel_first = NCHAN_PER_MUX; 159f3a72e40SRuslan Bukin mux_num = (sc->device_id * 2) + 1; 160f3a72e40SRuslan Bukin } else { 161f3a72e40SRuslan Bukin channel_first = 0; 162f3a72e40SRuslan Bukin mux_num = sc->device_id * 2; 16374b8d63dSPedro F. Giffuni } 164f3a72e40SRuslan Bukin 165f3a72e40SRuslan Bukin /* Take first unused eDMA channel */ 166f3a72e40SRuslan Bukin ch = NULL; 167f3a72e40SRuslan Bukin for (i = channel_first; i < (channel_first + NCHAN_PER_MUX); i++) { 168f3a72e40SRuslan Bukin ch = &edma_map[i]; 169f3a72e40SRuslan Bukin if (ch->enabled == 0) { 170f3a72e40SRuslan Bukin break; 171f3a72e40SRuslan Bukin } 172f3a72e40SRuslan Bukin ch = NULL; 17374b8d63dSPedro F. Giffuni } 174f3a72e40SRuslan Bukin 175f3a72e40SRuslan Bukin if (ch == NULL) { 176f3a72e40SRuslan Bukin /* Can't find free channel */ 177f3a72e40SRuslan Bukin return (-1); 17874b8d63dSPedro F. Giffuni } 179f3a72e40SRuslan Bukin 180f3a72e40SRuslan Bukin chnum = i; 181f3a72e40SRuslan Bukin 182f3a72e40SRuslan Bukin ch->enabled = 1; 183f3a72e40SRuslan Bukin ch->mux_num = mux_num; 184f3a72e40SRuslan Bukin ch->mux_src = mux_src; 185f3a72e40SRuslan Bukin ch->mux_chn = (chnum - channel_first); /* 0 to 15 */ 186f3a72e40SRuslan Bukin 187f3a72e40SRuslan Bukin dmamux_configure(ch->mux_num, ch->mux_src, ch->mux_chn, 1); 188f3a72e40SRuslan Bukin 189f3a72e40SRuslan Bukin return (chnum); 190f3a72e40SRuslan Bukin } 191f3a72e40SRuslan Bukin 192f3a72e40SRuslan Bukin static int 193f3a72e40SRuslan Bukin dma_stop(struct edma_softc *sc, int chnum) 194f3a72e40SRuslan Bukin { 195f3a72e40SRuslan Bukin int reg; 196f3a72e40SRuslan Bukin 197f3a72e40SRuslan Bukin reg = READ4(sc, DMA_ERQ); 198f3a72e40SRuslan Bukin reg &= ~(0x1 << chnum); 199f3a72e40SRuslan Bukin WRITE4(sc, DMA_ERQ, reg); 200f3a72e40SRuslan Bukin 201f3a72e40SRuslan Bukin return (0); 202f3a72e40SRuslan Bukin } 203f3a72e40SRuslan Bukin 204f3a72e40SRuslan Bukin static int 205f3a72e40SRuslan Bukin dma_setup(struct edma_softc *sc, struct tcd_conf *tcd) 206f3a72e40SRuslan Bukin { 207f3a72e40SRuslan Bukin struct edma_channel *ch; 208f3a72e40SRuslan Bukin int chnum; 209f3a72e40SRuslan Bukin int reg; 210f3a72e40SRuslan Bukin 211f3a72e40SRuslan Bukin chnum = tcd->channel; 212f3a72e40SRuslan Bukin 213f3a72e40SRuslan Bukin ch = &edma_map[chnum]; 214f3a72e40SRuslan Bukin ch->ih = tcd->ih; 215f3a72e40SRuslan Bukin ch->ih_user = tcd->ih_user; 216f3a72e40SRuslan Bukin 217f3a72e40SRuslan Bukin TCD_WRITE4(sc, DMA_TCDn_SADDR(chnum), tcd->saddr); 218f3a72e40SRuslan Bukin TCD_WRITE4(sc, DMA_TCDn_DADDR(chnum), tcd->daddr); 219f3a72e40SRuslan Bukin 220f3a72e40SRuslan Bukin reg = (tcd->smod << TCD_ATTR_SMOD_SHIFT); 221f3a72e40SRuslan Bukin reg |= (tcd->dmod << TCD_ATTR_DMOD_SHIFT); 222f3a72e40SRuslan Bukin reg |= (tcd->ssize << TCD_ATTR_SSIZE_SHIFT); 223f3a72e40SRuslan Bukin reg |= (tcd->dsize << TCD_ATTR_DSIZE_SHIFT); 224f3a72e40SRuslan Bukin TCD_WRITE2(sc, DMA_TCDn_ATTR(chnum), reg); 225f3a72e40SRuslan Bukin 226f3a72e40SRuslan Bukin TCD_WRITE2(sc, DMA_TCDn_SOFF(chnum), tcd->soff); 227f3a72e40SRuslan Bukin TCD_WRITE2(sc, DMA_TCDn_DOFF(chnum), tcd->doff); 228f3a72e40SRuslan Bukin TCD_WRITE4(sc, DMA_TCDn_SLAST(chnum), tcd->slast); 229f3a72e40SRuslan Bukin TCD_WRITE4(sc, DMA_TCDn_DLASTSGA(chnum), tcd->dlast_sga); 230f3a72e40SRuslan Bukin TCD_WRITE4(sc, DMA_TCDn_NBYTES_MLOFFYES(chnum), tcd->nbytes); 231f3a72e40SRuslan Bukin 232f3a72e40SRuslan Bukin reg = tcd->nmajor; /* Current Major Iteration Count */ 233f3a72e40SRuslan Bukin TCD_WRITE2(sc, DMA_TCDn_CITER_ELINKNO(chnum), reg); 234f3a72e40SRuslan Bukin TCD_WRITE2(sc, DMA_TCDn_BITER_ELINKNO(chnum), reg); 235f3a72e40SRuslan Bukin 236f3a72e40SRuslan Bukin reg = (TCD_CSR_INTMAJOR); 237f3a72e40SRuslan Bukin if(tcd->majorelink == 1) { 238f3a72e40SRuslan Bukin reg |= TCD_CSR_MAJORELINK; 239f3a72e40SRuslan Bukin reg |= (tcd->majorelinkch << TCD_CSR_MAJORELINKCH_SHIFT); 240f3a72e40SRuslan Bukin } 241f3a72e40SRuslan Bukin TCD_WRITE2(sc, DMA_TCDn_CSR(chnum), reg); 242f3a72e40SRuslan Bukin 243f3a72e40SRuslan Bukin /* Enable requests */ 244f3a72e40SRuslan Bukin reg = READ4(sc, DMA_ERQ); 245f3a72e40SRuslan Bukin reg |= (0x1 << chnum); 246f3a72e40SRuslan Bukin WRITE4(sc, DMA_ERQ, reg); 247f3a72e40SRuslan Bukin 248f3a72e40SRuslan Bukin /* Enable error interrupts */ 249f3a72e40SRuslan Bukin reg = READ4(sc, DMA_EEI); 250f3a72e40SRuslan Bukin reg |= (0x1 << chnum); 251f3a72e40SRuslan Bukin WRITE4(sc, DMA_EEI, reg); 252f3a72e40SRuslan Bukin 253f3a72e40SRuslan Bukin return (0); 254f3a72e40SRuslan Bukin } 255f3a72e40SRuslan Bukin 256f3a72e40SRuslan Bukin static int 257f3a72e40SRuslan Bukin dma_request(struct edma_softc *sc, int chnum) 258f3a72e40SRuslan Bukin { 259f3a72e40SRuslan Bukin int reg; 260f3a72e40SRuslan Bukin 261f3a72e40SRuslan Bukin /* Start */ 262f3a72e40SRuslan Bukin reg = TCD_READ2(sc, DMA_TCDn_CSR(chnum)); 263f3a72e40SRuslan Bukin reg |= TCD_CSR_START; 264f3a72e40SRuslan Bukin TCD_WRITE2(sc, DMA_TCDn_CSR(chnum), reg); 265f3a72e40SRuslan Bukin 266f3a72e40SRuslan Bukin return (0); 267f3a72e40SRuslan Bukin } 268f3a72e40SRuslan Bukin 269f3a72e40SRuslan Bukin static int 270f3a72e40SRuslan Bukin edma_attach(device_t dev) 271f3a72e40SRuslan Bukin { 272f3a72e40SRuslan Bukin struct edma_softc *sc; 273f3a72e40SRuslan Bukin phandle_t node; 274f3a72e40SRuslan Bukin int dts_value; 275f3a72e40SRuslan Bukin int len; 276f3a72e40SRuslan Bukin 277f3a72e40SRuslan Bukin sc = device_get_softc(dev); 278f3a72e40SRuslan Bukin sc->dev = dev; 279f3a72e40SRuslan Bukin 280f3a72e40SRuslan Bukin if ((node = ofw_bus_get_node(sc->dev)) == -1) 281f3a72e40SRuslan Bukin return (ENXIO); 282f3a72e40SRuslan Bukin 283f3a72e40SRuslan Bukin if ((len = OF_getproplen(node, "device-id")) <= 0) 284f3a72e40SRuslan Bukin return (ENXIO); 285f3a72e40SRuslan Bukin 286*9783ea5cSAndrew Turner OF_getencprop(node, "device-id", &dts_value, len); 287*9783ea5cSAndrew Turner sc->device_id = dts_value; 288f3a72e40SRuslan Bukin 289f3a72e40SRuslan Bukin sc->dma_stop = dma_stop; 290f3a72e40SRuslan Bukin sc->dma_setup = dma_setup; 291f3a72e40SRuslan Bukin sc->dma_request = dma_request; 292f3a72e40SRuslan Bukin sc->channel_configure = channel_configure; 293f3a72e40SRuslan Bukin sc->channel_free = channel_free; 294f3a72e40SRuslan Bukin 295f3a72e40SRuslan Bukin if (bus_alloc_resources(dev, edma_spec, sc->res)) { 296f3a72e40SRuslan Bukin device_printf(dev, "could not allocate resources\n"); 297f3a72e40SRuslan Bukin return (ENXIO); 298f3a72e40SRuslan Bukin } 299f3a72e40SRuslan Bukin 300f3a72e40SRuslan Bukin /* Memory interface */ 301f3a72e40SRuslan Bukin sc->bst = rman_get_bustag(sc->res[0]); 302f3a72e40SRuslan Bukin sc->bsh = rman_get_bushandle(sc->res[0]); 303f3a72e40SRuslan Bukin sc->bst_tcd = rman_get_bustag(sc->res[1]); 304f3a72e40SRuslan Bukin sc->bsh_tcd = rman_get_bushandle(sc->res[1]); 305f3a72e40SRuslan Bukin 306f3a72e40SRuslan Bukin /* Setup interrupt handlers */ 307f3a72e40SRuslan Bukin if (bus_setup_intr(dev, sc->res[2], INTR_TYPE_BIO | INTR_MPSAFE, 308f3a72e40SRuslan Bukin NULL, edma_transfer_complete_intr, sc, &sc->tc_ih)) { 309f3a72e40SRuslan Bukin device_printf(dev, "Unable to alloc DMA intr resource.\n"); 310f3a72e40SRuslan Bukin return (ENXIO); 311f3a72e40SRuslan Bukin } 312f3a72e40SRuslan Bukin 313f3a72e40SRuslan Bukin if (bus_setup_intr(dev, sc->res[3], INTR_TYPE_BIO | INTR_MPSAFE, 314f3a72e40SRuslan Bukin NULL, edma_err_intr, sc, &sc->err_ih)) { 315f3a72e40SRuslan Bukin device_printf(dev, "Unable to alloc DMA Err intr resource.\n"); 316f3a72e40SRuslan Bukin return (ENXIO); 317f3a72e40SRuslan Bukin } 318f3a72e40SRuslan Bukin 319f3a72e40SRuslan Bukin return (0); 320f3a72e40SRuslan Bukin } 321f3a72e40SRuslan Bukin 322f3a72e40SRuslan Bukin static device_method_t edma_methods[] = { 323f3a72e40SRuslan Bukin DEVMETHOD(device_probe, edma_probe), 324f3a72e40SRuslan Bukin DEVMETHOD(device_attach, edma_attach), 325f3a72e40SRuslan Bukin { 0, 0 } 326f3a72e40SRuslan Bukin }; 327f3a72e40SRuslan Bukin 328f3a72e40SRuslan Bukin static driver_t edma_driver = { 329f3a72e40SRuslan Bukin "edma", 330f3a72e40SRuslan Bukin edma_methods, 331f3a72e40SRuslan Bukin sizeof(struct edma_softc), 332f3a72e40SRuslan Bukin }; 333f3a72e40SRuslan Bukin 334f3a72e40SRuslan Bukin static devclass_t edma_devclass; 335f3a72e40SRuslan Bukin 336f3a72e40SRuslan Bukin DRIVER_MODULE(edma, simplebus, edma_driver, edma_devclass, 0, 0); 337