dma.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "../port/error.h"
  7. #include "io.h"
  8. #define DMAREGS ((Dmaregs*)PHYSDMA)
  9. typedef struct Dmadesc Dmadesc;
  10. typedef struct Dmaregs Dmaregs;
  11. struct Dmadesc {
  12. ulong ddadr; /* next descriptor address (0 mod 16) */
  13. ulong dsadr; /* source address (0 mod 8 if external, 0 mod 4 internal) */
  14. ulong dtadr; /* target address (same) */
  15. ulong dcmd; /* command */
  16. };
  17. struct Dmaregs {
  18. ulong dcsr[16]; /* control and status */
  19. uchar pad0[0xF0-0x40];
  20. ulong dint; /* mask of interrupting channels: 0 is bit 0 */
  21. uchar pad1[0x100-0xF4];
  22. ulong drcmr[40];
  23. Dmadesc chan[16]; /* offset 0x200 */
  24. };
  25. enum {
  26. /* dcsr */
  27. DcsRun= 1<<31, /* start the channel */
  28. DcsNodesc= 1<<30, /* set if channel is in no-descriptor fetch mode */
  29. DcsStopirq= 1<<29, /* enable interrupt if channel is uninitialised or stopped */
  30. DcsReqpend= 1<<8, /* channel has pending request */
  31. DcsStopstate= 1<<3, /* channel is uninitialised or stopped */
  32. DcsEndintr= 1<<2, /* transaction complete, length now 0 */
  33. DcsStartintr= 1<<1, /* successful descriptor fetch */
  34. DcsBuserr= 1<<0, /* bus error */
  35. /* drcmr */
  36. DmrValid= 1<<7, /* mapped to channel given by bits 0-3 */
  37. DmrChan= 0xF, /* channel number mask */
  38. /* ddadr */
  39. DdaStop= 1<<1, /* =0, run channel; =1, stop channel after this descriptor */
  40. /* dcmd */
  41. DcmIncsrc= 1<<31, /* increment source address after use */
  42. DcmIncdest= 1<<30, /* increment destination address after use */
  43. DcmFlowsrc= 1<<29, /* enable flow control on source */
  44. DcmFlowdest= 1<<28, /* enable flow control on target */
  45. DcmStartirq= 1<<22, /* interrupt when descriptor loaded (fetch mode) */
  46. DcmEndirq= 1<<21, /* interrupt when transfer complete */
  47. DcmEndian= 1<<18, /* must be zero (little endian) */
  48. DcmBurst8= 1<<16, /* burst size in bytes */
  49. DcmBurst16= 2<<16,
  50. DcmBurst32= 3<<16,
  51. DcmWidth0= 0<<14, /* width for external memory */
  52. DcmWidth1= 1<<14, /* width of on-chip peripheral */
  53. DcmWidth2= 2<<14,
  54. DcmWidth4= 3<<14,
  55. DcmLength= (1<<13)-1,
  56. Ndma= 16, /* number of dma channels */
  57. MaxDMAbytes= 8192-1, /* annoyingly small limit */
  58. };
  59. struct Dma {
  60. int chan;
  61. Dmadesc* desc;
  62. Dmadesc stop;
  63. ulong *csr;
  64. void (*interrupt)(void*, ulong);
  65. void* arg;
  66. Rendez r;
  67. ulong attrs; /* transfer attributes: flow control, burst size, width */
  68. };
  69. static struct {
  70. Lock;
  71. ulong avail;
  72. Dma dma[Ndma];
  73. } dmachans;
  74. static void dmaintr(Ureg*, void*);
  75. void
  76. dmareset(void)
  77. {
  78. int i;
  79. Dma *d;
  80. for(i=0; i<Ndma; i++){
  81. dmachans.avail |= 1<<i;
  82. d = &dmachans.dma[i];
  83. d->chan = i;
  84. d->csr = &DMAREGS->dcsr[i];
  85. d->desc = &DMAREGS->chan[i];
  86. d->stop.ddadr = (ulong)&d->stop | DdaStop;
  87. d->stop.dcmd = 0;
  88. }
  89. intrenable(IRQ, IRQdma, dmaintr, nil, "dma");
  90. }
  91. /*
  92. * allocate a DMA channel, reset it, and configure it for the given device
  93. */
  94. Dma*
  95. dmasetup(int owner, void (*interrupt)(void*, ulong), void *arg, ulong attrs)
  96. {
  97. Dma *d;
  98. Dmadesc *dc;
  99. int i;
  100. ilock(&dmachans);
  101. for(i=0; (dmachans.avail & (1<<i)) == 0; i++)
  102. if(i >= Ndma){
  103. iunlock(&dmachans);
  104. return nil;
  105. }
  106. dmachans.avail &= ~(1<<i);
  107. iunlock(&dmachans);
  108. d = &dmachans.dma[i];
  109. d->owner = owner;
  110. d->interrupt = interrupt;
  111. d->arg = arg;
  112. d->attrs = attrs;
  113. dc = d->desc;
  114. dc->ddadr = (ulong)&d->stop | DdaStop; /* empty list */
  115. dc->dcmd = 0;
  116. *d->csr = DcsEndintr | DcsStartintr | DcsBuserr; /* clear status, stopped */
  117. DMAREGS->drcmr[owner] = DmrValid | i;
  118. return d;
  119. }
  120. void
  121. dmafree(Dma *dma)
  122. {
  123. dmastop(dma);
  124. DMAREGS->drcmr[d->owner] = 0;
  125. ilock(&dmachans);
  126. dmachans.avail |= 1<<dma->chan;
  127. dma->interrupt = nil;
  128. iunlock(&dmachans);
  129. }
  130. /*
  131. * simple dma transfer on a channel, using `no fetch descriptor' mode.
  132. * virtual buffer addresses are assumed to refer to contiguous physical addresses.
  133. */
  134. int
  135. dmastart(Dma *dma, void *from, void *to, int nbytes)
  136. {
  137. Dmadesc *dc;
  138. if((ulong)nbytes > MaxDMAbytes)
  139. panic("dmastart");
  140. if((*dma->csr & DcsStopstate) == 0)
  141. return 0; /* busy */
  142. dc = dma->desc;
  143. dc->ddadr = DdaStop;
  144. dc->dsadr = PADDR(from);
  145. dc->dtadr = PADDR(to);
  146. dc->dcmd = dma->attrs | DcmEndirq | nbytes;
  147. *dma->csr = DcsRun | DcsNodesc | DcsEndintr | DcsStartintr | DcsBuserr;
  148. return 1;
  149. }
  150. /*
  151. * stop dma on a channel
  152. */
  153. void
  154. dmastop(Dma *dma)
  155. {
  156. *dma->csr = 0;
  157. while((*dma->csr & DcsStopstate) == 0)
  158. ;
  159. *dma->csr = DcsStopstate;
  160. }
  161. /*
  162. * return nonzero if there was a memory error during DMA,
  163. * and clear the error state
  164. */
  165. int
  166. dmaerror(Dma *dma)
  167. {
  168. ulong e;
  169. e = *dma->csr & DcsBuserr;
  170. *dma->csr |= e;
  171. return e;
  172. }
  173. /*
  174. * return nonzero if the DMA channel is not busy
  175. */
  176. int
  177. dmaidle(Dma *d)
  178. {
  179. return (*d->csr & DcsStopstate) == 0;
  180. }
  181. static int
  182. dmaidlep(void *a)
  183. {
  184. return dmaidle((Dma*)a);
  185. }
  186. void
  187. dmawait(Dma *d)
  188. {
  189. while(!dmaidle(d))
  190. sleep(&d->r, dmaidlep, d);
  191. }
  192. /*
  193. * this interface really only copes with one buffer at once
  194. */
  195. static void
  196. dmaintr(Ureg*, void*)
  197. {
  198. Dma *d;
  199. Dmaregs *dr;
  200. int i;
  201. ulong s, csr;
  202. dr = DMAREGS;
  203. s = dr->dint;
  204. dr->dint = s;
  205. for(i=0; i<Ndma && s != 0; i++)
  206. if(s & (1<<i)){
  207. d = &dmachans.dma[i];
  208. csr = *d->csr;
  209. if(csr & DcsBuserr)
  210. iprint("DMA error, chan %d status #%8.8lux\n", d->chan, csr);
  211. *d->csr = csr & (DcsRun | DcsNodesc | DcsEndintr | DcsStartintr | DcsBuserr);
  212. if(d->interrupt != nil)
  213. d->interrupt(d->arg, csr);
  214. else
  215. wakeup(&d->r);
  216. }
  217. }