4 * Copyright © 2012 Richard Miller <r.miller@acm.org>
6 * Assumes only one card on the bus
10 #include "../port/lib.h"
11 #include "../port/error.h"
17 #include "../port/sd.h"
19 #define CSD(end, start) rbits(csd, start, (end)-(start)+1)
21 typedef struct Ctlr Ctlr;
30 SEND_RELATIVE_ADDR= 3,
35 STOP_TRANSMISSION= 12,
38 READ_SINGLE_BLOCK= 17,
39 READ_MULTIPLE_BLOCK= 18,
41 WRITE_MULTIPLE_BLOCK= 25,
42 APP_CMD = 55, /* prefix for following app-specific commands */
46 /* Command arguments */
55 Hcs = 1<<30, /* host supports SDHC & SDXC */
56 Ccs = 1<<30, /* card is SDHC or SDXC */
57 V3_3 = 3<<20, /* 3.2-3.4 volts */
66 Checkfunc = 0x00FFFFF0,
70 /* OCR (operating conditions register) */
77 /* SD card registers */
84 extern SDifc sdmmcifc;
88 rbits(u32int *p, uint start, uint len)
97 v = p[w] >> off | p[w+1] << (32-off);
99 return v & ((1<<len) - 1);
105 identify(SDunit *unit, u32int *csd)
109 unit->secsize = 1 << CSD(83, 80);
110 switch(CSD(127, 126)){
111 case 0: /* CSD version 1 */
114 unit->sectors = (csize+1) * (1<<(mult+2));
116 case 1: /* CSD version 2 */
118 unit->sectors = (csize+1) * 0x80000LL / unit->secsize;
121 if(unit->secsize == 1024){
135 sdev = malloc(sizeof(SDev));
138 ctl = malloc(sizeof(Ctlr));
144 sdev->ifc = &sdmmcifc;
153 mmcverify(SDunit *unit)
158 ctl = unit->dev->ctlr;
159 n = ctl->io->inquiry((char*)&unit->inquiry[8], sizeof(unit->inquiry)-8);
162 unit->inquiry[0] = 0x00; /* direct access (disk) */
163 unit->inquiry[1] = 0x80; /* removable */
164 unit->inquiry[4] = sizeof(unit->inquiry)-4;
179 mmcswitchfunc(SDio *io, int arg)
188 print("mmcswitchfunc error\n");
192 io->iosetup(0, buf, n, 1);
193 io->cmd(SWITCH_FUNC, arg, r);
200 mmconline(SDunit *unit)
207 ctl = unit->dev->ctlr;
209 assert(unit->subno == 0);
215 if(unit->sectors != 0){
216 io->cmd(SEND_STATUS, ctl->rca<<Rcashift, r);
220 io->cmd(GO_IDLE_STATE, 0, r);
223 io->cmd(SD_SEND_IF_COND, Voltage|Checkpattern, r);
224 if(r[0] == (Voltage|Checkpattern)) /* SD 2.0 or above */
228 for(i = 0; i < Inittimeout; i++){
230 io->cmd(APP_CMD, 0, r);
231 io->cmd(SD_SEND_OP_COND, hcs|V3_3, r);
235 if(i == Inittimeout){
236 print("sdmmc: card won't power up\n");
241 io->cmd(ALL_SEND_CID, 0, r);
242 memmove(ctl->cid, r, sizeof ctl->cid);
243 io->cmd(SEND_RELATIVE_ADDR, 0, r);
245 io->cmd(SEND_CSD, ctl->rca<<Rcashift, r);
246 memmove(ctl->csd, r, sizeof ctl->csd);
247 identify(unit, ctl->csd);
248 io->cmd(SELECT_CARD, ctl->rca<<Rcashift, r);
249 io->cmd(SET_BLOCKLEN, unit->secsize, r);
250 io->cmd(APP_CMD, ctl->rca<<Rcashift, r);
251 io->cmd(SET_BUS_WIDTH, Width4, r);
254 mmcswitchfunc(io, Hispeed|Setfunc);
263 mmcrctl(SDunit *unit, char *p, int l)
268 ctl = unit->dev->ctlr;
269 assert(unit->subno == 0);
270 if(unit->sectors == 0){
272 if(unit->sectors == 0)
275 n = snprint(p, l, "rca %4.4ux ocr %8.8ux\ncid ", ctl->rca, ctl->ocr);
276 for(i = nelem(ctl->cid)-1; i >= 0; i--)
277 n += snprint(p+n, l-n, "%8.8ux", ctl->cid[i]);
278 n += snprint(p+n, l-n, " csd ");
279 for(i = nelem(ctl->csd)-1; i >= 0; i--)
280 n += snprint(p+n, l-n, "%8.8ux", ctl->csd[i]);
281 n += snprint(p+n, l-n, "\ngeometry %llud %ld\n",
282 unit->sectors, unit->secsize);
287 mmcbio(SDunit *unit, int lun, int write, void *data, long nb, uvlong bno)
297 ctl = unit->dev->ctlr;
299 assert(unit->subno == 0);
300 if(unit->sectors == 0)
310 io->iosetup(write, buf, len, nb);
312 io->cmd(STOP_TRANSMISSION, 0, r);
315 io->cmd(write? WRITE_MULTIPLE_BLOCK: READ_MULTIPLE_BLOCK,
316 ctl->ocr & Ccs? b: b * len, r);
317 io->io(write, buf, nb * len);
319 io->cmd(STOP_TRANSMISSION, 0, r);
323 for(b = bno; b < bno + nb; b++){
324 io->iosetup(write, buf, len, 1);
325 io->cmd(write? WRITE_BLOCK : READ_SINGLE_BLOCK,
326 ctl->ocr & Ccs? b: b * len, r);
327 io->io(write, buf, len);
331 return (b - bno) * len;
340 if((i = sdfakescsi(r)) != SDnostatus)
341 return r->status = i;
342 if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus)
344 r->rlen = mmcbio(r->unit, r->lun, rw == SDwrite, r->data, count, lba);
345 return r->status = SDok;