fh_mmc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. /*
  2. * This file is part of FH8620 BSP for RT-Thread distribution.
  3. *
  4. * Copyright (c) 2016 Shanghai Fullhan Microelectronics Co., Ltd.
  5. * All rights reserved
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along
  18. * with this program; if not, write to the Free Software Foundation, Inc.,
  19. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  20. *
  21. * Visit http://www.fullhan.com to get contact with Fullhan.
  22. *
  23. * Change Logs:
  24. * Date Author Notes
  25. */
  26. #include "inc/fh_driverlib.h"
  27. // *1: card off
  28. // *0: card on
  29. inline rt_uint32_t MMC_GetCardStatus(struct fh_mmc_obj *mmc_obj)
  30. {
  31. rt_uint32_t card_status = GET_REG(mmc_obj->base + OFFSET_SDC_CDETECT);
  32. return card_status & 0x1;
  33. }
  34. inline void MMC_StartDma(struct fh_mmc_obj *mmc_obj)
  35. {
  36. rt_uint32_t reg;
  37. SET_REG(mmc_obj->base + OFFSET_SDC_DBADDR, (rt_uint32_t)mmc_obj->descriptors);
  38. reg = GET_REG(mmc_obj->base + OFFSET_SDC_BMOD);
  39. reg |= 1 << 7;
  40. SET_REG(mmc_obj->base + OFFSET_SDC_BMOD, reg);
  41. }
  42. inline void MMC_StopDma(struct fh_mmc_obj *mmc_obj)
  43. {
  44. rt_uint32_t reg;
  45. reg = GET_REG(mmc_obj->base + OFFSET_SDC_BMOD);
  46. reg &= ~(1 << 7);
  47. SET_REG(mmc_obj->base + OFFSET_SDC_BMOD, reg);
  48. }
  49. void MMC_InitDescriptors(struct fh_mmc_obj *mmc_obj, rt_uint32_t *buf, rt_uint32_t size)
  50. {
  51. MMC_DMA_Descriptors *desc;
  52. rt_uint32_t len = 0;
  53. int i, desc_cnt = 0;
  54. desc = mmc_obj->descriptors;
  55. while(size > 0)
  56. {
  57. desc[desc_cnt].desc0.bit.own = 1;
  58. desc[desc_cnt].desc0.bit.sencond_address_chained = 1;
  59. desc[desc_cnt].desc1.bit.buffer1_size = MIN(MMC_DMA_DESC_BUFF_SIZE, size);
  60. desc[desc_cnt].desc2.bit.buffer_addr0 = (rt_uint32_t)buf + len;
  61. desc[desc_cnt].desc3.bit.buffer_addr1 = (rt_uint32_t)mmc_obj->descriptors + (desc_cnt + 1) * sizeof(MMC_DMA_Descriptors);
  62. size -= desc[desc_cnt].desc1.bit.buffer1_size;
  63. len += desc[desc_cnt].desc1.bit.buffer1_size;
  64. desc_cnt++;
  65. }
  66. desc[0].desc0.bit.first_descriptor = 1;
  67. desc[desc_cnt-1].desc0.bit.last_descriptor = 1;
  68. desc[desc_cnt-1].desc3.bit.buffer_addr1 = 0;
  69. }
  70. inline rt_uint32_t MMC_GetWaterlevel(struct fh_mmc_obj *mmc_obj)
  71. {
  72. return (GET_REG(mmc_obj->base + OFFSET_SDC_STATUS) >> 17) & 0x1fff;
  73. }
  74. inline rt_uint32_t MMC_GetStatus(struct fh_mmc_obj *mmc_obj)
  75. {
  76. return GET_REG(mmc_obj->base + OFFSET_SDC_STATUS);
  77. }
  78. inline rt_uint32_t MMC_GetRawInterrupt(struct fh_mmc_obj *mmc_obj)
  79. {
  80. return GET_REG(mmc_obj->base + OFFSET_SDC_RINTSTS);
  81. }
  82. inline rt_uint32_t MMC_GetUnmaskedInterrupt(struct fh_mmc_obj *mmc_obj)
  83. {
  84. return GET_REG(mmc_obj->base + OFFSET_SDC_MINTSTS);
  85. }
  86. inline rt_uint32_t MMC_ClearRawInterrupt(struct fh_mmc_obj *mmc_obj, rt_uint32_t interrupts)
  87. {
  88. return SET_REG(mmc_obj->base + OFFSET_SDC_RINTSTS, interrupts);
  89. }
  90. inline rt_uint32_t MMC_GetInterruptMask(struct fh_mmc_obj *mmc_obj)
  91. {
  92. return GET_REG(mmc_obj->base + OFFSET_SDC_INTMASK);
  93. }
  94. inline rt_uint32_t MMC_SetInterruptMask(struct fh_mmc_obj *mmc_obj, rt_uint32_t mask)
  95. {
  96. return SET_REG(mmc_obj->base + OFFSET_SDC_INTMASK, mask);
  97. }
  98. inline void MMC_SetByteCount(struct fh_mmc_obj *mmc_obj, rt_uint32_t bytes)
  99. {
  100. SET_REG(mmc_obj->base + OFFSET_SDC_BYTCNT, bytes);
  101. }
  102. inline void MMC_SetBlockSize(struct fh_mmc_obj *mmc_obj, rt_uint32_t size)
  103. {
  104. SET_REG(mmc_obj->base + OFFSET_SDC_BLKSIZ, size);
  105. }
  106. inline rt_uint32_t MMC_GetResponse(struct fh_mmc_obj *mmc_obj, int resp_num)
  107. {
  108. return GET_REG(mmc_obj->base + OFFSET_SDC_RESP0 + resp_num * 4);
  109. }
  110. inline rt_uint32_t MMC_IsFifoEmpty(struct fh_mmc_obj *mmc_obj)
  111. {
  112. return (GET_REG(mmc_obj->base + OFFSET_SDC_STATUS) >> 2) & 0x1;
  113. }
  114. inline rt_uint32_t MMC_IsDataStateBusy(struct fh_mmc_obj *mmc_obj)
  115. {
  116. return (GET_REG(mmc_obj->base + OFFSET_SDC_STATUS) >> 10) & 0x1;
  117. }
  118. int MMC_WriteData(struct fh_mmc_obj *mmc_obj, rt_uint32_t *buf, rt_uint32_t size)
  119. {
  120. int filled = 0, fifo_available, i, retries;
  121. for (i=0; i<size/4; i++)
  122. {
  123. retries = 0;
  124. do
  125. {
  126. fifo_available = MMC_FIFO_DEPTH - MMC_GetWaterlevel(mmc_obj);
  127. if(retries++ > 10000)
  128. {
  129. rt_kprintf("ERROR: %s, get water level timeout\n", __func__);
  130. return -RT_ETIMEOUT;
  131. }
  132. }
  133. while(!fifo_available);
  134. SET_REG(mmc_obj->base + OFFSET_SDC_FIFO, *buf++);
  135. }
  136. retries = 0;
  137. while(MMC_IsDataStateBusy(mmc_obj))
  138. {
  139. if(retries++ > 10000)
  140. {
  141. rt_kprintf("ERROR: %s, timeout, data line keep being busy\n", __func__);
  142. return -RT_ETIMEOUT;
  143. }
  144. }
  145. return 0;
  146. }
  147. int MMC_ReadData(struct fh_mmc_obj *mmc_obj, rt_uint32_t *buf, rt_uint32_t size)
  148. {
  149. int fifo_available, i, retries;
  150. for (i=0; i<size/4; i++)
  151. {
  152. retries = 0;
  153. do
  154. {
  155. fifo_available = MMC_GetWaterlevel(mmc_obj);
  156. if(retries++ > 10000)
  157. {
  158. rt_kprintf("ERROR: %s, get water level timeout\n", __func__);
  159. return -RT_ETIMEOUT;
  160. }
  161. }
  162. while(!fifo_available);
  163. *buf++ = GET_REG(mmc_obj->base + OFFSET_SDC_FIFO);
  164. }
  165. retries = 0;
  166. while(MMC_IsDataStateBusy(mmc_obj))
  167. {
  168. if(retries++ > 10000)
  169. {
  170. rt_kprintf("ERROR: %s, timeout, data line keep being busy\n", __func__);
  171. return -RT_ETIMEOUT;
  172. }
  173. }
  174. return 0;
  175. }
  176. int MMC_UpdateClockRegister(struct fh_mmc_obj *mmc_obj, int div)
  177. {
  178. rt_uint32_t tick, timeout;
  179. tick = rt_tick_get();
  180. timeout = tick + RT_TICK_PER_SECOND / 10; //100ms in total
  181. /* disable clock */
  182. SET_REG(mmc_obj->base + OFFSET_SDC_CLKENA, 0);
  183. SET_REG(mmc_obj->base + OFFSET_SDC_CLKSRC, 0);
  184. /* inform CIU */
  185. SET_REG(mmc_obj->base + OFFSET_SDC_CMD, 1<<31 | 1<<21);
  186. while(GET_REG(mmc_obj->base + OFFSET_SDC_CMD) & 0x80000000)
  187. {
  188. tick = rt_tick_get();
  189. if(tick > timeout)
  190. {
  191. rt_kprintf("ERROR: %s, update clock timeout\n", __func__);
  192. return -RT_ETIMEOUT;
  193. }
  194. }
  195. /* set clock to desired speed */
  196. SET_REG(mmc_obj->base + OFFSET_SDC_CLKDIV, div);
  197. /* inform CIU */
  198. SET_REG(mmc_obj->base + OFFSET_SDC_CMD, 1<<31 | 1<<21);
  199. while(GET_REG(mmc_obj->base + OFFSET_SDC_CMD) & 0x80000000)
  200. {
  201. tick = rt_tick_get();
  202. if(tick > timeout)
  203. {
  204. rt_kprintf("ERROR: %s, update clock timeout\n", __func__);
  205. return -RT_ETIMEOUT;
  206. }
  207. }
  208. /* enable clock */
  209. SET_REG(mmc_obj->base + OFFSET_SDC_CLKENA, 1);
  210. /* inform CIU */
  211. SET_REG(mmc_obj->base + OFFSET_SDC_CMD, 1<<31 | 1<<21);
  212. while(GET_REG(mmc_obj->base + OFFSET_SDC_CMD) & 0x80000000)
  213. {
  214. tick = rt_tick_get();
  215. if(tick > timeout)
  216. {
  217. rt_kprintf("ERROR: %s, update clock timeout\n", __func__);
  218. return -RT_ETIMEOUT;
  219. }
  220. }
  221. return 0;
  222. }
  223. int MMC_SetCardWidth(struct fh_mmc_obj *mmc_obj, int width)
  224. {
  225. switch(width)
  226. {
  227. case MMC_CARD_WIDTH_1BIT:
  228. SET_REG(mmc_obj->base + OFFSET_SDC_CTYPE, 0);
  229. break;
  230. case MMC_CARD_WIDTH_4BIT:
  231. SET_REG(mmc_obj->base + OFFSET_SDC_CTYPE, 1);
  232. break;
  233. default:
  234. rt_kprintf("ERROR: %s, card width %d is not supported\n", __func__, width);
  235. return -RT_ERROR;
  236. break;
  237. }
  238. return 0;
  239. }
  240. int MMC_SendCommand(struct fh_mmc_obj *mmc_obj, rt_uint32_t cmd, rt_uint32_t arg, rt_uint32_t flags)
  241. {
  242. rt_uint32_t reg, tick, timeout;
  243. tick = rt_tick_get();
  244. timeout = tick + RT_TICK_PER_SECOND; //1s
  245. SET_REG(mmc_obj->base + OFFSET_SDC_CMDARG, arg);
  246. flags |= 1<<31 | 1<<29 | cmd;
  247. SET_REG(mmc_obj->base + OFFSET_SDC_CMD, flags);
  248. while(GET_REG(mmc_obj->base + OFFSET_SDC_CMD) & MMC_CMD_START_CMD)
  249. {
  250. tick = rt_tick_get();
  251. if(tick > timeout)
  252. {
  253. rt_kprintf("ERROR: %s, send cmd timeout\n", __func__);
  254. return -RT_ETIMEOUT;
  255. }
  256. }
  257. //fixme: check HLE_INT_STATUS
  258. return 0;
  259. }
  260. int MMC_ResetFifo(struct fh_mmc_obj *mmc_obj)
  261. {
  262. rt_uint32_t reg, tick, timeout;
  263. tick = rt_tick_get();
  264. timeout = tick + RT_TICK_PER_SECOND / 10; //100ms
  265. reg = GET_REG(mmc_obj->base + OFFSET_SDC_CTRL);
  266. reg |= 1 << 1;
  267. SET_REG(mmc_obj->base + OFFSET_SDC_CTRL, reg);
  268. //wait until fifo reset finish
  269. while(GET_REG(mmc_obj->base + OFFSET_SDC_CTRL) & MMC_CTRL_FIFO_RESET)
  270. {
  271. tick = rt_tick_get();
  272. if(tick > timeout)
  273. {
  274. rt_kprintf("ERROR: %s, FIFO reset timeout\n", __func__);
  275. return -RT_ETIMEOUT;
  276. }
  277. }
  278. return 0;
  279. }
  280. int MMC_Reset(struct fh_mmc_obj *mmc_obj)
  281. {
  282. rt_uint32_t reg, tick, timeout;
  283. tick = rt_tick_get();
  284. timeout = tick + RT_TICK_PER_SECOND / 10; //100ms
  285. reg = GET_REG(mmc_obj->base + OFFSET_SDC_BMOD);
  286. reg |= MMC_BMOD_RESET;
  287. SET_REG(mmc_obj->base + OFFSET_SDC_BMOD, reg);
  288. while(GET_REG(mmc_obj->base + OFFSET_SDC_BMOD) & MMC_BMOD_RESET)
  289. {
  290. tick = rt_tick_get();
  291. if(tick > timeout)
  292. {
  293. rt_kprintf("ERROR: %s, BMOD Software reset timeout\n", __func__);
  294. return -RT_ETIMEOUT;
  295. }
  296. }
  297. reg = GET_REG(mmc_obj->base + OFFSET_SDC_CTRL);
  298. reg |= MMC_CTRL_CONTROLLER_RESET | MMC_CTRL_FIFO_RESET | MMC_CTRL_DMA_RESET;
  299. SET_REG(mmc_obj->base + OFFSET_SDC_CTRL, reg);
  300. tick = rt_tick_get();
  301. timeout = tick + RT_TICK_PER_SECOND / 10; //100ms
  302. while(GET_REG(mmc_obj->base + OFFSET_SDC_CTRL) & (MMC_CTRL_CONTROLLER_RESET | MMC_CTRL_FIFO_RESET | MMC_CTRL_DMA_RESET))
  303. {
  304. tick = rt_tick_get();
  305. if(tick > timeout)
  306. {
  307. rt_kprintf("ERROR: %s, CTRL dma|fifo|ctrl reset timeout\n", __func__);
  308. return -RT_ETIMEOUT;
  309. }
  310. }
  311. return 0;
  312. }
  313. void MMC_Init(struct fh_mmc_obj *mmc_obj)
  314. {
  315. rt_uint32_t reg;
  316. if(mmc_obj->mmc_reset)
  317. mmc_obj->mmc_reset(mmc_obj);
  318. MMC_Reset(mmc_obj);
  319. //fixed burst
  320. reg = GET_REG(mmc_obj->base + OFFSET_SDC_BMOD);
  321. reg |= 1 << 1;
  322. SET_REG(mmc_obj->base + OFFSET_SDC_BMOD, reg);
  323. //fixme: power on ? ctrl by gpio ?
  324. MMC_ClearRawInterrupt(mmc_obj, MMC_INT_STATUS_ALL);
  325. MMC_SetInterruptMask(mmc_obj, 0x0);
  326. //fixme: use_internal_dma
  327. reg = GET_REG(mmc_obj->base + OFFSET_SDC_CTRL);
  328. reg |= MMC_CTRL_INT_ENABLE;
  329. #ifdef MMC_USE_DMA
  330. reg |= MMC_CTRL_USE_DMA;
  331. #endif
  332. SET_REG(mmc_obj->base + OFFSET_SDC_CTRL, reg);
  333. //set timeout param
  334. SET_REG(mmc_obj->base + OFFSET_SDC_TMOUT, 0xffffffff);
  335. //set fifo
  336. reg = GET_REG(mmc_obj->base + OFFSET_SDC_FIFOTH);
  337. reg = (reg >> 16) & 0x7ff;
  338. reg = ((0x2 << 28) | ((reg/2) << 16) | ((reg/2 + 1) << 0));
  339. SET_REG(mmc_obj->base + OFFSET_SDC_FIFOTH, reg);
  340. }