fsdio.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. /*
  2. * Copyright : (C) 2022 Phytium Information Technology, Inc.
  3. * All Rights Reserved.
  4. *
  5. * This program is OPEN SOURCE software: you can redistribute it and/or modify it
  6. * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
  7. * either version 1.0 of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
  10. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. * See the Phytium Public License for more details.
  12. *
  13. *
  14. * FilePath: fsdio.c
  15. * Date: 2022-05-26 16:27:54
  16. * LastEditTime: 2022-05-26 16:27:54
  17. * Description:  This files is for SDIO user function implementation
  18. *
  19. * Modify History:
  20. * Ver   Who        Date         Changes
  21. * ----- ------     --------    --------------------------------------
  22. * 1.0 zhugengyu 2021/12/2 init
  23. * 1.1 zhugengyu 2022/6/6 modify according to tech manual.
  24. */
  25. /***************************** Include Files *********************************/
  26. #include "fio.h"
  27. #include "fdebug.h"
  28. #include "fassert.h"
  29. #include "ftypes.h"
  30. #include "fsleep.h"
  31. #include "fcache.h"
  32. #include "fsdio_hw.h"
  33. #include "fsdio.h"
  34. /************************** Constant Definitions *****************************/
  35. /**************************** Type Definitions *******************************/
  36. /***************** Macros (Inline Functions) Definitions *********************/
  37. #define FSDIO_DEBUG_TAG "FSDIO"
  38. #define FSDIO_ERROR(format, ...) FT_DEBUG_PRINT_E(FSDIO_DEBUG_TAG, format, ##__VA_ARGS__)
  39. #define FSDIO_WARN(format, ...) FT_DEBUG_PRINT_W(FSDIO_DEBUG_TAG, format, ##__VA_ARGS__)
  40. #define FSDIO_INFO(format, ...) FT_DEBUG_PRINT_I(FSDIO_DEBUG_TAG, format, ##__VA_ARGS__)
  41. #define FSDIO_DEBUG(format, ...) FT_DEBUG_PRINT_D(FSDIO_DEBUG_TAG, format, ##__VA_ARGS__)
  42. /************************** Function Prototypes ******************************/
  43. static FError FSdioReset(FSdio *const instance_p);
  44. static FError FSdioUpdateExternalClk(uintptr base_addr, u32 uhs_reg_val);
  45. /*****************************************************************************/
  46. /**
  47. * @name: FSdioCfgInitialize
  48. * @msg: initialization SDIO controller instance
  49. * @return {FError} FSDIO_SUCCESS if initialization success, otherwise failed
  50. * @param {FSdio} *instance_p, SDIO controller instance
  51. * @param {FSdioConfig} *input_config_p, SDIO controller configure
  52. * @note get into card-detect mode after initialization, bus width = 1, card freq = 400kHz
  53. */
  54. FError FSdioCfgInitialize(FSdio *const instance_p, const FSdioConfig *input_config_p)
  55. {
  56. FASSERT(instance_p && input_config_p);
  57. FError ret = FSDIO_SUCCESS;
  58. if (FT_COMPONENT_IS_READY == instance_p->is_ready)
  59. {
  60. FSDIO_WARN("device is already initialized!!!");
  61. }
  62. if (&instance_p->config != input_config_p)
  63. instance_p->config = *input_config_p;
  64. ret = FSdioReset(instance_p); /* reset the device */
  65. if (FSDIO_SUCCESS == ret)
  66. {
  67. instance_p->is_ready = FT_COMPONENT_IS_READY;
  68. FSDIO_INFO("device initialize success !!!");
  69. }
  70. return ret;
  71. }
  72. /**
  73. * @name: FSdioDeInitialize
  74. * @msg: deinitialization SDIO controller instance
  75. * @return {NONE}
  76. * @param {FSdio} *instance_p, SDIO controller instance
  77. */
  78. void FSdioDeInitialize(FSdio *const instance_p)
  79. {
  80. FASSERT(instance_p);
  81. uintptr base_addr = instance_p->config.base_addr;
  82. FSdioSetInterruptMask(instance_p, FSDIO_GENERAL_INTR, FSDIO_INT_ALL_BITS, FALSE); /* 关闭控制器中断位 */
  83. FSdioSetInterruptMask(instance_p, FSDIO_IDMA_INTR, FSDIO_DMAC_INT_ENA_ALL, FALSE); /* 关闭DMA中断位 */
  84. FSdioClearRawStatus(base_addr); /* 清除中断状态 */
  85. FSdioClearDMAStatus(base_addr);
  86. FSdioSetPower(base_addr, FALSE); /* 关闭电源 */
  87. FSdioSetClock(base_addr, FALSE); /* 关闭卡时钟 */
  88. FSDIO_CLR_BIT(base_addr, FSDIO_UHS_REG_EXT_OFFSET, FSDIO_UHS_EXT_CLK_ENA); /* 关闭外部时钟 */
  89. FSDIO_CLR_BIT(base_addr, FSDIO_UHS_REG_OFFSET, FSDIO_UHS_REG_VOLT_180); /* 恢复为3.3v默认电压 */
  90. instance_p->is_ready = 0;
  91. }
  92. /**
  93. * @name: FSdioSetClkFreq
  94. * @msg: Set the Card clock freqency
  95. * @return {None}
  96. * @param {FSdio} *instance_p, SDIO controller instance
  97. * @param {u32} input_clk_hz, Card clock freqency in Hz
  98. */
  99. FError FSdioSetClkFreq(FSdio *const instance_p, u32 input_clk_hz)
  100. {
  101. FASSERT(instance_p);
  102. uintptr base_addr = instance_p->config.base_addr;
  103. u32 reg_val;
  104. u32 div = 0xff, drv = 0, sample = 0;
  105. u32 first_uhs_div, tmp_ext_reg, div_reg;
  106. FError ret = FSDIO_SUCCESS;
  107. FSDIO_INFO("set clk as %ld", input_clk_hz);
  108. /* must set 2nd stage clcok first then set 1st stage clock */
  109. /* experimental uhs setting --> 2nd stage clock, below setting parameters get from
  110. experiment, for better sample timing */
  111. if (input_clk_hz >= FSDIO_SD_25_MHZ) /* e.g. 25MHz or 50MHz */
  112. {
  113. tmp_ext_reg = FSDIO_UHS_REG(0U, 0U, 0x2U) | FSDIO_UHS_EXT_CLK_ENA;
  114. FASSERT(tmp_ext_reg == 0x202);
  115. }
  116. else if (input_clk_hz == FSDIO_SD_400KHZ) /* 400kHz */
  117. {
  118. tmp_ext_reg = FSDIO_UHS_REG(0U, 0U, 0x5U) | FSDIO_UHS_EXT_CLK_ENA;
  119. FASSERT(tmp_ext_reg == 0x502);
  120. }
  121. else /* e.g. 20MHz */
  122. {
  123. tmp_ext_reg = FSDIO_UHS_REG(0U, 0U, 0x3U) | FSDIO_UHS_EXT_CLK_ENA;
  124. FASSERT(tmp_ext_reg == 0x302);
  125. }
  126. /* update uhs setting */
  127. ret = FSdioUpdateExternalClk(base_addr, tmp_ext_reg);
  128. if (FSDIO_SUCCESS != ret)
  129. return ret;
  130. FSdioSetClock(base_addr, FALSE); /* disable clock */
  131. /* send private cmd to update clock */
  132. ret = FSdioSendPrivateCmd(base_addr, FSDIO_CMD_UPD_CLK, 0U);
  133. if (FSDIO_SUCCESS != ret)
  134. return ret;
  135. /* experimental clk divide setting -- 1st stage clock */
  136. first_uhs_div = 1 + FSDIO_UHS_CLK_DIV_GET(tmp_ext_reg);
  137. div = FSDIO_CLK_RATE_HZ / (2 * first_uhs_div * input_clk_hz);
  138. if (div > 2)
  139. {
  140. sample = div / 2 + 1;
  141. drv = sample - 1;
  142. }
  143. else if (div == 2)
  144. {
  145. drv = 0;
  146. sample = 1;
  147. }
  148. div_reg = FSDIO_CLK_DIV(sample, drv, div);
  149. FSDIO_WRITE_REG(base_addr, FSDIO_CLKDIV_OFFSET, div_reg);
  150. FSDIO_INFO("UHS_REG_EXT: %x, CLKDIV: %x",
  151. FSDIO_READ_REG(base_addr, FSDIO_UHS_REG_EXT_OFFSET),
  152. FSDIO_READ_REG(base_addr, FSDIO_CLKDIV_OFFSET));
  153. FSDIO_INFO("UHS_REG_EXT ext: 0x%x, CLKDIV: 0x%x",
  154. FSDIO_READ_REG(base_addr, FSDIO_UHS_REG_EXT_OFFSET),
  155. FSDIO_READ_REG(base_addr, FSDIO_CLKDIV_OFFSET));
  156. FSdioSetClock(base_addr, TRUE); /* enable clock */
  157. /* update clock for 1 stage clock */
  158. ret = FSdioSendPrivateCmd(base_addr, FSDIO_CMD_UPD_CLK, 0U);
  159. if (FSDIO_SUCCESS != ret)
  160. return ret;
  161. return ret;
  162. }
  163. /**
  164. * @name: FSdioWaitClkReady
  165. * @msg: Wait clock ready after modify clock setting
  166. * @return {FError} FSDIO_SUCCESS if wait success, FSDIO_ERR_TIMEOUT if wait timeout
  167. * @param {uintptr} base_addr, base address of SDIO controller
  168. * @param {int} retries, retry times in waiting
  169. */
  170. static FError FSdioWaitClkReady(uintptr base_addr, int retries)
  171. {
  172. FASSERT(retries > 1);
  173. u32 reg_val = 0;
  174. do
  175. {
  176. reg_val = FSDIO_READ_REG(base_addr, FSDIO_GPIO_OFFSET);
  177. }
  178. while (!(reg_val & FSDIO_CLK_READY) && (retries-- > 0));
  179. if (!(reg_val & FSDIO_CLK_READY) && (retries <= 0))
  180. {
  181. FSDIO_ERROR("wait clk ready timeout !!! status: 0x%x",
  182. reg_val);
  183. return FSDIO_ERR_TIMEOUT;
  184. }
  185. return FSDIO_SUCCESS;
  186. }
  187. /**
  188. * @name: FSdioUpdateExternalClk
  189. * @msg: update uhs clock value and wait clock ready
  190. * @return {FError}
  191. * @param {uintptr} base_addr
  192. * @param {u32} uhs_reg_val
  193. */
  194. static FError FSdioUpdateExternalClk(uintptr base_addr, u32 uhs_reg_val)
  195. {
  196. u32 reg_val;
  197. int retries = FSDIO_TIMEOUT;
  198. FSDIO_WRITE_REG(base_addr, FSDIO_UHS_REG_EXT_OFFSET, 0U);
  199. FSDIO_WRITE_REG(base_addr, FSDIO_UHS_REG_EXT_OFFSET, uhs_reg_val);
  200. do
  201. {
  202. reg_val = FSDIO_READ_REG(base_addr, FSDIO_GPIO_OFFSET);
  203. if (--retries <= 0)
  204. break;
  205. }
  206. while (!(reg_val & FSDIO_CLK_READY));
  207. return (retries <= 0) ? FSDIO_ERR_TIMEOUT : FSDIO_SUCCESS;
  208. }
  209. /**
  210. * @name: FSdioResetCtrl
  211. * @msg: Reset fifo/DMA in cntrl register
  212. * @return {FError} FSDIO_SUCCESS if reset success
  213. * @param {uintptr} base_addr, base address of SDIO controller
  214. * @param {u32} reset_bits, bits to be reset
  215. */
  216. FError FSdioResetCtrl(uintptr base_addr, u32 reset_bits)
  217. {
  218. u32 reg_val;
  219. int retries = FSDIO_TIMEOUT;
  220. FSDIO_SET_BIT(base_addr, FSDIO_CNTRL_OFFSET, reset_bits);
  221. do
  222. {
  223. reg_val = FSDIO_READ_REG(base_addr, FSDIO_CNTRL_OFFSET);
  224. if (--retries <= 0)
  225. break;
  226. }
  227. while (reset_bits & reg_val);
  228. if (retries <= 0)
  229. return FSDIO_ERR_TIMEOUT;
  230. return FSDIO_SUCCESS;
  231. }
  232. /**
  233. * @name: FSdioResetBusyCard
  234. * @msg: reset controller from card busy state
  235. * @return {FError} FSDIO_SUCCESS if reset success
  236. * @param {uintptr} base_addr, base address of controller
  237. */
  238. FError FSdioResetBusyCard(uintptr base_addr)
  239. {
  240. u32 reg_val;
  241. int retries = FSDIO_TIMEOUT;
  242. FSDIO_SET_BIT(base_addr, FSDIO_CNTRL_OFFSET, FSDIO_CNTRL_CONTROLLER_RESET);
  243. do
  244. {
  245. FSDIO_SET_BIT(base_addr, FSDIO_CNTRL_OFFSET, FSDIO_CNTRL_CONTROLLER_RESET);
  246. reg_val = FSDIO_READ_REG(base_addr, FSDIO_STATUS_OFFSET);
  247. if (--retries <= 0)
  248. break;
  249. }
  250. while (reg_val & FSDIO_STATUS_DATA_BUSY);
  251. return (retries <= 0) ? FSDIO_ERR_BUSY : FSDIO_SUCCESS;
  252. }
  253. /**
  254. * @name: FSdioRestartClk
  255. * @msg: restart controller clock from error status
  256. * @return {FError} FSDIO_SUCCESS if reset success
  257. * @param {uintptr} base_addr, base address of controller
  258. */
  259. FError FSdioRestartClk(uintptr base_addr)
  260. {
  261. u32 clk_div, uhs;
  262. int retries = FSDIO_TIMEOUT;
  263. u32 reg_val;
  264. FError ret = FSDIO_SUCCESS;
  265. /* wait command finish if previous command is in error state */
  266. do
  267. {
  268. reg_val = FSDIO_READ_REG(base_addr, FSDIO_CMD_OFFSET);
  269. if (--retries <= 0)
  270. break;
  271. }
  272. while (reg_val & FSDIO_CMD_START);
  273. if (retries <= 0)
  274. return FSDIO_ERR_TIMEOUT;
  275. /* update clock */
  276. FSdioSetClock(base_addr, FALSE);
  277. clk_div = FSDIO_READ_REG(base_addr, FSDIO_CLKDIV_OFFSET);
  278. uhs = FSDIO_READ_REG(base_addr, FSDIO_UHS_REG_EXT_OFFSET);
  279. ret = FSdioUpdateExternalClk(base_addr, uhs);
  280. if (FSDIO_SUCCESS != ret)
  281. return ret;
  282. FSDIO_WRITE_REG(base_addr, FSDIO_CLKDIV_OFFSET, clk_div);
  283. FSdioSetClock(base_addr, TRUE);
  284. ret = FSdioSendPrivateCmd(base_addr, FSDIO_CMD_UPD_CLK, 0U);
  285. return ret;
  286. }
  287. /**
  288. * @name: FSdioReset
  289. * @msg: Reset SDIO controller instance
  290. * @return {FError} FSDIO_SUCCESS if reset success
  291. * @param {FSdio} *instance_p, SDIO controller instance
  292. */
  293. static FError FSdioReset(FSdio *const instance_p)
  294. {
  295. FASSERT(instance_p);
  296. uintptr base_addr = instance_p->config.base_addr;
  297. u32 reg_val;
  298. FError ret = FSDIO_SUCCESS;
  299. /* set creg_nand_mmcsd DMA path */
  300. FSDIO_INFO("Prev LSD CFG: 0x%x", FtIn32(FLSD_CONFIG_BASE + FLSD_NAND_MMCSD_HADDR));
  301. FtOut32(FLSD_CONFIG_BASE + FLSD_NAND_MMCSD_HADDR, 0x0U);
  302. FSDIO_INFO("Curr LSD CFG: 0x%x", FtIn32(FLSD_CONFIG_BASE + FLSD_NAND_MMCSD_HADDR));
  303. /* set fifo */
  304. reg_val = FSDIO_FIFOTH(FSDIO_FIFOTH_DMA_TRANS_8, FSDIO_RX_WMARK, FSDIO_TX_WMARK);
  305. FSDIO_WRITE_REG(base_addr, FSDIO_FIFOTH_OFFSET, reg_val);
  306. /* set card threshold */
  307. reg_val = FSDIO_CARD_THRCTL_THRESHOLD(FSDIO_FIFO_DEPTH_8) | FSDIO_CARD_THRCTL_CARDRD;
  308. FSDIO_WRITE_REG(base_addr, FSDIO_CARD_THRCTL_OFFSET, reg_val);
  309. /* disable clock and update ext clk */
  310. FSdioSetClock(base_addr, FALSE);
  311. /* set 1st clock */
  312. reg_val = FSDIO_UHS_REG(0U, 0U, 0x5U) | FSDIO_UHS_EXT_CLK_ENA;
  313. FASSERT_MSG(0x502 == reg_val, "invalid uhs config");
  314. ret = FSdioUpdateExternalClk(base_addr, reg_val);
  315. if (FSDIO_SUCCESS != ret)
  316. {
  317. FSDIO_ERROR("update extern clock failed !!!");
  318. return ret;
  319. }
  320. /* power on */
  321. FSdioSetPower(base_addr, TRUE);
  322. FSdioSetClock(base_addr, TRUE);
  323. FSdioSetExtClock(base_addr, TRUE);
  324. /* set voltage as 3.3v */
  325. if (FSDIO_SD_1_8V_VOLTAGE == instance_p->config.voltage)
  326. FSdioSetVoltage1_8V(base_addr, TRUE);
  327. else
  328. FSdioSetVoltage1_8V(base_addr, FALSE);
  329. /* reset controller and card */
  330. ret = FSdioResetCtrl(base_addr, FSDIO_CNTRL_FIFO_RESET | FSDIO_CNTRL_DMA_RESET);
  331. if (FSDIO_SUCCESS != ret)
  332. {
  333. FSDIO_ERROR("reset controller failed !!!");
  334. return ret;
  335. }
  336. /* send private command to update clock */
  337. ret = FSdioSendPrivateCmd(base_addr, FSDIO_CMD_UPD_CLK, 0U);
  338. if (FSDIO_SUCCESS != ret)
  339. {
  340. FSDIO_ERROR("update clock failed !!!");
  341. return ret;
  342. }
  343. /* reset card for no-removeable media, e.g. eMMC */
  344. if (TRUE == instance_p->config.non_removable)
  345. FSDIO_SET_BIT(base_addr, FSDIO_CARD_RESET_OFFSET, FSDIO_CARD_RESET_ENABLE);
  346. else
  347. FSDIO_CLR_BIT(base_addr, FSDIO_CARD_RESET_OFFSET, FSDIO_CARD_RESET_ENABLE);
  348. /* clear interrupt status */
  349. FSDIO_WRITE_REG(base_addr, FSDIO_INT_MASK_OFFSET, 0U);
  350. reg_val = FSDIO_READ_REG(base_addr, FSDIO_RAW_INTS_OFFSET);
  351. FSDIO_WRITE_REG(base_addr, FSDIO_RAW_INTS_OFFSET, reg_val);
  352. FSDIO_WRITE_REG(base_addr, FSDIO_DMAC_INT_EN_OFFSET, 0U);
  353. reg_val = FSDIO_READ_REG(base_addr, FSDIO_DMAC_STATUS_OFFSET);
  354. FSDIO_WRITE_REG(base_addr, FSDIO_DMAC_STATUS_OFFSET, reg_val);
  355. /* enable card detect interrupt */
  356. if (FALSE == instance_p->config.non_removable)
  357. FSDIO_SET_BIT(base_addr, FSDIO_INT_MASK_OFFSET, FSDIO_INT_CD_BIT);
  358. /* enable controller and internal DMA */
  359. FSDIO_SET_BIT(base_addr, FSDIO_CNTRL_OFFSET, FSDIO_CNTRL_INT_ENABLE | FSDIO_CNTRL_USE_INTERNAL_DMAC);
  360. /* set data and resp timeout */
  361. FSDIO_WRITE_REG(base_addr, FSDIO_TMOUT_OFFSET,
  362. FSDIO_TIMEOUT_DATA(FSDIO_MAX_DATA_TIMEOUT, FSDIO_MAX_RESP_TIMEOUT));
  363. /* reset descriptors and dma */
  364. FSdioSetDescriptor(base_addr, (uintptr)NULL); /* set decriptor list as NULL */
  365. FSdioResetIDMA(base_addr);
  366. FSDIO_INFO("init hardware done !!!");
  367. return ret;
  368. }
  369. /**
  370. * @name: FSdioRestart
  371. * @msg: reset controller from error state
  372. * @return {FError} FSDIO_SUCCESS if restart success
  373. * @param {FSdio} *instance_p, instance of controller
  374. */
  375. FError FSdioRestart(FSdio *const instance_p)
  376. {
  377. FASSERT(instance_p);
  378. uintptr base_addr = instance_p->config.base_addr;
  379. u32 reg_val;
  380. FError ret = FSDIO_SUCCESS;
  381. if (FT_COMPONENT_IS_READY != instance_p->is_ready)
  382. {
  383. FSDIO_ERROR("device is not yet initialized!!!");
  384. return FSDIO_ERR_NOT_INIT;
  385. }
  386. /* reset controller */
  387. ret = FSdioResetCtrl(base_addr, FSDIO_CNTRL_FIFO_RESET);
  388. if (FSDIO_SUCCESS != ret)
  389. return ret;
  390. /* reset controller if in busy state */
  391. ret = FSdioResetBusyCard(base_addr);
  392. if (FSDIO_SUCCESS != ret)
  393. return ret;
  394. /* reset clock */
  395. ret = FSdioRestartClk(base_addr);
  396. if (FSDIO_SUCCESS != ret)
  397. return ret;
  398. /* reset internal DMA */
  399. FSdioResetIDMA(base_addr);
  400. return ret;
  401. }