sdio.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. /*
  2. * kirkwood SDIO / SDMem / MMC host interface
  3. */
  4. #include "u.h"
  5. #include "../port/lib.h"
  6. #include "../port/error.h"
  7. #include "mem.h"
  8. #include "dat.h"
  9. #include "fns.h"
  10. #include "io.h"
  11. #include "../port/sd.h"
  12. #define TM(bits) ((bits)<<16)
  13. #define GETTM(bits) (((bits)>>16)&0xFFFF)
  14. #define GETCMD(bits) ((bits)&0xFFFF)
  15. typedef struct Ctlr Ctlr;
  16. enum {
  17. Clkfreq = 100000000, /* external clk frequency */
  18. Initfreq= 400000, /* initialisation frequency for MMC */
  19. SDfreq = 25000000, /* standard SD frequency */
  20. PIOread = 0, /* use programmed i/o (not dma) for reading */
  21. PIOwrite= 0, /* use programmed i/o (not dma) writing */
  22. Polldone= 0, /* poll for Datadone status, don't use interrupt */
  23. Pollread= 1, /* poll for reading blocks */
  24. Pollwrite= 1, /* poll for writing blocks */
  25. MMCSelect= 7, /* mmc/sd card select command */
  26. Setbuswidth= 6, /* mmc/sd set bus width command */
  27. };
  28. enum {
  29. /* Controller registers */
  30. DmaLSB = 0x0>>2,
  31. DmaMSB = 0x4>>2,
  32. Blksize = 0x8>>2,
  33. Blkcount = 0xc>>2,
  34. ArgLSB = 0x10>>2,
  35. ArgMSB = 0x14>>2,
  36. Tm = 0x18>>2,
  37. Cmd = 0x1c>>2,
  38. Resp0 = 0x20>>2,
  39. Resp1 = 0x24>>2,
  40. Resp2 = 0x28>>2,
  41. Resp3 = 0x2c>>2,
  42. Resp4 = 0x30>>2,
  43. Resp5 = 0x34>>2,
  44. Resp6 = 0x38>>2,
  45. Resp7 = 0x3c>>2,
  46. Data = 0x40>>2,
  47. Hoststat = 0x48>>2,
  48. Hostctl = 0x50>>2,
  49. Clockctl = 0x58>>2,
  50. Softreset = 0x5C>>2,
  51. Interrupt = 0x60>>2,
  52. ErrIntr = 0x64>>2,
  53. Irptmask = 0x68>>2,
  54. ErrIrptmask = 0x6C>>2,
  55. Irpten = 0x70>>2,
  56. ErrIrpten = 0x74>>2,
  57. Mbuslo = 0x100>>2,
  58. Mbushi = 0x104>>2,
  59. Win0ctl = 0x108>>2,
  60. Win0base = 0x10c>>2,
  61. Win1ctl = 0x110>>2,
  62. Win1base = 0x114>>2,
  63. Win2ctl = 0x118>>2,
  64. Win2base = 0x11c>>2,
  65. Win3ctl = 0x120>>2,
  66. Win3base = 0x124>>2,
  67. Clockdiv = 0x128>>2,
  68. /* Hostctl */
  69. Timeouten = 1<<15,
  70. Datatoshift = 11,
  71. Datatomask = 0x7800,
  72. Hispeed = 1<<10,
  73. Dwidth4 = 1<<9,
  74. Dwidth1 = 0<<9,
  75. Bigendian = 1<<3,
  76. LSBfirst = 1<<4,
  77. Cardtypemask = 3<<1,
  78. Cardtypemem = 0<<1,
  79. Cardtypeio = 1<<1,
  80. Cardtypeiomem = 2<<1,
  81. Cardtypsdio = 3<<1,
  82. Pushpullen = 1<<0,
  83. /* Clockctl */
  84. Sdclken = 1<<0,
  85. /* Softreset */
  86. Swreset = 1<<8,
  87. /* Cmd */
  88. Indexshift = 8,
  89. Isdata = 1<<5,
  90. Ixchken = 1<<4,
  91. Crcchken = 3<<2,
  92. Respmask = 3<<0,
  93. Respnone = 0<<0,
  94. Resp136 = 1<<0,
  95. Resp48 = 2<<0,
  96. Resp48busy = 3<<0,
  97. /* Tm */
  98. Hostdma = 0<<6,
  99. Hostpio = 1<<6,
  100. Stopclken = 1<<5,
  101. Host2card = 0<<4,
  102. Card2host = 1<<4,
  103. Autocmd12 = 1<<2,
  104. Hwwrdata = 1<<1,
  105. Swwrdata = 1<<0,
  106. /* ErrIntr */
  107. Crcstaterr = 1<<14,
  108. Crcstartbiterr = 1<<13,
  109. Crcendbiterr = 1<<12,
  110. Resptbiterr = 1<<11,
  111. Xfersizeerr = 1<<10,
  112. Cmdstarterr = 1<<9,
  113. Acmderr = 1<<8,
  114. Denderr = 1<<6,
  115. Dcrcerr = 1<<5,
  116. Dtoerr = 1<<4,
  117. Cbaderr = 1<<3,
  118. Cenderr = 1<<2,
  119. Ccrcerr = 1<<1,
  120. Ctoerr = 1<<0,
  121. /* Interrupt */
  122. Err = 1<<15,
  123. Write8ready = 1<<11,
  124. Read8wready = 1<<10,
  125. Cardintr = 1<<8,
  126. Readrdy = 1<<5,
  127. Writerdy = 1<<4,
  128. Dmadone = 1<<3,
  129. Blockgap = 1<<2,
  130. Datadone = 1<<1,
  131. Cmddone = 1<<0,
  132. /* Hoststat */
  133. Fifoempty = 1<<13,
  134. Fifofull = 1<<12,
  135. Rxactive = 1<<9,
  136. Txactive = 1<<8,
  137. Cardbusy = 1<<1,
  138. Cmdinhibit = 1<<0,
  139. };
  140. int cmdinfo[64] = {
  141. [0] Ixchken,
  142. [2] Resp136,
  143. [3] Resp48 | Ixchken | Crcchken,
  144. [6] Resp48 | Ixchken | Crcchken,
  145. [7] Resp48busy | Ixchken | Crcchken,
  146. [8] Resp48 | Ixchken | Crcchken,
  147. [9] Resp136,
  148. [12] Resp48busy | Ixchken | Crcchken,
  149. [13] Resp48 | Ixchken | Crcchken,
  150. [16] Resp48,
  151. [17] Resp48 | Isdata | TM(Card2host) | Ixchken | Crcchken,
  152. [18] Resp48 | Isdata | TM(Card2host) | Ixchken | Crcchken,
  153. [24] Resp48 | Isdata | TM(Host2card | Hwwrdata) | Ixchken | Crcchken,
  154. [25] Resp48 | Isdata | TM(Host2card | Hwwrdata) | Ixchken | Crcchken,
  155. [41] Resp48,
  156. [55] Resp48 | Ixchken | Crcchken,
  157. };
  158. struct Ctlr {
  159. Rendez r;
  160. int datadone;
  161. int fastclock;
  162. };
  163. static Ctlr ctlr;
  164. static void sdiointerrupt(Ureg*, void*);
  165. void
  166. WR(int reg, u32int val)
  167. {
  168. u32int *r;
  169. r = (u32int*)AddrSdio;
  170. val &= 0xFFFF;
  171. if(0)iprint("WR %#4.4ux %#ux\n", reg<<2, val);
  172. r[reg] = val;
  173. }
  174. static uint
  175. clkdiv(uint d)
  176. {
  177. assert(d < 1<<11);
  178. return d;
  179. }
  180. static int
  181. datadone(void*)
  182. {
  183. return ctlr.datadone;
  184. }
  185. static int
  186. sdioinit(void)
  187. {
  188. u32int *r;
  189. r = (u32int*)AddrSdio;
  190. WR(Softreset, Swreset);
  191. while(r[Softreset] & Swreset)
  192. ;
  193. delay(10);
  194. return 0;
  195. }
  196. static int
  197. sdioinquiry(char *inquiry, int inqlen)
  198. {
  199. return snprint(inquiry, inqlen, "SDIO Host Controller");
  200. }
  201. static void
  202. sdioenable(void)
  203. {
  204. u32int *r;
  205. r = (u32int*)AddrSdio;
  206. WR(Clockdiv, clkdiv(Clkfreq/Initfreq - 1));
  207. delay(10);
  208. WR(Clockctl, r[Clockctl] & ~Sdclken);
  209. WR(Hostctl, Pushpullen|Bigendian|Cardtypemem);
  210. WR(Irpten, 0);
  211. WR(Interrupt, ~0);
  212. WR(ErrIntr, ~0);
  213. WR(Irptmask, ~0);
  214. WR(ErrIrptmask, ~Dtoerr);
  215. intrenable(Irqlo, IRQ0sdio, sdiointerrupt, &ctlr, "sdio");
  216. }
  217. static int
  218. awaitdone(u32int *r, int bits, int ticks)
  219. {
  220. int i;
  221. ulong start;
  222. start = m->ticks;
  223. while(((i = r[Interrupt]) & (bits|Err)) == 0)
  224. if(m->ticks - start > ticks)
  225. break;
  226. return i;
  227. }
  228. static void
  229. ckerr(u32int *r, int i, int len, char *op)
  230. {
  231. int err;
  232. if(i & Err){
  233. err = r[ErrIntr];
  234. iprint("sdioio: (%d) %s error intr %#ux err %#ux stat %#ux\n",
  235. len, op, i, err, r[Hoststat]);
  236. WR(ErrIntr, err);
  237. WR(Interrupt, i);
  238. error(Eio);
  239. }
  240. }
  241. static void
  242. ckdmadone(u32int *r, int i, char *msg)
  243. {
  244. if((i & Dmadone) == 0){
  245. iprint("sdioio: %s intr %#ux stat %#ux\n", msg, i, r[Hoststat]);
  246. WR(Interrupt, i);
  247. error(Eio);
  248. }
  249. }
  250. static void
  251. getresp(u32int *r, u32int *resp, int resptype)
  252. {
  253. switch(resptype){
  254. case Resp136:
  255. resp[0] = r[Resp7]<<8 | r[Resp6]<<22;
  256. resp[1] = r[Resp6]>>10 | r[Resp5]<<6 | r[Resp4]<<22;
  257. resp[2] = r[Resp4]>>10 | r[Resp3]<<6 | r[Resp2]<<22;
  258. resp[3] = r[Resp2]>>10 | r[Resp1]<<6 | r[Resp0]<<22;
  259. break;
  260. case Resp48:
  261. case Resp48busy:
  262. resp[0] = r[Resp2] | r[Resp1]<<6 | r[Resp0]<<22;
  263. break;
  264. case Respnone:
  265. resp[0] = 0;
  266. break;
  267. }
  268. }
  269. static void
  270. awaitresp48data(u32int *r, u32int cmd)
  271. {
  272. int i;
  273. if(Polldone)
  274. i = awaitdone(r, Datadone, 3*HZ);
  275. else{
  276. WR(Irpten, Datadone|Err);
  277. tsleep(&ctlr.r, datadone, 0, 3000);
  278. i = ctlr.datadone;
  279. ctlr.datadone = 0;
  280. WR(Irpten, 0);
  281. }
  282. if((i & Datadone) == 0)
  283. iprint("sdioio: no Datadone after CMD%d\n", cmd);
  284. if(i & Err)
  285. iprint("sdioio: CMD%d error interrupt %#ux %#ux\n",
  286. cmd, r[Interrupt], r[ErrIntr]);
  287. WR(Interrupt, i);
  288. }
  289. static void
  290. finishcmd(u32int cmd, u32int arg)
  291. {
  292. u32int *r;
  293. /*
  294. * Once card is selected, use faster clock.
  295. * If card bus width changes, change host bus width.
  296. */
  297. r = (u32int*)AddrSdio;
  298. if(cmd == MMCSelect){
  299. delay(10);
  300. WR(Clockdiv, clkdiv(Clkfreq/SDfreq - 1));
  301. delay(10);
  302. ctlr.fastclock = 1;
  303. } else if(cmd == Setbuswidth)
  304. switch(arg){
  305. case 0:
  306. WR(Hostctl, r[Hostctl] & ~Dwidth4);
  307. break;
  308. case 2:
  309. WR(Hostctl, r[Hostctl] | Dwidth4);
  310. break;
  311. }
  312. }
  313. static int
  314. sdiocmd(u32int cmd, u32int arg, u32int *resp)
  315. {
  316. int i, err;
  317. u32int c;
  318. u32int *r;
  319. assert(cmd < nelem(cmdinfo) && cmdinfo[cmd] != 0);
  320. i = GETTM(cmdinfo[cmd]);
  321. c = cmd<<Indexshift | GETCMD(cmdinfo[cmd]);
  322. if(c & Isdata)
  323. if(i & Card2host)
  324. i |= PIOread? Hostpio: Hostdma;
  325. else
  326. i |= PIOwrite? Hostpio: Hostdma;
  327. WR(Tm, i);
  328. WR(ArgLSB, arg);
  329. WR(ArgMSB, arg>>16);
  330. WR(ErrIntr, ~0);
  331. WR(Cmd, c);
  332. r = (u32int*)AddrSdio;
  333. i = awaitdone(r, Cmddone, HZ);
  334. if((i & (Cmddone|Err)) != Cmddone){
  335. if((err = r[ErrIntr]) != Ctoerr)
  336. iprint("sdio: cmd %#ux error intr %#ux %#ux stat %#ux\n",
  337. c, i, err, r[Hoststat]);
  338. WR(ErrIntr, err);
  339. WR(Interrupt, i);
  340. error(Eio);
  341. }
  342. WR(Interrupt, i & ~Datadone);
  343. c &= Respmask;
  344. getresp(r, resp, c);
  345. if(c == Resp48busy)
  346. awaitresp48data(r, cmd);
  347. finishcmd(cmd, arg);
  348. return 0;
  349. }
  350. static void
  351. sdioiosetup(int write, void *buf, int bsize, int bcount)
  352. {
  353. int len;
  354. uintptr pa;
  355. pa = PADDR(buf);
  356. if(write && !PIOwrite){
  357. WR(DmaLSB, pa);
  358. WR(DmaMSB, pa>>16);
  359. len = bsize * bcount;
  360. cachedwbse(buf, len);
  361. l2cacheuwbse(buf, len);
  362. }else if(!write && !PIOread){
  363. WR(DmaLSB, pa);
  364. WR(DmaMSB, pa>>16);
  365. len = bsize * bcount;
  366. cachedwbinvse(buf, len);
  367. l2cacheuwbinvse(buf, len);
  368. }
  369. WR(Blksize, bsize);
  370. WR(Blkcount, bcount);
  371. }
  372. static uchar *
  373. getdatas(u32int *r, uchar *buf)
  374. {
  375. ushort d;
  376. d = r[Data];
  377. *buf++ = d;
  378. *buf++ = d>>8;
  379. return buf;
  380. }
  381. static int
  382. sdioread(uchar *buf, int *lenp)
  383. {
  384. int i, now, len;
  385. u32int *r;
  386. r = (u32int*)AddrSdio;
  387. i = 0;
  388. len = *lenp;
  389. while(len > 0){
  390. if(Pollread){
  391. now = m->ticks;
  392. i = awaitdone(r, Read8wready|Readrdy, 3*HZ);
  393. if(m->ticks - now > 3*HZ){
  394. print("sdioio: (%d) no Readrdy intr %#ux stat %#ux\n",
  395. len, i, r[Hoststat]);
  396. error(Eio);
  397. }
  398. }else{
  399. i = r[Interrupt];
  400. if((i & (Read8wready|Readrdy|Err)) == 0){
  401. WR(Irpten, (len > 8*4? Read8wready:
  402. Readrdy) | Err);
  403. tsleep(&ctlr.r, datadone, 0, 3000);
  404. WR(Irpten, 0);
  405. i = ctlr.datadone;
  406. ctlr.datadone = 0;
  407. if((i & (Read8wready|Readrdy|Err)) == 0){
  408. print("sdioio: (%d) no Readrdy intr %#ux stat %#ux\n",
  409. len, i, r[Hoststat]);
  410. error(Eio);
  411. }
  412. }
  413. }
  414. if((i & Read8wready) && len >= 8*2*2){
  415. for(i = 0; i < 8*2; i++)
  416. buf = getdatas(r, buf);
  417. len -= 8*2*2;
  418. }else if(i & Readrdy){
  419. buf = getdatas(r, buf);
  420. buf = getdatas(r, buf);
  421. len -= 2*2;
  422. } else
  423. ckerr(r, i, len, "read");
  424. }
  425. *lenp = len;
  426. return i;
  427. }
  428. static int
  429. sdiowrite(uchar *buf, int *lenp)
  430. {
  431. int i, now, len;
  432. u32int *r;
  433. r = (u32int*)AddrSdio;
  434. i = 0;
  435. len = *lenp;
  436. while(len > 0){
  437. if(Pollwrite){
  438. now = m->ticks;
  439. i = awaitdone(r, Writerdy, 8*HZ);
  440. if(m->ticks - now > 8*HZ){
  441. print("sdioio: (%d) no Writerdy intr %#ux stat %#ux\n",
  442. len, i, r[Hoststat]);
  443. error(Eio);
  444. }
  445. }else{
  446. i = r[Interrupt];
  447. if((i & (Writerdy|Err)) == 0){
  448. WR(Irpten, Writerdy | Err);
  449. tsleep(&ctlr.r, datadone, 0, 8000);
  450. WR(Irpten, 0);
  451. i = ctlr.datadone;
  452. ctlr.datadone = 0;
  453. if((i & (Writerdy|Err)) == 0){
  454. print("sdioio: (%d) no Writerdy intr %#ux stat %#ux\n",
  455. len, i, r[Hoststat]);
  456. error(Eio);
  457. }
  458. }
  459. }
  460. if(i & Writerdy){
  461. r[Data] = buf[0] | buf[1]<<8;
  462. r[Data] = buf[2] | buf[3]<<8;
  463. buf += 4;
  464. len -= 4;
  465. } else
  466. ckerr(r, i, len, "write");
  467. }
  468. *lenp = len;
  469. return i;
  470. }
  471. static void
  472. sdioio(int write, uchar *buf, int len)
  473. {
  474. int i;
  475. u32int *r;
  476. assert((len & 3) == 0);
  477. r = (u32int*)AddrSdio;
  478. if(write && PIOwrite)
  479. i = sdiowrite(buf, &len);
  480. else if(!write && PIOread)
  481. i = sdioread(buf, &len);
  482. else{
  483. WR(Irpten, Dmadone|Err);
  484. tsleep(&ctlr.r, datadone, 0, 3000);
  485. WR(Irpten, 0);
  486. i = ctlr.datadone;
  487. ctlr.datadone = 0;
  488. ckerr(r, i, len, "dma");
  489. ckdmadone(r, i, "no dma done");
  490. WR(Interrupt, Dmadone);
  491. }
  492. if(Polldone)
  493. i = awaitdone(r, Datadone, 3*HZ);
  494. else if((i & Datadone) == 0){
  495. WR(Irpten, Datadone|Err);
  496. tsleep(&ctlr.r, datadone, 0, 3000);
  497. i = ctlr.datadone;
  498. ctlr.datadone = 0;
  499. WR(Irpten, 0);
  500. }
  501. ckerr(r, i, len, "IO");
  502. ckdmadone(r, i, "IO timeout");
  503. if(i)
  504. WR(Interrupt, i);
  505. }
  506. static void
  507. sdiointerrupt(Ureg*, void*)
  508. {
  509. u32int *r;
  510. r = (u32int*)AddrSdio;
  511. ctlr.datadone = r[Interrupt];
  512. WR(Irpten, 0);
  513. wakeup(&ctlr.r);
  514. }
  515. SDio sdio = {
  516. "sdio",
  517. sdioinit,
  518. sdioenable,
  519. sdioinquiry,
  520. sdiocmd,
  521. sdioiosetup,
  522. sdioio,
  523. };