1 /*
2 * bcm2835 dma controller
3 *
4 * simplest to use only channels 0-6
5 * channels 7-14 have reduced functionality
6 * channel 15 is at a weird address
7 * channels 0 and 15 have an "external 128 bit 8 word read FIFO"
8 * for memory to memory transfers
9 *
10 * Experiments show that only channels 2-5,11-12 work with mmc
11 */
12
13 #include "u.h"
14 #include "../port/lib.h"
15 #include "../port/error.h"
16 #include "mem.h"
17 #include "dat.h"
18 #include "fns.h"
19 #include "io.h"
20
21 #define DMAREGS (VIRTIO+0x7000)
22
23 #define DBG if(Dbg)
24
25 enum {
26 Nchan = 7, /* number of dma channels */
27 Regsize = 0x100, /* size of regs for each chan */
28 Cbalign = 32, /* control block byte alignment */
29 Dbg = 0,
30
31 /* registers for each dma controller */
32 Cs = 0x00>>2,
33 Conblkad = 0x04>>2,
34 Ti = 0x08>>2,
35 Sourcead = 0x0c>>2,
36 Destad = 0x10>>2,
37 Txfrlen = 0x14>>2,
38 Stride = 0x18>>2,
39 Nextconbk = 0x1c>>2,
40 Debug = 0x20>>2,
41
42 /* collective registers */
43 Intstatus = 0xfe0>>2,
44 Enable = 0xff0>>2,
45
46 /* Cs */
47 Reset = 1<<31,
48 Abort = 1<<30,
49 Error = 1<<8,
50 Waitwrite = 1<<6,
51 Waitdreq = 1<<5,
52 Paused = 1<<4,
53 Dreq = 1<<3,
54 Int = 1<<2,
55 End = 1<<1,
56 Active = 1<<0,
57
58 /* Ti */
59 Permapshift= 16,
60 Srcignore = 1<<11,
61 Srcdreq = 1<<10,
62 Srcwidth128 = 1<<9,
63 Srcinc = 1<<8,
64 Destignore = 1<<7,
65 Destdreq = 1<<6,
66 Destwidth128 = 1<<5,
67 Destinc = 1<<4,
68 Waitresp = 1<<3,
69 Tdmode = 1<<1,
70 Inten = 1<<0,
71
72 /* Debug */
73 Lite = 1<<28,
74 Clrerrors = 7<<0,
75 };
76
77 typedef struct Ctlr Ctlr;
78 typedef struct Cb Cb;
79
80 struct Ctlr {
81 u32int *regs;
82 Cb *cb;
83 Rendez r;
84 int dmadone;
85 };
86
87 struct Cb {
88 u32int ti;
89 u32int sourcead;
90 u32int destad;
91 u32int txfrlen;
92 u32int stride;
93 u32int nextconbk;
94 u32int reserved[2];
95 };
96
97 static Ctlr dma[Nchan];
98 static u32int *dmaregs = (u32int*)DMAREGS;
99
100 static void
dump(char * msg,uchar * p,int n)101 dump(char *msg, uchar *p, int n)
102 {
103 print("%s", msg);
104 while(n-- > 0)
105 print(" %2.2x", *p++);
106 print("\n");
107 }
108
109 static void
dumpdregs(char * msg,u32int * r)110 dumpdregs(char *msg, u32int *r)
111 {
112 int i;
113
114 print("%s: %#p =", msg, r);
115 for(i = 0; i < 9; i++)
116 print(" %8.8uX", r[i]);
117 print("\n");
118 }
119
120 static int
dmadone(void * a)121 dmadone(void *a)
122 {
123 return ((Ctlr*)a)->dmadone;
124 }
125
126 static void
dmainterrupt(Ureg *,void * a)127 dmainterrupt(Ureg*, void *a)
128 {
129 Ctlr *ctlr;
130
131 ctlr = a;
132 ctlr->regs[Cs] = Int;
133 ctlr->dmadone = 1;
134 wakeup(&ctlr->r);
135 }
136
137 void
dmastart(int chan,int dev,int dir,void * src,void * dst,int len)138 dmastart(int chan, int dev, int dir, void *src, void *dst, int len)
139 {
140 Ctlr *ctlr;
141 Cb *cb;
142 int ti;
143
144 ctlr = &dma[chan];
145 if(ctlr->regs == nil){
146 ctlr->regs = (u32int*)(DMAREGS + chan*Regsize);
147 ctlr->cb = xspanalloc(sizeof(Cb), Cbalign, 0);
148 assert(ctlr->cb != nil);
149 dmaregs[Enable] |= 1<<chan;
150 ctlr->regs[Cs] = Reset;
151 while(ctlr->regs[Cs] & Reset)
152 ;
153 intrenable(IRQDMA(chan), dmainterrupt, ctlr, 0, "dma");
154 }
155 cb = ctlr->cb;
156 ti = 0;
157 switch(dir){
158 case DmaD2M:
159 cachedwbinvse(dst, len);
160 ti = Srcdreq | Destinc;
161 cb->sourcead = DMAIO(src);
162 cb->destad = DMAADDR(dst);
163 break;
164 case DmaM2D:
165 cachedwbse(src, len);
166 ti = Destdreq | Srcinc;
167 cb->sourcead = DMAADDR(src);
168 cb->destad = DMAIO(dst);
169 break;
170 case DmaM2M:
171 cachedwbse(src, len);
172 cachedwbinvse(dst, len);
173 ti = Srcinc | Destinc;
174 cb->sourcead = DMAADDR(src);
175 cb->destad = DMAADDR(dst);
176 break;
177 }
178 cb->ti = ti | dev<<Permapshift | Inten;
179 cb->txfrlen = len;
180 cb->stride = 0;
181 cb->nextconbk = 0;
182 cachedwbse(cb, sizeof(Cb));
183 ctlr->regs[Cs] = 0;
184 microdelay(1);
185 ctlr->regs[Conblkad] = DMAADDR(cb);
186 DBG print("dma start: %ux %ux %ux %ux %ux %ux\n",
187 cb->ti, cb->sourcead, cb->destad, cb->txfrlen,
188 cb->stride, cb->nextconbk);
189 DBG print("intstatus %ux\n", dmaregs[Intstatus]);
190 dmaregs[Intstatus] = 0;
191 ctlr->regs[Cs] = Int;
192 microdelay(1);
193 coherence();
194 DBG dumpdregs("before Active", ctlr->regs);
195 ctlr->regs[Cs] = Active;
196 DBG dumpdregs("after Active", ctlr->regs);
197 }
198
199 int
dmawait(int chan)200 dmawait(int chan)
201 {
202 Ctlr *ctlr;
203 u32int *r;
204 int s;
205
206 ctlr = &dma[chan];
207 tsleep(&ctlr->r, dmadone, ctlr, 3000);
208 ctlr->dmadone = 0;
209 r = ctlr->regs;
210 DBG dumpdregs("after sleep", r);
211 s = r[Cs];
212 if((s & (Active|End|Error)) != End){
213 print("dma chan %d %s Cs %ux Debug %ux\n", chan,
214 (s&End)? "error" : "timeout", s, r[Debug]);
215 r[Cs] = Reset;
216 r[Debug] = Clrerrors;
217 return -1;
218 }
219 r[Cs] = Int|End;
220 return 0;
221 }
222