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