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