dma.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /*
  2. * omap3530 system dma controller
  3. *
  4. * terminology: a block consist of frame(s), a frame consist of elements
  5. * (uchar, ushort, or ulong sized).
  6. */
  7. #include "u.h"
  8. #include "../port/lib.h"
  9. #include "mem.h"
  10. #include "dat.h"
  11. #include "fns.h"
  12. #include "io.h"
  13. #include "../port/error.h"
  14. #include "../port/netif.h"
  15. enum {
  16. Nirq = 4,
  17. Baseirq = 12,
  18. Nchan = 32,
  19. };
  20. /*
  21. * has a sw reset bit
  22. * dma req lines 1, 2, 6, 63 are available for `system expansion'
  23. */
  24. typedef struct Regs Regs;
  25. typedef struct Dchan Dchan;
  26. struct Regs {
  27. uchar _pad0[8];
  28. /* bitfield of intrs pending, by Dchan; write 1s to clear */
  29. ulong irqsts[Nirq];
  30. ulong irqen[Nirq]; /* bitfield of intrs enabled, by Dchan */
  31. ulong syssts; /* 1<<0 is Resetdone */
  32. ulong syscfg; /* 1<<1 is Softreset */
  33. uchar _pad1[0x64 - 0x30];
  34. ulong caps[5]; /* caps[1] not defined */
  35. ulong gcr; /* knobs */
  36. ulong _pad2;
  37. struct Dchan {
  38. ulong ccr; /* chan ctrl: incr, etc. */
  39. ulong clnkctrl; /* link ctrl */
  40. ulong cicr; /* intr ctrl */
  41. ulong csr; /* status */
  42. ulong csdp; /* src & dest params */
  43. ulong cen; /* element # */
  44. ulong cfn; /* frame # */
  45. ulong cssa; /* src start addr */
  46. ulong cdsa; /* dest start addr */
  47. ulong csei; /* src element index */
  48. ulong csfi; /* src frame index | pkt size */
  49. ulong cdei; /* dest element index */
  50. ulong cdfi; /* dest frame index | pkt size */
  51. ulong csac; /* src addr value (read-only?) */
  52. ulong cdac; /* dest addr value */
  53. ulong ccen; /* curr transferred element # (in frame) */
  54. ulong ccfn; /* curr transferred frame # (in xfer) */
  55. ulong color;
  56. uchar _pad3[24];
  57. } chan[Nchan];
  58. };
  59. enum {
  60. /* cicr/csr bits */
  61. Blocki = 1 << 5,
  62. /* ccr bits */
  63. Enable = 1 << 7,
  64. };
  65. typedef struct Xfer Xfer;
  66. static struct Xfer {
  67. Rendez *rend;
  68. int *done; /* flag to set on intr */
  69. } xfer[Nirq];
  70. int
  71. isdmadone(int irq)
  72. {
  73. Dchan *cp;
  74. Regs *regs = (Regs *)PHYSSDMA;
  75. cp = regs->chan + irq;
  76. return cp->csr & Blocki;
  77. }
  78. static void
  79. dmaintr(Ureg *, void *a)
  80. {
  81. int i = (int)a; /* dma request & chan # */
  82. Dchan *cp;
  83. Regs *regs = (Regs *)PHYSSDMA;
  84. assert(i >= 0 && i < Nirq);
  85. *xfer[i].done = 1;
  86. assert(xfer[i].rend != nil);
  87. wakeup(xfer[i].rend);
  88. cp = regs->chan + i;
  89. if(!(cp->csr & Blocki))
  90. iprint("dmaintr: req %d: Blocki not set; csr %#lux\n",
  91. i, cp->csr);
  92. cp->csr |= cp->csr; /* extinguish intr source */
  93. coherence();
  94. regs->irqsts[i] = regs->irqsts[i]; /* extinguish intr source */
  95. coherence();
  96. regs->irqen[i] &= ~(1 << i);
  97. coherence();
  98. xfer[i].rend = nil;
  99. coherence();
  100. }
  101. void
  102. zerowds(ulong *wdp, int cnt)
  103. {
  104. while (cnt-- > 0)
  105. *wdp++ = 0;
  106. }
  107. static int
  108. istestdmadone(void *arg)
  109. {
  110. return *(int *)arg;
  111. }
  112. void
  113. dmainit(void)
  114. {
  115. int n;
  116. char name[16];
  117. Dchan *cp;
  118. Regs *regs = (Regs *)PHYSSDMA;
  119. if (probeaddr((uintptr)&regs->syssts) < 0)
  120. panic("dmainit: no syssts reg");
  121. regs->syssts = 0;
  122. coherence();
  123. regs->syscfg |= 1<<1; /* Softreset */
  124. coherence();
  125. while(!(regs->syssts & (1<<0))) /* Resetdone? */
  126. ;
  127. for (n = 0; n < Nchan; n++) {
  128. cp = regs->chan + n;
  129. cp->ccr = 0;
  130. cp->clnkctrl = 0;
  131. cp->cicr = 0;
  132. cp->csr = 0;
  133. cp->csdp = 0;
  134. cp->cen = cp->cfn = 0;
  135. cp->cssa = cp->cdsa = 0;
  136. cp->csei = cp->csfi = 0;
  137. cp->cdei = cp->cdfi = 0;
  138. // cp->csac = cp->cdac = 0; // ro
  139. cp->ccen = cp->ccfn = 0;
  140. cp->color = 0;
  141. }
  142. zerowds((void *)regs->irqsts, sizeof regs->irqsts / sizeof(ulong));
  143. zerowds((void *)regs->irqen, sizeof regs->irqen / sizeof(ulong));
  144. coherence();
  145. regs->gcr = 65; /* burst size + 1 */
  146. coherence();
  147. for (n = 0; n < Nirq; n++) {
  148. snprint(name, sizeof name, "dma%d", n);
  149. intrenable(Baseirq + n, dmaintr, (void *)n, nil, name);
  150. }
  151. }
  152. enum {
  153. Testbyte = 0252,
  154. Testsize = 256,
  155. Scratch = MB,
  156. };
  157. /*
  158. * try to confirm sane operation
  159. */
  160. void
  161. dmatest(void)
  162. {
  163. int n, done;
  164. uchar *bp;
  165. static ulong pat = 0x87654321;
  166. static Rendez trendez;
  167. if (up == nil)
  168. panic("dmatest: up not set yet");
  169. bp = (uchar *)KADDR(PHYSDRAM + 128*MB);
  170. memset(bp, Testbyte, Scratch);
  171. done = 0;
  172. dmastart((void *)PADDR(bp), Postincr, (void *)PADDR(&pat), Const,
  173. Testsize, &trendez, &done);
  174. sleep(&trendez, istestdmadone, &done);
  175. cachedinvse(bp, Scratch);
  176. if (((ulong *)bp)[0] != pat)
  177. panic("dmainit: copied incorrect data %#lux != %#lux",
  178. ((ulong *)bp)[0], pat);
  179. for (n = Testsize; n < Scratch && bp[n] != Testbyte; n++)
  180. ;
  181. if (n >= Scratch)
  182. panic("dmainit: ran wild over memory, clobbered ≥%,d bytes", n);
  183. if (bp[n] == Testbyte && n != Testsize)
  184. iprint("dma: %d-byte dma stopped after %d bytes!\n",
  185. Testsize, n);
  186. }
  187. /* addresses are physical */
  188. int
  189. dmastart(void *to, int tmode, void *from, int fmode, uint len, Rendez *rend,
  190. int *done)
  191. {
  192. int irq, chan;
  193. uint ruplen;
  194. Dchan *cp;
  195. Regs *regs = (Regs *)PHYSSDMA;
  196. static Lock alloclck;
  197. /* allocate free irq (and chan) */
  198. ilock(&alloclck);
  199. for (irq = 0; irq < Nirq && xfer[irq].rend != nil; irq++)
  200. ;
  201. if (irq >= Nirq)
  202. panic("dmastart: no available irqs; too many concurrent dmas");
  203. chan = irq;
  204. xfer[irq].rend = rend; /* for wakeup at intr time */
  205. xfer[irq].done = done;
  206. *done = 0;
  207. iunlock(&alloclck);
  208. ruplen = ROUNDUP(len, sizeof(ulong));
  209. assert(to != from);
  210. cp = regs->chan + chan;
  211. cp->ccr &= ~Enable; /* paranoia */
  212. cp->cicr = 0;
  213. regs->irqen[irq] &= ~(1 << chan);
  214. coherence();
  215. cp->csdp = 2; /* 2 = log2(sizeof(ulong)) */
  216. cp->cssa = (uintptr)from;
  217. cp->cdsa = (uintptr)to;
  218. cp->ccr = tmode << 14 | fmode << 12;
  219. cp->csei = cp->csfi = cp->cdei = cp->cdfi = 1;
  220. cp->cen = ruplen / sizeof(ulong); /* ulongs / frame */
  221. cp->cfn = 1; /* 1 frame / xfer */
  222. cp->cicr = Blocki; /* intr at end of block */
  223. regs->irqen[irq] |= 1 << chan;
  224. coherence();
  225. cp->ccr |= Enable; /* fire! */
  226. coherence();
  227. return irq;
  228. }