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