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