1 /* $NetBSD: dmac3.c,v 1.6 2003/07/15 02:59:28 lukem Exp $ */ 2 3 /*- 4 * Copyright (c) 2000 Tsubai Masanari. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: dmac3.c,v 1.6 2003/07/15 02:59:28 lukem Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/device.h> 34 #include <sys/kernel.h> 35 #include <sys/systm.h> 36 37 #include <uvm/uvm_extern.h> 38 39 #include <machine/locore.h> 40 41 #include <newsmips/apbus/apbusvar.h> 42 #include <newsmips/apbus/dmac3reg.h> 43 44 #include <mips/cache.h> 45 46 #define DMA_BURST 47 #define DMA_APAD_OFF 48 49 #ifdef DMA_APAD_OFF 50 # define APAD_MODE 0 51 #else 52 # define APAD_MODE DMAC3_CSR_APAD 53 #endif 54 55 #ifdef DMA_BURST 56 # define BURST_MODE (DMAC3_CSR_DBURST | DMAC3_CSR_MBURST) 57 #else 58 # define BURST_MODE 0 59 #endif 60 61 struct dmac3_softc { 62 struct device sc_dev; 63 struct dmac3reg *sc_reg; 64 vaddr_t sc_dmaaddr; 65 int *sc_dmamap; 66 int sc_conf; 67 int sc_ctlnum; 68 }; 69 70 int dmac3_match __P((struct device *, struct cfdata *, void *)); 71 void dmac3_attach __P((struct device *, struct device *, void *)); 72 73 paddr_t kvtophys __P((vaddr_t)); 74 75 CFATTACH_DECL(dmac, sizeof(struct dmac3_softc), 76 dmac3_match, dmac3_attach, NULL, NULL); 77 78 int 79 dmac3_match(parent, cf, aux) 80 struct device *parent; 81 struct cfdata *cf; 82 void *aux; 83 { 84 struct apbus_attach_args *apa = aux; 85 86 if (strcmp(apa->apa_name, "dmac3") == 0) 87 return 1; 88 89 return 0; 90 } 91 92 void 93 dmac3_attach(parent, self, aux) 94 struct device *parent, *self; 95 void *aux; 96 { 97 struct dmac3_softc *sc = (void *)self; 98 struct apbus_attach_args *apa = aux; 99 struct dmac3reg *reg; 100 101 static paddr_t dmamap = DMAC3_PAGEMAP; 102 static vaddr_t dmaaddr = 0; 103 104 reg = (void *)apa->apa_hwbase; 105 sc->sc_reg = reg; 106 sc->sc_ctlnum = apa->apa_ctlnum; 107 sc->sc_dmamap = (int *)dmamap; 108 sc->sc_dmaaddr = dmaaddr; 109 dmamap += 0x1000; 110 dmaaddr += 0x200000; 111 112 sc->sc_conf = DMAC3_CONF_PCEN | DMAC3_CONF_DCEN | DMAC3_CONF_FASTACCESS; 113 114 dmac3_reset(sc); 115 116 printf(" slot%d addr 0x%lx", apa->apa_slotno, apa->apa_hwbase); 117 printf(": ctlnum = %d, map = %p, va = %lx", 118 apa->apa_ctlnum, sc->sc_dmamap, sc->sc_dmaaddr); 119 printf("\n"); 120 } 121 122 void * 123 dmac3_link(ctlnum) 124 int ctlnum; 125 { 126 struct dmac3_softc *sc; 127 struct device *dv; 128 129 for (dv = alldevs.tqh_first; dv; dv = dv->dv_list.tqe_next) { 130 if (strncmp(dv->dv_xname, "dmac", 4) == 0) { 131 sc = (void *)dv; 132 if (sc->sc_ctlnum == ctlnum) 133 return sc; 134 } 135 } 136 return NULL; 137 } 138 139 void 140 dmac3_reset(sc) 141 struct dmac3_softc *sc; 142 { 143 struct dmac3reg *reg = sc->sc_reg; 144 145 reg->csr = DMAC3_CSR_RESET; 146 reg->csr = 0; 147 reg->intr = DMAC3_INTR_EOPIE | DMAC3_INTR_INTEN; 148 reg->conf = sc->sc_conf; 149 } 150 151 void 152 dmac3_start(sc, addr, len, direction) 153 struct dmac3_softc *sc; 154 vaddr_t addr; 155 int len, direction; 156 { 157 struct dmac3reg *reg = sc->sc_reg; 158 paddr_t pa; 159 vaddr_t start, end, v; 160 u_int *p; 161 162 if (reg->csr & DMAC3_CSR_ENABLE) 163 dmac3_reset(sc); 164 165 start = mips_trunc_page(addr); 166 end = mips_round_page(addr + len); 167 p = sc->sc_dmamap; 168 for (v = start; v < end; v += PAGE_SIZE) { 169 pa = kvtophys(v); 170 mips_dcache_wbinv_range(MIPS_PHYS_TO_KSEG0(pa), PAGE_SIZE); 171 *p++ = 0; 172 *p++ = (pa >> PGSHIFT) | 0xc0000000; 173 } 174 *p++ = 0; 175 *p++ = 0x003fffff; 176 177 addr &= PGOFSET; 178 addr += sc->sc_dmaaddr; 179 180 reg->len = len; 181 reg->addr = addr; 182 reg->intr = DMAC3_INTR_EOPIE | DMAC3_INTR_INTEN; 183 reg->csr = DMAC3_CSR_ENABLE | direction | BURST_MODE | APAD_MODE; 184 } 185 186 int 187 dmac3_intr(v) 188 void *v; 189 { 190 struct dmac3_softc *sc = v; 191 struct dmac3reg *reg = sc->sc_reg; 192 int intr, conf, rv = 1; 193 194 intr = reg->intr; 195 if ((intr & DMAC3_INTR_INT) == 0) 196 return 0; 197 198 /* clear interrupt */ 199 conf = reg->conf; 200 reg->conf = conf; 201 reg->intr = intr; 202 203 if (intr & DMAC3_INTR_PERR) { 204 printf("%s: intr = 0x%x\n", sc->sc_dev.dv_xname, intr); 205 rv = -1; 206 } 207 208 if (conf & (DMAC3_CONF_IPER | DMAC3_CONF_MPER | DMAC3_CONF_DERR)) { 209 printf("%s: conf = 0x%x\n", sc->sc_dev.dv_xname, conf); 210 if (conf & DMAC3_CONF_DERR) { 211 printf("DMA address = 0x%x\n", reg->addr); 212 printf("resetting DMA...\n"); 213 dmac3_reset(sc); 214 } 215 } 216 217 return rv; 218 } 219 220 void 221 dmac3_misc(sc, cmd) 222 struct dmac3_softc *sc; 223 int cmd; 224 { 225 struct dmac3reg *reg = sc->sc_reg; 226 int conf; 227 228 conf = DMAC3_CONF_PCEN | DMAC3_CONF_DCEN | cmd; 229 sc->sc_conf = conf; 230 reg->conf = conf; 231 } 232