xref: /inferno-os/os/mpc/dsp.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
1 /*
2  * DSP support functions
3  */
4 
5 #include	"u.h"
6 #include	"../port/lib.h"
7 #include	"mem.h"
8 #include	"dat.h"
9 #include	"fns.h"
10 #include	"../port/error.h"
11 
12 #include	"io.h"
13 
14 #include	"dsp.h"
15 
16 enum {
17 	Ndsp = 2,		/* determined by hardware */
18 
19 	NHOLES=	64
20 };
21 
22 typedef struct DSPparam DSPparam;
23 struct DSPparam {
24 	ulong	fdbase;	/* function descriptor table physical base address */
25 	ulong	fd_ptr;	/* function descriptor pointer */
26 	ulong	dstate;	/* DSP state */
27 	ulong	resvd[2];
28 	ushort	dstatus;	/* current function descriptor status */
29 	ushort	i;	/* number of iterations */
30 	ushort	tap;	/* number of TAPs */
31 	ushort	cbase;
32 	ushort	anon1;	/* sample buffer size-1 */
33 	ushort	xptr;	/* pointer to sample */
34 	ushort	anon2;	/* output buffer size-1 */
35 	ushort	yptr;	/* pointer to output */
36 	ushort	m;	/* sample buffer size-1 */
37 	ushort	anon3;	/* sample buffer pointer */
38 	ushort	n;	/* output buffer size -1 */
39 	ushort	anon4;	/* output buffer pointer */
40 	ushort	k;	/* coefficient buffer size - 1 */
41 	ushort	anon5;	/* coefficient buffer pointer */
42 };
43 
44 struct DSP {
45 	Lock;	/* protects state */
46 	void	(*done)(void*);
47 	void*	arg;
48 	DSPparam*	par;
49 	CPMdev*	cpm;
50 
51 	QLock;	/* protects busyr */
52 	int	busy;
53 	Rendez	busyr;
54 };
55 
56 static	DSP	dsps[Ndsp];
57 static	Lock	dsplock;
58 static	int	dspinit;
59 static struct {
60 	QLock;
61 	ulong	avail;
62 	Rendez	wantr;
63 } dspalloc;
64 
65 static	Map	fndmapv[NHOLES];
66 static	RMap	fndmap = {"DSP function descriptors"};
67 
68 static void
69 dspinterrupt(Ureg*, void*)
70 {
71 	int i;
72 	ushort events;
73 	DSP *dsp;
74 
75 	events = m->iomem->sdsr;
76 	m->iomem->sdsr = events;
77 	if(events & (1<<7))
78 		panic("dsp: SDMA channel bus error sdar=#%lux", m->iomem->sdar);
79 	for(i=0; i<Ndsp; i++)
80 		if(events & (1<<i)){
81 			dsp = &dsps[i];
82 			if(dsp->busy){
83 				dsp->busy = 0;
84 				if(dsp->done)
85 					dsp->done(dsp->arg);
86 				else
87 					wakeup(&dsp->busyr);
88 			}else
89 				print("dsp%d: empty interrupt\n", i);
90 		}
91 }
92 
93 /*
94  * called by system initialisation to set up the DSPs
95  */
96 void
97 dspinitialise(void)
98 {
99 	CPMdev *d;
100 
101 	ilock(&dsplock);
102 	if(dspinit == 0){
103 		mapinit(&fndmap, fndmapv, sizeof(fndmapv));
104 		d = cpmdev(CPdsp1);
105 		dsps[0].cpm = d;
106 		dsps[0].par = d->param;
107 		d = cpmdev(CPdsp2);
108 		dsps[1].cpm = d;
109 		dsps[1].par = d->param;
110 		intrenable(VectorCPIC+d->irq, dspinterrupt, nil, BUSUNKNOWN, "dsp");
111 		dspalloc.avail = (1<<Ndsp)-1;
112 		dspinit = 1;
113 	}
114 	iunlock(&dsplock);
115 }
116 
117 static int
118 dspavail(void*)
119 {
120 	return dspalloc.avail != 0;
121 }
122 
123 /*
124  * wait for a DSP to become available, and return a reference to it.
125  * if done is not nil, it will be called (with the given arg) when that
126  * DSP completes each function (if set to interrupt).
127  */
128 DSP*
129 dspacquire(void (*done)(void*), void *arg)
130 {
131 	DSP *dsp;
132 	int i;
133 
134 	if(dspinit == 0)
135 		dspinitialise();
136 	qlock(&dspalloc);
137 	if(waserror()){
138 		qunlock(&dspalloc);
139 		nexterror();
140 	}
141 	for(i=0;; i++){
142 		if(i >= Ndsp){
143 			sleep(&dspalloc.wantr, dspavail, nil);
144 			i = 0;
145 		}
146 		if(dspalloc.avail & (1<<i))
147 			break;
148 	}
149 	dsp = &dsps[i];
150 	if(dsp->busy)
151 		panic("dspacquire");
152 	dsp->done = done;
153 	dsp->arg = arg;
154 	poperror();
155 	qunlock(&dspalloc);
156 	return dsp;
157 }
158 
159 /*
160  * relinquish access to the given DSP
161  */
162 void
163 dsprelease(DSP *dsp)
164 {
165 	ulong bit;
166 
167 	if(dsp == nil)
168 		return;
169 	bit = 1 << (dsp-dsps);
170 	if(dspalloc.avail & bit)
171 		panic("dsprelease");
172 	dspalloc.avail |= bit;
173 	wakeup(&dspalloc.wantr);
174 }
175 
176 /*
177  * execute f[0] to f[n-1] on the given DSP
178  */
179 void
180 dspexec(DSP *dsp, FnD *f, ulong n)
181 {
182 	dspsetfn(dsp, f, n);
183 	dspstart(dsp);
184 }
185 
186 /*
187  * set the DSP to execute f[0] to f[n-1]
188  */
189 void
190 dspsetfn(DSP *dsp, FnD *f, ulong n)
191 {
192 	f[n-1].status |= FnWrap;
193 	ilock(dsp);
194 	dsp->par->fdbase = PADDR(f);
195 	iunlock(dsp);
196 	cpmop(dsp->cpm, InitDSP, 0);
197 }
198 
199 /*
200  * start execution of the preset function(s)
201  */
202 void
203 dspstart(DSP *dsp)
204 {
205 	ilock(dsp);
206 	dsp->busy = 1;
207 	iunlock(dsp);
208 	cpmop(dsp->cpm, StartDSP, 0);
209 }
210 
211 static int
212 dspdone(void *a)
213 {
214 	return ((DSP*)a)->busy;
215 }
216 
217 /*
218  * wait until the DSP has completed execution
219  */
220 void
221 dspsleep(DSP *dsp)
222 {
223 	sleep(&dsp->busyr, dspdone, dsp);
224 }
225 
226 /*
227  * allocate n function descriptors
228  */
229 FnD*
230 fndalloc(ulong n)
231 {
232 	ulong a, nb, pgn;
233 	FnD *f;
234 
235 	if(n == 0)
236 		return nil;
237 	if(dspinit == 0)
238 		dspinitialise();
239 	nb = n*sizeof(FnD);
240 	while((a = rmapalloc(&fndmap, 0, nb, sizeof(FnD))) != 0){
241 		/* expected to loop just once, but might lose a race with another dsp user */
242 		pgn = (nb+BY2PG-1)&~(BY2PG-1);
243 		a = PADDR(xspanalloc(pgn, sizeof(FnD), 0));
244 		if(a == 0)
245 			return nil;
246 		mapfree(&fndmap, a, pgn);
247 	}
248 	f = KADDR(a);
249 	f[n-1].status = FnWrap;
250 	return f;
251 }
252 
253 /*
254  * free n function descriptors
255  */
256 void
257 fndfree(FnD *f, ulong n)
258 {
259 	if(f != nil)
260 		mapfree(&fndmap, PADDR(f), n*sizeof(FnD));
261 }
262 
263 /*
264  * allocate an IO buffer region in shared memory for use by the DSP
265  */
266 void*
267 dspmalloc(ulong n)
268 {
269 	ulong i;
270 
271 	n = (n+3)&~4;
272 	i = n;
273 	if(n & (n-1)){
274 		/* align on a power of two */
275 		for(i=1; i < n; i <<= 1)
276 			;
277 	}
278 	return cpmalloc(n, i);	/* this seems to be what 16.3.3.2 is trying to say */
279 }
280 
281 /*
282  * free DSP buffer memory
283  */
284 void
285 dspfree(void *p, ulong n)
286 {
287 	if(p != nil)
288 		cpmfree(p, (n+3)&~4);
289 }
290