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,
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->vid == 0x1180 && p->did == 0xe823) /* Ricoh */
228 if(p == nil || p->mem[0].size < 256)
231 if(p->did == 0x1180 && p->vid == 0xe823){ /* Ricoh */
232 /* Enable SD2.0 mode. */
233 pcicfgw8(p, 0xf9, 0xfc);
234 pcicfgw8(p, 0x150, 0x10);
235 pcicfgw8(p, 0xf9, 0x00);
238 * Some SD/MMC cards don't work with the default base
239 * clock frequency of 200MHz. Lower it to 50Hz.
241 pcicfgw8(p, 0xfc, 0x01);
242 pcicfgw8(p, 0xe1, 50);
243 pcicfgw8(p, 0xfc, 0x00);
246 pmmc->mmio = vmap(p->mem[0].bar & ~0x0F, p->mem[0].size);
247 if(pmmc->mmio == nil)
254 pmmcinquiry(char *inquiry, int inqlen)
256 return snprint(inquiry, inqlen, "MMC Host Controller");
260 softreset(Ctlr *c, int all)
266 for(i=10; i>=0; i--){
267 if((CR8(c, Rsrst) & m) == 0)
272 if(i < 0) iprint("mmc: didnt reset\n");
276 setpower(Ctlr *c, int on)
279 Vcap18 = 1<<26, Vset18 = 0x05,
280 Vcap30 = 1<<25, Vset30 = 0x06,
281 Vcap33 = 1<<24, Vset33 = 0x07,
291 CR8(c, Rpwr) = on ? ((v<<1) | 1) : 0;
295 setclkfreq(Ctlr *c, int khz)
297 u32int caps, intfreq;
301 CR16(c, Rclc) |= ~4; /* sd clock disable */
305 caps = CR32(c, Rcap);
306 intfreq = 1000*((caps >> 8) & 0x3f);
307 for(div = 1; div <= 256; div <<= 1){
308 if((intfreq / div) <= khz){
314 CR16(c, Rclc) = div<<8;
315 CR16(c, Rclc) |= 1; /* int clock enable */
316 for(i=1000; i>=0; i--){
317 if(CR16(c, Rclc) & 2) /* int clock stable */
321 if(i < 0) iprint("mmc: clock didnt stabilize\n");
322 CR16(c, Rclc) |= 4; /* sd clock enable */
331 CR16(c, Rnise) = 0; /* interrupts off */
334 c->waitmsk = c->waitsts = 0;
340 m = Srem | Sins | Srrdy | Swrdy | Sdint | Sbge | Strac | Scmdc;
342 CR16(c, Reie) = Emask;
344 CR16(c, Reise) = Emask;
357 return (c->waitsts & c->waitmsk) != 0;
361 intrwait(Ctlr *c, u32int mask, int tmo)
365 c->waitmsk = Seint | mask;
368 tsleep(&c->r, waitcond, c, 100);
371 mmcinterrupt(nil, c);
379 c->waitsts &= ~(status & mask);
381 if((status & mask) == 0 || (status & Seint) != 0){
382 /* abort command on timeout/error interrupt */
402 intrenable(p->intl, mmcinterrupt, c, p->tbdf, "mmc");
406 pmmccmd(u32int cmd, u32int arg, u32int *resp)
412 if(cmd >= nelem(cmdinfo) || cmdinfo[cmd] == 0)
414 mode = cmdinfo[cmd] >> 8;
415 cmd = (cmd << 8) | (cmdinfo[cmd] & 0xFF);
421 if((CR32(c, Rpres) & Pcrdin) == 0)
425 if((cmd & Isdata) != 0 || (cmd & Respmask) == Resp48busy)
427 for(i=1000; (CR32(c, Rpres) & status) != 0 && i>=0; i--)
433 if((mode & (Mcnt|Mblk)) == (Mcnt|Mblk)){
434 CR16(c, Rbsize) = c->io.bsize;
435 CR16(c, Rbcount) = c->io.bcount;
438 CR16(c, Rmode) = mode;
442 if(!intrwait(c, Scmdc, 1000))
445 switch(cmd & Respmask){
447 resp[0] = CR32(c, Rresp0);
448 if(!intrwait(c, Strac, 3000))
452 resp[0] = CR32(c, Rresp0);
455 resp[0] = CR32(c, Rresp0)<<8;
456 resp[1] = CR32(c, Rresp0)>>24 | CR32(c, Rresp1)<<8;
457 resp[2] = CR32(c, Rresp1)>>24 | CR32(c, Rresp2)<<8;
458 resp[3] = CR32(c, Rresp2)>>24 | CR32(c, Rresp3)<<8;
466 if(cmd == 0x06){ /* buswidth */
481 pmmciosetup(int write, void *buf, int bsize, int bcount)
488 if(bsize == 0 || (bsize & 3) != 0)
493 c->io.bcount = bcount;
497 readblock(Ctlr *c, uchar *buf, int len)
499 for(len >>= 2; len > 0; len--){
500 *((u32int*)buf) = CR32(c, Rdat0);
506 writeblock(Ctlr *c, uchar *buf, int len)
508 for(len >>= 2; len > 0; len--){
509 CR32(c, Rdat0) = *((u32int*)buf);
515 pmmcio(int write, uchar *buf, int len)
521 if(len != c->io.bsize*c->io.bcount)
524 if(!intrwait(c, write ? Swrdy : Srrdy, 3000))
530 writeblock(c, buf, n);
532 readblock(c, buf, n);
536 if(!intrwait(c, Strac, 1000))