mmc.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. /*
  2. * (C) Copyright 2003
  3. * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
  4. *
  5. * See file CREDITS for list of people who contributed to this
  6. * project.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21. * MA 02111-1307 USA
  22. */
  23. #include <config.h>
  24. #include <common.h>
  25. #include <mmc.h>
  26. #include <asm/errno.h>
  27. #include <asm/arch/hardware.h>
  28. #include <part.h>
  29. #ifdef CONFIG_MMC
  30. extern int
  31. fat_register_device(block_dev_desc_t *dev_desc, int part_no);
  32. static block_dev_desc_t mmc_dev;
  33. block_dev_desc_t * mmc_get_dev(int dev)
  34. {
  35. return (dev == 0) ? &mmc_dev : NULL;
  36. }
  37. /*
  38. * FIXME needs to read cid and csd info to determine block size
  39. * and other parameters
  40. */
  41. static uchar mmc_buf[MMC_BLOCK_SIZE];
  42. static mmc_csd_t mmc_csd;
  43. static int mmc_ready = 0;
  44. static uchar *
  45. /****************************************************/
  46. mmc_cmd(ushort cmd, ushort argh, ushort argl, ushort cmdat)
  47. /****************************************************/
  48. {
  49. static uchar resp[20];
  50. ulong status;
  51. int words, i;
  52. debug("mmc_cmd %x %x %x %x\n", cmd, argh, argl, cmdat);
  53. MMC_STRPCL = MMC_STRPCL_STOP_CLK;
  54. MMC_I_MASK = ~MMC_I_MASK_CLK_IS_OFF;
  55. while (!(MMC_I_REG & MMC_I_REG_CLK_IS_OFF));
  56. MMC_CMD = cmd;
  57. MMC_ARGH = argh;
  58. MMC_ARGL = argl;
  59. MMC_CMDAT = cmdat;
  60. MMC_I_MASK = ~MMC_I_MASK_END_CMD_RES;
  61. MMC_STRPCL = MMC_STRPCL_START_CLK;
  62. while (!(MMC_I_REG & MMC_I_REG_END_CMD_RES));
  63. status = MMC_STAT;
  64. debug("MMC status %x\n", status);
  65. if (status & MMC_STAT_TIME_OUT_RESPONSE) {
  66. return 0;
  67. }
  68. switch (cmdat & 0x3) {
  69. case MMC_CMDAT_R1:
  70. case MMC_CMDAT_R3:
  71. words = 3;
  72. break;
  73. case MMC_CMDAT_R2:
  74. words = 8;
  75. break;
  76. default:
  77. return 0;
  78. }
  79. for (i = words-1; i >= 0; i--) {
  80. ulong res_fifo = MMC_RES;
  81. int offset = i << 1;
  82. resp[offset] = ((uchar *)&res_fifo)[0];
  83. resp[offset+1] = ((uchar *)&res_fifo)[1];
  84. }
  85. #ifdef MMC_DEBUG
  86. for (i=0; i<words*2; i += 2) {
  87. printf("MMC resp[%d] = %02x\n", i, resp[i]);
  88. printf("MMC resp[%d] = %02x\n", i+1, resp[i+1]);
  89. }
  90. #endif
  91. return resp;
  92. }
  93. int
  94. /****************************************************/
  95. mmc_block_read(uchar *dst, ulong src, ulong len)
  96. /****************************************************/
  97. {
  98. uchar *resp;
  99. ushort argh, argl;
  100. ulong status;
  101. if (len == 0) {
  102. return 0;
  103. }
  104. debug("mmc_block_rd dst %lx src %lx len %d\n", (ulong)dst, src, len);
  105. argh = len >> 16;
  106. argl = len & 0xffff;
  107. /* set block len */
  108. resp = mmc_cmd(MMC_CMD_SET_BLOCKLEN, argh, argl, MMC_CMDAT_R1);
  109. /* send read command */
  110. argh = src >> 16;
  111. argl = src & 0xffff;
  112. MMC_STRPCL = MMC_STRPCL_STOP_CLK;
  113. MMC_RDTO = 0xffff;
  114. MMC_NOB = 1;
  115. MMC_BLKLEN = len;
  116. resp = mmc_cmd(MMC_CMD_READ_BLOCK, argh, argl,
  117. MMC_CMDAT_R1|MMC_CMDAT_READ|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN);
  118. MMC_I_MASK = ~MMC_I_MASK_RXFIFO_RD_REQ;
  119. while (len) {
  120. if (MMC_I_REG & MMC_I_REG_RXFIFO_RD_REQ) {
  121. #ifdef CONFIG_PXA27X
  122. int i;
  123. for (i=min(len,32); i; i--) {
  124. *dst++ = * ((volatile uchar *) &MMC_RXFIFO);
  125. len--;
  126. }
  127. #else
  128. *dst++ = MMC_RXFIFO;
  129. len--;
  130. #endif
  131. }
  132. status = MMC_STAT;
  133. if (status & MMC_STAT_ERRORS) {
  134. printf("MMC_STAT error %lx\n", status);
  135. return -1;
  136. }
  137. }
  138. MMC_I_MASK = ~MMC_I_MASK_DATA_TRAN_DONE;
  139. while (!(MMC_I_REG & MMC_I_REG_DATA_TRAN_DONE));
  140. status = MMC_STAT;
  141. if (status & MMC_STAT_ERRORS) {
  142. printf("MMC_STAT error %lx\n", status);
  143. return -1;
  144. }
  145. return 0;
  146. }
  147. int
  148. /****************************************************/
  149. mmc_block_write(ulong dst, uchar *src, int len)
  150. /****************************************************/
  151. {
  152. uchar *resp;
  153. ushort argh, argl;
  154. ulong status;
  155. if (len == 0) {
  156. return 0;
  157. }
  158. debug("mmc_block_wr dst %lx src %lx len %d\n", dst, (ulong)src, len);
  159. argh = len >> 16;
  160. argl = len & 0xffff;
  161. /* set block len */
  162. resp = mmc_cmd(MMC_CMD_SET_BLOCKLEN, argh, argl, MMC_CMDAT_R1);
  163. /* send write command */
  164. argh = dst >> 16;
  165. argl = dst & 0xffff;
  166. MMC_STRPCL = MMC_STRPCL_STOP_CLK;
  167. MMC_NOB = 1;
  168. MMC_BLKLEN = len;
  169. resp = mmc_cmd(MMC_CMD_WRITE_BLOCK, argh, argl,
  170. MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN);
  171. MMC_I_MASK = ~MMC_I_MASK_TXFIFO_WR_REQ;
  172. while (len) {
  173. if (MMC_I_REG & MMC_I_REG_TXFIFO_WR_REQ) {
  174. int i, bytes = min(32,len);
  175. for (i=0; i<bytes; i++) {
  176. MMC_TXFIFO = *src++;
  177. }
  178. if (bytes < 32) {
  179. MMC_PRTBUF = MMC_PRTBUF_BUF_PART_FULL;
  180. }
  181. len -= bytes;
  182. }
  183. status = MMC_STAT;
  184. if (status & MMC_STAT_ERRORS) {
  185. printf("MMC_STAT error %lx\n", status);
  186. return -1;
  187. }
  188. }
  189. MMC_I_MASK = ~MMC_I_MASK_DATA_TRAN_DONE;
  190. while (!(MMC_I_REG & MMC_I_REG_DATA_TRAN_DONE));
  191. MMC_I_MASK = ~MMC_I_MASK_PRG_DONE;
  192. while (!(MMC_I_REG & MMC_I_REG_PRG_DONE));
  193. status = MMC_STAT;
  194. if (status & MMC_STAT_ERRORS) {
  195. printf("MMC_STAT error %lx\n", status);
  196. return -1;
  197. }
  198. return 0;
  199. }
  200. int
  201. /****************************************************/
  202. mmc_read(ulong src, uchar *dst, int size)
  203. /****************************************************/
  204. {
  205. ulong end, part_start, part_end, part_len, aligned_start, aligned_end;
  206. ulong mmc_block_size, mmc_block_address;
  207. if (size == 0) {
  208. return 0;
  209. }
  210. if (!mmc_ready) {
  211. printf("Please initial the MMC first\n");
  212. return -1;
  213. }
  214. mmc_block_size = MMC_BLOCK_SIZE;
  215. mmc_block_address = ~(mmc_block_size - 1);
  216. src -= CFG_MMC_BASE;
  217. end = src + size;
  218. part_start = ~mmc_block_address & src;
  219. part_end = ~mmc_block_address & end;
  220. aligned_start = mmc_block_address & src;
  221. aligned_end = mmc_block_address & end;
  222. /* all block aligned accesses */
  223. debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
  224. src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
  225. if (part_start) {
  226. part_len = mmc_block_size - part_start;
  227. debug("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
  228. src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
  229. if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < 0) {
  230. return -1;
  231. }
  232. memcpy(dst, mmc_buf+part_start, part_len);
  233. dst += part_len;
  234. src += part_len;
  235. }
  236. debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
  237. src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
  238. for (; src < aligned_end; src += mmc_block_size, dst += mmc_block_size) {
  239. debug("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
  240. src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
  241. if ((mmc_block_read((uchar *)(dst), src, mmc_block_size)) < 0) {
  242. return -1;
  243. }
  244. }
  245. debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
  246. src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
  247. if (part_end && src < end) {
  248. debug("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
  249. src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
  250. if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0) {
  251. return -1;
  252. }
  253. memcpy(dst, mmc_buf, part_end);
  254. }
  255. return 0;
  256. }
  257. int
  258. /****************************************************/
  259. mmc_write(uchar *src, ulong dst, int size)
  260. /****************************************************/
  261. {
  262. ulong end, part_start, part_end, part_len, aligned_start, aligned_end;
  263. ulong mmc_block_size, mmc_block_address;
  264. if (size == 0) {
  265. return 0;
  266. }
  267. if (!mmc_ready) {
  268. printf("Please initial the MMC first\n");
  269. return -1;
  270. }
  271. mmc_block_size = MMC_BLOCK_SIZE;
  272. mmc_block_address = ~(mmc_block_size - 1);
  273. dst -= CFG_MMC_BASE;
  274. end = dst + size;
  275. part_start = ~mmc_block_address & dst;
  276. part_end = ~mmc_block_address & end;
  277. aligned_start = mmc_block_address & dst;
  278. aligned_end = mmc_block_address & end;
  279. /* all block aligned accesses */
  280. debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
  281. src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
  282. if (part_start) {
  283. part_len = mmc_block_size - part_start;
  284. debug("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
  285. (ulong)src, dst, end, part_start, part_end, aligned_start, aligned_end);
  286. if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < 0) {
  287. return -1;
  288. }
  289. memcpy(mmc_buf+part_start, src, part_len);
  290. if ((mmc_block_write(aligned_start, mmc_buf, mmc_block_size)) < 0) {
  291. return -1;
  292. }
  293. dst += part_len;
  294. src += part_len;
  295. }
  296. debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
  297. src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
  298. for (; dst < aligned_end; src += mmc_block_size, dst += mmc_block_size) {
  299. debug("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
  300. src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
  301. if ((mmc_block_write(dst, (uchar *)src, mmc_block_size)) < 0) {
  302. return -1;
  303. }
  304. }
  305. debug("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
  306. src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
  307. if (part_end && dst < end) {
  308. debug("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
  309. src, (ulong)dst, end, part_start, part_end, aligned_start, aligned_end);
  310. if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0) {
  311. return -1;
  312. }
  313. memcpy(mmc_buf, src, part_end);
  314. if ((mmc_block_write(aligned_end, mmc_buf, mmc_block_size)) < 0) {
  315. return -1;
  316. }
  317. }
  318. return 0;
  319. }
  320. ulong
  321. /****************************************************/
  322. mmc_bread(int dev_num, ulong blknr, ulong blkcnt, void *dst)
  323. /****************************************************/
  324. {
  325. int mmc_block_size = MMC_BLOCK_SIZE;
  326. ulong src = blknr * mmc_block_size + CFG_MMC_BASE;
  327. mmc_read(src, (uchar *)dst, blkcnt*mmc_block_size);
  328. return blkcnt;
  329. }
  330. int
  331. /****************************************************/
  332. mmc_init(int verbose)
  333. /****************************************************/
  334. {
  335. int retries, rc = -ENODEV;
  336. uchar *resp;
  337. #ifdef CONFIG_LUBBOCK
  338. set_GPIO_mode( GPIO6_MMCCLK_MD );
  339. set_GPIO_mode( GPIO8_MMCCS0_MD );
  340. #endif
  341. CKEN |= CKEN12_MMC; /* enable MMC unit clock */
  342. #if defined(CONFIG_ADSVIX)
  343. /* turn on the power */
  344. GPCR(114) = GPIO_bit(114);
  345. udelay(1000);
  346. #endif
  347. mmc_csd.c_size = 0;
  348. MMC_CLKRT = MMC_CLKRT_0_3125MHZ;
  349. MMC_RESTO = MMC_RES_TO_MAX;
  350. MMC_SPI = MMC_SPI_DISABLE;
  351. /* reset */
  352. retries = 10;
  353. resp = mmc_cmd(0, 0, 0, 0);
  354. resp = mmc_cmd(1, 0x00ff, 0xc000, MMC_CMDAT_INIT|MMC_CMDAT_BUSY|MMC_CMDAT_R3);
  355. while (retries-- && resp && !(resp[4] & 0x80)) {
  356. debug("resp %x %x\n", resp[0], resp[1]);
  357. #ifdef CONFIG_PXA27X
  358. udelay(10000);
  359. #else
  360. udelay(50);
  361. #endif
  362. resp = mmc_cmd(1, 0x00ff, 0xff00, MMC_CMDAT_BUSY|MMC_CMDAT_R3);
  363. }
  364. /* try to get card id */
  365. resp = mmc_cmd(2, 0, 0, MMC_CMDAT_R2);
  366. if (resp) {
  367. /* TODO configure mmc driver depending on card attributes */
  368. mmc_cid_t *cid = (mmc_cid_t *)resp;
  369. if (verbose) {
  370. printf("MMC found. Card desciption is:\n");
  371. printf("Manufacturer ID = %02x%02x%02x\n",
  372. cid->id[0], cid->id[1], cid->id[2]);
  373. printf("HW/FW Revision = %x %x\n",cid->hwrev, cid->fwrev);
  374. cid->hwrev = cid->fwrev = 0; /* null terminate string */
  375. printf("Product Name = %s\n",cid->name);
  376. printf("Serial Number = %02x%02x%02x\n",
  377. cid->sn[0], cid->sn[1], cid->sn[2]);
  378. printf("Month = %d\n",cid->month);
  379. printf("Year = %d\n",1997 + cid->year);
  380. }
  381. /* fill in device description */
  382. mmc_dev.if_type = IF_TYPE_MMC;
  383. mmc_dev.part_type = PART_TYPE_DOS;
  384. mmc_dev.dev = 0;
  385. mmc_dev.lun = 0;
  386. mmc_dev.type = 0;
  387. /* FIXME fill in the correct size (is set to 32MByte) */
  388. mmc_dev.blksz = 512;
  389. mmc_dev.lba = 0x10000;
  390. sprintf(mmc_dev.vendor,"Man %02x%02x%02x Snr %02x%02x%02x",
  391. cid->id[0], cid->id[1], cid->id[2],
  392. cid->sn[0], cid->sn[1], cid->sn[2]);
  393. sprintf(mmc_dev.product,"%s",cid->name);
  394. sprintf(mmc_dev.revision,"%x %x",cid->hwrev, cid->fwrev);
  395. mmc_dev.removable = 0;
  396. mmc_dev.block_read = mmc_bread;
  397. /* MMC exists, get CSD too */
  398. resp = mmc_cmd(MMC_CMD_SET_RCA, MMC_DEFAULT_RCA, 0, MMC_CMDAT_R1);
  399. resp = mmc_cmd(MMC_CMD_SEND_CSD, MMC_DEFAULT_RCA, 0, MMC_CMDAT_R2);
  400. if (resp) {
  401. mmc_csd_t *csd = (mmc_csd_t *)resp;
  402. memcpy(&mmc_csd, csd, sizeof(csd));
  403. rc = 0;
  404. mmc_ready = 1;
  405. /* FIXME add verbose printout for csd */
  406. }
  407. }
  408. #ifdef CONFIG_PXA27X
  409. MMC_CLKRT = 1; /* 10 MHz - see Intel errata */
  410. #else
  411. MMC_CLKRT = 0; /* 20 MHz */
  412. #endif
  413. resp = mmc_cmd(7, MMC_DEFAULT_RCA, 0, MMC_CMDAT_R1);
  414. fat_register_device(&mmc_dev,1); /* partitions start counting with 1 */
  415. return rc;
  416. }
  417. int
  418. mmc_ident(block_dev_desc_t *dev)
  419. {
  420. return 0;
  421. }
  422. int
  423. mmc2info(ulong addr)
  424. {
  425. /* FIXME hard codes to 32 MB device */
  426. if (addr >= CFG_MMC_BASE && addr < CFG_MMC_BASE + 0x02000000) {
  427. return 1;
  428. }
  429. return 0;
  430. }
  431. #endif /* CONFIG_MMC */