1 /* $NetBSD: iomd_dma.c,v 1.9 2005/12/11 12:16:47 christos Exp $ */
4 * Copyright (c) 1995 Scott Stevens
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Scott Stevens.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * RiscBSD kernel project
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: iomd_dma.c,v 1.9 2005/12/11 12:16:47 christos Exp $");
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
47 #include <uvm/uvm_extern.h>
49 #include <machine/intr.h>
50 #include <machine/pmap.h>
51 #include <arm/iomd/iomdreg.h>
52 #include <arm/iomd/iomdvar.h>
53 #include <arm/iomd/iomd_dma.h>
57 * Only for non ARM7500 machines but the kernel could be booted on a
61 static struct dma_ctrl ctrl
[6];
63 void dma_dumpdc(struct dma_ctrl
*);
66 dma_go(struct dma_ctrl
*dp
)
72 if (dp
->dc_flags
& DMA_FL_READY
) {
73 dp
->dc_flags
= DMA_FL_ACTIVE
;
74 enable_irq(IRQ_DMACH0
+ dp
->dc_channel
);
76 panic("dma not ready");
80 dma_reset(struct dma_ctrl
*dp
)
84 printf("dma_reset()\n");
87 *dp
->dc_cr
= DMA_CR_CLEAR
;
89 disable_irq(IRQ_DMACH0
+ dp
->dc_channel
);
94 * Setup dma transfer, prior to the dma_go call
97 dma_setup(struct dma_ctrl
*dp
, u_char
*start
, int len
, int readp
)
101 printf("dma_setup(start = %p, len = 0x%08x, readp = %d\n",
104 if (((u_int
)start
& (dp
->dc_dmasize
- 1)) ||
105 (len
& (dp
->dc_dmasize
- 1))) {
106 printf("dma_setup: unaligned DMA, %p (0x%08x)\n",
109 *dp
->dc_cr
= DMA_CR_CLEAR
| DMA_CR_ENABLE
| (readp
?DMA_CR_DIR
:0) |
111 *dp
->dc_cr
= DMA_CR_ENABLE
| (readp
?DMA_CR_DIR
:0) | dp
->dc_dmasize
;
113 dp
->dc_nextaddr
= start
;
116 dp
->dc_flags
= DMA_FL_READY
;
121 * return true if DMA is active
124 dma_isactive(struct dma_ctrl
*dp
)
127 return dp
->dc_flags
& DMA_FL_ACTIVE
;
131 * return true if interrupt pending
134 dma_isintr(struct dma_ctrl
*dp
)
138 /* printf("dma_isintr() returning %d\n", *dp->dc_st & DMA_ST_INT);*/
140 return *dp
->dc_st
& DMA_ST_INT
;
144 dma_intr(void *cookie
)
146 struct dma_ctrl
*dp
= cookie
;
147 u_char status
= (*dp
->dc_st
) & DMA_ST_MASK
;
153 printf("dma_intr() status = 0x%02x\n", status
);
156 if (!(dp
->dc_flags
& DMA_FL_ACTIVE
)) {
157 /* interrupt whilst not active */
158 /* ie. last buffer programmed */
164 case DMA_ST_OVER
| DMA_ST_INT
:
165 case DMA_ST_OVER
| DMA_ST_INT
| DMA_ST_CHAN
:
166 /* idle, either first buffer or finished */
167 if (status
& DMA_ST_CHAN
) {
179 case DMA_ST_INT
| DMA_ST_CHAN
:
181 if (status
& DMA_ST_CHAN
) {
193 /* Shouldn't be here */
195 printf("DMA ch %d bad status [%x]\n", dp
->dc_channel
, status
);
203 #define PHYS(x, y) pmap_extract(pmap_kernel(), (vaddr_t)x, (paddr_t *)(y))
208 if (dp
->dc_len
== 0) goto done
;
209 PHYS(dp
->dc_nextaddr
, &cur
);
210 len
= PAGE_SIZE
- (cur
& PGOFSET
);
211 if (len
> dp
->dc_len
) {
218 /* ptsc_dump_mem(dp->dc_nextaddr, len);*/
221 * Flush the cache for this address
223 cpu_dcache_wbinv_range((vaddr_t
)dp
->dc_nextaddr
, len
);
225 dp
->dc_nextaddr
+= len
;
229 *dp
->dc_cura
= (u_int
)cur
;
230 *dp
->dc_enda
= ((u_int
)cur
+ len
- dp
->dc_dmasize
) |
231 (dp
->dc_len
== 0 ? DMA_END_STOP
: 0);
232 if (dp
->dc_len
== 0) {
233 /* Last buffer, fill other buffer with garbage */
234 *dp
->dc_endb
= (u_int
)cur
;
237 *dp
->dc_curb
= (u_int
)cur
;
238 *dp
->dc_endb
= ((u_int
)cur
+ len
- dp
->dc_dmasize
) |
239 (dp
->dc_len
== 0 ? DMA_END_STOP
: 0);
240 if (dp
->dc_len
== 0) {
241 /* Last buffer, fill other buffer with garbage */
242 *dp
->dc_enda
= (u_int
)cur
;
247 /* ptsc_dump_mem(dp->dc_nextaddr - len, len);*/
248 printf("about to return\n");
257 disable_irq(IRQ_DMACH0
+ dp
->dc_channel
);
259 printf("about to return\n");
265 dma_dumpdc(struct dma_ctrl
*dc
)
269 "dc_channel:\t%p=0x%08x\tdc_flags:\t%p=0x%08x\n"
270 "dc_cura:\t%p=0x%08x\tdc_enda:\t%p=0x%08x\n"
271 "dc_curb:\t%p=0x%08x\tdc_endb:\t%p=0x%08x\n"
272 "dc_cr:\t%p=0x%02x\t\tdc_st:\t%p=0x%02x\n"
273 "dc_nextaddr:\t%p=0x%08x\tdc_len:\t%p=0x%08x\n",
275 &dc
->dc_channel
, (int)dc
->dc_channel
,
276 &dc
->dc_flags
, (int)dc
->dc_flags
,
277 dc
->dc_cura
, (int)*dc
->dc_cura
,
278 dc
->dc_enda
, (int)*dc
->dc_enda
,
279 dc
->dc_curb
, (int)*dc
->dc_curb
,
280 dc
->dc_endb
, (int)*dc
->dc_endb
,
281 dc
->dc_cr
, (int)*dc
->dc_cr
,
282 dc
->dc_st
, (int)(*dc
->dc_st
) & DMA_ST_MASK
,
283 &dc
->dc_nextaddr
, (int)dc
->dc_nextaddr
,
284 &dc
->dc_len
, dc
->dc_len
);
288 dma_init(int ch
, int extp
, int dmasize
, int ipl
)
290 struct dma_ctrl
*dp
= &ctrl
[ch
];
291 int offset
= ch
* 0x20;
292 volatile u_char
*dmaext
= (volatile u_char
*)(IOMD_ADDRESS(IOMD_DMAEXT
));
294 printf("Initialising DMA channel %d\n", ch
);
298 dp
->dc_dmasize
= dmasize
;
299 dp
->dc_cura
= (volatile u_int
*)(IOMD_ADDRESS(IOMD_IO0CURA
) + offset
);
300 dp
->dc_enda
= (volatile u_int
*)(IOMD_ADDRESS(IOMD_IO0ENDA
) + offset
);
301 dp
->dc_curb
= (volatile u_int
*)(IOMD_ADDRESS(IOMD_IO0CURB
) + offset
);
302 dp
->dc_endb
= (volatile u_int
*)(IOMD_ADDRESS(IOMD_IO0ENDB
) + offset
);
303 dp
->dc_cr
= (volatile u_char
*)(IOMD_ADDRESS(IOMD_IO0CR
) + offset
);
304 dp
->dc_st
= (volatile u_char
*)(IOMD_ADDRESS(IOMD_IO0ST
) + offset
);
307 *dmaext
|= (1 << ch
);
309 printf("about to claim interrupt\n");
311 dp
->dc_ih
.ih_func
= dma_intr
;
312 dp
->dc_ih
.ih_arg
= dp
;
313 dp
->dc_ih
.ih_level
= ipl
;
314 dp
->dc_ih
.ih_name
= "dma";
315 dp
->dc_ih
.ih_maskaddr
= (u_int
) IOMD_ADDRESS(IOMD_DMARQ
);
316 dp
->dc_ih
.ih_maskbits
= (1 << ch
);
318 if (irq_claim(IRQ_DMACH0
+ ch
, &dp
->dc_ih
))
319 panic("Cannot install DMA IRQ handler");