summaryrefslogtreecommitdiff
path: root/os/mpc/dsp.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
commit74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch)
treec6e220ba61db3a6ea4052e6841296d829654e664 /os/mpc/dsp.c
parent46439007cf417cbd9ac8049bb4122c890097a0fa (diff)
20060303
Diffstat (limited to 'os/mpc/dsp.c')
-rw-r--r--os/mpc/dsp.c289
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);
+}