diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /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-x | sys/src/9/omap/dma.c | 263 |
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)®s->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; +} |