123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- /*
- * 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;
- }
|