diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
| commit | 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch) | |
| tree | c6e220ba61db3a6ea4052e6841296d829654e664 /os/mpc/dsp.c | |
| parent | 46439007cf417cbd9ac8049bb4122c890097a0fa (diff) | |
20060303
Diffstat (limited to 'os/mpc/dsp.c')
| -rw-r--r-- | os/mpc/dsp.c | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/os/mpc/dsp.c b/os/mpc/dsp.c new file mode 100644 index 00000000..ffe906e9 --- /dev/null +++ b/os/mpc/dsp.c @@ -0,0 +1,289 @@ +/* + * DSP support functions + */ + +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +#include "io.h" + +#include "dsp.h" + +enum { + Ndsp = 2, /* determined by hardware */ + + NHOLES= 64 +}; + +typedef struct DSPparam DSPparam; +struct DSPparam { + ulong fdbase; /* function descriptor table physical base address */ + ulong fd_ptr; /* function descriptor pointer */ + ulong dstate; /* DSP state */ + ulong resvd[2]; + ushort dstatus; /* current function descriptor status */ + ushort i; /* number of iterations */ + ushort tap; /* number of TAPs */ + ushort cbase; + ushort anon1; /* sample buffer size-1 */ + ushort xptr; /* pointer to sample */ + ushort anon2; /* output buffer size-1 */ + ushort yptr; /* pointer to output */ + ushort m; /* sample buffer size-1 */ + ushort anon3; /* sample buffer pointer */ + ushort n; /* output buffer size -1 */ + ushort anon4; /* output buffer pointer */ + ushort k; /* coefficient buffer size - 1 */ + ushort anon5; /* coefficient buffer pointer */ +}; + +struct DSP { + Lock; /* protects state */ + void (*done)(void*); + void* arg; + DSPparam* par; + CPMdev* cpm; + + QLock; /* protects busyr */ + int busy; + Rendez busyr; +}; + +static DSP dsps[Ndsp]; +static Lock dsplock; +static int dspinit; +static struct { + QLock; + ulong avail; + Rendez wantr; +} dspalloc; + +static Map fndmapv[NHOLES]; +static RMap fndmap = {"DSP function descriptors"}; + +static void +dspinterrupt(Ureg*, void*) +{ + int i; + ushort events; + DSP *dsp; + + events = m->iomem->sdsr; + m->iomem->sdsr = events; + if(events & (1<<7)) + panic("dsp: SDMA channel bus error sdar=#%lux", m->iomem->sdar); + for(i=0; i<Ndsp; i++) + if(events & (1<<i)){ + dsp = &dsps[i]; + if(dsp->busy){ + dsp->busy = 0; + if(dsp->done) + dsp->done(dsp->arg); + else + wakeup(&dsp->busyr); + }else + print("dsp%d: empty interrupt\n", i); + } +} + +/* + * called by system initialisation to set up the DSPs + */ +void +dspinitialise(void) +{ + CPMdev *d; + + ilock(&dsplock); + if(dspinit == 0){ + mapinit(&fndmap, fndmapv, sizeof(fndmapv)); + d = cpmdev(CPdsp1); + dsps[0].cpm = d; + dsps[0].par = d->param; + d = cpmdev(CPdsp2); + dsps[1].cpm = d; + dsps[1].par = d->param; + intrenable(VectorCPIC+d->irq, dspinterrupt, nil, BUSUNKNOWN, "dsp"); + dspalloc.avail = (1<<Ndsp)-1; + dspinit = 1; + } + iunlock(&dsplock); +} + +static int +dspavail(void*) +{ + return dspalloc.avail != 0; +} + +/* + * wait for a DSP to become available, and return a reference to it. + * if done is not nil, it will be called (with the given arg) when that + * DSP completes each function (if set to interrupt). + */ +DSP* +dspacquire(void (*done)(void*), void *arg) +{ + DSP *dsp; + int i; + + if(dspinit == 0) + dspinitialise(); + qlock(&dspalloc); + if(waserror()){ + qunlock(&dspalloc); + nexterror(); + } + for(i=0;; i++){ + if(i >= Ndsp){ + sleep(&dspalloc.wantr, dspavail, nil); + i = 0; + } + if(dspalloc.avail & (1<<i)) + break; + } + dsp = &dsps[i]; + if(dsp->busy) + panic("dspacquire"); + dsp->done = done; + dsp->arg = arg; + poperror(); + qunlock(&dspalloc); + return dsp; +} + +/* + * relinquish access to the given DSP + */ +void +dsprelease(DSP *dsp) +{ + ulong bit; + + if(dsp == nil) + return; + bit = 1 << (dsp-dsps); + if(dspalloc.avail & bit) + panic("dsprelease"); + dspalloc.avail |= bit; + wakeup(&dspalloc.wantr); +} + +/* + * execute f[0] to f[n-1] on the given DSP + */ +void +dspexec(DSP *dsp, FnD *f, ulong n) +{ + dspsetfn(dsp, f, n); + dspstart(dsp); +} + +/* + * set the DSP to execute f[0] to f[n-1] + */ +void +dspsetfn(DSP *dsp, FnD *f, ulong n) +{ + f[n-1].status |= FnWrap; + ilock(dsp); + dsp->par->fdbase = PADDR(f); + iunlock(dsp); + cpmop(dsp->cpm, InitDSP, 0); +} + +/* + * start execution of the preset function(s) + */ +void +dspstart(DSP *dsp) +{ + ilock(dsp); + dsp->busy = 1; + iunlock(dsp); + cpmop(dsp->cpm, StartDSP, 0); +} + +static int +dspdone(void *a) +{ + return ((DSP*)a)->busy; +} + +/* + * wait until the DSP has completed execution + */ +void +dspsleep(DSP *dsp) +{ + sleep(&dsp->busyr, dspdone, dsp); +} + +/* + * allocate n function descriptors + */ +FnD* +fndalloc(ulong n) +{ + ulong a, nb, pgn; + FnD *f; + + if(n == 0) + return nil; + if(dspinit == 0) + dspinitialise(); + nb = n*sizeof(FnD); + while((a = rmapalloc(&fndmap, 0, nb, sizeof(FnD))) != 0){ + /* expected to loop just once, but might lose a race with another dsp user */ + pgn = (nb+BY2PG-1)&~(BY2PG-1); + a = PADDR(xspanalloc(pgn, sizeof(FnD), 0)); + if(a == 0) + return nil; + mapfree(&fndmap, a, pgn); + } + f = KADDR(a); + f[n-1].status = FnWrap; + return f; +} + +/* + * free n function descriptors + */ +void +fndfree(FnD *f, ulong n) +{ + if(f != nil) + mapfree(&fndmap, PADDR(f), n*sizeof(FnD)); +} + +/* + * allocate an IO buffer region in shared memory for use by the DSP + */ +void* +dspmalloc(ulong n) +{ + ulong i; + + n = (n+3)&~4; + i = n; + if(n & (n-1)){ + /* align on a power of two */ + for(i=1; i < n; i <<= 1) + ; + } + return cpmalloc(n, i); /* this seems to be what 16.3.3.2 is trying to say */ +} + +/* + * free DSP buffer memory + */ +void +dspfree(void *p, ulong n) +{ + if(p != nil) + cpmfree(p, (n+3)&~4); +} |
