2 * bcm2835 external mass media controller (mmc / sd host interface)
4 * Copyright © 2012 Richard Miller <r.miller@acm.org>
8 Not officially documented: emmc can be connected to different gpio pins
11 34-39 (wifi - pi3 only)
12 using ALT3 function to activate the required routing
16 #include "../port/lib.h"
17 #include "../port/error.h"
22 #include "../port/sd.h"
24 #define EMMCREGS (VIRTIO+0x300000)
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) */
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 */
38 Switchfunc = 6, /* mmc/sd switch function command */
39 Voltageswitch = 11, /* md/sdio switch to 1.8V */
40 IORWdirect = 52, /* sdio read/write direct command */
41 IORWextended = 53, /* sdio read/write extended command */
42 Appcmd = 55, /* mmc/sd application command prefix */
46 /* Controller registers */
64 Boottimeout = 0x70>>2,
66 Exrdfifocfg = 0x80>>2,
69 Tunestepsstd = 0x8c>>2,
70 Tunestepsddr = 0x90>>2,
80 Srstdata = 1<<26, /* reset data circuit */
81 Srstcmd = 1<<25, /* reset command circuit */
82 Srsthc = 1<<24, /* reset complete host controller */
83 Datatoshift = 16, /* data timeout unit exponent */
85 Clkfreq8shift = 8, /* SD clock base divider LSBs */
86 Clkfreq8mask = 0xFF00,
87 Clkfreqms2shift = 6, /* SD clock base divider MSBs */
88 Clkfreqms2mask = 0xC0,
89 Clkgendiv = 0<<5, /* SD clock divided */
90 Clkgenprog = 1<<5, /* SD clock programmable */
91 Clken = 1<<2, /* SD clock enable */
93 Clkintlen = 1<<0, /* enable internal EMMC clocks */
125 Cardintr = 1<<8, /* not in Broadcom datasheet */
126 Cardinsert = 1<<6, /* not in Broadcom datasheet */
133 Bufread = 1<<11, /* not in Broadcom datasheet */
134 Bufwrite = 1<<10, /* not in Broadcom datasheet */
142 static int cmdinfo[64] = {
145 [3] Resp48 | Ixchken | Crcchken,
147 [6] Resp48 | Ixchken | Crcchken,
148 [7] Resp48busy | Ixchken | Crcchken,
149 [8] Resp48 | Ixchken | Crcchken,
151 [11] Resp48 | Ixchken | Crcchken,
152 [12] Resp48busy | Ixchken | Crcchken,
153 [13] Resp48 | Ixchken | Crcchken,
155 [17] Resp48 | Isdata | Card2host | Ixchken | Crcchken,
156 [18] Resp48 | Isdata | Card2host | Multiblock | Blkcnten | Ixchken | Crcchken,
157 [24] Resp48 | Isdata | Host2card | Ixchken | Crcchken,
158 [25] Resp48 | Isdata | Host2card | Multiblock | Blkcnten | Ixchken | Crcchken,
160 [52] Resp48 | Ixchken | Crcchken,
161 [53] Resp48 | Ixchken | Crcchken | Isdata,
162 [55] Resp48 | Ixchken | Crcchken,
165 typedef struct Ctlr Ctlr;
177 static void mmcinterrupt(Ureg*, void*);
180 WR(int reg, u32int val)
182 u32int *r = (u32int*)EMMCREGS;
184 if(0)print("WR %2.2ux %ux\n", reg<<2, val);
185 microdelay(emmc.fastclock ? 2: 20);
196 v = (d << Clkfreq8shift) & Clkfreq8mask;
197 v |= ((d >> 8) << Clkfreqms2shift) & Clkfreqms2mask;
208 r = (u32int*)EMMCREGS;
209 div = emmc.extclk / (freq<<1);
210 if(emmc.extclk / (div<<1) > freq)
212 WR(Control1, clkdiv(div) |
213 DTO<<Datatoshift | Clkgendiv | Clken | Clkintlen);
214 for(i = 0; i < 1000; i++){
216 if(r[Control1] & Clkstable)
220 print("emmc: can't set clock to %ud\n", freq);
228 u32int *r = (u32int*)EMMCREGS;
230 return i & (Datadone|Err);
238 u32int *r = (u32int*)EMMCREGS;
249 clk = getclkrate(ClkEmmc);
252 print("emmc: assuming external clock %lud Mhz\n", clk/1000000);
255 r = (u32int*)EMMCREGS;
256 if(0)print("emmc control %8.8ux %8.8ux %8.8ux\n",
257 r[Control0], r[Control1], r[Control2]);
258 WR(Control1, Srsthc);
260 while(r[Control1] & Srsthc)
262 WR(Control1, Srstdata);
269 emmcinquiry(char *inquiry, int inqlen)
274 r = (u32int*)EMMCREGS;
275 ver = r[Slotisrver] >> 16;
276 return snprint(inquiry, inqlen,
277 "Arasan eMMC SD Host Controller %2.2x Version %2.2x",
288 intrenable(IRQmmc, mmcinterrupt, nil, BUSUNKNOWN, "mmc");
292 emmccmd(u32int cmd, u32int arg, u32int *resp)
299 r = (u32int*)EMMCREGS;
300 assert(cmd < nelem(cmdinfo) && cmdinfo[cmd] != 0);
301 c = (cmd << Indexshift) | cmdinfo[cmd];
303 * CMD6 may be Setbuswidth or Switchfunc depending on Appcmd prefix
305 if(cmd == Switchfunc && !emmc.appcmd)
306 c |= Isdata|Card2host;
307 if(cmd == IORWextended){
312 if((r[Blksizecnt]&0xFFFF0000) != 0x10000)
313 c |= Multiblock | Blkcnten;
316 * GoIdle indicates new card insertion: reset bus width & speed
319 WR(Control0, r[Control0] & ~(Dwidth4|Hispeed));
322 if((r[Status] & Datinhibit) &&
323 ((c & Isdata) || (c & Respmask) == Resp48busy)){
324 print("emmccmd: need to reset Cmdinhibit intr %ux stat %ux\n",
325 r[Interrupt], r[Status]);
326 WR(Control1, r[Control1] | Srstcmd);
327 while(r[Control1] & Srstcmd)
329 while(r[Status] & Cmdinhibit)
332 if((c & Isdata || (c & Respmask) == Resp48busy) &&
333 r[Status] & Datinhibit){
334 print("emmccmd: need to reset Datinhibit intr %ux stat %ux\n",
335 r[Interrupt], r[Status]);
336 WR(Control1, r[Control1] | Srstdata);
337 while(r[Control1] & Srstdata)
339 while(r[Status] & Datinhibit)
343 if((i = (r[Interrupt] & ~Cardintr)) != 0){
345 print("emmc: before command, intr was %ux\n", i);
350 while(((i=r[Interrupt])&(Cmddone|Err)) == 0)
351 if(m->ticks-now > HZ)
353 if((i&(Cmddone|Err)) != Cmddone){
354 if((i&~(Err|Cardintr)) != Ctoerr)
355 print("emmc: cmd %ux arg %ux error intr %ux stat %ux\n", c, arg, i, r[Status]);
357 if(r[Status]&Cmdinhibit){
358 WR(Control1, r[Control1]|Srstcmd);
359 while(r[Control1]&Srstcmd)
364 WR(Interrupt, i & ~(Datadone|Readrdy|Writerdy));
365 switch(c & Respmask){
367 resp[0] = r[Resp0]<<8;
368 resp[1] = r[Resp0]>>24 | r[Resp1]<<8;
369 resp[2] = r[Resp1]>>24 | r[Resp2]<<8;
370 resp[3] = r[Resp2]>>24 | r[Resp3]<<8;
380 if((c & Respmask) == Resp48busy){
381 WR(Irpten, r[Irpten]|Datadone|Err);
382 tsleep(&emmc.r, datadone, 0, 3000);
384 if((i & Datadone) == 0)
385 print("emmcio: no Datadone after CMD%d\n", cmd);
387 print("emmcio: CMD%d error interrupt %ux\n",
392 * Once card is selected, use faster clock
394 if(cmd == MMCSelect){
400 if(cmd == Setbuswidth){
403 * If card bus width changes, change host bus width
407 WR(Control0, r[Control0] & ~Dwidth4);
410 WR(Control0, r[Control0] | Dwidth4);
415 * If card switched into high speed mode, increase clock speed
417 if((arg&0x8000000F) == 0x80000001){
423 }else if(cmd == IORWdirect && (arg & ~0xFF) == (1<<31|0<<28|7<<9)){
426 WR(Control0, r[Control0] & ~Dwidth4);
429 WR(Control0, r[Control0] | Dwidth4);
430 //WR(Control0, r[Control0] | Hispeed);
434 emmc.appcmd = (cmd == Appcmd);
439 emmciosetup(int write, void *buf, int bsize, int bcount)
443 WR(Blksizecnt, bcount<<16 | bsize);
447 emmcio(int write, uchar *buf, int len)
452 r = (u32int*)EMMCREGS;
453 assert((len&3) == 0);
460 dmastart(DmaChanEmmc, DmaDevEmmc, DmaM2D,
463 dmastart(DmaChanEmmc, DmaDevEmmc, DmaD2M,
465 if(dmawait(DmaChanEmmc) < 0)
467 WR(Irpten, r[Irpten]|Datadone|Err);
468 tsleep(&emmc.r, datadone, 0, 3000);
469 i = r[Interrupt]&~Cardintr;
470 if((i & Datadone) == 0){
471 print("emmcio: %d timeout intr %ux stat %ux\n",
472 write, i, r[Status]);
477 print("emmcio: %d error intr %ux stat %ux\n",
478 write, r[Interrupt], r[Status]);
489 mmcinterrupt(Ureg*, void*)
494 r = (u32int*)EMMCREGS;
500 WR(Irpten, r[Irpten] & ~i);