2 * bcm2711 sd host controller
4 * Copyright © 2012,2019 Richard Miller <r.miller@acm.org>
6 * adapted from emmc.c - the two should really be merged
10 #include "../port/lib.h"
11 #include "../port/error.h"
16 #include "../port/sd.h"
18 #define EMMCREGS (VIRTIO+0x340000)
21 Extfreq = 100*Mhz, /* guess external clock frequency if */
22 /* not available from vcore */
23 Initfreq = 400000, /* initialisation frequency for MMC */
24 SDfreq = 25*Mhz, /* standard SD frequency */
25 SDfreqhs = 50*Mhz, /* high speed frequency */
26 DTO = 14, /* data timeout exponent (guesswork) */
28 GoIdle = 0, /* mmc/sdio go idle state */
29 MMCSelect = 7, /* mmc/sd card select command */
30 Setbuswidth = 6, /* mmc/sd set bus width command */
31 Switchfunc = 6, /* mmc/sd switch function command */
32 Voltageswitch = 11, /* md/sdio switch to 1.8V */
33 IORWdirect = 52, /* sdio read/write direct command */
34 IORWextended = 53, /* sdio read/write extended command */
35 Appcmd = 55, /* mmc/sd application command prefix */
39 /* Controller registers */
59 Boottimeout = 0x70>>2,
61 Exrdfifocfg = 0x80>>2,
64 Tunestepsstd = 0x8c>>2,
65 Tunestepsddr = 0x90>>2,
86 Srstdata = 1<<26, /* reset data circuit */
87 Srstcmd = 1<<25, /* reset command circuit */
88 Srsthc = 1<<24, /* reset complete host controller */
89 Datatoshift = 16, /* data timeout unit exponent */
91 Clkfreq8shift = 8, /* SD clock base divider LSBs */
92 Clkfreq8mask = 0xFF00,
93 Clkfreqms2shift = 6, /* SD clock base divider MSBs */
94 Clkfreqms2mask = 0xC0,
95 Clkgendiv = 0<<5, /* SD clock divided */
96 Clkgenprog = 1<<5, /* SD clock programmable */
97 Clken = 1<<2, /* SD clock enable */
99 Clkintlen = 1<<0, /* enable internal EMMC clocks */
134 Cardinsert = 1<<6, /* not in Broadcom datasheet */
142 Bufread = 1<<11, /* not in Broadcom datasheet */
143 Bufwrite = 1<<10, /* not in Broadcom datasheet */
151 static int cmdinfo[64] = {
154 [3] Resp48 | Ixchken | Crcchken,
156 [6] Resp48 | Ixchken | Crcchken,
157 [7] Resp48busy | Ixchken | Crcchken,
158 [8] Resp48 | Ixchken | Crcchken,
160 [11] Resp48 | Ixchken | Crcchken,
161 [12] Resp48busy | Ixchken | Crcchken,
162 [13] Resp48 | Ixchken | Crcchken,
164 [17] Resp48 | Isdata | Card2host | Ixchken | Crcchken,
165 [18] Resp48 | Isdata | Card2host | Multiblock | Blkcnten | Ixchken | Crcchken,
166 [24] Resp48 | Isdata | Host2card | Ixchken | Crcchken,
167 [25] Resp48 | Isdata | Host2card | Multiblock | Blkcnten | Ixchken | Crcchken,
169 [52] Resp48 | Ixchken | Crcchken,
170 [53] Resp48 | Ixchken | Crcchken | Isdata,
171 [55] Resp48 | Ixchken | Crcchken,
174 typedef struct Adma Adma;
175 typedef struct Ctlr Ctlr;
179 * See SD Host Controller Simplified Specification Version 2.00
196 /* maximum value for Length field */
197 Maxdma = ((1<<16) - 4),
211 static void mmcinterrupt(Ureg*, void*);
214 WR(int reg, u32int val)
216 u32int *r = (u32int*)EMMCREGS;
218 if(0)print("WR %2.2ux %ux\n", reg<<2, val);
229 v = (d << Clkfreq8shift) & Clkfreq8mask;
230 v |= ((d >> 8) << Clkfreqms2shift) & Clkfreqms2mask;
235 dmaalloc(void *addr, int len)
242 n = (len + Maxdma-1) / Maxdma;
243 adma = sdmalloc(n * sizeof(Adma));
244 for(p = adma; len > 0; p++){
245 p->desc = Valid | Tran;
247 p->desc |= len<<OLength | End | Int;
249 p->desc |= Maxdma<<OLength;
250 p->addr = dmaaddr((void*)a);
255 cachedwbse(adma, (char*)p - (char*)adma);
266 r = (u32int*)EMMCREGS;
267 div = emmc.extclk / (freq<<1);
268 if(emmc.extclk / (div<<1) > freq)
270 WR(Control1, clkdiv(div) |
271 DTO<<Datatoshift | Clkgendiv | Clken | Clkintlen);
272 for(i = 0; i < 1000; i++){
274 if(r[Control1] & Clkstable)
278 print("emmc: can't set clock to %ud\n", freq);
286 u32int *r = (u32int*)EMMCREGS;
288 return i & (Datadone|Err);
297 clk = getclkrate(ClkEmmc2);
300 print("emmc: assuming external clock %lud Mhz\n", clk/1000000);
303 r = (u32int*)EMMCREGS;
304 if(0)print("emmc control %8.8ux %8.8ux %8.8ux\n",
305 r[Control0], r[Control1], r[Control2]);
306 WR(Control1, Srsthc);
308 while(r[Control1] & Srsthc)
310 WR(Control1, Srstdata);
317 emmcinquiry(char *inquiry, int inqlen)
322 r = (u32int*)EMMCREGS;
323 ver = r[Slotisrver] >> 16;
324 return snprint(inquiry, inqlen,
325 "BCM SD Host Controller %2.2x Version %2.2x",
335 WR(Control0, V3_3 | Buspower | Dwidth1 | DmaADMA2);
340 WR(Irptmask, ~(Cardintr|Dmaintr));
342 intrenable(IRQmmc, mmcinterrupt, nil, BUSUNKNOWN, "sdhc");
346 emmccmd(u32int cmd, u32int arg, u32int *resp)
353 r = (u32int*)EMMCREGS;
354 assert(cmd < nelem(cmdinfo) && cmdinfo[cmd] != 0);
355 c = (cmd << Indexshift) | cmdinfo[cmd];
357 * CMD6 may be Setbuswidth or Switchfunc depending on Appcmd prefix
359 if(cmd == Switchfunc && !emmc.appcmd)
360 c |= Isdata|Card2host;
363 if(cmd == IORWextended){
368 if((r[Blksizecnt]&0xFFFF0000) != 0x10000)
369 c |= Multiblock | Blkcnten;
372 * GoIdle indicates new card insertion: reset bus width & speed
375 WR(Control0, r[Control0] & ~(Dwidth4|Hispeed));
378 if(r[Status] & Cmdinhibit){
379 print("emmccmd: need to reset Cmdinhibit intr %ux stat %ux\n",
380 r[Interrupt], r[Status]);
381 WR(Control1, r[Control1] | Srstcmd);
382 while(r[Control1] & Srstcmd)
384 while(r[Status] & Cmdinhibit)
387 if((r[Status] & Datinhibit) &&
388 ((c & Isdata) || (c & Respmask) == Resp48busy)){
389 print("emmccmd: need to reset Datinhibit intr %ux stat %ux\n",
390 r[Interrupt], r[Status]);
391 WR(Control1, r[Control1] | Srstdata);
392 while(r[Control1] & Srstdata)
394 while(r[Status] & Datinhibit)
398 if((i = (r[Interrupt] & ~Cardintr)) != 0){
400 print("emmc: before command, intr was %ux\n", i);
405 while(((i=r[Interrupt])&(Cmddone|Err)) == 0)
406 if(m->ticks-now > HZ)
408 if((i&(Cmddone|Err)) != Cmddone){
409 if((i&~(Err|Cardintr)) != Ctoerr)
410 print("emmc: cmd %ux arg %ux error intr %ux stat %ux\n", c, arg, i, r[Status]);
412 if(r[Status]&Cmdinhibit){
413 WR(Control1, r[Control1]|Srstcmd);
414 while(r[Control1]&Srstcmd)
419 WR(Interrupt, i & ~(Datadone|Readrdy|Writerdy));
420 switch(c & Respmask){
422 resp[0] = r[Resp0]<<8;
423 resp[1] = r[Resp0]>>24 | r[Resp1]<<8;
424 resp[2] = r[Resp1]>>24 | r[Resp2]<<8;
425 resp[3] = r[Resp2]>>24 | r[Resp3]<<8;
435 if((c & Respmask) == Resp48busy){
436 WR(Irpten, r[Irpten]|Datadone|Err);
437 tsleep(&emmc.r, datadone, 0, 3000);
439 if((i & Datadone) == 0)
440 print("emmcio: no Datadone after CMD%d\n", cmd);
442 print("emmcio: CMD%d error interrupt %ux\n",
447 * Once card is selected, use faster clock
449 if(cmd == MMCSelect){
455 if(cmd == Setbuswidth){
458 * If card bus width changes, change host bus width
462 WR(Control0, r[Control0] & ~Dwidth4);
465 WR(Control0, r[Control0] | Dwidth4);
470 * If card switched into high speed mode, increase clock speed
472 if((arg&0x8000000F) == 0x80000001){
478 }else if(cmd == IORWdirect && (arg & ~0xFF) == (1<<31|0<<28|7<<9)){
481 WR(Control0, r[Control0] & ~Dwidth4);
484 WR(Control0, r[Control0] | Dwidth4);
485 //WR(Control0, r[Control0] | Hispeed);
489 emmc.appcmd = (cmd == Appcmd);
494 emmciosetup(int write, void *buf, int bsize, int bcount)
498 len = bsize * bcount;
499 assert(((uintptr)buf&3) == 0);
500 assert((len&3) == 0);
501 assert(bsize <= 2048);
502 WR(Blksizecnt, bcount<<16 | bsize);
505 emmc.dma = dmaalloc(buf, len);
507 cachedwbse(buf, len);
509 cachedwbinvse(buf, len);
510 WR(Dmadesc, dmaaddr(emmc.dma));
515 emmcio(int write, uchar *buf, int len)
520 r = (u32int*)EMMCREGS;
525 WR(Irpten, r[Irpten] | Datadone|Err);
526 tsleep(&emmc.r, datadone, 0, 3000);
527 WR(Irpten, r[Irpten] & ~(Datadone|Err));
529 if((i & (Datadone|Err)) != Datadone){
530 print("sdhc: %s error intr %ux stat %ux\n",
531 write? "write" : "read", i, r[Status]);
537 cachedinvse(buf, len);
543 mmcinterrupt(Ureg*, void*)
548 r = (u32int*)EMMCREGS;
554 WR(Irpten, r[Irpten] & ~i);