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