xref: /plan9/sys/src/9/bcm/dma.c (revision b4d1cf41cd5301e4c76aef9c04ddee28ac168a8e)
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