sa1110dma.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. #include "../port/error.h"
  8. #include "sa1110dma.h"
  9. static int debug = 0;
  10. /*
  11. * DMA helper routines
  12. */
  13. enum {
  14. NDMA = 6, /* Number of DMA channels */
  15. DMAREGS = 0xb0000000, /* DMA registers, physical */
  16. };
  17. enum {
  18. /* Device Address Register, DDAR */
  19. RW = 0,
  20. E = 1,
  21. BS = 2,
  22. DW = 3,
  23. DS = 4, /* bits 4 - 7 */
  24. DA = 8 /* bits 8 - 31 */
  25. };
  26. enum {
  27. /* Device Control & Status Register, DCSR */
  28. RUN = 0,
  29. IE = 1,
  30. ERROR = 2,
  31. DONEA = 3,
  32. STRTA = 4,
  33. DONEB = 5,
  34. STRTB = 6,
  35. BIU = 7
  36. };
  37. typedef struct DMAchan {
  38. int allocated;
  39. Rendez r;
  40. void (*intr)(void*, ulong);
  41. void *param;
  42. } DMAchan;
  43. struct {
  44. Lock;
  45. DMAchan chan[6];
  46. } dma;
  47. struct dmaregs {
  48. ulong ddar;
  49. ulong dcsr_set;
  50. ulong dcsr_clr;
  51. ulong dcsr_rd;
  52. ulong dstrtA;
  53. ulong dxcntA;
  54. ulong dstrtB;
  55. ulong dxcntB;
  56. } *dmaregs;
  57. static void dmaintr(Ureg*, void *);
  58. void
  59. dmainit(void) {
  60. int i;
  61. /* map the lcd regs into the kernel's virtual space */
  62. dmaregs = (struct dmaregs*)mapspecial(DMAREGS, NDMA*sizeof(struct dmaregs));
  63. if (debug) print("dma: dmaalloc registers 0x%ux mapped at 0x%p\n",
  64. DMAREGS, dmaregs);
  65. for (i = 0; i < NDMA; i++) {
  66. intrenable(IRQ, IRQdma0+i, dmaintr, &dmaregs[i], "DMA");
  67. }
  68. }
  69. void
  70. dmareset(int i, int rd, int bigendian, int burstsize, int datumsize, int device, ulong port) {
  71. ulong ddar;
  72. ddar =
  73. (rd?1:0)<<RW |
  74. (bigendian?1:0)<<E |
  75. ((burstsize==8)?1:0)<<BS |
  76. ((datumsize==2)?1:0)<<DW |
  77. device<<DS |
  78. 0x80000000 | ((ulong)port << 6);
  79. dmaregs[i].ddar = ddar;
  80. dmaregs[i].dcsr_clr = 0xff;
  81. if (debug) print("dma: dmareset: 0x%lux\n", ddar);
  82. }
  83. int
  84. dmaalloc(int rd, int bigendian, int burstsize, int datumsize, int device, ulong port, void (*intr)(void*, ulong), void *param) {
  85. int i;
  86. lock(&dma);
  87. for (i = 0; i < NDMA; i++) {
  88. if (dma.chan[i].allocated)
  89. continue;
  90. dma.chan[i].allocated++;
  91. unlock(&dma);
  92. dmareset(i, rd, bigendian, burstsize, datumsize, device, port);
  93. dma.chan[i].intr = intr;
  94. dma.chan[i].param = param;
  95. return i;
  96. }
  97. unlock(&dma);
  98. return -1;
  99. }
  100. void
  101. dmafree(int i) {
  102. dmaregs[i].dcsr_clr = 0xff;
  103. dmaregs[i].ddar = 0;
  104. dma.chan[i].allocated = 0;
  105. dma.chan[i].intr = nil;
  106. }
  107. void
  108. dmastop(int i) {
  109. dmaregs[i].dcsr_clr = 0xff;
  110. }
  111. ulong
  112. dmastart(int chan, ulong addr, int count) {
  113. ulong status, n;
  114. static int last;
  115. /* If this gets called from interrupt routines, make sure ilocks are used */
  116. status = dmaregs[chan].dcsr_rd;
  117. if (debug > 1)
  118. iprint("dma: dmastart 0x%lux\n", status);
  119. if ((status & (1<<STRTA|1<<STRTB|1<<RUN)) == (1<<STRTA|1<<STRTB|1<<RUN)) {
  120. return 0;
  121. }
  122. cachewbregion(addr, count);
  123. n = 0x100;
  124. if ((status & (1<<BIU | 1<<STRTB)) == (1<<BIU | 1<<STRTB) ||
  125. (status & (1<<BIU | 1<<STRTA)) == 0) {
  126. if (status & 1<<STRTA)
  127. iprint("writing busy dma entry 0x%lux\n", status);
  128. if (status & 1<<STRTB)
  129. n = (last == 1)?0x200:0x300;
  130. last = 2;
  131. dmaregs[chan].dstrtA = addr;
  132. dmaregs[chan].dxcntA = count;
  133. dmaregs[chan].dcsr_set = 1<<RUN | 1<<IE | 1<<STRTA;
  134. n |= 1<<DONEA;
  135. } else {
  136. if (status & 1<<STRTB)
  137. iprint("writing busy dma entry 0x%lux\n", status);
  138. if (status & 1<<STRTA)
  139. n = (last == 2)?0x200:0x300;
  140. last = 1;
  141. dmaregs[chan].dstrtB = addr;
  142. dmaregs[chan].dxcntB = count;
  143. dmaregs[chan].dcsr_set = 1<<RUN | 1<<IE | 1<<STRTB;
  144. n |= 1<<DONEB;
  145. }
  146. return n;
  147. }
  148. int
  149. dmaidle(int chan) {
  150. ulong status;
  151. status = dmaregs[chan].dcsr_rd;
  152. if (debug > 1) print("dmaidle: 0x%lux\n", status);
  153. return (status & (1<<STRTA|1<<STRTB)) == 0;
  154. }
  155. static int
  156. _dmaidle(void* chan) {
  157. ulong status;
  158. status = dmaregs[(int)chan].dcsr_rd;
  159. return (status & (1<<STRTA|1<<STRTB)) == 0;
  160. }
  161. void
  162. dmawait(int chan) {
  163. while (!dmaidle(chan))
  164. sleep(&dma.chan[chan].r, _dmaidle, (void*)chan);
  165. }
  166. /*
  167. * interrupt routine
  168. */
  169. static void
  170. dmaintr(Ureg*, void *x)
  171. {
  172. int i;
  173. struct dmaregs *regs = x;
  174. ulong dcsr, donebit;
  175. i = regs - dmaregs;
  176. dcsr = regs->dcsr_rd;
  177. if (debug > 1)
  178. iprint("dma: interrupt channel %d, status 0x%lux\n", i, dcsr);
  179. if (dcsr & 1<<ERROR)
  180. iprint("error, channel %d, status 0x%lux\n", i, dcsr);
  181. donebit = 1<<((dcsr&1<<BIU)?DONEA:DONEB);
  182. if (dcsr & donebit) {
  183. regs->dcsr_clr = 1<<DONEA|1<<DONEB;
  184. if (dma.chan[i].intr) {
  185. (*dma.chan[i].intr)(dma.chan[i].param, dcsr & (1<<DONEA|1<<DONEB));
  186. }
  187. wakeup(&dma.chan[i].r);
  188. return;
  189. }
  190. if (dcsr & 1<<ERROR) {
  191. regs->dcsr_clr = ERROR;
  192. iprint("DMA error, channel %d, status 0x%lux\n", i, dcsr);
  193. if (dma.chan[i].intr) {
  194. (*dma.chan[i].intr)(dma.chan[i].param, 0);
  195. }
  196. wakeup(&dma.chan[i].r);
  197. return;
  198. }
  199. iprint("spurious DMA interrupt, channel %d, status 0x%lux\n", i, dcsr);
  200. }