fh_mmc.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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. void MMC_InitDescriptors(struct fh_mmc_obj *mmc_obj, rt_uint32_t *buf, rt_uint32_t size)
  30. {
  31. MMC_DMA_Descriptors *desc;
  32. rt_uint32_t len = 0;
  33. int i, desc_cnt = 0;
  34. desc = mmc_obj->descriptors;
  35. while(size > 0)
  36. {
  37. desc[desc_cnt].desc0.bit.own = 1;
  38. desc[desc_cnt].desc0.bit.sencond_address_chained = 1;
  39. desc[desc_cnt].desc1.bit.buffer1_size = MIN(MMC_DMA_DESC_BUFF_SIZE, size);
  40. desc[desc_cnt].desc2.bit.buffer_addr0 = (rt_uint32_t)buf + len;
  41. desc[desc_cnt].desc3.bit.buffer_addr1 = (rt_uint32_t)mmc_obj->descriptors + (desc_cnt + 1) * sizeof(MMC_DMA_Descriptors);
  42. size -= desc[desc_cnt].desc1.bit.buffer1_size;
  43. len += desc[desc_cnt].desc1.bit.buffer1_size;
  44. desc_cnt++;
  45. }
  46. desc[0].desc0.bit.first_descriptor = 1;
  47. desc[desc_cnt-1].desc0.bit.last_descriptor = 1;
  48. desc[desc_cnt-1].desc3.bit.buffer_addr1 = 0;
  49. }
  50. int MMC_WriteData(struct fh_mmc_obj *mmc_obj, rt_uint32_t *buf, rt_uint32_t size)
  51. {
  52. int filled = 0, fifo_available, i, retries;
  53. for (i=0; i<size/4; i++)
  54. {
  55. retries = 0;
  56. do
  57. {
  58. fifo_available = MMC_FIFO_DEPTH - MMC_GetWaterlevel(mmc_obj);
  59. if(retries++ > 10000)
  60. {
  61. rt_kprintf("ERROR: %s, get water level timeout\n", __func__);
  62. return -RT_ETIMEOUT;
  63. }
  64. }
  65. while(!fifo_available);
  66. SET_REG(mmc_obj->base + OFFSET_SDC_FIFO, *buf++);
  67. }
  68. retries = 0;
  69. while(MMC_IsDataStateBusy(mmc_obj))
  70. {
  71. if(retries++ > 10000)
  72. {
  73. rt_kprintf("ERROR: %s, timeout, data line keep being busy\n", __func__);
  74. return -RT_ETIMEOUT;
  75. }
  76. }
  77. return 0;
  78. }
  79. int MMC_ReadData(struct fh_mmc_obj *mmc_obj, rt_uint32_t *buf, rt_uint32_t size)
  80. {
  81. int fifo_available, i, retries;
  82. for (i=0; i<size/4; i++)
  83. {
  84. retries = 0;
  85. do
  86. {
  87. fifo_available = MMC_GetWaterlevel(mmc_obj);
  88. if(retries++ > 10000)
  89. {
  90. rt_kprintf("ERROR: %s, get water level timeout\n", __func__);
  91. return -RT_ETIMEOUT;
  92. }
  93. }
  94. while(!fifo_available);
  95. *buf++ = GET_REG(mmc_obj->base + OFFSET_SDC_FIFO);
  96. }
  97. retries = 0;
  98. while(MMC_IsDataStateBusy(mmc_obj))
  99. {
  100. if(retries++ > 10000)
  101. {
  102. rt_kprintf("ERROR: %s, timeout, data line keep being busy\n", __func__);
  103. return -RT_ETIMEOUT;
  104. }
  105. }
  106. return 0;
  107. }
  108. int MMC_UpdateClockRegister(struct fh_mmc_obj *mmc_obj, int div)
  109. {
  110. rt_uint32_t tick, timeout;
  111. tick = rt_tick_get();
  112. timeout = tick + RT_TICK_PER_SECOND / 10; //100ms in total
  113. /* disable clock */
  114. SET_REG(mmc_obj->base + OFFSET_SDC_CLKENA, 0);
  115. SET_REG(mmc_obj->base + OFFSET_SDC_CLKSRC, 0);
  116. /* inform CIU */
  117. SET_REG(mmc_obj->base + OFFSET_SDC_CMD, 1<<31 | 1<<21);
  118. while(GET_REG(mmc_obj->base + OFFSET_SDC_CMD) & 0x80000000)
  119. {
  120. tick = rt_tick_get();
  121. if(tick > timeout)
  122. {
  123. rt_kprintf("ERROR: %s, update clock timeout\n", __func__);
  124. return -RT_ETIMEOUT;
  125. }
  126. }
  127. /* set clock to desired speed */
  128. SET_REG(mmc_obj->base + OFFSET_SDC_CLKDIV, div);
  129. /* inform CIU */
  130. SET_REG(mmc_obj->base + OFFSET_SDC_CMD, 1<<31 | 1<<21);
  131. while(GET_REG(mmc_obj->base + OFFSET_SDC_CMD) & 0x80000000)
  132. {
  133. tick = rt_tick_get();
  134. if(tick > timeout)
  135. {
  136. rt_kprintf("ERROR: %s, update clock timeout\n", __func__);
  137. return -RT_ETIMEOUT;
  138. }
  139. }
  140. /* enable clock */
  141. SET_REG(mmc_obj->base + OFFSET_SDC_CLKENA, 1);
  142. /* inform CIU */
  143. SET_REG(mmc_obj->base + OFFSET_SDC_CMD, 1<<31 | 1<<21);
  144. while(GET_REG(mmc_obj->base + OFFSET_SDC_CMD) & 0x80000000)
  145. {
  146. tick = rt_tick_get();
  147. if(tick > timeout)
  148. {
  149. rt_kprintf("ERROR: %s, update clock timeout\n", __func__);
  150. return -RT_ETIMEOUT;
  151. }
  152. }
  153. return 0;
  154. }
  155. int MMC_SetCardWidth(struct fh_mmc_obj *mmc_obj, int width)
  156. {
  157. switch(width)
  158. {
  159. case MMC_CARD_WIDTH_1BIT:
  160. SET_REG(mmc_obj->base + OFFSET_SDC_CTYPE, 0);
  161. break;
  162. case MMC_CARD_WIDTH_4BIT:
  163. SET_REG(mmc_obj->base + OFFSET_SDC_CTYPE, 1);
  164. break;
  165. default:
  166. rt_kprintf("ERROR: %s, card width %d is not supported\n", __func__, width);
  167. return -RT_ERROR;
  168. break;
  169. }
  170. return 0;
  171. }
  172. int MMC_SendCommand(struct fh_mmc_obj *mmc_obj, rt_uint32_t cmd, rt_uint32_t arg, rt_uint32_t flags)
  173. {
  174. rt_uint32_t reg, tick, timeout;
  175. tick = rt_tick_get();
  176. timeout = tick + RT_TICK_PER_SECOND; //1s
  177. SET_REG(mmc_obj->base + OFFSET_SDC_CMDARG, arg);
  178. flags |= 1<<31 | 1<<29 | cmd;
  179. SET_REG(mmc_obj->base + OFFSET_SDC_CMD, flags);
  180. while(GET_REG(mmc_obj->base + OFFSET_SDC_CMD) & MMC_CMD_START_CMD)
  181. {
  182. tick = rt_tick_get();
  183. if(tick > timeout)
  184. {
  185. rt_kprintf("ERROR: %s, send cmd timeout\n", __func__);
  186. return -RT_ETIMEOUT;
  187. }
  188. }
  189. //fixme: check HLE_INT_STATUS
  190. return 0;
  191. }
  192. int MMC_ResetFifo(struct fh_mmc_obj *mmc_obj)
  193. {
  194. rt_uint32_t reg, tick, timeout;
  195. tick = rt_tick_get();
  196. timeout = tick + RT_TICK_PER_SECOND / 10; //100ms
  197. reg = GET_REG(mmc_obj->base + OFFSET_SDC_CTRL);
  198. reg |= 1 << 1;
  199. SET_REG(mmc_obj->base + OFFSET_SDC_CTRL, reg);
  200. //wait until fifo reset finish
  201. while(GET_REG(mmc_obj->base + OFFSET_SDC_CTRL) & MMC_CTRL_FIFO_RESET)
  202. {
  203. tick = rt_tick_get();
  204. if(tick > timeout)
  205. {
  206. rt_kprintf("ERROR: %s, FIFO reset timeout\n", __func__);
  207. return -RT_ETIMEOUT;
  208. }
  209. }
  210. return 0;
  211. }
  212. int MMC_Reset(struct fh_mmc_obj *mmc_obj)
  213. {
  214. rt_uint32_t reg, tick, timeout;
  215. tick = rt_tick_get();
  216. timeout = tick + RT_TICK_PER_SECOND / 10; //100ms
  217. reg = GET_REG(mmc_obj->base + OFFSET_SDC_BMOD);
  218. reg |= MMC_BMOD_RESET;
  219. SET_REG(mmc_obj->base + OFFSET_SDC_BMOD, reg);
  220. while(GET_REG(mmc_obj->base + OFFSET_SDC_BMOD) & MMC_BMOD_RESET)
  221. {
  222. tick = rt_tick_get();
  223. if(tick > timeout)
  224. {
  225. rt_kprintf("ERROR: %s, BMOD Software reset timeout\n", __func__);
  226. return -RT_ETIMEOUT;
  227. }
  228. }
  229. reg = GET_REG(mmc_obj->base + OFFSET_SDC_CTRL);
  230. reg |= MMC_CTRL_CONTROLLER_RESET | MMC_CTRL_FIFO_RESET | MMC_CTRL_DMA_RESET;
  231. SET_REG(mmc_obj->base + OFFSET_SDC_CTRL, reg);
  232. tick = rt_tick_get();
  233. timeout = tick + RT_TICK_PER_SECOND / 10; //100ms
  234. while(GET_REG(mmc_obj->base + OFFSET_SDC_CTRL) & (MMC_CTRL_CONTROLLER_RESET | MMC_CTRL_FIFO_RESET | MMC_CTRL_DMA_RESET))
  235. {
  236. tick = rt_tick_get();
  237. if(tick > timeout)
  238. {
  239. rt_kprintf("ERROR: %s, CTRL dma|fifo|ctrl reset timeout\n", __func__);
  240. return -RT_ETIMEOUT;
  241. }
  242. }
  243. return 0;
  244. }
  245. void MMC_Init(struct fh_mmc_obj *mmc_obj)
  246. {
  247. rt_uint32_t reg;
  248. if(mmc_obj->mmc_reset)
  249. mmc_obj->mmc_reset(mmc_obj);
  250. MMC_Reset(mmc_obj);
  251. //fixed burst
  252. reg = GET_REG(mmc_obj->base + OFFSET_SDC_BMOD);
  253. reg |= 1 << 1;
  254. SET_REG(mmc_obj->base + OFFSET_SDC_BMOD, reg);
  255. //fixme: power on ? ctrl by gpio ?
  256. MMC_ClearRawInterrupt(mmc_obj, MMC_INT_STATUS_ALL);
  257. MMC_SetInterruptMask(mmc_obj, 0x0);
  258. //fixme: use_internal_dma
  259. reg = GET_REG(mmc_obj->base + OFFSET_SDC_CTRL);
  260. reg |= MMC_CTRL_INT_ENABLE;
  261. #ifdef MMC_USE_DMA
  262. reg |= MMC_CTRL_USE_DMA;
  263. #endif
  264. SET_REG(mmc_obj->base + OFFSET_SDC_CTRL, reg);
  265. //set timeout param
  266. SET_REG(mmc_obj->base + OFFSET_SDC_TMOUT, 0xffffffff);
  267. //set fifo
  268. reg = GET_REG(mmc_obj->base + OFFSET_SDC_FIFOTH);
  269. reg = (reg >> 16) & 0x7ff;
  270. reg = ((0x2 << 28) | ((reg/2) << 16) | ((reg/2 + 1) << 0));
  271. SET_REG(mmc_obj->base + OFFSET_SDC_FIFOTH, reg);
  272. }