xref: /plan9/sys/src/9/bcm/emmc.c (revision b4d1cf41cd5301e4c76aef9c04ddee28ac168a8e)
1 /*
2  * bcm2835 external mass media controller (mmc / sd host interface)
3  *
4  * Copyright © 2012 Richard Miller <r.miller@acm.org>
5  */
6 
7 #include "u.h"
8 #include "../port/lib.h"
9 #include "../port/error.h"
10 #include "mem.h"
11 #include "dat.h"
12 #include "fns.h"
13 #include "io.h"
14 #include "../port/sd.h"
15 
16 #define EMMCREGS	(VIRTIO+0x300000)
17 
18 enum {
19 	Extfreq		= 100*Mhz,	/* guess external clock frequency if */
20 					/* not available from vcore */
21 	Initfreq	= 400000,	/* initialisation frequency for MMC */
22 	SDfreq		= 25*Mhz,	/* standard SD frequency */
23 	DTO		= 14,		/* data timeout exponent (guesswork) */
24 
25 	MMCSelect	= 7,		/* mmc/sd card select command */
26 	Setbuswidth	= 6,		/* mmc/sd set bus width command */
27 };
28 
29 enum {
30 	/* Controller registers */
31 	Arg2			= 0x00>>2,
32 	Blksizecnt		= 0x04>>2,
33 	Arg1			= 0x08>>2,
34 	Cmdtm			= 0x0c>>2,
35 	Resp0			= 0x10>>2,
36 	Resp1			= 0x14>>2,
37 	Resp2			= 0x18>>2,
38 	Resp3			= 0x1c>>2,
39 	Data			= 0x20>>2,
40 	Status			= 0x24>>2,
41 	Control0		= 0x28>>2,
42 	Control1		= 0x2c>>2,
43 	Interrupt		= 0x30>>2,
44 	Irptmask		= 0x34>>2,
45 	Irpten			= 0x38>>2,
46 	Control2		= 0x3c>>2,
47 	Forceirpt		= 0x50>>2,
48 	Boottimeout		= 0x70>>2,
49 	Dbgsel			= 0x74>>2,
50 	Exrdfifocfg		= 0x80>>2,
51 	Exrdfifoen		= 0x84>>2,
52 	Tunestep		= 0x88>>2,
53 	Tunestepsstd		= 0x8c>>2,
54 	Tunestepsddr		= 0x90>>2,
55 	Spiintspt		= 0xf0>>2,
56 	Slotisrver		= 0xfc>>2,
57 
58 	/* Control0 */
59 	Dwidth4			= 1<<1,
60 	Dwidth1			= 0<<1,
61 
62 	/* Control1 */
63 	Srstdata		= 1<<26,	/* reset data circuit */
64 	Srstcmd			= 1<<25,	/* reset command circuit */
65 	Srsthc			= 1<<24,	/* reset complete host controller */
66 	Datatoshift		= 16,		/* data timeout unit exponent */
67 	Datatomask		= 0xF0000,
68 	Clkfreq8shift		= 8,		/* SD clock base divider LSBs */
69 	Clkfreq8mask		= 0xFF00,
70 	Clkfreqms2shift		= 6,		/* SD clock base divider MSBs */
71 	Clkfreqms2mask		= 0xC0,
72 	Clkgendiv		= 0<<5,		/* SD clock divided */
73 	Clkgenprog		= 1<<5,		/* SD clock programmable */
74 	Clken			= 1<<2,		/* SD clock enable */
75 	Clkstable		= 1<<1,
76 	Clkintlen		= 1<<0,		/* enable internal EMMC clocks */
77 
78 	/* Cmdtm */
79 	Indexshift		= 24,
80 	Suspend			= 1<<22,
81 	Resume			= 2<<22,
82 	Abort			= 3<<22,
83 	Isdata			= 1<<21,
84 	Ixchken			= 1<<20,
85 	Crcchken		= 1<<19,
86 	Respmask		= 3<<16,
87 	Respnone		= 0<<16,
88 	Resp136			= 1<<16,
89 	Resp48			= 2<<16,
90 	Resp48busy		= 3<<16,
91 	Multiblock		= 1<<5,
92 	Host2card		= 0<<4,
93 	Card2host		= 1<<4,
94 	Autocmd12		= 1<<2,
95 	Autocmd23		= 2<<2,
96 	Blkcnten		= 1<<1,
97 
98 	/* Interrupt */
99 	Acmderr		= 1<<24,
100 	Denderr		= 1<<22,
101 	Dcrcerr		= 1<<21,
102 	Dtoerr		= 1<<20,
103 	Cbaderr		= 1<<19,
104 	Cenderr		= 1<<18,
105 	Ccrcerr		= 1<<17,
106 	Ctoerr		= 1<<16,
107 	Err		= 1<<15,
108 	Cardintr	= 1<<8,		/* not in Broadcom datasheet */
109 	Cardinsert	= 1<<6,		/* not in Broadcom datasheet */
110 	Readrdy		= 1<<5,
111 	Writerdy	= 1<<4,
112 	Datadone	= 1<<1,
113 	Cmddone		= 1<<0,
114 
115 	/* Status */
116 	Bufread		= 1<<11,	/* not in Broadcom datasheet */
117 	Bufwrite	= 1<<10,	/* not in Broadcom datasheet */
118 	Readtrans	= 1<<9,
119 	Writetrans	= 1<<8,
120 	Datactive	= 1<<2,
121 	Datinhibit	= 1<<1,
122 	Cmdinhibit	= 1<<0,
123 };
124 
125 int cmdinfo[64] = {
126 [0]  Ixchken,
127 [2]  Resp136,
128 [3]  Resp48 | Ixchken | Crcchken,
129 [6]  Resp48 | Ixchken | Crcchken,
130 [7]  Resp48busy | Ixchken | Crcchken,
131 [8]  Resp48 | Ixchken | Crcchken,
132 [9]  Resp136,
133 [12] Resp48busy | Ixchken | Crcchken,
134 [13] Resp48 | Ixchken | Crcchken,
135 [16] Resp48,
136 [17] Resp48 | Isdata | Card2host | Ixchken | Crcchken,
137 [18] Resp48 | Isdata | Card2host | Multiblock | Blkcnten | Ixchken | Crcchken,
138 [24] Resp48 | Isdata | Host2card | Ixchken | Crcchken,
139 [25] Resp48 | Isdata | Host2card | Multiblock | Blkcnten | Ixchken | Crcchken,
140 [41] Resp48,
141 [55] Resp48 | Ixchken | Crcchken,
142 };
143 
144 typedef struct Ctlr Ctlr;
145 
146 struct Ctlr {
147 	Rendez	r;
148 	int	datadone;
149 	int	fastclock;
150 	ulong	extclk;
151 };
152 
153 static Ctlr emmc;
154 
155 static void mmcinterrupt(Ureg*, void*);
156 
157 static void
WR(int reg,u32int val)158 WR(int reg, u32int val)
159 {
160 	u32int *r = (u32int*)EMMCREGS;
161 
162 	if(0)print("WR %2.2ux %ux\n", reg<<2, val);
163 	microdelay(emmc.fastclock? 2 : 20);
164 	r[reg] = val;
165 }
166 
167 static uint
clkdiv(uint d)168 clkdiv(uint d)
169 {
170 	uint v;
171 
172 	assert(d < 1<<10);
173 	v = (d << Clkfreq8shift) & Clkfreq8mask;
174 	v |= ((d >> 8) << Clkfreqms2shift) & Clkfreqms2mask;
175 	return v;
176 }
177 
178 static int
datadone(void *)179 datadone(void*)
180 {
181 	return emmc.datadone;
182 }
183 
184 static int
emmcinit(void)185 emmcinit(void)
186 {
187 	u32int *r;
188 	ulong clk;
189 	char *s;
190 
191 	clk = getclkrate(ClkEmmc);
192 	s = "";
193 	if(clk == 0){
194 		s = "Assuming ";
195 		clk = Extfreq;
196 	}
197 	emmc.extclk = clk;
198 	print("%seMMC external clock %lud Mhz\n", s, clk/1000000);
199 	r = (u32int*)EMMCREGS;
200 	if(0)print("emmc control %8.8ux %8.8ux %8.8ux\n",
201 		r[Control0], r[Control1], r[Control2]);
202 	WR(Control1, Srsthc);
203 	delay(10);
204 	while(r[Control1] & Srsthc)
205 		;
206 	return 0;
207 }
208 
209 static int
emmcinquiry(char * inquiry,int inqlen)210 emmcinquiry(char *inquiry, int inqlen)
211 {
212 	u32int *r;
213 	uint ver;
214 
215 	r = (u32int*)EMMCREGS;
216 	ver = r[Slotisrver] >> 16;
217 	return snprint(inquiry, inqlen,
218 		"Arasan eMMC SD Host Controller %2.2x Version %2.2x",
219 		ver&0xFF, ver>>8);
220 }
221 
222 static void
emmcenable(void)223 emmcenable(void)
224 {
225 	u32int *r;
226 	int i;
227 
228 	r = (u32int*)EMMCREGS;
229 	WR(Control1, clkdiv(emmc.extclk/Initfreq - 1) |
230 		DTO<<Datatoshift | Clkgendiv | Clken | Clkintlen);
231 	for(i = 0; i < 1000; i++){
232 		delay(1);
233 		if(r[Control1] & Clkstable)
234 			break;
235 	}
236 	if(i == 1000)
237 		print("SD clock won't initialise!\n");
238 	WR(Irptmask, ~(Dtoerr|Cardintr));
239 	intrenable(IRQmmc, mmcinterrupt, nil, 0, "mmc");
240 }
241 
242 static int
emmccmd(u32int cmd,u32int arg,u32int * resp)243 emmccmd(u32int cmd, u32int arg, u32int *resp)
244 {
245 	u32int *r;
246 	u32int c;
247 	int i;
248 	ulong now;
249 
250 	r = (u32int*)EMMCREGS;
251 	assert(cmd < nelem(cmdinfo) && cmdinfo[cmd] != 0);
252 	c = (cmd << Indexshift) | cmdinfo[cmd];
253 	if(r[Status] & Cmdinhibit){
254 		print("emmccmd: need to reset Cmdinhibit intr %ux stat %ux\n",
255 			r[Interrupt], r[Status]);
256 		WR(Control1, r[Control1] | Srstcmd);
257 		while(r[Control1] & Srstcmd)
258 			;
259 		while(r[Status] & Cmdinhibit)
260 			;
261 	}
262 	if((r[Status] & Datinhibit) &&
263 	   ((c & Isdata) || (c & Respmask) == Resp48busy)){
264 		print("emmccmd: need to reset Datinhibit intr %ux stat %ux\n",
265 			r[Interrupt], r[Status]);
266 		WR(Control1, r[Control1] | Srstdata);
267 		while(r[Control1] & Srstdata)
268 			;
269 		while(r[Status] & Datinhibit)
270 			;
271 	}
272 	WR(Arg1, arg);
273 	if((i = r[Interrupt]) != 0){
274 		if(i != Cardinsert)
275 			print("emmc: before command, intr was %ux\n", i);
276 		WR(Interrupt, i);
277 	}
278 	WR(Cmdtm, c);
279 	now = m->ticks;
280 	while(((i=r[Interrupt])&(Cmddone|Err)) == 0)
281 		if(m->ticks-now > HZ)
282 			break;
283 	if((i&(Cmddone|Err)) != Cmddone){
284 		if((i&~Err) != Ctoerr)
285 			print("emmc: cmd %ux error intr %ux stat %ux\n", c, i, r[Status]);
286 		WR(Interrupt, i);
287 		if(r[Status]&Cmdinhibit){
288 			WR(Control1, r[Control1]|Srstcmd);
289 			while(r[Control1]&Srstcmd)
290 				;
291 		}
292 		error(Eio);
293 	}
294 	WR(Interrupt, i & ~(Datadone|Readrdy|Writerdy));
295 	switch(c & Respmask){
296 	case Resp136:
297 		resp[0] = r[Resp0]<<8;
298 		resp[1] = r[Resp0]>>24 | r[Resp1]<<8;
299 		resp[2] = r[Resp1]>>24 | r[Resp2]<<8;
300 		resp[3] = r[Resp2]>>24 | r[Resp3]<<8;
301 		break;
302 	case Resp48:
303 	case Resp48busy:
304 		resp[0] = r[Resp0];
305 		break;
306 	case Respnone:
307 		resp[0] = 0;
308 		break;
309 	}
310 	if((c & Respmask) == Resp48busy){
311 		WR(Irpten, Datadone|Err);
312 		tsleep(&emmc.r, datadone, 0, 3000);
313 		i = emmc.datadone;
314 		emmc.datadone = 0;
315 		WR(Irpten, 0);
316 		if((i & Datadone) == 0)
317 			print("emmcio: no Datadone after CMD%d\n", cmd);
318 		if(i & Err)
319 			print("emmcio: CMD%d error interrupt %ux\n",
320 				cmd, r[Interrupt]);
321 		WR(Interrupt, i);
322 	}
323 	/*
324 	 * Once card is selected, use faster clock
325 	 */
326 	if(cmd == MMCSelect){
327 		delay(10);
328 		WR(Control1, clkdiv(emmc.extclk/SDfreq - 1) |
329 			DTO<<Datatoshift | Clkgendiv | Clken | Clkintlen);
330 		for(i = 0; i < 1000; i++){
331 			delay(1);
332 			if(r[Control1] & Clkstable)
333 				break;
334 		}
335 		delay(10);
336 		emmc.fastclock = 1;
337 	}
338 	/*
339 	 * If card bus width changes, change host bus width
340 	 */
341 	if(cmd == Setbuswidth){
342 		switch(arg){
343 		case 0:
344 			WR(Control0, r[Control0] & ~Dwidth4);
345 			break;
346 		case 2:
347 			WR(Control0, r[Control0] | Dwidth4);
348 			break;
349 		}
350 	}
351 	return 0;
352 }
353 
354 void
emmciosetup(int write,void * buf,int bsize,int bcount)355 emmciosetup(int write, void *buf, int bsize, int bcount)
356 {
357 	USED(write);
358 	USED(buf);
359 	WR(Blksizecnt, bcount<<16 | bsize);
360 }
361 
362 static void
emmcio(int write,uchar * buf,int len)363 emmcio(int write, uchar *buf, int len)
364 {
365 	u32int *r;
366 	int i;
367 
368 	r = (u32int*)EMMCREGS;
369 	assert((len&3) == 0);
370 	okay(1);
371 	if(waserror()){
372 		okay(0);
373 		nexterror();
374 	}
375 	if(write)
376 		dmastart(DmaChanEmmc, DmaDevEmmc, DmaM2D,
377 			buf, &r[Data], len);
378 	else
379 		dmastart(DmaChanEmmc, DmaDevEmmc, DmaD2M,
380 			&r[Data], buf, len);
381 	if(dmawait(DmaChanEmmc) < 0)
382 		error(Eio);
383 	WR(Irpten, Datadone|Err);
384 	tsleep(&emmc.r, datadone, 0, 3000);
385 	i = emmc.datadone;
386 	emmc.datadone = 0;
387 	WR(Irpten, 0);
388 	if((i & Datadone) == 0){
389 		print("emmcio: %d timeout intr %ux stat %ux\n",
390 			write, i, r[Status]);
391 		WR(Interrupt, i);
392 		error(Eio);
393 	}
394 	if(i & Err){
395 		print("emmcio: %d error intr %ux stat %ux\n",
396 			write, r[Interrupt], r[Status]);
397 		WR(Interrupt, i);
398 		error(Eio);
399 	}
400 	if(i)
401 		WR(Interrupt, i);
402 	poperror();
403 	okay(0);
404 }
405 
406 static void
mmcinterrupt(Ureg *,void *)407 mmcinterrupt(Ureg*, void*)
408 {
409 	u32int *r;
410 	int i;
411 
412 	r = (u32int*)EMMCREGS;
413 	i = r[Interrupt];
414 	r[Interrupt] = i & (Datadone|Err);
415 	emmc.datadone = i;
416 	wakeup(&emmc.r);
417 }
418 
419 SDio sdio = {
420 	"emmc",
421 	emmcinit,
422 	emmcenable,
423 	emmcinquiry,
424 	emmccmd,
425 	emmciosetup,
426 	emmcio,
427 };
428