2 #include "../port/lib.h"
7 #include "../port/error.h"
17 NDMA = 6, /* Number of DMA channels */
18 DMAREGS = 0xb0000000, /* DMA registers, physical */
22 /* Device Address Register, DDAR */
27 DS = 4, /* bits 4 - 7 */
28 DA = 8 /* bits 8 - 31 */
32 /* Device Control & Status Register, DCSR */
43 typedef struct DMAchan {
46 void (*intr)(void*, ulong);
66 static void dmaintr(Ureg*, void *);
72 /* map the lcd regs into the kernel's virtual space */
73 dmaregs = (struct dmaregs*)mapspecial(DMAREGS, NDMA*sizeof(struct dmaregs));
74 if (debug) print("dma: dmaalloc registers 0x%ux mapped at 0x%p\n",
76 for (i = 0; i < NDMA; i++) {
77 intrenable(IRQ, IRQdma0+i, dmaintr, &dmaregs[i], "DMA");
82 dmareset(int i, int rd, int bigendian, int burstsize, int datumsize, int device, ulong port) {
88 ((burstsize==8)?1:0)<<BS |
89 ((datumsize==2)?1:0)<<DW |
91 0x80000000 | ((ulong)port << 6);
92 dmaregs[i].ddar = ddar;
93 dmaregs[i].dcsr_clr = 0xff;
94 if (debug) print("dma: dmareset: 0x%lux\n", ddar);
98 dmaalloc(int rd, int bigendian, int burstsize, int datumsize, int device, ulong port, void (*intr)(void*, ulong), void *param) {
102 for (i = 0; i < NDMA; i++) {
103 if (dma.chan[i].allocated)
105 dma.chan[i].allocated++;
107 dmareset(i, rd, bigendian, burstsize, datumsize, device, port);
108 dma.chan[i].intr = intr;
109 dma.chan[i].param = param;
118 dmaregs[i].dcsr_clr = 0xff;
120 dma.chan[i].allocated = 0;
121 dma.chan[i].intr = nil;
126 dmaregs[i].dcsr_clr = 0xff;
130 dmastart(int chan, ulong addr, int count) {
134 /* If this gets called from interrupt routines, make sure ilocks are used */
135 status = dmaregs[chan].dcsr_rd;
137 iprint("dma: dmastart 0x%lux\n", status);
139 if ((status & (1<<STRTA|1<<STRTB|1<<RUN)) == (1<<STRTA|1<<STRTB|1<<RUN)) {
142 cachewbregion(addr, count);
144 if ((status & (1<<BIU | 1<<STRTB)) == (1<<BIU | 1<<STRTB) ||
145 (status & (1<<BIU | 1<<STRTA)) == 0) {
146 if (status & 1<<STRTA)
147 iprint("writing busy dma entry 0x%lux\n", status);
148 if (status & 1<<STRTB)
149 n = (last == 1)?0x200:0x300;
151 dmaregs[chan].dstrtA = addr;
152 dmaregs[chan].dxcntA = count;
153 dmaregs[chan].dcsr_set = 1<<RUN | 1<<IE | 1<<STRTA;
156 if (status & 1<<STRTB)
157 iprint("writing busy dma entry 0x%lux\n", status);
158 if (status & 1<<STRTA)
159 n = (last == 2)?0x200:0x300;
161 dmaregs[chan].dstrtB = addr;
162 dmaregs[chan].dxcntB = count;
163 dmaregs[chan].dcsr_set = 1<<RUN | 1<<IE | 1<<STRTB;
173 status = dmaregs[chan].dcsr_rd;
174 if (debug > 1) print("dmaidle: 0x%lux\n", status);
175 return (status & (1<<STRTA|1<<STRTB)) == 0;
179 _dmaidle(void* chan) {
182 status = dmaregs[(int)chan].dcsr_rd;
183 return (status & (1<<STRTA|1<<STRTB)) == 0;
188 while (!dmaidle(chan))
189 sleep(&dma.chan[chan].r, _dmaidle, (void*)chan);
196 dmaintr(Ureg*, void *x)
199 struct dmaregs *regs = x;
203 dcsr = regs->dcsr_rd;
205 iprint("dma: interrupt channel %d, status 0x%lux\n", i, dcsr);
207 iprint("error, channel %d, status 0x%lux\n", i, dcsr);
208 donebit = 1<<((dcsr&1<<BIU)?DONEA:DONEB);
209 if (dcsr & donebit) {
210 regs->dcsr_clr = 1<<DONEA|1<<DONEB;
211 if (dma.chan[i].intr) {
212 (*dma.chan[i].intr)(dma.chan[i].param, dcsr & (1<<DONEA|1<<DONEB));
214 wakeup(&dma.chan[i].r);
217 if (dcsr & 1<<ERROR) {
218 regs->dcsr_clr = ERROR;
219 iprint("DMA error, channel %d, status 0x%lux\n", i, dcsr);
220 if (dma.chan[i].intr) {
221 (*dma.chan[i].intr)(dma.chan[i].param, 0);
223 wakeup(&dma.chan[i].r);
226 iprint("spurious DMA interrupt, channel %d, status 0x%lux\n", i, dcsr);