1*cdafe74eSOleksandr Tymoshenko /* 2*cdafe74eSOleksandr Tymoshenko * Copyright (c) 2013 Daisuke Aoyama <aoyama@peach.ne.jp> 3*cdafe74eSOleksandr Tymoshenko * Copyright (c) 2013 Oleksandr Tymoshenko <gonzo@bluezbox.com> 4*cdafe74eSOleksandr Tymoshenko * 5*cdafe74eSOleksandr Tymoshenko * Redistribution and use in source and binary forms, with or without 6*cdafe74eSOleksandr Tymoshenko * modification, are permitted provided that the following conditions 7*cdafe74eSOleksandr Tymoshenko * are met: 8*cdafe74eSOleksandr Tymoshenko * 1. Redistributions of source code must retain the above copyright 9*cdafe74eSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer. 10*cdafe74eSOleksandr Tymoshenko * 2. Redistributions in binary form must reproduce the above copyright 11*cdafe74eSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer in the 12*cdafe74eSOleksandr Tymoshenko * documentation and/or other materials provided with the distribution. 13*cdafe74eSOleksandr Tymoshenko * 14*cdafe74eSOleksandr Tymoshenko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*cdafe74eSOleksandr Tymoshenko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*cdafe74eSOleksandr Tymoshenko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*cdafe74eSOleksandr Tymoshenko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*cdafe74eSOleksandr Tymoshenko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*cdafe74eSOleksandr Tymoshenko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*cdafe74eSOleksandr Tymoshenko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*cdafe74eSOleksandr Tymoshenko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*cdafe74eSOleksandr Tymoshenko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*cdafe74eSOleksandr Tymoshenko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*cdafe74eSOleksandr Tymoshenko * SUCH DAMAGE. 25*cdafe74eSOleksandr Tymoshenko * 26*cdafe74eSOleksandr Tymoshenko */ 27*cdafe74eSOleksandr Tymoshenko 28*cdafe74eSOleksandr Tymoshenko #include <sys/cdefs.h> 29*cdafe74eSOleksandr Tymoshenko __FBSDID("$FreeBSD$"); 30*cdafe74eSOleksandr Tymoshenko 31*cdafe74eSOleksandr Tymoshenko #include <sys/param.h> 32*cdafe74eSOleksandr Tymoshenko #include <sys/systm.h> 33*cdafe74eSOleksandr Tymoshenko #include <sys/bus.h> 34*cdafe74eSOleksandr Tymoshenko #include <sys/kernel.h> 35*cdafe74eSOleksandr Tymoshenko #include <sys/lock.h> 36*cdafe74eSOleksandr Tymoshenko #include <sys/malloc.h> 37*cdafe74eSOleksandr Tymoshenko #include <sys/module.h> 38*cdafe74eSOleksandr Tymoshenko #include <sys/mutex.h> 39*cdafe74eSOleksandr Tymoshenko #include <sys/queue.h> 40*cdafe74eSOleksandr Tymoshenko #include <sys/resource.h> 41*cdafe74eSOleksandr Tymoshenko #include <sys/rman.h> 42*cdafe74eSOleksandr Tymoshenko 43*cdafe74eSOleksandr Tymoshenko #include <dev/fdt/fdt_common.h> 44*cdafe74eSOleksandr Tymoshenko #include <dev/ofw/openfirm.h> 45*cdafe74eSOleksandr Tymoshenko #include <dev/ofw/ofw_bus.h> 46*cdafe74eSOleksandr Tymoshenko #include <dev/ofw/ofw_bus_subr.h> 47*cdafe74eSOleksandr Tymoshenko 48*cdafe74eSOleksandr Tymoshenko #include <vm/vm.h> 49*cdafe74eSOleksandr Tymoshenko #include <vm/pmap.h> 50*cdafe74eSOleksandr Tymoshenko #include <machine/bus.h> 51*cdafe74eSOleksandr Tymoshenko #include <machine/cpu.h> 52*cdafe74eSOleksandr Tymoshenko #include <machine/cpufunc.h> 53*cdafe74eSOleksandr Tymoshenko #include <machine/pmap.h> 54*cdafe74eSOleksandr Tymoshenko 55*cdafe74eSOleksandr Tymoshenko #include "bcm2835_dma.h" 56*cdafe74eSOleksandr Tymoshenko #include "bcm2835_vcbus.h" 57*cdafe74eSOleksandr Tymoshenko 58*cdafe74eSOleksandr Tymoshenko #define MAX_REG 9 59*cdafe74eSOleksandr Tymoshenko 60*cdafe74eSOleksandr Tymoshenko /* private flags */ 61*cdafe74eSOleksandr Tymoshenko #define BCM_DMA_CH_USED 0x00000001 62*cdafe74eSOleksandr Tymoshenko #define BCM_DMA_CH_FREE 0x40000000 63*cdafe74eSOleksandr Tymoshenko #define BCM_DMA_CH_UNMAP 0x80000000 64*cdafe74eSOleksandr Tymoshenko 65*cdafe74eSOleksandr Tymoshenko /* Register Map (4.2.1.2) */ 66*cdafe74eSOleksandr Tymoshenko #define BCM_DMA_CS(n) (0x100*(n) + 0x00) 67*cdafe74eSOleksandr Tymoshenko #define CS_ACTIVE (1 << 0) 68*cdafe74eSOleksandr Tymoshenko #define CS_END (1 << 1) 69*cdafe74eSOleksandr Tymoshenko #define CS_INT (1 << 2) 70*cdafe74eSOleksandr Tymoshenko #define CS_DREQ (1 << 3) 71*cdafe74eSOleksandr Tymoshenko #define CS_ISPAUSED (1 << 4) 72*cdafe74eSOleksandr Tymoshenko #define CS_ISHELD (1 << 5) 73*cdafe74eSOleksandr Tymoshenko #define CS_ISWAIT (1 << 6) 74*cdafe74eSOleksandr Tymoshenko #define CS_ERR (1 << 8) 75*cdafe74eSOleksandr Tymoshenko #define CS_WAITWRT (1 << 28) 76*cdafe74eSOleksandr Tymoshenko #define CS_DISDBG (1 << 29) 77*cdafe74eSOleksandr Tymoshenko #define CS_ABORT (1 << 30) 78*cdafe74eSOleksandr Tymoshenko #define CS_RESET (1 << 31) 79*cdafe74eSOleksandr Tymoshenko #define BCM_DMA_CBADDR(n) (0x100*(n) + 0x04) 80*cdafe74eSOleksandr Tymoshenko #define BCM_DMA_INFO(n) (0x100*(n) + 0x08) 81*cdafe74eSOleksandr Tymoshenko #define INFO_INT_EN (1 << 0) 82*cdafe74eSOleksandr Tymoshenko #define INFO_TDMODE (1 << 1) 83*cdafe74eSOleksandr Tymoshenko #define INFO_WAIT_RESP (1 << 3) 84*cdafe74eSOleksandr Tymoshenko #define INFO_D_INC (1 << 4) 85*cdafe74eSOleksandr Tymoshenko #define INFO_D_WIDTH (1 << 5) 86*cdafe74eSOleksandr Tymoshenko #define INFO_D_DREQ (1 << 6) 87*cdafe74eSOleksandr Tymoshenko #define INFO_S_INC (1 << 8) 88*cdafe74eSOleksandr Tymoshenko #define INFO_S_WIDTH (1 << 9) 89*cdafe74eSOleksandr Tymoshenko #define INFO_S_DREQ (1 << 10) 90*cdafe74eSOleksandr Tymoshenko #define INFO_WAITS_SHIFT (21) 91*cdafe74eSOleksandr Tymoshenko #define INFO_PERMAP_SHIFT (16) 92*cdafe74eSOleksandr Tymoshenko #define INFO_PERMAP_MASK (0x1f << INFO_PERMAP_SHIFT) 93*cdafe74eSOleksandr Tymoshenko 94*cdafe74eSOleksandr Tymoshenko #define BCM_DMA_SRC(n) (0x100*(n) + 0x0C) 95*cdafe74eSOleksandr Tymoshenko #define BCM_DMA_DST(n) (0x100*(n) + 0x10) 96*cdafe74eSOleksandr Tymoshenko #define BCM_DMA_LEN(n) (0x100*(n) + 0x14) 97*cdafe74eSOleksandr Tymoshenko #define BCM_DMA_STRIDE(n) (0x100*(n) + 0x18) 98*cdafe74eSOleksandr Tymoshenko #define BCM_DMA_CBNEXT(n) (0x100*(n) + 0x1C) 99*cdafe74eSOleksandr Tymoshenko #define BCM_DMA_DEBUG(n) (0x100*(n) + 0x20) 100*cdafe74eSOleksandr Tymoshenko #define DEBUG_ERROR_MASK (7) 101*cdafe74eSOleksandr Tymoshenko 102*cdafe74eSOleksandr Tymoshenko #define BCM_DMA_INT_STATUS 0xfe0 103*cdafe74eSOleksandr Tymoshenko #define BCM_DMA_ENABLE 0xff0 104*cdafe74eSOleksandr Tymoshenko 105*cdafe74eSOleksandr Tymoshenko /* relative offset from BCM_VC_DMA0_BASE (p.39) */ 106*cdafe74eSOleksandr Tymoshenko #define BCM_DMA_CH(n) (0x100*(n)) 107*cdafe74eSOleksandr Tymoshenko 108*cdafe74eSOleksandr Tymoshenko /* DMA Control Block - 256bit aligned (p.40) */ 109*cdafe74eSOleksandr Tymoshenko struct bcm_dma_cb { 110*cdafe74eSOleksandr Tymoshenko uint32_t info; /* Transfer Information */ 111*cdafe74eSOleksandr Tymoshenko uint32_t src; /* Source Address */ 112*cdafe74eSOleksandr Tymoshenko uint32_t dst; /* Destination Address */ 113*cdafe74eSOleksandr Tymoshenko uint32_t len; /* Transfer Length */ 114*cdafe74eSOleksandr Tymoshenko uint32_t stride; /* 2D Mode Stride */ 115*cdafe74eSOleksandr Tymoshenko uint32_t next; /* Next Control Block Address */ 116*cdafe74eSOleksandr Tymoshenko uint32_t rsvd1; /* Reserved */ 117*cdafe74eSOleksandr Tymoshenko uint32_t rsvd2; /* Reserved */ 118*cdafe74eSOleksandr Tymoshenko }; 119*cdafe74eSOleksandr Tymoshenko 120*cdafe74eSOleksandr Tymoshenko #ifdef DEBUG 121*cdafe74eSOleksandr Tymoshenko static void bcm_dma_cb_dump(struct bcm_dma_cb *cb); 122*cdafe74eSOleksandr Tymoshenko static void bcm_dma_reg_dump(int ch); 123*cdafe74eSOleksandr Tymoshenko #endif 124*cdafe74eSOleksandr Tymoshenko 125*cdafe74eSOleksandr Tymoshenko /* DMA channel private info */ 126*cdafe74eSOleksandr Tymoshenko struct bcm_dma_ch { 127*cdafe74eSOleksandr Tymoshenko int ch; 128*cdafe74eSOleksandr Tymoshenko uint32_t flags; 129*cdafe74eSOleksandr Tymoshenko struct bcm_dma_cb * cb; 130*cdafe74eSOleksandr Tymoshenko uint32_t vc_cb; 131*cdafe74eSOleksandr Tymoshenko bus_dmamap_t dma_map; 132*cdafe74eSOleksandr Tymoshenko void (*intr_func)(int, void *); 133*cdafe74eSOleksandr Tymoshenko void * intr_arg; 134*cdafe74eSOleksandr Tymoshenko }; 135*cdafe74eSOleksandr Tymoshenko 136*cdafe74eSOleksandr Tymoshenko struct bcm_dma_softc { 137*cdafe74eSOleksandr Tymoshenko device_t sc_dev; 138*cdafe74eSOleksandr Tymoshenko struct mtx sc_mtx; 139*cdafe74eSOleksandr Tymoshenko struct resource * sc_mem; 140*cdafe74eSOleksandr Tymoshenko struct resource * sc_irq[BCM_DMA_CH_MAX]; 141*cdafe74eSOleksandr Tymoshenko void * sc_intrhand[BCM_DMA_CH_MAX]; 142*cdafe74eSOleksandr Tymoshenko struct bcm_dma_ch sc_dma_ch[BCM_DMA_CH_MAX]; 143*cdafe74eSOleksandr Tymoshenko bus_dma_tag_t sc_dma_tag; 144*cdafe74eSOleksandr Tymoshenko }; 145*cdafe74eSOleksandr Tymoshenko 146*cdafe74eSOleksandr Tymoshenko static struct bcm_dma_softc *bcm_dma_sc = NULL; 147*cdafe74eSOleksandr Tymoshenko 148*cdafe74eSOleksandr Tymoshenko static void 149*cdafe74eSOleksandr Tymoshenko bcm_dmamap_cb(void *arg, bus_dma_segment_t *segs, 150*cdafe74eSOleksandr Tymoshenko int nseg, int err) 151*cdafe74eSOleksandr Tymoshenko { 152*cdafe74eSOleksandr Tymoshenko bus_addr_t *addr; 153*cdafe74eSOleksandr Tymoshenko 154*cdafe74eSOleksandr Tymoshenko if (err) 155*cdafe74eSOleksandr Tymoshenko return; 156*cdafe74eSOleksandr Tymoshenko 157*cdafe74eSOleksandr Tymoshenko addr = (bus_addr_t*)arg; 158*cdafe74eSOleksandr Tymoshenko *addr = PHYS_TO_VCBUS(segs[0].ds_addr); 159*cdafe74eSOleksandr Tymoshenko } 160*cdafe74eSOleksandr Tymoshenko 161*cdafe74eSOleksandr Tymoshenko static void 162*cdafe74eSOleksandr Tymoshenko bcm_dma_reset(device_t dev, int ch) 163*cdafe74eSOleksandr Tymoshenko { 164*cdafe74eSOleksandr Tymoshenko struct bcm_dma_softc *sc = device_get_softc(dev); 165*cdafe74eSOleksandr Tymoshenko struct bcm_dma_cb *cb; 166*cdafe74eSOleksandr Tymoshenko uint32_t cs; 167*cdafe74eSOleksandr Tymoshenko int count; 168*cdafe74eSOleksandr Tymoshenko 169*cdafe74eSOleksandr Tymoshenko if (ch < 0 || ch >= BCM_DMA_CH_MAX) 170*cdafe74eSOleksandr Tymoshenko return; 171*cdafe74eSOleksandr Tymoshenko 172*cdafe74eSOleksandr Tymoshenko cs = bus_read_4(sc->sc_mem, BCM_DMA_CS(ch)); 173*cdafe74eSOleksandr Tymoshenko 174*cdafe74eSOleksandr Tymoshenko if (cs & CS_ACTIVE) { 175*cdafe74eSOleksandr Tymoshenko /* pause current task */ 176*cdafe74eSOleksandr Tymoshenko bus_write_4(sc->sc_mem, BCM_DMA_CS(ch), 0); 177*cdafe74eSOleksandr Tymoshenko 178*cdafe74eSOleksandr Tymoshenko count = 1000; 179*cdafe74eSOleksandr Tymoshenko do { 180*cdafe74eSOleksandr Tymoshenko cs = bus_read_4(sc->sc_mem, BCM_DMA_CS(ch)); 181*cdafe74eSOleksandr Tymoshenko } while (!(cs & CS_ISPAUSED) && (count-- > 0)); 182*cdafe74eSOleksandr Tymoshenko 183*cdafe74eSOleksandr Tymoshenko if (!(cs & CS_ISPAUSED)) { 184*cdafe74eSOleksandr Tymoshenko device_printf(dev, 185*cdafe74eSOleksandr Tymoshenko "Can't abort DMA transfer at channel %d\n", ch); 186*cdafe74eSOleksandr Tymoshenko } 187*cdafe74eSOleksandr Tymoshenko 188*cdafe74eSOleksandr Tymoshenko bus_write_4(sc->sc_mem, BCM_DMA_CBNEXT(ch), 0); 189*cdafe74eSOleksandr Tymoshenko 190*cdafe74eSOleksandr Tymoshenko /* Complete everything, clear interrupt */ 191*cdafe74eSOleksandr Tymoshenko bus_write_4(sc->sc_mem, BCM_DMA_CS(ch), 192*cdafe74eSOleksandr Tymoshenko CS_ABORT | CS_INT | CS_END| CS_ACTIVE); 193*cdafe74eSOleksandr Tymoshenko } 194*cdafe74eSOleksandr Tymoshenko 195*cdafe74eSOleksandr Tymoshenko /* clear control blocks */ 196*cdafe74eSOleksandr Tymoshenko bus_write_4(sc->sc_mem, BCM_DMA_CBADDR(ch), 0); 197*cdafe74eSOleksandr Tymoshenko bus_write_4(sc->sc_mem, BCM_DMA_CBNEXT(ch), 0); 198*cdafe74eSOleksandr Tymoshenko 199*cdafe74eSOleksandr Tymoshenko /* Reset control block */ 200*cdafe74eSOleksandr Tymoshenko cb = sc->sc_dma_ch[ch].cb; 201*cdafe74eSOleksandr Tymoshenko bzero(cb, sizeof(cb)); 202*cdafe74eSOleksandr Tymoshenko } 203*cdafe74eSOleksandr Tymoshenko 204*cdafe74eSOleksandr Tymoshenko static int 205*cdafe74eSOleksandr Tymoshenko bcm_dma_init(device_t dev) 206*cdafe74eSOleksandr Tymoshenko { 207*cdafe74eSOleksandr Tymoshenko struct bcm_dma_softc *sc = device_get_softc(dev); 208*cdafe74eSOleksandr Tymoshenko uint32_t mask; 209*cdafe74eSOleksandr Tymoshenko struct bcm_dma_ch *ch; 210*cdafe74eSOleksandr Tymoshenko void *cb_virt; 211*cdafe74eSOleksandr Tymoshenko vm_paddr_t cb_phys; 212*cdafe74eSOleksandr Tymoshenko int err; 213*cdafe74eSOleksandr Tymoshenko int i; 214*cdafe74eSOleksandr Tymoshenko 215*cdafe74eSOleksandr Tymoshenko /* disable and clear interrupt status */ 216*cdafe74eSOleksandr Tymoshenko bus_write_4(sc->sc_mem, BCM_DMA_ENABLE, 0); 217*cdafe74eSOleksandr Tymoshenko bus_write_4(sc->sc_mem, BCM_DMA_INT_STATUS, 0); 218*cdafe74eSOleksandr Tymoshenko 219*cdafe74eSOleksandr Tymoshenko /* Allocate DMA chunks control blocks */ 220*cdafe74eSOleksandr Tymoshenko /* p.40 of spec - control block should be 32-bit aligned */ 221*cdafe74eSOleksandr Tymoshenko err = bus_dma_tag_create(bus_get_dma_tag(dev), 222*cdafe74eSOleksandr Tymoshenko 1, 0, BUS_SPACE_MAXADDR_32BIT, 223*cdafe74eSOleksandr Tymoshenko BUS_SPACE_MAXADDR, NULL, NULL, 224*cdafe74eSOleksandr Tymoshenko sizeof(struct bcm_dma_cb), 1, 225*cdafe74eSOleksandr Tymoshenko sizeof(struct bcm_dma_cb), 226*cdafe74eSOleksandr Tymoshenko BUS_DMA_ALLOCNOW, NULL, NULL, 227*cdafe74eSOleksandr Tymoshenko &sc->sc_dma_tag); 228*cdafe74eSOleksandr Tymoshenko 229*cdafe74eSOleksandr Tymoshenko if (err) { 230*cdafe74eSOleksandr Tymoshenko device_printf(dev, "failed allocate DMA tag"); 231*cdafe74eSOleksandr Tymoshenko return (err); 232*cdafe74eSOleksandr Tymoshenko } 233*cdafe74eSOleksandr Tymoshenko 234*cdafe74eSOleksandr Tymoshenko /* setup initial settings */ 235*cdafe74eSOleksandr Tymoshenko for (i = 0; i < BCM_DMA_CH_MAX; i++) { 236*cdafe74eSOleksandr Tymoshenko ch = &sc->sc_dma_ch[i]; 237*cdafe74eSOleksandr Tymoshenko 238*cdafe74eSOleksandr Tymoshenko err = bus_dmamem_alloc(sc->sc_dma_tag, &cb_virt, 239*cdafe74eSOleksandr Tymoshenko BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, 240*cdafe74eSOleksandr Tymoshenko &ch->dma_map); 241*cdafe74eSOleksandr Tymoshenko if (err) { 242*cdafe74eSOleksandr Tymoshenko device_printf(dev, "cannot allocate DMA memory\n"); 243*cdafe74eSOleksandr Tymoshenko break; 244*cdafe74eSOleksandr Tymoshenko } 245*cdafe74eSOleksandr Tymoshenko 246*cdafe74eSOleksandr Tymoshenko /* 247*cdafe74eSOleksandr Tymoshenko * Least alignment for busdma-allocated stuff is cache 248*cdafe74eSOleksandr Tymoshenko * line size, so just make sure nothing stupid happend 249*cdafe74eSOleksandr Tymoshenko * and we got properly aligned address 250*cdafe74eSOleksandr Tymoshenko */ 251*cdafe74eSOleksandr Tymoshenko if ((uintptr_t)cb_virt & 0x1f) { 252*cdafe74eSOleksandr Tymoshenko device_printf(dev, 253*cdafe74eSOleksandr Tymoshenko "DMA address is not 32-bytes aligned: %p\n", 254*cdafe74eSOleksandr Tymoshenko (void*)cb_virt); 255*cdafe74eSOleksandr Tymoshenko break; 256*cdafe74eSOleksandr Tymoshenko } 257*cdafe74eSOleksandr Tymoshenko 258*cdafe74eSOleksandr Tymoshenko err = bus_dmamap_load(sc->sc_dma_tag, ch->dma_map, cb_virt, 259*cdafe74eSOleksandr Tymoshenko sizeof(struct bcm_dma_cb), bcm_dmamap_cb, &cb_phys, 260*cdafe74eSOleksandr Tymoshenko BUS_DMA_WAITOK); 261*cdafe74eSOleksandr Tymoshenko if (err) { 262*cdafe74eSOleksandr Tymoshenko device_printf(dev, "cannot load DMA memory\n"); 263*cdafe74eSOleksandr Tymoshenko break; 264*cdafe74eSOleksandr Tymoshenko } 265*cdafe74eSOleksandr Tymoshenko 266*cdafe74eSOleksandr Tymoshenko bzero(ch, sizeof(struct bcm_dma_ch)); 267*cdafe74eSOleksandr Tymoshenko ch->ch = i; 268*cdafe74eSOleksandr Tymoshenko ch->cb = cb_virt; 269*cdafe74eSOleksandr Tymoshenko ch->vc_cb = cb_phys; 270*cdafe74eSOleksandr Tymoshenko ch->intr_func = NULL; 271*cdafe74eSOleksandr Tymoshenko ch->intr_arg = NULL; 272*cdafe74eSOleksandr Tymoshenko ch->flags = BCM_DMA_CH_UNMAP; 273*cdafe74eSOleksandr Tymoshenko 274*cdafe74eSOleksandr Tymoshenko ch->cb->info = INFO_WAIT_RESP; 275*cdafe74eSOleksandr Tymoshenko 276*cdafe74eSOleksandr Tymoshenko /* reset DMA engine */ 277*cdafe74eSOleksandr Tymoshenko bcm_dma_reset(dev, i); 278*cdafe74eSOleksandr Tymoshenko } 279*cdafe74eSOleksandr Tymoshenko 280*cdafe74eSOleksandr Tymoshenko /* now use DMA2/DMA3 only */ 281*cdafe74eSOleksandr Tymoshenko sc->sc_dma_ch[2].flags = BCM_DMA_CH_FREE; 282*cdafe74eSOleksandr Tymoshenko sc->sc_dma_ch[3].flags = BCM_DMA_CH_FREE; 283*cdafe74eSOleksandr Tymoshenko 284*cdafe74eSOleksandr Tymoshenko /* enable DMAs */ 285*cdafe74eSOleksandr Tymoshenko mask = 0; 286*cdafe74eSOleksandr Tymoshenko 287*cdafe74eSOleksandr Tymoshenko for (i = 0; i < BCM_DMA_CH_MAX; i++) 288*cdafe74eSOleksandr Tymoshenko if (sc->sc_dma_ch[i].flags & BCM_DMA_CH_FREE) 289*cdafe74eSOleksandr Tymoshenko mask |= (1 << i); 290*cdafe74eSOleksandr Tymoshenko 291*cdafe74eSOleksandr Tymoshenko bus_write_4(sc->sc_mem, BCM_DMA_ENABLE, mask); 292*cdafe74eSOleksandr Tymoshenko 293*cdafe74eSOleksandr Tymoshenko return (0); 294*cdafe74eSOleksandr Tymoshenko } 295*cdafe74eSOleksandr Tymoshenko 296*cdafe74eSOleksandr Tymoshenko /* 297*cdafe74eSOleksandr Tymoshenko * Allocate DMA channel for further use, returns channel # or 298*cdafe74eSOleksandr Tymoshenko * BCM_DMA_CH_INVALID 299*cdafe74eSOleksandr Tymoshenko */ 300*cdafe74eSOleksandr Tymoshenko int 301*cdafe74eSOleksandr Tymoshenko bcm_dma_allocate(int req_ch) 302*cdafe74eSOleksandr Tymoshenko { 303*cdafe74eSOleksandr Tymoshenko struct bcm_dma_softc *sc = bcm_dma_sc; 304*cdafe74eSOleksandr Tymoshenko int ch = BCM_DMA_CH_INVALID; 305*cdafe74eSOleksandr Tymoshenko int i; 306*cdafe74eSOleksandr Tymoshenko 307*cdafe74eSOleksandr Tymoshenko if (req_ch >= BCM_DMA_CH_MAX) 308*cdafe74eSOleksandr Tymoshenko return (BCM_DMA_CH_INVALID); 309*cdafe74eSOleksandr Tymoshenko 310*cdafe74eSOleksandr Tymoshenko /* Auto(req_ch < 0) or CH specified */ 311*cdafe74eSOleksandr Tymoshenko mtx_lock(&sc->sc_mtx); 312*cdafe74eSOleksandr Tymoshenko 313*cdafe74eSOleksandr Tymoshenko if (req_ch < 0) { 314*cdafe74eSOleksandr Tymoshenko for (i = 0; i < BCM_DMA_CH_MAX; i++) { 315*cdafe74eSOleksandr Tymoshenko if (sc->sc_dma_ch[i].flags & BCM_DMA_CH_FREE) { 316*cdafe74eSOleksandr Tymoshenko ch = i; 317*cdafe74eSOleksandr Tymoshenko sc->sc_dma_ch[ch].flags &= ~BCM_DMA_CH_FREE; 318*cdafe74eSOleksandr Tymoshenko sc->sc_dma_ch[ch].flags |= BCM_DMA_CH_USED; 319*cdafe74eSOleksandr Tymoshenko break; 320*cdafe74eSOleksandr Tymoshenko } 321*cdafe74eSOleksandr Tymoshenko } 322*cdafe74eSOleksandr Tymoshenko } 323*cdafe74eSOleksandr Tymoshenko else { 324*cdafe74eSOleksandr Tymoshenko if (sc->sc_dma_ch[req_ch].flags & BCM_DMA_CH_FREE) { 325*cdafe74eSOleksandr Tymoshenko ch = req_ch; 326*cdafe74eSOleksandr Tymoshenko sc->sc_dma_ch[ch].flags &= ~BCM_DMA_CH_FREE; 327*cdafe74eSOleksandr Tymoshenko sc->sc_dma_ch[ch].flags |= BCM_DMA_CH_USED; 328*cdafe74eSOleksandr Tymoshenko } 329*cdafe74eSOleksandr Tymoshenko } 330*cdafe74eSOleksandr Tymoshenko 331*cdafe74eSOleksandr Tymoshenko mtx_unlock(&sc->sc_mtx); 332*cdafe74eSOleksandr Tymoshenko return (ch); 333*cdafe74eSOleksandr Tymoshenko } 334*cdafe74eSOleksandr Tymoshenko 335*cdafe74eSOleksandr Tymoshenko /* 336*cdafe74eSOleksandr Tymoshenko * Frees allocated channel. Returns 0 on success, -1 otherwise 337*cdafe74eSOleksandr Tymoshenko */ 338*cdafe74eSOleksandr Tymoshenko int 339*cdafe74eSOleksandr Tymoshenko bcm_dma_free(int ch) 340*cdafe74eSOleksandr Tymoshenko { 341*cdafe74eSOleksandr Tymoshenko struct bcm_dma_softc *sc = bcm_dma_sc; 342*cdafe74eSOleksandr Tymoshenko 343*cdafe74eSOleksandr Tymoshenko if (ch < 0 || ch >= BCM_DMA_CH_MAX) 344*cdafe74eSOleksandr Tymoshenko return (-1); 345*cdafe74eSOleksandr Tymoshenko 346*cdafe74eSOleksandr Tymoshenko mtx_lock(&sc->sc_mtx); 347*cdafe74eSOleksandr Tymoshenko if (sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED) { 348*cdafe74eSOleksandr Tymoshenko sc->sc_dma_ch[ch].flags |= BCM_DMA_CH_FREE; 349*cdafe74eSOleksandr Tymoshenko sc->sc_dma_ch[ch].flags &= ~BCM_DMA_CH_USED; 350*cdafe74eSOleksandr Tymoshenko sc->sc_dma_ch[ch].intr_func = NULL; 351*cdafe74eSOleksandr Tymoshenko sc->sc_dma_ch[ch].intr_arg = NULL; 352*cdafe74eSOleksandr Tymoshenko 353*cdafe74eSOleksandr Tymoshenko /* reset DMA engine */ 354*cdafe74eSOleksandr Tymoshenko bcm_dma_reset(sc->sc_dev, ch); 355*cdafe74eSOleksandr Tymoshenko } 356*cdafe74eSOleksandr Tymoshenko 357*cdafe74eSOleksandr Tymoshenko mtx_unlock(&sc->sc_mtx); 358*cdafe74eSOleksandr Tymoshenko return (0); 359*cdafe74eSOleksandr Tymoshenko } 360*cdafe74eSOleksandr Tymoshenko 361*cdafe74eSOleksandr Tymoshenko /* 362*cdafe74eSOleksandr Tymoshenko * Assign handler function for channel interrupt 363*cdafe74eSOleksandr Tymoshenko * Returns 0 on success, -1 otherwise 364*cdafe74eSOleksandr Tymoshenko */ 365*cdafe74eSOleksandr Tymoshenko int 366*cdafe74eSOleksandr Tymoshenko bcm_dma_setup_intr(int ch, void (*func)(int, void *), void *arg) 367*cdafe74eSOleksandr Tymoshenko { 368*cdafe74eSOleksandr Tymoshenko struct bcm_dma_softc *sc = bcm_dma_sc; 369*cdafe74eSOleksandr Tymoshenko struct bcm_dma_cb *cb; 370*cdafe74eSOleksandr Tymoshenko 371*cdafe74eSOleksandr Tymoshenko if (ch < 0 || ch >= BCM_DMA_CH_MAX) 372*cdafe74eSOleksandr Tymoshenko return (-1); 373*cdafe74eSOleksandr Tymoshenko 374*cdafe74eSOleksandr Tymoshenko if (!(sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED)) 375*cdafe74eSOleksandr Tymoshenko return (-1); 376*cdafe74eSOleksandr Tymoshenko 377*cdafe74eSOleksandr Tymoshenko sc->sc_dma_ch[ch].intr_func = func; 378*cdafe74eSOleksandr Tymoshenko sc->sc_dma_ch[ch].intr_arg = arg; 379*cdafe74eSOleksandr Tymoshenko cb = sc->sc_dma_ch[ch].cb; 380*cdafe74eSOleksandr Tymoshenko cb->info |= INFO_INT_EN; 381*cdafe74eSOleksandr Tymoshenko 382*cdafe74eSOleksandr Tymoshenko return (0); 383*cdafe74eSOleksandr Tymoshenko } 384*cdafe74eSOleksandr Tymoshenko 385*cdafe74eSOleksandr Tymoshenko /* 386*cdafe74eSOleksandr Tymoshenko * Setup DMA source parameters 387*cdafe74eSOleksandr Tymoshenko * ch - channel number 388*cdafe74eSOleksandr Tymoshenko * dreq - hardware DREQ # or BCM_DMA_DREQ_NONE if 389*cdafe74eSOleksandr Tymoshenko * source is physical memory 390*cdafe74eSOleksandr Tymoshenko * inc_addr - BCM_DMA_INC_ADDR if source address 391*cdafe74eSOleksandr Tymoshenko * should be increased after each access or 392*cdafe74eSOleksandr Tymoshenko * BCM_DMA_SAME_ADDR if address should remain 393*cdafe74eSOleksandr Tymoshenko * the same 394*cdafe74eSOleksandr Tymoshenko * width - size of read operation, BCM_DMA_32BIT 395*cdafe74eSOleksandr Tymoshenko * for 32bit bursts, BCM_DMA_128BIT for 128 bits 396*cdafe74eSOleksandr Tymoshenko * 397*cdafe74eSOleksandr Tymoshenko * Returns 0 on success, -1 otherwise 398*cdafe74eSOleksandr Tymoshenko */ 399*cdafe74eSOleksandr Tymoshenko int 400*cdafe74eSOleksandr Tymoshenko bcm_dma_setup_src(int ch, int dreq, int inc_addr, int width) 401*cdafe74eSOleksandr Tymoshenko { 402*cdafe74eSOleksandr Tymoshenko struct bcm_dma_softc *sc = bcm_dma_sc; 403*cdafe74eSOleksandr Tymoshenko uint32_t info; 404*cdafe74eSOleksandr Tymoshenko 405*cdafe74eSOleksandr Tymoshenko if (ch < 0 || ch >= BCM_DMA_CH_MAX) 406*cdafe74eSOleksandr Tymoshenko return (-1); 407*cdafe74eSOleksandr Tymoshenko 408*cdafe74eSOleksandr Tymoshenko if (!(sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED)) 409*cdafe74eSOleksandr Tymoshenko return (-1); 410*cdafe74eSOleksandr Tymoshenko 411*cdafe74eSOleksandr Tymoshenko info = sc->sc_dma_ch[ch].cb->info; 412*cdafe74eSOleksandr Tymoshenko info &= ~INFO_PERMAP_MASK; 413*cdafe74eSOleksandr Tymoshenko info |= (dreq << INFO_PERMAP_SHIFT) & INFO_PERMAP_MASK; 414*cdafe74eSOleksandr Tymoshenko 415*cdafe74eSOleksandr Tymoshenko if (dreq) 416*cdafe74eSOleksandr Tymoshenko info |= INFO_S_DREQ; 417*cdafe74eSOleksandr Tymoshenko else 418*cdafe74eSOleksandr Tymoshenko info &= ~INFO_S_DREQ; 419*cdafe74eSOleksandr Tymoshenko 420*cdafe74eSOleksandr Tymoshenko if (width == BCM_DMA_128BIT) 421*cdafe74eSOleksandr Tymoshenko info |= INFO_S_WIDTH; 422*cdafe74eSOleksandr Tymoshenko else 423*cdafe74eSOleksandr Tymoshenko info &= ~INFO_S_WIDTH; 424*cdafe74eSOleksandr Tymoshenko 425*cdafe74eSOleksandr Tymoshenko if (inc_addr == BCM_DMA_INC_ADDR) 426*cdafe74eSOleksandr Tymoshenko info |= INFO_S_INC; 427*cdafe74eSOleksandr Tymoshenko else 428*cdafe74eSOleksandr Tymoshenko info &= ~INFO_S_INC; 429*cdafe74eSOleksandr Tymoshenko 430*cdafe74eSOleksandr Tymoshenko sc->sc_dma_ch[ch].cb->info = info; 431*cdafe74eSOleksandr Tymoshenko 432*cdafe74eSOleksandr Tymoshenko return (0); 433*cdafe74eSOleksandr Tymoshenko } 434*cdafe74eSOleksandr Tymoshenko 435*cdafe74eSOleksandr Tymoshenko /* 436*cdafe74eSOleksandr Tymoshenko * Setup DMA destination parameters 437*cdafe74eSOleksandr Tymoshenko * ch - channel number 438*cdafe74eSOleksandr Tymoshenko * dreq - hardware DREQ # or BCM_DMA_DREQ_NONE if 439*cdafe74eSOleksandr Tymoshenko * destination is physical memory 440*cdafe74eSOleksandr Tymoshenko * inc_addr - BCM_DMA_INC_ADDR if source address 441*cdafe74eSOleksandr Tymoshenko * should be increased after each access or 442*cdafe74eSOleksandr Tymoshenko * BCM_DMA_SAME_ADDR if address should remain 443*cdafe74eSOleksandr Tymoshenko * the same 444*cdafe74eSOleksandr Tymoshenko * width - size of write operation, BCM_DMA_32BIT 445*cdafe74eSOleksandr Tymoshenko * for 32bit bursts, BCM_DMA_128BIT for 128 bits 446*cdafe74eSOleksandr Tymoshenko * 447*cdafe74eSOleksandr Tymoshenko * Returns 0 on success, -1 otherwise 448*cdafe74eSOleksandr Tymoshenko */ 449*cdafe74eSOleksandr Tymoshenko int 450*cdafe74eSOleksandr Tymoshenko bcm_dma_setup_dst(int ch, int dreq, int inc_addr, int width) 451*cdafe74eSOleksandr Tymoshenko { 452*cdafe74eSOleksandr Tymoshenko struct bcm_dma_softc *sc = bcm_dma_sc; 453*cdafe74eSOleksandr Tymoshenko uint32_t info; 454*cdafe74eSOleksandr Tymoshenko 455*cdafe74eSOleksandr Tymoshenko if (ch < 0 || ch >= BCM_DMA_CH_MAX) 456*cdafe74eSOleksandr Tymoshenko return (-1); 457*cdafe74eSOleksandr Tymoshenko 458*cdafe74eSOleksandr Tymoshenko if (!(sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED)) 459*cdafe74eSOleksandr Tymoshenko return (-1); 460*cdafe74eSOleksandr Tymoshenko 461*cdafe74eSOleksandr Tymoshenko info = sc->sc_dma_ch[ch].cb->info; 462*cdafe74eSOleksandr Tymoshenko info &= ~INFO_PERMAP_MASK; 463*cdafe74eSOleksandr Tymoshenko info |= (dreq << INFO_PERMAP_SHIFT) & INFO_PERMAP_MASK; 464*cdafe74eSOleksandr Tymoshenko 465*cdafe74eSOleksandr Tymoshenko if (dreq) 466*cdafe74eSOleksandr Tymoshenko info |= INFO_D_DREQ; 467*cdafe74eSOleksandr Tymoshenko else 468*cdafe74eSOleksandr Tymoshenko info &= ~INFO_D_DREQ; 469*cdafe74eSOleksandr Tymoshenko 470*cdafe74eSOleksandr Tymoshenko if (width == BCM_DMA_128BIT) 471*cdafe74eSOleksandr Tymoshenko info |= INFO_D_WIDTH; 472*cdafe74eSOleksandr Tymoshenko else 473*cdafe74eSOleksandr Tymoshenko info &= ~INFO_D_WIDTH; 474*cdafe74eSOleksandr Tymoshenko 475*cdafe74eSOleksandr Tymoshenko if (inc_addr == BCM_DMA_INC_ADDR) 476*cdafe74eSOleksandr Tymoshenko info |= INFO_D_INC; 477*cdafe74eSOleksandr Tymoshenko else 478*cdafe74eSOleksandr Tymoshenko info &= ~INFO_D_INC; 479*cdafe74eSOleksandr Tymoshenko 480*cdafe74eSOleksandr Tymoshenko sc->sc_dma_ch[ch].cb->info = info; 481*cdafe74eSOleksandr Tymoshenko 482*cdafe74eSOleksandr Tymoshenko return (0); 483*cdafe74eSOleksandr Tymoshenko } 484*cdafe74eSOleksandr Tymoshenko 485*cdafe74eSOleksandr Tymoshenko #ifdef DEBUG 486*cdafe74eSOleksandr Tymoshenko void 487*cdafe74eSOleksandr Tymoshenko bcm_dma_cb_dump(struct bcm_dma_cb *cb) 488*cdafe74eSOleksandr Tymoshenko { 489*cdafe74eSOleksandr Tymoshenko 490*cdafe74eSOleksandr Tymoshenko printf("DMA CB "); 491*cdafe74eSOleksandr Tymoshenko printf("INFO: %8.8x ", cb->info); 492*cdafe74eSOleksandr Tymoshenko printf("SRC: %8.8x ", cb->src); 493*cdafe74eSOleksandr Tymoshenko printf("DST: %8.8x ", cb->dst); 494*cdafe74eSOleksandr Tymoshenko printf("LEN: %8.8x ", cb->len); 495*cdafe74eSOleksandr Tymoshenko printf("\n"); 496*cdafe74eSOleksandr Tymoshenko printf("STRIDE: %8.8x ", cb->stride); 497*cdafe74eSOleksandr Tymoshenko printf("NEXT: %8.8x ", cb->next); 498*cdafe74eSOleksandr Tymoshenko printf("RSVD1: %8.8x ", cb->rsvd1); 499*cdafe74eSOleksandr Tymoshenko printf("RSVD2: %8.8x ", cb->rsvd2); 500*cdafe74eSOleksandr Tymoshenko printf("\n"); 501*cdafe74eSOleksandr Tymoshenko } 502*cdafe74eSOleksandr Tymoshenko 503*cdafe74eSOleksandr Tymoshenko void 504*cdafe74eSOleksandr Tymoshenko bcm_dma_reg_dump(int ch) 505*cdafe74eSOleksandr Tymoshenko { 506*cdafe74eSOleksandr Tymoshenko struct bcm_dma_softc *sc = bcm_dma_sc; 507*cdafe74eSOleksandr Tymoshenko int i; 508*cdafe74eSOleksandr Tymoshenko uint32_t reg; 509*cdafe74eSOleksandr Tymoshenko 510*cdafe74eSOleksandr Tymoshenko if (ch < 0 || ch >= BCM_DMA_CH_MAX) 511*cdafe74eSOleksandr Tymoshenko return; 512*cdafe74eSOleksandr Tymoshenko 513*cdafe74eSOleksandr Tymoshenko printf("DMA%d: ", ch); 514*cdafe74eSOleksandr Tymoshenko for (i = 0; i < MAX_REG; i++) { 515*cdafe74eSOleksandr Tymoshenko reg = bus_read_4(sc->sc_mem, BCM_DMA_CH(ch) + i*4); 516*cdafe74eSOleksandr Tymoshenko printf("%8.8x ", reg); 517*cdafe74eSOleksandr Tymoshenko } 518*cdafe74eSOleksandr Tymoshenko printf("\n"); 519*cdafe74eSOleksandr Tymoshenko } 520*cdafe74eSOleksandr Tymoshenko #endif 521*cdafe74eSOleksandr Tymoshenko 522*cdafe74eSOleksandr Tymoshenko /* 523*cdafe74eSOleksandr Tymoshenko * Start DMA transaction 524*cdafe74eSOleksandr Tymoshenko * ch - channel number 525*cdafe74eSOleksandr Tymoshenko * src, dst - source and destination address in 526*cdafe74eSOleksandr Tymoshenko * ARM physical memory address space. 527*cdafe74eSOleksandr Tymoshenko * len - amount of bytes to be transfered 528*cdafe74eSOleksandr Tymoshenko * 529*cdafe74eSOleksandr Tymoshenko * Returns 0 on success, -1 otherwise 530*cdafe74eSOleksandr Tymoshenko */ 531*cdafe74eSOleksandr Tymoshenko int 532*cdafe74eSOleksandr Tymoshenko bcm_dma_start(int ch, vm_paddr_t src, vm_paddr_t dst, int len) 533*cdafe74eSOleksandr Tymoshenko { 534*cdafe74eSOleksandr Tymoshenko struct bcm_dma_softc *sc = bcm_dma_sc; 535*cdafe74eSOleksandr Tymoshenko struct bcm_dma_cb *cb; 536*cdafe74eSOleksandr Tymoshenko 537*cdafe74eSOleksandr Tymoshenko if (ch < 0 || ch >= BCM_DMA_CH_MAX) 538*cdafe74eSOleksandr Tymoshenko return (-1); 539*cdafe74eSOleksandr Tymoshenko 540*cdafe74eSOleksandr Tymoshenko if (!(sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED)) 541*cdafe74eSOleksandr Tymoshenko return (-1); 542*cdafe74eSOleksandr Tymoshenko 543*cdafe74eSOleksandr Tymoshenko cb = sc->sc_dma_ch[ch].cb; 544*cdafe74eSOleksandr Tymoshenko if (BCM2835_ARM_IS_IO(src)) 545*cdafe74eSOleksandr Tymoshenko cb->src = IO_TO_VCBUS(src); 546*cdafe74eSOleksandr Tymoshenko else 547*cdafe74eSOleksandr Tymoshenko cb->src = PHYS_TO_VCBUS(src); 548*cdafe74eSOleksandr Tymoshenko if (BCM2835_ARM_IS_IO(dst)) 549*cdafe74eSOleksandr Tymoshenko cb->dst = IO_TO_VCBUS(dst); 550*cdafe74eSOleksandr Tymoshenko else 551*cdafe74eSOleksandr Tymoshenko cb->dst = PHYS_TO_VCBUS(dst); 552*cdafe74eSOleksandr Tymoshenko cb->len = len; 553*cdafe74eSOleksandr Tymoshenko 554*cdafe74eSOleksandr Tymoshenko bus_dmamap_sync(sc->sc_dma_tag, 555*cdafe74eSOleksandr Tymoshenko sc->sc_dma_ch[ch].dma_map, BUS_DMASYNC_PREWRITE); 556*cdafe74eSOleksandr Tymoshenko 557*cdafe74eSOleksandr Tymoshenko bus_write_4(sc->sc_mem, BCM_DMA_CBADDR(ch), 558*cdafe74eSOleksandr Tymoshenko sc->sc_dma_ch[ch].vc_cb); 559*cdafe74eSOleksandr Tymoshenko bus_write_4(sc->sc_mem, BCM_DMA_CS(ch), CS_ACTIVE); 560*cdafe74eSOleksandr Tymoshenko 561*cdafe74eSOleksandr Tymoshenko #ifdef DEBUG 562*cdafe74eSOleksandr Tymoshenko bcm_dma_cb_dump(sc->sc_dma_ch[ch].cb); 563*cdafe74eSOleksandr Tymoshenko bcm_dma_reg_dump(ch); 564*cdafe74eSOleksandr Tymoshenko #endif 565*cdafe74eSOleksandr Tymoshenko 566*cdafe74eSOleksandr Tymoshenko return (0); 567*cdafe74eSOleksandr Tymoshenko } 568*cdafe74eSOleksandr Tymoshenko 569*cdafe74eSOleksandr Tymoshenko /* 570*cdafe74eSOleksandr Tymoshenko * Get length requested for DMA transaction 571*cdafe74eSOleksandr Tymoshenko * ch - channel number 572*cdafe74eSOleksandr Tymoshenko * 573*cdafe74eSOleksandr Tymoshenko * Returns size of transaction, 0 if channel is invalid 574*cdafe74eSOleksandr Tymoshenko */ 575*cdafe74eSOleksandr Tymoshenko uint32_t 576*cdafe74eSOleksandr Tymoshenko bcm_dma_length(int ch) 577*cdafe74eSOleksandr Tymoshenko { 578*cdafe74eSOleksandr Tymoshenko struct bcm_dma_softc *sc = bcm_dma_sc; 579*cdafe74eSOleksandr Tymoshenko struct bcm_dma_cb *cb; 580*cdafe74eSOleksandr Tymoshenko 581*cdafe74eSOleksandr Tymoshenko if (ch < 0 || ch >= BCM_DMA_CH_MAX) 582*cdafe74eSOleksandr Tymoshenko return (0); 583*cdafe74eSOleksandr Tymoshenko 584*cdafe74eSOleksandr Tymoshenko if (!(sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED)) 585*cdafe74eSOleksandr Tymoshenko return (0); 586*cdafe74eSOleksandr Tymoshenko 587*cdafe74eSOleksandr Tymoshenko cb = sc->sc_dma_ch[ch].cb; 588*cdafe74eSOleksandr Tymoshenko 589*cdafe74eSOleksandr Tymoshenko return (cb->len); 590*cdafe74eSOleksandr Tymoshenko } 591*cdafe74eSOleksandr Tymoshenko 592*cdafe74eSOleksandr Tymoshenko static void 593*cdafe74eSOleksandr Tymoshenko bcm_dma_intr(void *arg) 594*cdafe74eSOleksandr Tymoshenko { 595*cdafe74eSOleksandr Tymoshenko struct bcm_dma_softc *sc = bcm_dma_sc; 596*cdafe74eSOleksandr Tymoshenko struct bcm_dma_ch *ch = (struct bcm_dma_ch *)arg; 597*cdafe74eSOleksandr Tymoshenko uint32_t cs, debug; 598*cdafe74eSOleksandr Tymoshenko 599*cdafe74eSOleksandr Tymoshenko /* my interrupt? */ 600*cdafe74eSOleksandr Tymoshenko cs = bus_read_4(sc->sc_mem, BCM_DMA_CS(ch->ch)); 601*cdafe74eSOleksandr Tymoshenko 602*cdafe74eSOleksandr Tymoshenko if (!(cs & (CS_INT | CS_ERR))) 603*cdafe74eSOleksandr Tymoshenko return; 604*cdafe74eSOleksandr Tymoshenko 605*cdafe74eSOleksandr Tymoshenko /* running? */ 606*cdafe74eSOleksandr Tymoshenko if (!(ch->flags & BCM_DMA_CH_USED)) { 607*cdafe74eSOleksandr Tymoshenko device_printf(sc->sc_dev, 608*cdafe74eSOleksandr Tymoshenko "unused DMA intr CH=%d, CS=%x\n", ch->ch, cs); 609*cdafe74eSOleksandr Tymoshenko return; 610*cdafe74eSOleksandr Tymoshenko } 611*cdafe74eSOleksandr Tymoshenko 612*cdafe74eSOleksandr Tymoshenko if (cs & CS_ERR) { 613*cdafe74eSOleksandr Tymoshenko debug = bus_read_4(sc->sc_mem, BCM_DMA_DEBUG(ch->ch)); 614*cdafe74eSOleksandr Tymoshenko device_printf(sc->sc_dev, "DMA error %d on CH%d\n", 615*cdafe74eSOleksandr Tymoshenko debug & DEBUG_ERROR_MASK, ch->ch); 616*cdafe74eSOleksandr Tymoshenko bus_write_4(sc->sc_mem, BCM_DMA_DEBUG(ch->ch), 617*cdafe74eSOleksandr Tymoshenko debug & DEBUG_ERROR_MASK); 618*cdafe74eSOleksandr Tymoshenko } 619*cdafe74eSOleksandr Tymoshenko 620*cdafe74eSOleksandr Tymoshenko if (cs & CS_INT) { 621*cdafe74eSOleksandr Tymoshenko /* acknowledge interrupt */ 622*cdafe74eSOleksandr Tymoshenko bus_write_4(sc->sc_mem, BCM_DMA_CS(ch->ch), 623*cdafe74eSOleksandr Tymoshenko CS_INT | CS_END); 624*cdafe74eSOleksandr Tymoshenko 625*cdafe74eSOleksandr Tymoshenko /* Prepare for possible access to len field */ 626*cdafe74eSOleksandr Tymoshenko bus_dmamap_sync(sc->sc_dma_tag, ch->dma_map, 627*cdafe74eSOleksandr Tymoshenko BUS_DMASYNC_POSTWRITE); 628*cdafe74eSOleksandr Tymoshenko 629*cdafe74eSOleksandr Tymoshenko /* save callback function and argument */ 630*cdafe74eSOleksandr Tymoshenko if (ch->intr_func) 631*cdafe74eSOleksandr Tymoshenko ch->intr_func(ch->ch, ch->intr_arg); 632*cdafe74eSOleksandr Tymoshenko } 633*cdafe74eSOleksandr Tymoshenko } 634*cdafe74eSOleksandr Tymoshenko 635*cdafe74eSOleksandr Tymoshenko static int 636*cdafe74eSOleksandr Tymoshenko bcm_dma_probe(device_t dev) 637*cdafe74eSOleksandr Tymoshenko { 638*cdafe74eSOleksandr Tymoshenko 639*cdafe74eSOleksandr Tymoshenko if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-dma")) 640*cdafe74eSOleksandr Tymoshenko return (ENXIO); 641*cdafe74eSOleksandr Tymoshenko 642*cdafe74eSOleksandr Tymoshenko device_set_desc(dev, "BCM2835 DMA Controller"); 643*cdafe74eSOleksandr Tymoshenko return (BUS_PROBE_DEFAULT); 644*cdafe74eSOleksandr Tymoshenko } 645*cdafe74eSOleksandr Tymoshenko 646*cdafe74eSOleksandr Tymoshenko static int 647*cdafe74eSOleksandr Tymoshenko bcm_dma_attach(device_t dev) 648*cdafe74eSOleksandr Tymoshenko { 649*cdafe74eSOleksandr Tymoshenko struct bcm_dma_softc *sc = device_get_softc(dev); 650*cdafe74eSOleksandr Tymoshenko int rid, err = 0; 651*cdafe74eSOleksandr Tymoshenko int i; 652*cdafe74eSOleksandr Tymoshenko 653*cdafe74eSOleksandr Tymoshenko sc->sc_dev = dev; 654*cdafe74eSOleksandr Tymoshenko 655*cdafe74eSOleksandr Tymoshenko if (bcm_dma_sc) 656*cdafe74eSOleksandr Tymoshenko return (ENXIO); 657*cdafe74eSOleksandr Tymoshenko 658*cdafe74eSOleksandr Tymoshenko for (i = 0; i < BCM_DMA_CH_MAX; i++) { 659*cdafe74eSOleksandr Tymoshenko sc->sc_irq[i] = NULL; 660*cdafe74eSOleksandr Tymoshenko sc->sc_intrhand[i] = NULL; 661*cdafe74eSOleksandr Tymoshenko } 662*cdafe74eSOleksandr Tymoshenko 663*cdafe74eSOleksandr Tymoshenko /* DMA0 - DMA14 */ 664*cdafe74eSOleksandr Tymoshenko rid = 0; 665*cdafe74eSOleksandr Tymoshenko sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 666*cdafe74eSOleksandr Tymoshenko if (sc->sc_mem == NULL) { 667*cdafe74eSOleksandr Tymoshenko device_printf(dev, "could not allocate memory resource\n"); 668*cdafe74eSOleksandr Tymoshenko return (ENXIO); 669*cdafe74eSOleksandr Tymoshenko } 670*cdafe74eSOleksandr Tymoshenko 671*cdafe74eSOleksandr Tymoshenko /* IRQ DMA0 - DMA11 XXX NOT USE DMA12(spurious?) */ 672*cdafe74eSOleksandr Tymoshenko for (rid = 0; rid < BCM_DMA_CH_MAX; rid++) { 673*cdafe74eSOleksandr Tymoshenko sc->sc_irq[rid] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 674*cdafe74eSOleksandr Tymoshenko RF_ACTIVE); 675*cdafe74eSOleksandr Tymoshenko if (sc->sc_irq[rid] == NULL) { 676*cdafe74eSOleksandr Tymoshenko device_printf(dev, "cannot allocate interrupt\n"); 677*cdafe74eSOleksandr Tymoshenko err = ENXIO; 678*cdafe74eSOleksandr Tymoshenko goto fail; 679*cdafe74eSOleksandr Tymoshenko } 680*cdafe74eSOleksandr Tymoshenko if (bus_setup_intr(dev, sc->sc_irq[rid], INTR_TYPE_MISC | INTR_MPSAFE, 681*cdafe74eSOleksandr Tymoshenko NULL, bcm_dma_intr, &sc->sc_dma_ch[rid], 682*cdafe74eSOleksandr Tymoshenko &sc->sc_intrhand[rid])) { 683*cdafe74eSOleksandr Tymoshenko device_printf(dev, "cannot setup interrupt handler\n"); 684*cdafe74eSOleksandr Tymoshenko err = ENXIO; 685*cdafe74eSOleksandr Tymoshenko goto fail; 686*cdafe74eSOleksandr Tymoshenko } 687*cdafe74eSOleksandr Tymoshenko } 688*cdafe74eSOleksandr Tymoshenko 689*cdafe74eSOleksandr Tymoshenko mtx_init(&sc->sc_mtx, "bcmdma", "bcmdma", MTX_DEF); 690*cdafe74eSOleksandr Tymoshenko bcm_dma_sc = sc; 691*cdafe74eSOleksandr Tymoshenko 692*cdafe74eSOleksandr Tymoshenko err = bcm_dma_init(dev); 693*cdafe74eSOleksandr Tymoshenko if (err) 694*cdafe74eSOleksandr Tymoshenko goto fail; 695*cdafe74eSOleksandr Tymoshenko 696*cdafe74eSOleksandr Tymoshenko return (err); 697*cdafe74eSOleksandr Tymoshenko 698*cdafe74eSOleksandr Tymoshenko fail: 699*cdafe74eSOleksandr Tymoshenko if (sc->sc_mem) 700*cdafe74eSOleksandr Tymoshenko bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem); 701*cdafe74eSOleksandr Tymoshenko 702*cdafe74eSOleksandr Tymoshenko for (i = 0; i < BCM_DMA_CH_MAX; i++) { 703*cdafe74eSOleksandr Tymoshenko if (sc->sc_intrhand[i]) 704*cdafe74eSOleksandr Tymoshenko bus_teardown_intr(dev, sc->sc_irq[i], sc->sc_intrhand[i]); 705*cdafe74eSOleksandr Tymoshenko if (sc->sc_irq[i]) 706*cdafe74eSOleksandr Tymoshenko bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq[i]); 707*cdafe74eSOleksandr Tymoshenko } 708*cdafe74eSOleksandr Tymoshenko 709*cdafe74eSOleksandr Tymoshenko return (err); 710*cdafe74eSOleksandr Tymoshenko } 711*cdafe74eSOleksandr Tymoshenko 712*cdafe74eSOleksandr Tymoshenko static device_method_t bcm_dma_methods[] = { 713*cdafe74eSOleksandr Tymoshenko DEVMETHOD(device_probe, bcm_dma_probe), 714*cdafe74eSOleksandr Tymoshenko DEVMETHOD(device_attach, bcm_dma_attach), 715*cdafe74eSOleksandr Tymoshenko { 0, 0 } 716*cdafe74eSOleksandr Tymoshenko }; 717*cdafe74eSOleksandr Tymoshenko 718*cdafe74eSOleksandr Tymoshenko static driver_t bcm_dma_driver = { 719*cdafe74eSOleksandr Tymoshenko "bcm_dma", 720*cdafe74eSOleksandr Tymoshenko bcm_dma_methods, 721*cdafe74eSOleksandr Tymoshenko sizeof(struct bcm_dma_softc), 722*cdafe74eSOleksandr Tymoshenko }; 723*cdafe74eSOleksandr Tymoshenko 724*cdafe74eSOleksandr Tymoshenko static devclass_t bcm_dma_devclass; 725*cdafe74eSOleksandr Tymoshenko 726*cdafe74eSOleksandr Tymoshenko DRIVER_MODULE(bcm_dma, simplebus, bcm_dma_driver, bcm_dma_devclass, 0, 0); 727*cdafe74eSOleksandr Tymoshenko MODULE_VERSION(bcm_dma, 1); 728