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,
34 STOP_TRANSMISSION= 12,
37 READ_SINGLE_BLOCK= 17,
38 READ_MULTIPLE_BLOCK= 18,
40 WRITE_MULTIPLE_BLOCK= 25,
41 APP_CMD = 55, /* prefix for following app-specific commands */
45 /* Command arguments */
54 Hcs = 1<<30, /* host supports SDHC & SDXC */
55 Ccs = 1<<30, /* card is SDHC or SDXC */
56 V3_3 = 3<<20, /* 3.2-3.4 volts */
62 /* OCR (operating conditions register) */
69 /* SD card registers */
76 extern SDifc sdmmcifc;
80 rbits(u32int *p, uint start, uint len)
89 v = p[w] >> off | p[w+1] << (32-off);
91 return v & ((1<<len) - 1);
97 identify(SDunit *unit, u32int *csd)
101 unit->secsize = 1 << CSD(83, 80);
102 switch(CSD(127, 126)){
103 case 0: /* CSD version 1 */
106 unit->sectors = (csize+1) * (1<<(mult+2));
108 case 1: /* CSD version 2 */
110 unit->sectors = (csize+1) * 0x80000LL / unit->secsize;
113 if(unit->secsize == 1024){
127 sdev = malloc(sizeof(SDev));
130 ctl = malloc(sizeof(Ctlr));
136 sdev->ifc = &sdmmcifc;
145 mmcverify(SDunit *unit)
150 ctl = unit->dev->ctlr;
151 n = ctl->io->inquiry((char*)&unit->inquiry[8], sizeof(unit->inquiry)-8);
154 unit->inquiry[0] = 0x00; /* direct access (disk) */
155 unit->inquiry[1] = 0x80; /* removable */
156 unit->inquiry[4] = sizeof(unit->inquiry)-4;
171 mmconline(SDunit *unit)
178 ctl = unit->dev->ctlr;
180 assert(unit->subno == 0);
186 if(unit->sectors != 0){
187 io->cmd(SEND_STATUS, ctl->rca<<Rcashift, r);
191 io->cmd(GO_IDLE_STATE, 0, r);
194 io->cmd(SD_SEND_IF_COND, Voltage|Checkpattern, r);
195 if(r[0] == (Voltage|Checkpattern)) /* SD 2.0 or above */
199 for(i = 0; i < Inittimeout; i++){
201 io->cmd(APP_CMD, 0, r);
202 io->cmd(SD_SEND_OP_COND, hcs|V3_3, r);
206 if(i == Inittimeout){
207 print("sdmmc: card won't power up\n");
212 io->cmd(ALL_SEND_CID, 0, r);
213 memmove(ctl->cid, r, sizeof ctl->cid);
214 io->cmd(SEND_RELATIVE_ADDR, 0, r);
216 io->cmd(SEND_CSD, ctl->rca<<Rcashift, r);
217 memmove(ctl->csd, r, sizeof ctl->csd);
218 identify(unit, ctl->csd);
219 io->cmd(SELECT_CARD, ctl->rca<<Rcashift, r);
220 io->cmd(SET_BLOCKLEN, unit->secsize, r);
221 io->cmd(APP_CMD, ctl->rca<<Rcashift, r);
222 io->cmd(SET_BUS_WIDTH, Width4, r);
228 mmcrctl(SDunit *unit, char *p, int l)
233 ctl = unit->dev->ctlr;
234 assert(unit->subno == 0);
235 if(unit->sectors == 0){
237 if(unit->sectors == 0)
240 n = snprint(p, l, "rca %4.4ux ocr %8.8ux\ncid ", ctl->rca, ctl->ocr);
241 for(i = nelem(ctl->cid)-1; i >= 0; i--)
242 n += snprint(p+n, l-n, "%8.8ux", ctl->cid[i]);
243 n += snprint(p+n, l-n, " csd ");
244 for(i = nelem(ctl->csd)-1; i >= 0; i--)
245 n += snprint(p+n, l-n, "%8.8ux", ctl->csd[i]);
246 n += snprint(p+n, l-n, "\ngeometry %llud %ld\n",
247 unit->sectors, unit->secsize);
252 mmcbio(SDunit *unit, int lun, int write, void *data, long nb, uvlong bno)
262 ctl = unit->dev->ctlr;
264 assert(unit->subno == 0);
265 if(unit->sectors == 0)
275 io->iosetup(write, buf, len, nb);
277 io->cmd(STOP_TRANSMISSION, 0, r);
280 io->cmd(write? WRITE_MULTIPLE_BLOCK: READ_MULTIPLE_BLOCK,
281 ctl->ocr & Ccs? b: b * len, r);
282 io->io(write, buf, nb * len);
284 io->cmd(STOP_TRANSMISSION, 0, r);
288 for(b = bno; b < bno + nb; b++){
289 io->iosetup(write, buf, len, 1);
290 io->cmd(write? WRITE_BLOCK : READ_SINGLE_BLOCK,
291 ctl->ocr & Ccs? b: b * len, r);
292 io->io(write, buf, len);
296 return (b - bno) * len;
305 if((i = sdfakescsi(r)) != SDnostatus)
306 return r->status = i;
307 if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus)
309 r->rlen = mmcbio(r->unit, r->lun, rw == SDwrite, r->data, count, lba);
310 return r->status = SDok;