1 /*
2 * omap3530 system dma controller
3 *
4 * terminology: a block consist of frame(s), a frame consist of elements
5 * (uchar, ushort, or ulong sized).
6 */
7 #include "u.h"
8 #include "../port/lib.h"
9 #include "mem.h"
10 #include "dat.h"
11 #include "fns.h"
12 #include "io.h"
13 #include "../port/error.h"
14 #include "../port/netif.h"
15
16 enum {
17 Nirq = 4,
18 Baseirq = 12,
19
20 Nchan = 32,
21 };
22
23 /*
24 * has a sw reset bit
25 * dma req lines 1, 2, 6, 63 are available for `system expansion'
26 */
27
28 typedef struct Regs Regs;
29 typedef struct Dchan Dchan;
30 struct Regs {
31 uchar _pad0[8];
32 /* bitfield of intrs pending, by Dchan; write 1s to clear */
33 ulong irqsts[Nirq];
34 ulong irqen[Nirq]; /* bitfield of intrs enabled, by Dchan */
35 ulong syssts; /* 1<<0 is Resetdone */
36 ulong syscfg; /* 1<<1 is Softreset */
37 uchar _pad1[0x64 - 0x30];
38
39 ulong caps[5]; /* caps[1] not defined */
40 ulong gcr; /* knobs */
41 ulong _pad2;
42
43 struct Dchan {
44 ulong ccr; /* chan ctrl: incr, etc. */
45 ulong clnkctrl; /* link ctrl */
46 ulong cicr; /* intr ctrl */
47 ulong csr; /* status */
48 ulong csdp; /* src & dest params */
49 ulong cen; /* element # */
50 ulong cfn; /* frame # */
51 ulong cssa; /* src start addr */
52 ulong cdsa; /* dest start addr */
53 ulong csei; /* src element index */
54 ulong csfi; /* src frame index | pkt size */
55 ulong cdei; /* dest element index */
56 ulong cdfi; /* dest frame index | pkt size */
57 ulong csac; /* src addr value (read-only?) */
58 ulong cdac; /* dest addr value */
59 ulong ccen; /* curr transferred element # (in frame) */
60 ulong ccfn; /* curr transferred frame # (in xfer) */
61 ulong color;
62 uchar _pad3[24];
63 } chan[Nchan];
64 };
65
66 enum {
67 /* cicr/csr bits */
68 Blocki = 1 << 5,
69
70 /* ccr bits */
71 Enable = 1 << 7,
72 };
73
74 typedef struct Xfer Xfer;
75 static struct Xfer {
76 Rendez *rend;
77 int *done; /* flag to set on intr */
78 } xfer[Nirq];
79
80 int
isdmadone(int irq)81 isdmadone(int irq)
82 {
83 Dchan *cp;
84 Regs *regs = (Regs *)PHYSSDMA;
85
86 cp = regs->chan + irq;
87 return cp->csr & Blocki;
88 }
89
90 static void
dmaintr(Ureg *,void * a)91 dmaintr(Ureg *, void *a)
92 {
93 int i = (int)a; /* dma request & chan # */
94 Dchan *cp;
95 Regs *regs = (Regs *)PHYSSDMA;
96
97 assert(i >= 0 && i < Nirq);
98
99 *xfer[i].done = 1;
100 assert(xfer[i].rend != nil);
101 wakeup(xfer[i].rend);
102
103 cp = regs->chan + i;
104 if(!(cp->csr & Blocki))
105 iprint("dmaintr: req %d: Blocki not set; csr %#lux\n",
106 i, cp->csr);
107 cp->csr |= cp->csr; /* extinguish intr source */
108 coherence();
109 regs->irqsts[i] = regs->irqsts[i]; /* extinguish intr source */
110 coherence();
111 regs->irqen[i] &= ~(1 << i);
112 coherence();
113
114 xfer[i].rend = nil;
115 coherence();
116 }
117
118 void
zerowds(ulong * wdp,int cnt)119 zerowds(ulong *wdp, int cnt)
120 {
121 while (cnt-- > 0)
122 *wdp++ = 0;
123 }
124
125 static int
istestdmadone(void * arg)126 istestdmadone(void *arg)
127 {
128 return *(int *)arg;
129 }
130
131 void
dmainit(void)132 dmainit(void)
133 {
134 int n;
135 char name[16];
136 Dchan *cp;
137 Regs *regs = (Regs *)PHYSSDMA;
138
139 if (probeaddr((uintptr)®s->syssts) < 0)
140 panic("dmainit: no syssts reg");
141 regs->syssts = 0;
142 coherence();
143 regs->syscfg |= 1<<1; /* Softreset */
144 coherence();
145 while(!(regs->syssts & (1<<0))) /* Resetdone? */
146 ;
147
148 for (n = 0; n < Nchan; n++) {
149 cp = regs->chan + n;
150 cp->ccr = 0;
151 cp->clnkctrl = 0;
152 cp->cicr = 0;
153 cp->csr = 0;
154 cp->csdp = 0;
155 cp->cen = cp->cfn = 0;
156 cp->cssa = cp->cdsa = 0;
157 cp->csei = cp->csfi = 0;
158 cp->cdei = cp->cdfi = 0;
159 // cp->csac = cp->cdac = 0; // ro
160 cp->ccen = cp->ccfn = 0;
161 cp->color = 0;
162 }
163 zerowds((void *)regs->irqsts, sizeof regs->irqsts / sizeof(ulong));
164 zerowds((void *)regs->irqen, sizeof regs->irqen / sizeof(ulong));
165 coherence();
166
167 regs->gcr = 65; /* burst size + 1 */
168 coherence();
169
170 for (n = 0; n < Nirq; n++) {
171 snprint(name, sizeof name, "dma%d", n);
172 intrenable(Baseirq + n, dmaintr, (void *)n, nil, name);
173 }
174 }
175
176 enum {
177 Testbyte = 0252,
178 Testsize = 256,
179 Scratch = MB,
180 };
181
182 /*
183 * try to confirm sane operation
184 */
185 void
dmatest(void)186 dmatest(void)
187 {
188 int n, done;
189 uchar *bp;
190 static ulong pat = 0x87654321;
191 static Rendez trendez;
192
193 if (up == nil)
194 panic("dmatest: up not set yet");
195 bp = (uchar *)KADDR(PHYSDRAM + 128*MB);
196 memset(bp, Testbyte, Scratch);
197 done = 0;
198 dmastart((void *)PADDR(bp), Postincr, (void *)PADDR(&pat), Const,
199 Testsize, &trendez, &done);
200 sleep(&trendez, istestdmadone, &done);
201 cachedinvse(bp, Scratch);
202
203 if (((ulong *)bp)[0] != pat)
204 panic("dmainit: copied incorrect data %#lux != %#lux",
205 ((ulong *)bp)[0], pat);
206 for (n = Testsize; n < Scratch && bp[n] != Testbyte; n++)
207 ;
208 if (n >= Scratch)
209 panic("dmainit: ran wild over memory, clobbered ≥%,d bytes", n);
210 if (bp[n] == Testbyte && n != Testsize)
211 iprint("dma: %d-byte dma stopped after %d bytes!\n",
212 Testsize, n);
213 }
214
215 /* addresses are physical */
216 int
dmastart(void * to,int tmode,void * from,int fmode,uint len,Rendez * rend,int * done)217 dmastart(void *to, int tmode, void *from, int fmode, uint len, Rendez *rend,
218 int *done)
219 {
220 int irq, chan;
221 uint ruplen;
222 Dchan *cp;
223 Regs *regs = (Regs *)PHYSSDMA;
224 static Lock alloclck;
225
226 /* allocate free irq (and chan) */
227 ilock(&alloclck);
228 for (irq = 0; irq < Nirq && xfer[irq].rend != nil; irq++)
229 ;
230 if (irq >= Nirq)
231 panic("dmastart: no available irqs; too many concurrent dmas");
232 chan = irq;
233 xfer[irq].rend = rend; /* for wakeup at intr time */
234 xfer[irq].done = done;
235 *done = 0;
236 iunlock(&alloclck);
237
238 ruplen = ROUNDUP(len, sizeof(ulong));
239 assert(to != from);
240
241 cp = regs->chan + chan;
242 cp->ccr &= ~Enable; /* paranoia */
243 cp->cicr = 0;
244 regs->irqen[irq] &= ~(1 << chan);
245 coherence();
246
247 cp->csdp = 2; /* 2 = log2(sizeof(ulong)) */
248 cp->cssa = (uintptr)from;
249 cp->cdsa = (uintptr)to;
250 cp->ccr = tmode << 14 | fmode << 12;
251 cp->csei = cp->csfi = cp->cdei = cp->cdfi = 1;
252 cp->cen = ruplen / sizeof(ulong); /* ulongs / frame */
253 cp->cfn = 1; /* 1 frame / xfer */
254 cp->cicr = Blocki; /* intr at end of block */
255
256 regs->irqen[irq] |= 1 << chan;
257 coherence();
258
259 cp->ccr |= Enable; /* fire! */
260 coherence();
261
262 return irq;
263 }
264