2 * bcm2835 external mass media controller (mmc / sd host interface)
4 * Copyright © 2012 Richard Miller <r.miller@acm.org>
8 #include "../port/lib.h"
9 #include "../port/error.h"
14 #include "../port/sd.h"
16 #define EMMCREGS (VIRTIO+0x300000)
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) */
25 MMCSelect = 7, /* mmc/sd card select command */
26 Setbuswidth = 6, /* mmc/sd set bus width command */
30 /* Controller registers */
48 Boottimeout = 0x70>>2,
50 Exrdfifocfg = 0x80>>2,
53 Tunestepsstd = 0x8c>>2,
54 Tunestepsddr = 0x90>>2,
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 */
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 */
76 Clkintlen = 1<<0, /* enable internal EMMC clocks */
108 Cardintr = 1<<8, /* not in Broadcom datasheet */
109 Cardinsert = 1<<6, /* not in Broadcom datasheet */
116 Bufread = 1<<11, /* not in Broadcom datasheet */
117 Bufwrite = 1<<10, /* not in Broadcom datasheet */
128 [3] Resp48 | Ixchken | Crcchken,
129 [6] Resp48 | Ixchken | Crcchken,
130 [7] Resp48busy | Ixchken | Crcchken,
131 [8] Resp48 | Ixchken | Crcchken,
133 [12] Resp48busy | Ixchken | Crcchken,
134 [13] Resp48 | Ixchken | Crcchken,
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,
141 [55] Resp48 | Ixchken | Crcchken,
144 typedef struct Ctlr Ctlr;
155 static void mmcinterrupt(Ureg*, void*);
158 WR(int reg, u32int val)
160 u32int *r = (u32int*)EMMCREGS;
162 if(0)print("WR %2.2ux %ux\n", reg<<2, val);
163 microdelay(emmc.fastclock? 2: 20);
173 v = (d << Clkfreq8shift) & Clkfreq8mask;
174 v |= ((d >> 8) << Clkfreqms2shift) & Clkfreqms2mask;
181 return emmc.datadone;
191 clk = getclkrate(ClkEmmc);
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);
204 while(r[Control1] & Srsthc)
210 emmcinquiry(char *inquiry, int inqlen)
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",
228 r = (u32int*)EMMCREGS;
229 WR(Control1, clkdiv(emmc.extclk / Initfreq - 1) | DTO << Datatoshift |
230 Clkgendiv | Clken | Clkintlen);
231 for(i = 0; i < 1000; i++){
233 if(r[Control1] & Clkstable)
237 print("SD clock won't initialise!\n");
238 WR(Irptmask, ~(Dtoerr|Cardintr));
239 intrenable(IRQmmc, mmcinterrupt, nil, 0, "mmc");
243 emmccmd(u32int cmd, u32int arg, u32int *resp)
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)
259 while(r[Status] & Cmdinhibit)
262 if((c & Isdata || (c & Respmask) == Resp48busy) &&
263 r[Status] & Datinhibit){
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)
269 while(r[Status] & Datinhibit)
273 if((i = r[Interrupt]) != 0){
275 print("emmc: before command, intr was %ux\n", i);
280 while(((i=r[Interrupt])&(Cmddone|Err)) == 0)
281 if(m->ticks-now > HZ)
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]);
287 if(r[Status]&Cmdinhibit){
288 WR(Control1, r[Control1]|Srstcmd);
289 while(r[Control1]&Srstcmd)
294 WR(Interrupt, i & ~(Datadone|Readrdy|Writerdy));
295 switch(c & Respmask){
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;
310 if((c & Respmask) == Resp48busy){
311 WR(Irpten, Datadone|Err);
312 tsleep(&emmc.r, datadone, 0, 3000);
316 if((i & Datadone) == 0)
317 print("emmcio: no Datadone after CMD%d\n", cmd);
319 print("emmcio: CMD%d error interrupt %ux\n",
324 * Once card is selected, use faster clock
326 if(cmd == MMCSelect){
328 WR(Control1, clkdiv(emmc.extclk / SDfreq - 1) |
329 DTO << Datatoshift | Clkgendiv | Clken | Clkintlen);
330 for(i = 0; i < 1000; i++){
332 if(r[Control1] & Clkstable)
339 * If card bus width changes, change host bus width
341 if(cmd == Setbuswidth)
344 WR(Control0, r[Control0] & ~Dwidth4);
347 WR(Control0, r[Control0] | Dwidth4);
354 emmciosetup(int write, void *buf, int bsize, int bcount)
358 WR(Blksizecnt, bcount<<16 | bsize);
362 emmcio(int write, uchar *buf, int len)
367 r = (u32int*)EMMCREGS;
368 assert((len&3) == 0);
375 dmastart(DmaChanEmmc, DmaDevEmmc, DmaM2D,
378 dmastart(DmaChanEmmc, DmaDevEmmc, DmaD2M,
380 if(dmawait(DmaChanEmmc) < 0)
382 WR(Irpten, Datadone|Err);
383 tsleep(&emmc.r, datadone, 0, 3000);
387 if((i & Datadone) == 0){
388 print("emmcio: %d timeout intr %ux stat %ux\n",
389 write, i, r[Status]);
394 print("emmcio: %d error intr %ux stat %ux\n",
395 write, r[Interrupt], r[Status]);
406 mmcinterrupt(Ureg*, void*)
411 r = (u32int*)EMMCREGS;
413 r[Interrupt] = i & (Datadone|Err);