xref: /plan9/sys/src/9/omap/dma.c (revision 8e32b40042777e974f5a655264a3b7b672154d02)
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)&regs->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