summaryrefslogtreecommitdiff
path: root/sys/src/9/omap/dma.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/9/omap/dma.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/9/omap/dma.c')
-rwxr-xr-xsys/src/9/omap/dma.c263
1 files changed, 263 insertions, 0 deletions
diff --git a/sys/src/9/omap/dma.c b/sys/src/9/omap/dma.c
new file mode 100755
index 000000000..385fcd45d
--- /dev/null
+++ b/sys/src/9/omap/dma.c
@@ -0,0 +1,263 @@
+/*
+ * omap3530 system dma controller
+ *
+ * terminology: a block consist of frame(s), a frame consist of elements
+ * (uchar, ushort, or ulong sized).
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+#include "../port/netif.h"
+
+enum {
+ Nirq = 4,
+ Baseirq = 12,
+
+ Nchan = 32,
+};
+
+/*
+ * has a sw reset bit
+ * dma req lines 1, 2, 6, 63 are available for `system expansion'
+ */
+
+typedef struct Regs Regs;
+typedef struct Dchan Dchan;
+struct Regs {
+ uchar _pad0[8];
+ /* bitfield of intrs pending, by Dchan; write 1s to clear */
+ ulong irqsts[Nirq];
+ ulong irqen[Nirq]; /* bitfield of intrs enabled, by Dchan */
+ ulong syssts; /* 1<<0 is Resetdone */
+ ulong syscfg; /* 1<<1 is Softreset */
+ uchar _pad1[0x64 - 0x30];
+
+ ulong caps[5]; /* caps[1] not defined */
+ ulong gcr; /* knobs */
+ ulong _pad2;
+
+ struct Dchan {
+ ulong ccr; /* chan ctrl: incr, etc. */
+ ulong clnkctrl; /* link ctrl */
+ ulong cicr; /* intr ctrl */
+ ulong csr; /* status */
+ ulong csdp; /* src & dest params */
+ ulong cen; /* element # */
+ ulong cfn; /* frame # */
+ ulong cssa; /* src start addr */
+ ulong cdsa; /* dest start addr */
+ ulong csei; /* src element index */
+ ulong csfi; /* src frame index | pkt size */
+ ulong cdei; /* dest element index */
+ ulong cdfi; /* dest frame index | pkt size */
+ ulong csac; /* src addr value (read-only?) */
+ ulong cdac; /* dest addr value */
+ ulong ccen; /* curr transferred element # (in frame) */
+ ulong ccfn; /* curr transferred frame # (in xfer) */
+ ulong color;
+ uchar _pad3[24];
+ } chan[Nchan];
+};
+
+enum {
+ /* cicr/csr bits */
+ Blocki = 1 << 5,
+
+ /* ccr bits */
+ Enable = 1 << 7,
+};
+
+typedef struct Xfer Xfer;
+static struct Xfer {
+ Rendez *rend;
+ int *done; /* flag to set on intr */
+} xfer[Nirq];
+
+int
+isdmadone(int irq)
+{
+ Dchan *cp;
+ Regs *regs = (Regs *)PHYSSDMA;
+
+ cp = regs->chan + irq;
+ return cp->csr & Blocki;
+}
+
+static void
+dmaintr(Ureg *, void *a)
+{
+ int i = (int)a; /* dma request & chan # */
+ Dchan *cp;
+ Regs *regs = (Regs *)PHYSSDMA;
+
+ assert(i >= 0 && i < Nirq);
+
+ *xfer[i].done = 1;
+ assert(xfer[i].rend != nil);
+ wakeup(xfer[i].rend);
+
+ cp = regs->chan + i;
+ if(!(cp->csr & Blocki))
+ iprint("dmaintr: req %d: Blocki not set; csr %#lux\n",
+ i, cp->csr);
+ cp->csr |= cp->csr; /* extinguish intr source */
+ coherence();
+ regs->irqsts[i] = regs->irqsts[i]; /* extinguish intr source */
+ coherence();
+ regs->irqen[i] &= ~(1 << i);
+ coherence();
+
+ xfer[i].rend = nil;
+ coherence();
+}
+
+void
+zerowds(ulong *wdp, int cnt)
+{
+ while (cnt-- > 0)
+ *wdp++ = 0;
+}
+
+static int
+istestdmadone(void *arg)
+{
+ return *(int *)arg;
+}
+
+void
+dmainit(void)
+{
+ int n;
+ char name[16];
+ Dchan *cp;
+ Regs *regs = (Regs *)PHYSSDMA;
+
+ if (probeaddr((uintptr)&regs->syssts) < 0)
+ panic("dmainit: no syssts reg");
+ regs->syssts = 0;
+ coherence();
+ regs->syscfg |= 1<<1; /* Softreset */
+ coherence();
+ while(!(regs->syssts & (1<<0))) /* Resetdone? */
+ ;
+
+ for (n = 0; n < Nchan; n++) {
+ cp = regs->chan + n;
+ cp->ccr = 0;
+ cp->clnkctrl = 0;
+ cp->cicr = 0;
+ cp->csr = 0;
+ cp->csdp = 0;
+ cp->cen = cp->cfn = 0;
+ cp->cssa = cp->cdsa = 0;
+ cp->csei = cp->csfi = 0;
+ cp->cdei = cp->cdfi = 0;
+// cp->csac = cp->cdac = 0; // ro
+ cp->ccen = cp->ccfn = 0;
+ cp->color = 0;
+ }
+ zerowds((void *)regs->irqsts, sizeof regs->irqsts / sizeof(ulong));
+ zerowds((void *)regs->irqen, sizeof regs->irqen / sizeof(ulong));
+ coherence();
+
+ regs->gcr = 65; /* burst size + 1 */
+ coherence();
+
+ for (n = 0; n < Nirq; n++) {
+ snprint(name, sizeof name, "dma%d", n);
+ intrenable(Baseirq + n, dmaintr, (void *)n, nil, name);
+ }
+}
+
+enum {
+ Testbyte = 0252,
+ Testsize = 256,
+ Scratch = MB,
+};
+
+/*
+ * try to confirm sane operation
+ */
+void
+dmatest(void)
+{
+ int n, done;
+ uchar *bp;
+ static ulong pat = 0x87654321;
+ static Rendez trendez;
+
+ if (up == nil)
+ panic("dmatest: up not set yet");
+ bp = (uchar *)KADDR(PHYSDRAM + 128*MB);
+ memset(bp, Testbyte, Scratch);
+ done = 0;
+ dmastart((void *)PADDR(bp), Postincr, (void *)PADDR(&pat), Const,
+ Testsize, &trendez, &done);
+ sleep(&trendez, istestdmadone, &done);
+ cachedinvse(bp, Scratch);
+
+ if (((ulong *)bp)[0] != pat)
+ panic("dmainit: copied incorrect data %#lux != %#lux",
+ ((ulong *)bp)[0], pat);
+ for (n = Testsize; n < Scratch && bp[n] != Testbyte; n++)
+ ;
+ if (n >= Scratch)
+ panic("dmainit: ran wild over memory, clobbered ≥%,d bytes", n);
+ if (bp[n] == Testbyte && n != Testsize)
+ iprint("dma: %d-byte dma stopped after %d bytes!\n",
+ Testsize, n);
+}
+
+/* addresses are physical */
+int
+dmastart(void *to, int tmode, void *from, int fmode, uint len, Rendez *rend,
+ int *done)
+{
+ int irq, chan;
+ uint ruplen;
+ Dchan *cp;
+ Regs *regs = (Regs *)PHYSSDMA;
+ static Lock alloclck;
+
+ /* allocate free irq (and chan) */
+ ilock(&alloclck);
+ for (irq = 0; irq < Nirq && xfer[irq].rend != nil; irq++)
+ ;
+ if (irq >= Nirq)
+ panic("dmastart: no available irqs; too many concurrent dmas");
+ chan = irq;
+ xfer[irq].rend = rend; /* for wakeup at intr time */
+ xfer[irq].done = done;
+ *done = 0;
+ iunlock(&alloclck);
+
+ ruplen = ROUNDUP(len, sizeof(ulong));
+ assert(to != from);
+
+ cp = regs->chan + chan;
+ cp->ccr &= ~Enable; /* paranoia */
+ cp->cicr = 0;
+ regs->irqen[irq] &= ~(1 << chan);
+ coherence();
+
+ cp->csdp = 2; /* 2 = log2(sizeof(ulong)) */
+ cp->cssa = (uintptr)from;
+ cp->cdsa = (uintptr)to;
+ cp->ccr = tmode << 14 | fmode << 12;
+ cp->csei = cp->csfi = cp->cdei = cp->cdfi = 1;
+ cp->cen = ruplen / sizeof(ulong); /* ulongs / frame */
+ cp->cfn = 1; /* 1 frame / xfer */
+ cp->cicr = Blocki; /* intr at end of block */
+
+ regs->irqen[irq] |= 1 << chan;
+ coherence();
+
+ cp->ccr |= Enable; /* fire! */
+ coherence();
+
+ return irq;
+}