]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/bitsy/sa1110dma.c
merge
[plan9front.git] / sys / src / 9 / bitsy / sa1110dma.c
1 #include        "u.h"
2 #include        "../port/lib.h"
3 #include        "mem.h"
4 #include        "dat.h"
5 #include        "fns.h"
6 #include        "io.h"
7 #include        "../port/error.h"
8 #include        "sa1110dma.h"
9
10 static int debug = 0;
11
12 /*
13  *      DMA helper routines
14  */
15
16 enum {
17         NDMA    =       6,                      /* Number of DMA channels */
18         DMAREGS =       0xb0000000,     /* DMA registers, physical */
19 };
20
21 enum {
22         /* Device Address Register, DDAR */
23         RW              =       0,
24         E               =       1,
25         BS              =       2,
26         DW              =       3,
27         DS              =       4,      /* bits 4 - 7 */
28         DA              =       8       /* bits 8 - 31 */
29 };
30
31 enum {
32         /* Device Control & Status Register, DCSR */
33         RUN             =       0,
34         IE              =       1,
35         ERROR   =       2,
36         DONEA   =       3,
37         STRTA   =       4,
38         DONEB   =       5,
39         STRTB   =       6,
40         BIU             =       7
41 };
42
43 typedef struct DMAchan {
44         int             allocated;
45         Rendez  r;
46         void    (*intr)(void*, ulong);
47         void    *param;
48 } DMAchan;
49
50 struct {
51         Lock;
52         DMAchan chan[6];
53 } dma;
54
55 struct dmaregs {
56         ulong   ddar;
57         ulong   dcsr_set;
58         ulong   dcsr_clr;
59         ulong   dcsr_rd;
60         ulong   dstrtA;
61         ulong   dxcntA;
62         ulong   dstrtB;
63         ulong   dxcntB;
64 } *dmaregs;
65
66 static void     dmaintr(Ureg*, void *);
67
68 void
69 dmainit(void) {
70         int i;
71
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",
75                 DMAREGS, dmaregs);
76         for (i = 0; i < NDMA; i++) {
77                 intrenable(IRQ, IRQdma0+i, dmaintr, &dmaregs[i], "DMA");
78         }
79 }
80
81 void
82 dmareset(int i, int rd, int bigendian, int burstsize, int datumsize, int device, ulong port) {
83         ulong ddar;
84
85         ddar =
86                 (rd?1:0)<<RW |
87                 (bigendian?1:0)<<E |
88                 ((burstsize==8)?1:0)<<BS |
89                 ((datumsize==2)?1:0)<<DW |
90                 device<<DS |
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);
95 }
96
97 int
98 dmaalloc(int rd, int bigendian, int burstsize, int datumsize, int device, ulong port, void (*intr)(void*, ulong), void *param) {
99         int i;
100
101         lock(&dma);
102         for (i = 0; i < NDMA; i++) {
103                 if (dma.chan[i].allocated)
104                         continue;
105                 dma.chan[i].allocated++;
106                 unlock(&dma);
107                 dmareset(i, rd, bigendian, burstsize, datumsize, device, port);
108                 dma.chan[i].intr = intr;
109                 dma.chan[i].param = param;
110                 return i;
111         }
112         unlock(&dma);
113         return -1;
114 }
115
116 void
117 dmafree(int i) {
118         dmaregs[i].dcsr_clr = 0xff;
119         dmaregs[i].ddar = 0;
120         dma.chan[i].allocated = 0;
121         dma.chan[i].intr = nil;
122 }
123
124 void
125 dmastop(int i) {
126         dmaregs[i].dcsr_clr = 0xff;
127 }
128
129 ulong
130 dmastart(int chan,  ulong addr, int count) {
131         ulong status, n;
132         static int last;
133
134         /* If this gets called from interrupt routines, make sure ilocks are used */
135         status = dmaregs[chan].dcsr_rd;
136         if (debug > 1)
137                 iprint("dma: dmastart 0x%lux\n", status);
138
139         if ((status & (1<<STRTA|1<<STRTB|1<<RUN)) == (1<<STRTA|1<<STRTB|1<<RUN)) {
140                 return 0;
141         }
142         cachewbregion(addr, count);
143         n = 0x100;
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;
150                 last = 2;
151                 dmaregs[chan].dstrtA = addr;
152                 dmaregs[chan].dxcntA = count;
153                 dmaregs[chan].dcsr_set = 1<<RUN | 1<<IE | 1<<STRTA;
154                 n |= 1<<DONEA;
155         } else {
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;
160                 last = 1;
161                 dmaregs[chan].dstrtB = addr;
162                 dmaregs[chan].dxcntB = count;
163                 dmaregs[chan].dcsr_set = 1<<RUN | 1<<IE | 1<<STRTB;
164                 n |= 1<<DONEB;
165         }
166         return n;
167 }
168
169 int
170 dmaidle(int chan) {
171         ulong status;
172
173         status = dmaregs[chan].dcsr_rd;
174         if (debug > 1) print("dmaidle: 0x%lux\n", status);
175         return (status & (1<<STRTA|1<<STRTB)) == 0;
176 }
177
178 static int
179 _dmaidle(void* chan) {
180         ulong status;
181
182         status = dmaregs[(int)chan].dcsr_rd;
183         return (status & (1<<STRTA|1<<STRTB)) == 0;
184 }
185
186 void
187 dmawait(int chan) {
188         while (!dmaidle(chan))
189                 sleep(&dma.chan[chan].r, _dmaidle, (void*)chan);
190 }
191
192 /*
193  *  interrupt routine
194  */
195 static void
196 dmaintr(Ureg*, void *x)
197 {
198         int i;
199         struct dmaregs *regs = x;
200         ulong dcsr, donebit;
201
202         i = regs - dmaregs;
203         dcsr = regs->dcsr_rd;
204         if (debug > 1)
205                 iprint("dma: interrupt channel %d, status 0x%lux\n", i, dcsr);
206         if (dcsr & 1<<ERROR)
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));
213                 }
214                 wakeup(&dma.chan[i].r);
215                 return;
216         }
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);
222                 }
223                 wakeup(&dma.chan[i].r);
224                 return;
225         }
226         iprint("spurious DMA interrupt, channel %d, status 0x%lux\n", i, dcsr);
227 }