1 1.10 bjh21 /* $NetBSD: iomd_dma.c,v 1.10 2006/08/05 18:22:57 bjh21 Exp $ */ 2 1.1 reinoud 3 1.1 reinoud /* 4 1.1 reinoud * Copyright (c) 1995 Scott Stevens 5 1.1 reinoud * All rights reserved. 6 1.1 reinoud * 7 1.1 reinoud * Redistribution and use in source and binary forms, with or without 8 1.1 reinoud * modification, are permitted provided that the following conditions 9 1.1 reinoud * are met: 10 1.1 reinoud * 1. Redistributions of source code must retain the above copyright 11 1.1 reinoud * notice, this list of conditions and the following disclaimer. 12 1.1 reinoud * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 reinoud * notice, this list of conditions and the following disclaimer in the 14 1.1 reinoud * documentation and/or other materials provided with the distribution. 15 1.1 reinoud * 3. All advertising materials mentioning features or use of this software 16 1.1 reinoud * must display the following acknowledgement: 17 1.1 reinoud * This product includes software developed by Scott Stevens. 18 1.1 reinoud * 4. The name of the author may not be used to endorse or promote products 19 1.1 reinoud * derived from this software without specific prior written permission. 20 1.1 reinoud * 21 1.1 reinoud * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 1.1 reinoud * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 1.1 reinoud * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 1.1 reinoud * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 1.1 reinoud * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 1.1 reinoud * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 1.1 reinoud * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 1.1 reinoud * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 1.1 reinoud * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 1.1 reinoud * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 1.1 reinoud * 32 1.1 reinoud * RiscBSD kernel project 33 1.1 reinoud * 34 1.1 reinoud * dma.c 35 1.1 reinoud * 36 1.1 reinoud * Created : 15/03/97 37 1.1 reinoud */ 38 1.8 lukem 39 1.8 lukem #include <sys/cdefs.h> 40 1.10 bjh21 __KERNEL_RCSID(0, "$NetBSD: iomd_dma.c,v 1.10 2006/08/05 18:22:57 bjh21 Exp $"); 41 1.1 reinoud 42 1.1 reinoud #define DMA_DEBUG 43 1.1 reinoud #include <sys/param.h> 44 1.1 reinoud #include <sys/systm.h> 45 1.1 reinoud #include <sys/kernel.h> 46 1.1 reinoud 47 1.1 reinoud #include <uvm/uvm_extern.h> 48 1.1 reinoud 49 1.2 thorpej #include <machine/intr.h> 50 1.1 reinoud #include <machine/pmap.h> 51 1.1 reinoud #include <arm/iomd/iomdreg.h> 52 1.1 reinoud #include <arm/iomd/iomdvar.h> 53 1.1 reinoud #include <arm/iomd/iomd_dma.h> 54 1.1 reinoud 55 1.1 reinoud 56 1.1 reinoud /* 57 1.10 bjh21 * Only for non ARM7500 machines but the kernel could be booted on a 58 1.10 bjh21 * different machine 59 1.1 reinoud */ 60 1.1 reinoud 61 1.1 reinoud static struct dma_ctrl ctrl[6]; 62 1.1 reinoud 63 1.10 bjh21 void dma_dumpdc(struct dma_ctrl *); 64 1.1 reinoud 65 1.1 reinoud void 66 1.10 bjh21 dma_go(struct dma_ctrl *dp) 67 1.1 reinoud { 68 1.10 bjh21 69 1.1 reinoud #ifdef DMA_DEBUG 70 1.1 reinoud printf("dma_go()\n"); 71 1.1 reinoud #endif 72 1.10 bjh21 if (dp->dc_flags & DMA_FL_READY) { 73 1.1 reinoud dp->dc_flags = DMA_FL_ACTIVE; 74 1.1 reinoud enable_irq(IRQ_DMACH0 + dp->dc_channel); 75 1.10 bjh21 } else 76 1.1 reinoud panic("dma not ready"); 77 1.1 reinoud } 78 1.1 reinoud 79 1.1 reinoud int 80 1.10 bjh21 dma_reset(struct dma_ctrl *dp) 81 1.1 reinoud { 82 1.10 bjh21 83 1.1 reinoud #ifdef DMA_DEBUG 84 1.1 reinoud printf("dma_reset()\n"); 85 1.1 reinoud dma_dumpdc(dp); 86 1.1 reinoud #endif 87 1.1 reinoud *dp->dc_cr = DMA_CR_CLEAR; 88 1.1 reinoud dp->dc_flags = 0; 89 1.1 reinoud disable_irq(IRQ_DMACH0 + dp->dc_channel); 90 1.10 bjh21 return 0; 91 1.1 reinoud } 92 1.1 reinoud 93 1.1 reinoud /* 94 1.1 reinoud * Setup dma transfer, prior to the dma_go call 95 1.1 reinoud */ 96 1.1 reinoud int 97 1.10 bjh21 dma_setup(struct dma_ctrl *dp, u_char *start, int len, int readp) 98 1.1 reinoud { 99 1.10 bjh21 100 1.1 reinoud #ifdef DMA_DEBUG 101 1.10 bjh21 printf("dma_setup(start = %p, len = 0x%08x, readp = %d\n", 102 1.10 bjh21 start, len, readp); 103 1.1 reinoud #endif 104 1.10 bjh21 if (((u_int)start & (dp->dc_dmasize - 1)) || 105 1.1 reinoud (len & (dp->dc_dmasize - 1))) { 106 1.1 reinoud printf("dma_setup: unaligned DMA, %p (0x%08x)\n", 107 1.1 reinoud start, len); 108 1.1 reinoud } 109 1.10 bjh21 *dp->dc_cr = DMA_CR_CLEAR | DMA_CR_ENABLE | (readp?DMA_CR_DIR:0) | 110 1.10 bjh21 dp->dc_dmasize; 111 1.1 reinoud *dp->dc_cr = DMA_CR_ENABLE | (readp?DMA_CR_DIR:0) | dp->dc_dmasize; 112 1.1 reinoud 113 1.1 reinoud dp->dc_nextaddr = start; 114 1.1 reinoud dp->dc_len = len; 115 1.1 reinoud 116 1.1 reinoud dp->dc_flags = DMA_FL_READY; 117 1.10 bjh21 return 0; 118 1.1 reinoud } 119 1.1 reinoud 120 1.1 reinoud /* 121 1.1 reinoud * return true if DMA is active 122 1.1 reinoud */ 123 1.1 reinoud int 124 1.10 bjh21 dma_isactive(struct dma_ctrl *dp) 125 1.1 reinoud { 126 1.10 bjh21 127 1.10 bjh21 return dp->dc_flags & DMA_FL_ACTIVE; 128 1.1 reinoud } 129 1.1 reinoud 130 1.1 reinoud /* 131 1.1 reinoud * return true if interrupt pending 132 1.1 reinoud */ 133 1.1 reinoud int 134 1.10 bjh21 dma_isintr(struct dma_ctrl *dp) 135 1.1 reinoud { 136 1.10 bjh21 137 1.1 reinoud #ifdef DMA_DEBUG 138 1.1 reinoud /* printf("dma_isintr() returning %d\n", *dp->dc_st & DMA_ST_INT);*/ 139 1.1 reinoud #endif 140 1.10 bjh21 return *dp->dc_st & DMA_ST_INT; 141 1.1 reinoud } 142 1.1 reinoud 143 1.1 reinoud int 144 1.10 bjh21 dma_intr(void *cookie) 145 1.1 reinoud { 146 1.4 bjh21 struct dma_ctrl *dp = cookie; 147 1.1 reinoud u_char status = (*dp->dc_st) & DMA_ST_MASK; 148 1.5 thorpej paddr_t cur; 149 1.1 reinoud int len; 150 1.1 reinoud int bufap = 0; 151 1.1 reinoud 152 1.1 reinoud #ifdef DMA_DEBUG 153 1.1 reinoud printf("dma_intr() status = 0x%02x\n", status); 154 1.1 reinoud #endif 155 1.1 reinoud 156 1.10 bjh21 if (!(dp->dc_flags & DMA_FL_ACTIVE)) { 157 1.1 reinoud /* interrupt whilst not active */ 158 1.1 reinoud /* ie. last buffer programmed */ 159 1.1 reinoud dma_reset(dp); 160 1.10 bjh21 return 0; 161 1.1 reinoud } 162 1.1 reinoud 163 1.10 bjh21 switch (status) { 164 1.1 reinoud case DMA_ST_OVER | DMA_ST_INT: 165 1.1 reinoud case DMA_ST_OVER | DMA_ST_INT | DMA_ST_CHAN: 166 1.1 reinoud /* idle, either first buffer or finished */ 167 1.10 bjh21 if (status & DMA_ST_CHAN) { 168 1.1 reinoud /* fill buffer B */ 169 1.1 reinoud bufap = 0; 170 1.1 reinoud goto fill; 171 1.1 reinoud } 172 1.1 reinoud else { 173 1.1 reinoud /* fill buffer A */ 174 1.1 reinoud bufap = 1; 175 1.1 reinoud goto fill; 176 1.1 reinoud } 177 1.1 reinoud break; 178 1.1 reinoud case DMA_ST_INT: 179 1.1 reinoud case DMA_ST_INT | DMA_ST_CHAN: 180 1.1 reinoud /* buffer ready */ 181 1.10 bjh21 if (status & DMA_ST_CHAN) { 182 1.1 reinoud /* fill buffer A */ 183 1.1 reinoud bufap = 1; 184 1.1 reinoud goto fill; 185 1.1 reinoud } 186 1.1 reinoud else { 187 1.1 reinoud /* fill buffer B */ 188 1.1 reinoud bufap = 0; 189 1.1 reinoud goto fill; 190 1.1 reinoud } 191 1.1 reinoud break; 192 1.1 reinoud default: 193 1.1 reinoud /* Shouldn't be here */ 194 1.1 reinoud #ifdef DMA_DEBUG 195 1.1 reinoud printf("DMA ch %d bad status [%x]\n", dp->dc_channel, status); 196 1.1 reinoud dma_dumpdc(dp); 197 1.1 reinoud #endif 198 1.1 reinoud break; 199 1.1 reinoud } 200 1.1 reinoud 201 1.1 reinoud /* return(0);*/ 202 1.1 reinoud /* XXX */ 203 1.1 reinoud #define PHYS(x, y) pmap_extract(pmap_kernel(), (vaddr_t)x, (paddr_t *)(y)) 204 1.1 reinoud fill: 205 1.1 reinoud #ifdef DMA_DEBUG 206 1.1 reinoud printf("fill:\n"); 207 1.1 reinoud #endif 208 1.1 reinoud if (dp->dc_len == 0) goto done; 209 1.1 reinoud PHYS(dp->dc_nextaddr, &cur); 210 1.7 thorpej len = PAGE_SIZE - (cur & PGOFSET); 211 1.1 reinoud if (len > dp->dc_len) { 212 1.1 reinoud /* Last buffer */ 213 1.1 reinoud len = dp->dc_len; 214 1.1 reinoud } 215 1.1 reinoud 216 1.1 reinoud #ifdef DMA_DEBUG 217 1.1 reinoud dma_dumpdc(dp); 218 1.1 reinoud /* ptsc_dump_mem(dp->dc_nextaddr, len);*/ 219 1.1 reinoud #endif 220 1.1 reinoud /* 221 1.1 reinoud * Flush the cache for this address 222 1.1 reinoud */ 223 1.5 thorpej cpu_dcache_wbinv_range((vaddr_t)dp->dc_nextaddr, len); 224 1.1 reinoud 225 1.1 reinoud dp->dc_nextaddr += len; 226 1.1 reinoud dp->dc_len -= len; 227 1.1 reinoud 228 1.10 bjh21 if (bufap) { 229 1.1 reinoud *dp->dc_cura = (u_int)cur; 230 1.1 reinoud *dp->dc_enda = ((u_int)cur + len - dp->dc_dmasize) | 231 1.1 reinoud (dp->dc_len == 0 ? DMA_END_STOP : 0); 232 1.1 reinoud if (dp->dc_len == 0) { 233 1.1 reinoud /* Last buffer, fill other buffer with garbage */ 234 1.1 reinoud *dp->dc_endb = (u_int)cur; 235 1.1 reinoud } 236 1.10 bjh21 } else { 237 1.1 reinoud *dp->dc_curb = (u_int)cur; 238 1.1 reinoud *dp->dc_endb = ((u_int)cur + len - dp->dc_dmasize) | 239 1.1 reinoud (dp->dc_len == 0 ? DMA_END_STOP : 0); 240 1.1 reinoud if (dp->dc_len == 0) { 241 1.1 reinoud /* Last buffer, fill other buffer with garbage */ 242 1.1 reinoud *dp->dc_enda = (u_int)cur; 243 1.1 reinoud } 244 1.1 reinoud } 245 1.1 reinoud #ifdef DMA_DEBUG 246 1.1 reinoud dma_dumpdc(dp); 247 1.1 reinoud /* ptsc_dump_mem(dp->dc_nextaddr - len, len);*/ 248 1.1 reinoud printf("about to return\n"); 249 1.1 reinoud #endif 250 1.10 bjh21 return 1; 251 1.1 reinoud done: 252 1.1 reinoud #ifdef DMA_DEBUG 253 1.1 reinoud printf("done:\n"); 254 1.1 reinoud #endif 255 1.1 reinoud dp->dc_flags = 0; 256 1.1 reinoud *dp->dc_cr = 0; 257 1.1 reinoud disable_irq(IRQ_DMACH0 + dp->dc_channel); 258 1.1 reinoud #ifdef DMA_DEBUG 259 1.1 reinoud printf("about to return\n"); 260 1.1 reinoud #endif 261 1.10 bjh21 return 1; 262 1.1 reinoud } 263 1.1 reinoud 264 1.1 reinoud void 265 1.10 bjh21 dma_dumpdc(struct dma_ctrl *dc) 266 1.1 reinoud { 267 1.10 bjh21 268 1.1 reinoud printf("\ndc:\t%p\n" 269 1.1 reinoud "dc_channel:\t%p=0x%08x\tdc_flags:\t%p=0x%08x\n" 270 1.1 reinoud "dc_cura:\t%p=0x%08x\tdc_enda:\t%p=0x%08x\n" 271 1.1 reinoud "dc_curb:\t%p=0x%08x\tdc_endb:\t%p=0x%08x\n" 272 1.1 reinoud "dc_cr:\t%p=0x%02x\t\tdc_st:\t%p=0x%02x\n" 273 1.1 reinoud "dc_nextaddr:\t%p=0x%08x\tdc_len:\t%p=0x%08x\n", 274 1.1 reinoud dc, 275 1.1 reinoud &dc->dc_channel, (int)dc->dc_channel, 276 1.1 reinoud &dc->dc_flags, (int)dc->dc_flags, 277 1.1 reinoud dc->dc_cura, (int)*dc->dc_cura, 278 1.1 reinoud dc->dc_enda, (int)*dc->dc_enda, 279 1.1 reinoud dc->dc_curb, (int)*dc->dc_curb, 280 1.1 reinoud dc->dc_endb, (int)*dc->dc_endb, 281 1.1 reinoud dc->dc_cr, (int)*dc->dc_cr, 282 1.1 reinoud dc->dc_st, (int)(*dc->dc_st) & DMA_ST_MASK, 283 1.1 reinoud &dc->dc_nextaddr, (int)dc->dc_nextaddr, 284 1.1 reinoud &dc->dc_len, dc->dc_len); 285 1.1 reinoud } 286 1.1 reinoud 287 1.1 reinoud struct dma_ctrl * 288 1.10 bjh21 dma_init(int ch, int extp, int dmasize, int ipl) 289 1.1 reinoud { 290 1.1 reinoud struct dma_ctrl *dp = &ctrl[ch]; 291 1.1 reinoud int offset = ch * 0x20; 292 1.1 reinoud volatile u_char *dmaext = (volatile u_char *)(IOMD_ADDRESS(IOMD_DMAEXT)); 293 1.1 reinoud 294 1.1 reinoud printf("Initialising DMA channel %d\n", ch); 295 1.1 reinoud 296 1.1 reinoud dp->dc_channel = ch; 297 1.1 reinoud dp->dc_flags = 0; 298 1.1 reinoud dp->dc_dmasize = dmasize; 299 1.1 reinoud dp->dc_cura = (volatile u_int *)(IOMD_ADDRESS(IOMD_IO0CURA) + offset); 300 1.1 reinoud dp->dc_enda = (volatile u_int *)(IOMD_ADDRESS(IOMD_IO0ENDA) + offset); 301 1.1 reinoud dp->dc_curb = (volatile u_int *)(IOMD_ADDRESS(IOMD_IO0CURB) + offset); 302 1.1 reinoud dp->dc_endb = (volatile u_int *)(IOMD_ADDRESS(IOMD_IO0ENDB) + offset); 303 1.1 reinoud dp->dc_cr = (volatile u_char *)(IOMD_ADDRESS(IOMD_IO0CR) + offset); 304 1.1 reinoud dp->dc_st = (volatile u_char *)(IOMD_ADDRESS(IOMD_IO0ST) + offset); 305 1.1 reinoud 306 1.1 reinoud if (extp) 307 1.1 reinoud *dmaext |= (1 << ch); 308 1.1 reinoud 309 1.1 reinoud printf("about to claim interrupt\n"); 310 1.1 reinoud 311 1.1 reinoud dp->dc_ih.ih_func = dma_intr; 312 1.1 reinoud dp->dc_ih.ih_arg = dp; 313 1.1 reinoud dp->dc_ih.ih_level = ipl; 314 1.1 reinoud dp->dc_ih.ih_name = "dma"; 315 1.1 reinoud dp->dc_ih.ih_maskaddr = (u_int) IOMD_ADDRESS(IOMD_DMARQ); 316 1.1 reinoud dp->dc_ih.ih_maskbits = (1 << ch); 317 1.1 reinoud 318 1.1 reinoud if (irq_claim(IRQ_DMACH0 + ch, &dp->dc_ih)) 319 1.6 provos panic("Cannot install DMA IRQ handler"); 320 1.1 reinoud 321 1.10 bjh21 return dp; 322 1.1 reinoud } 323 1.1 reinoud 324