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
dspinterrupt(Ureg *,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
dspinitialise(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
dspavail(void *)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*
dspacquire(void (* done)(void *),void * arg)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
dsprelease(DSP * dsp)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
dspexec(DSP * dsp,FnD * f,ulong n)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
dspsetfn(DSP * dsp,FnD * f,ulong n)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
dspstart(DSP * dsp)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
dspdone(void * a)212 dspdone(void *a)
213 {
214 return ((DSP*)a)->busy;
215 }
216
217 /*
218 * wait until the DSP has completed execution
219 */
220 void
dspsleep(DSP * dsp)221 dspsleep(DSP *dsp)
222 {
223 sleep(&dsp->busyr, dspdone, dsp);
224 }
225
226 /*
227 * allocate n function descriptors
228 */
229 FnD*
fndalloc(ulong n)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
fndfree(FnD * f,ulong n)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*
dspmalloc(ulong n)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
dspfree(void * p,ulong n)285 dspfree(void *p, ulong n)
286 {
287 if(p != nil)
288 cpmfree(p, (n+3)&~4);
289 }
290