4 * initially written for X230 Ricoh MMC controller.
5 * cmdinfo[] table stolen from bcm/emmc.c, thanks richard.
7 * for sdhc documentation see: https://www.sdcard.org/
10 #include "../port/lib.h"
11 #include "../port/error.h"
16 #include "../port/sd.h"
137 /* fake for cmdinfo */
139 Blkcnten = Mblk << 8,
140 Multiblock = Mcnt << 8,
141 Card2host = Mrd << 8,
142 Host2card = Mwr << 8,
145 static int cmdinfo[64] = {
148 [3] Resp48 | Ixchken | Crcchken,
149 [6] Resp48 | Ixchken | Crcchken,
150 [7] Resp48busy | Ixchken | Crcchken,
151 [8] Resp48 | Ixchken | Crcchken,
153 [12] Resp48busy | Ixchken | Crcchken,
154 [13] Resp48 | Ixchken | Crcchken,
156 [17] Resp48 | Isdata | Card2host | Ixchken | Crcchken,
157 [18] Resp48 | Isdata | Card2host | Multiblock | Blkcnten | Ixchken | Crcchken,
158 [24] Resp48 | Isdata | Host2card | Ixchken | Crcchken,
159 [25] Resp48 | Isdata | Host2card | Multiblock | Blkcnten | Ixchken | Crcchken,
161 [55] Resp48 | Ixchken | Crcchken,
164 typedef struct Ctlr Ctlr;
185 #define CR8(c, off) *((u8int*)(c->mmio + off))
186 #define CR16(c, off) *((u16int*)(c->mmio + off))
187 #define CR32(c, off) *((u32int*)(c->mmio + off))
190 mmcinterrupt(Ureg*, void *arg)
197 if((nis & Smask) == 0)
198 return; /* not for us */
200 CR16(c, Rnis) = nis; /* ack */
203 if((nis & Seint) != 0){
205 CR16(c, Reis) = eis; /* ack */
207 if((nis & Snint) != 0)
208 CR16(c, Rnie) |= Snint; /* ack */
209 if((nis & (Srem|Sins)) != 0)
211 c->waitsts |= nis | (eis << 16);
212 if((c->waitsts & c->waitmsk) != 0)
223 while((p = pcimatch(p, 0, 0)) != nil){
224 if(p->ccrb == 8 && p->ccru == 5)
226 if(p->vid == 0x1180){ /* Ricoh */
227 if(p->did == 0xe822) /* 5U822 SD/MMC */
229 if(p->did == 0xe823) /* 5U823 SD/MMC */
234 if(p == nil || p->mem[0].size < 256)
237 pmmc->mmio = vmap(p->mem[0].bar & ~0x0F, p->mem[0].size);
238 if(pmmc->mmio == nil)
244 if(p->did == 0x1180 && p->vid == 0xe823){ /* Ricoh */
245 /* Enable SD2.0 mode. */
246 pcicfgw8(p, 0xf9, 0xfc);
247 pcicfgw8(p, 0x150, 0x10);
248 pcicfgw8(p, 0xf9, 0x00);
251 * Some SD/MMC cards don't work with the default base
252 * clock frequency of 200MHz. Lower it to 50Hz.
254 pcicfgw8(p, 0xfc, 0x01);
255 pcicfgw8(p, 0xe1, 50);
256 pcicfgw8(p, 0xfc, 0x00);
263 pmmcinquiry(char *inquiry, int inqlen)
265 return snprint(inquiry, inqlen, "MMC Host Controller");
269 softreset(Ctlr *c, int all)
275 for(i=10; i>=0; i--){
276 if((CR8(c, Rsrst) & m) == 0)
281 if(i < 0) iprint("mmc: didnt reset\n");
285 setpower(Ctlr *c, int on)
288 Vcap18 = 1<<26, Vset18 = 0x05,
289 Vcap30 = 1<<25, Vset30 = 0x06,
290 Vcap33 = 1<<24, Vset33 = 0x07,
300 CR8(c, Rpwr) = on ? ((v<<1) | 1) : 0;
304 setclkfreq(Ctlr *c, int khz)
306 u32int caps, intfreq;
310 CR16(c, Rclc) |= ~4; /* sd clock disable */
314 caps = CR32(c, Rcap);
315 intfreq = 1000*((caps >> 8) & 0x3f);
316 for(div = 1; div <= 256; div <<= 1){
317 if((intfreq / div) <= khz){
323 CR16(c, Rclc) = div<<8;
324 CR16(c, Rclc) |= 1; /* int clock enable */
325 for(i=1000; i>=0; i--){
326 if(CR16(c, Rclc) & 2) /* int clock stable */
330 if(i < 0) iprint("mmc: clock didnt stabilize\n");
331 CR16(c, Rclc) |= 4; /* sd clock enable */
340 CR16(c, Rnise) = 0; /* interrupts off */
343 c->waitmsk = c->waitsts = 0;
349 m = Srem | Sins | Srrdy | Swrdy | Sdint | Sbge | Strac | Scmdc;
351 CR16(c, Reie) = Emask;
353 CR16(c, Reise) = Emask;
366 return (c->waitsts & c->waitmsk) != 0;
370 intrwait(Ctlr *c, u32int mask, int tmo)
375 c->waitmsk = Seint | mask;
379 tsleep(&c->r, waitcond, c, 100);
382 mmcinterrupt(nil, c);
390 c->waitsts &= ~(status & mask);
391 if((status & mask) == 0 || (status & Seint) != 0){
392 /* abort command on timeout/error interrupt */
399 return status & mask;
412 intrenable(p->intl, mmcinterrupt, c, p->tbdf, "mmc");
416 pmmccmd(u32int cmd, u32int arg, u32int *resp)
422 if(cmd >= nelem(cmdinfo) || cmdinfo[cmd] == 0)
424 mode = cmdinfo[cmd] >> 8;
425 cmd = (cmd << 8) | (cmdinfo[cmd] & 0xFF);
431 if((CR32(c, Rpres) & Pcrdin) == 0)
435 if((cmd & Isdata) != 0 || (cmd & Respmask) == Resp48busy)
437 for(i=1000; (CR32(c, Rpres) & status) != 0 && i>=0; i--)
443 if((mode & (Mcnt|Mblk)) == (Mcnt|Mblk)){
444 CR16(c, Rbsize) = c->io.bsize;
445 CR16(c, Rbcount) = c->io.bcount;
448 CR16(c, Rmode) = mode;
452 if(!intrwait(c, Scmdc, 1000))
455 switch(cmd & Respmask){
457 resp[0] = CR32(c, Rresp0);
458 if(!intrwait(c, Strac, 3000))
462 resp[0] = CR32(c, Rresp0);
465 resp[0] = CR32(c, Rresp0)<<8;
466 resp[1] = CR32(c, Rresp0)>>24 | CR32(c, Rresp1)<<8;
467 resp[2] = CR32(c, Rresp1)>>24 | CR32(c, Rresp2)<<8;
468 resp[3] = CR32(c, Rresp2)>>24 | CR32(c, Rresp3)<<8;
476 if(cmd == 0x06){ /* buswidth */
491 pmmciosetup(int write, void *buf, int bsize, int bcount)
498 if(bsize == 0 || (bsize & 3) != 0)
503 c->io.bcount = bcount;
507 readblock(Ctlr *c, uchar *buf, int len)
509 for(len >>= 2; len > 0; len--){
510 *((u32int*)buf) = CR32(c, Rdat0);
516 writeblock(Ctlr *c, uchar *buf, int len)
518 for(len >>= 2; len > 0; len--){
519 CR32(c, Rdat0) = *((u32int*)buf);
525 pmmcio(int write, uchar *buf, int len)
531 if(len != c->io.bsize*c->io.bcount)
534 if(!intrwait(c, write ? Swrdy : Srrdy, 3000))
540 writeblock(c, buf, n);
542 readblock(c, buf, n);
546 if(!intrwait(c, Strac, 1000))