drv_sdio.c 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066
  1. /*
  2. * Copyright (C) 2022-2024, Xiaohua Semiconductor Co., Ltd.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-02-14 CDT first version
  9. */
  10. /*******************************************************************************
  11. * Include files
  12. ******************************************************************************/
  13. #include <rtthread.h>
  14. #include <rtdevice.h>
  15. #if defined(RT_USING_SDIO)
  16. #if defined(BSP_USING_SDIO1) || defined(BSP_USING_SDIO2)
  17. #include "drv_sdio.h"
  18. #include "board_config.h"
  19. /*******************************************************************************
  20. * Local type definitions ('typedef')
  21. ******************************************************************************/
  22. /* rthw sdio */
  23. struct rthw_sdio
  24. {
  25. struct rt_mmcsd_host *host;
  26. struct hc32_sdio_config *config;
  27. struct hc32_sdio_des des;
  28. struct rt_event event;
  29. struct rt_mutex mutex;
  30. struct sdio_pkg *pkg;
  31. uint8_t *cache_buf;
  32. };
  33. /*******************************************************************************
  34. * Local pre-processor symbols/macros ('#define')
  35. ******************************************************************************/
  36. //#define DRV_DEBUG
  37. #define LOG_TAG "drv.sdio"
  38. #include <drv_log.h>
  39. #ifndef SDIO_BUFF_SIZE
  40. #define SDIO_BUFF_SIZE (4096)
  41. #endif
  42. #ifndef SDIO_ALIGN_LEN
  43. #define SDIO_ALIGN_LEN (4)
  44. #endif
  45. #ifndef SDIO_MAX_FREQ
  46. #define SDIO_MAX_FREQ (50*1000*1000)
  47. #endif
  48. #define RTHW_SDIO_LOCK(_sdio) rt_mutex_take(&(_sdio)->mutex, RT_WAITING_FOREVER)
  49. #define RTHW_SDIO_UNLOCK(_sdio) rt_mutex_release(&(_sdio)->mutex);
  50. /*******************************************************************************
  51. * Global variable definitions (declared in header file with 'extern')
  52. ******************************************************************************/
  53. extern rt_err_t rt_hw_board_sdio_init(CM_SDIOC_TypeDef *SDIOCx);
  54. /*******************************************************************************
  55. * Local function prototypes ('static')
  56. ******************************************************************************/
  57. #ifdef BSP_USING_SDIO1
  58. static void _sdio1_handler(void);
  59. #endif
  60. #ifdef BSP_USING_SDIO2
  61. static void _sdio2_handler(void);
  62. #endif
  63. /*******************************************************************************
  64. * Local variable definitions ('static')
  65. ******************************************************************************/
  66. enum
  67. {
  68. #ifdef BSP_USING_SDIO1
  69. SDIO1_INDEX,
  70. #endif
  71. #ifdef BSP_USING_SDIO2
  72. SDIO2_INDEX,
  73. #endif
  74. };
  75. static struct hc32_sdio_config _sdio_config[] =
  76. {
  77. #ifdef BSP_USING_SDIO1
  78. SDIO1_BUS_CONFIG,
  79. #endif /* BSP_USING_SDIO1 */
  80. #ifdef BSP_USING_SDIO2
  81. SDIO2_BUS_CONFIG,
  82. #endif /* BSP_USING_SDIO2 */
  83. };
  84. static const func_ptr_t _sdio_irq_handler[] =
  85. {
  86. #ifdef BSP_USING_SDIO1
  87. _sdio1_handler,
  88. #endif /* BSP_USING_SDIO1 */
  89. #ifdef BSP_USING_SDIO2
  90. _sdio2_handler,
  91. #endif /* BSP_USING_SDIO2 */
  92. };
  93. #ifdef BSP_USING_SDIO1
  94. rt_align(SDIO_ALIGN_LEN)
  95. static rt_uint8_t _sdio1_cache_buf[SDIO_BUFF_SIZE];
  96. #endif
  97. #ifdef BSP_USING_SDIO2
  98. rt_align(SDIO_ALIGN_LEN)
  99. static rt_uint8_t _sdio2_cache_buf[SDIO_BUFF_SIZE];
  100. #endif
  101. static rt_uint8_t *const _sdio_cache_buf[] =
  102. {
  103. #ifdef BSP_USING_SDIO1
  104. _sdio1_cache_buf,
  105. #endif /* BSP_USING_SDIO1 */
  106. #ifdef BSP_USING_SDIO2
  107. _sdio2_cache_buf,
  108. #endif /* BSP_USING_SDIO2 */
  109. };
  110. static struct rt_mmcsd_host *_sdio_host[sizeof(_sdio_config) / sizeof(_sdio_config[0])] = {0};
  111. /*******************************************************************************
  112. * Function implementation - global ('extern') and local ('static')
  113. ******************************************************************************/
  114. /**
  115. * @brief Get the response type of hc32 sdioc driver.
  116. * @param [in] rt_resp_type SDIO command response type defined in mmcs_core.h
  117. * @retval The response type of hc32 sdioc driver
  118. */
  119. static rt_uint32_t _sdio_get_cmd_resptype(rt_uint32_t rt_resptype)
  120. {
  121. rt_uint32_t sdioc_resptype;
  122. switch (rt_resptype)
  123. {
  124. case RESP_NONE:
  125. sdioc_resptype = SDIOC_RESP_TYPE_NO;
  126. break;
  127. case RESP_R1:
  128. sdioc_resptype = SDIOC_RESP_TYPE_R1_R5_R6_R7;
  129. break;
  130. case RESP_R2:
  131. sdioc_resptype = SDIOC_RESP_TYPE_R2;
  132. break;
  133. case RESP_R3:
  134. case RESP_R4:
  135. sdioc_resptype = SDIOC_RESP_TYPE_R3_R4;
  136. break;
  137. case RESP_R5:
  138. case RESP_R6:
  139. case RESP_R7:
  140. sdioc_resptype = SDIOC_RESP_TYPE_R1_R5_R6_R7;
  141. break;
  142. case RESP_R1B:
  143. sdioc_resptype = SDIOC_RESP_TYPE_R1B_R5B;
  144. break;
  145. default:
  146. sdioc_resptype = SDIOC_RESP_TYPE_NO;
  147. LOG_E("unknown response type: %d", rt_resptype);
  148. break;
  149. }
  150. return sdioc_resptype;
  151. }
  152. /**
  153. * @brief This function wait sdio completed.
  154. * @param [in] sdio Pointer to a @ref rthw_sdio structure
  155. * @retval None
  156. */
  157. static void _sdio_wait_completed(struct rthw_sdio *sdio)
  158. {
  159. rt_uint32_t status;
  160. rt_uint32_t response[4];
  161. __IO rt_uint32_t to_count;
  162. struct rt_mmcsd_cmd *cmd = sdio->pkg->cmd;
  163. struct rt_mmcsd_data *data = cmd->data;
  164. CM_SDIOC_TypeDef *instance = sdio->config->instance;
  165. if (rt_event_recv(&sdio->event, 0xFFFFFFFF, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
  166. rt_tick_from_millisecond(5000), &status) != RT_EOK)
  167. {
  168. LOG_E("[%s timeout] sta=0x%08X, cmd %d, arg:0x%08X", __func__, status, cmd->cmd_code, cmd->arg);
  169. cmd->err = -RT_ETIMEOUT;
  170. return;
  171. }
  172. if (sdio->pkg == RT_NULL)
  173. {
  174. return;
  175. }
  176. if (resp_type(cmd) == RESP_NONE)
  177. {
  178. ;
  179. }
  180. else if (resp_type(cmd) == RESP_R2)
  181. {
  182. LOG_D("R2");
  183. (void)SDIOC_GetResponse(instance, SDIOC_RESP_REG_BIT0_31, &response[0]);
  184. (void)SDIOC_GetResponse(instance, SDIOC_RESP_REG_BIT32_63, &response[1]);
  185. (void)SDIOC_GetResponse(instance, SDIOC_RESP_REG_BIT64_95, &response[2]);
  186. (void)SDIOC_GetResponse(instance, SDIOC_RESP_REG_BIT96_127, &response[3]);
  187. cmd->resp[0] = (response[3] << 8) + ((response[2] >> 24) & 0xFF);
  188. cmd->resp[1] = (response[2] << 8) + ((response[1] >> 24) & 0xFF);
  189. cmd->resp[2] = (response[1] << 8) + ((response[0] >> 24) & 0xFF);
  190. cmd->resp[3] = (response[0] << 8) + 0x00;
  191. }
  192. else
  193. {
  194. (void)SDIOC_GetResponse(instance, SDIOC_RESP_REG_BIT0_31, &response[0]);
  195. cmd->resp[0] = response[0];
  196. }
  197. if (status & SDIOC_INT_FLAG_EI)
  198. {
  199. if (status & (SDIOC_INT_FLAG_CTOE | SDIOC_INT_FLAG_CCE | SDIOC_INT_FLAG_CEBE | SDIOC_INT_FLAG_CIE))
  200. {
  201. SDIOC_SWReset(instance, SDIOC_SW_RST_CMD_LINE);
  202. cmd->err = -RT_ERROR;
  203. LOG_D("[%s cmd err] sta=0x%08X, %s%s%s%s cmd %d arg:0x%08X",
  204. __func__,
  205. status,
  206. status & SDIOC_INT_FLAG_CCE ? "Command CRC Error " : "",
  207. status & SDIOC_INT_FLAG_CEBE ? "Command End Bit Error" : "",
  208. status & SDIOC_INT_FLAG_CTOE ? "Command Timeout Error" : "",
  209. status == 0 ? "NULL" : "",
  210. cmd->cmd_code,
  211. cmd->arg);
  212. }
  213. if (status & (SDIOC_INT_FLAG_DTOE | SDIOC_INT_FLAG_DCE | SDIOC_INT_FLAG_DEBE))
  214. {
  215. SDIOC_SWReset(instance, SDIOC_SW_RST_DATA_LINE);
  216. if (data != NULL)
  217. {
  218. data->err = -RT_ERROR;
  219. LOG_D("[%s dat err] sta=0x%08X, %s%s%s%s cmd %d arg:0x%08X rw:%c len:%d blksize:%d",
  220. __func__,
  221. status,
  222. status & SDIOC_INT_FLAG_DCE ? "Data CRC Error " : "",
  223. status & SDIOC_INT_FLAG_DEBE ? "Data End Bit Error" : "",
  224. status & SDIOC_INT_FLAG_DTOE ? "Data Timeout Error" : "",
  225. status == 0 ? "NULL" : "",
  226. cmd->cmd_code,
  227. cmd->arg,
  228. data ? (data->flags & DATA_DIR_WRITE ? 'w' : 'r') : '-',
  229. data ? data->blks * data->blksize : 0,
  230. data ? data->blksize : 0);
  231. }
  232. }
  233. }
  234. else
  235. {
  236. cmd->err = RT_EOK;
  237. LOG_D("[%s xfer ok] sta=0x%08X, cmd %d, arg:0x%08X, resp[%08X %08X %08X %08X]",
  238. __func__,
  239. status,
  240. cmd->cmd_code,
  241. cmd->arg,
  242. cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
  243. }
  244. }
  245. /**
  246. * @brief Transfer data by dma.
  247. * @param [in] sdio Pointer to a @ref rthw_sdio structure
  248. * @param [in] pkg Pointer to a @ref sdio_pkg structure
  249. * @retval None
  250. */
  251. static void _sdio_transfer_by_dma(struct rthw_sdio *sdio, struct sdio_pkg *pkg)
  252. {
  253. struct rt_mmcsd_data *data = pkg->cmd->data;
  254. if ((NULL == sdio) || (NULL == pkg) || (NULL == pkg->buf) || (NULL == pkg->cmd) || (NULL == pkg->cmd->data))
  255. {
  256. LOG_E("%s function arguments error: %s %s %s %s %s",
  257. __func__,
  258. (sdio == RT_NULL ? "sdio is NULL" : ""),
  259. (pkg == RT_NULL ? "pkg is NULL" : ""),
  260. (sdio ? (pkg->buf == RT_NULL ? "pkg->buf is NULL" : "") : ""),
  261. (sdio ? (pkg->cmd == RT_NULL ? "pkg->cmd is NULL" : "") : ""),
  262. (sdio ? (pkg->cmd->data == RT_NULL ? "pkg->cmd->data is NULL" : "") : "")
  263. );
  264. return;
  265. }
  266. if (data->flags & DATA_DIR_WRITE)
  267. {
  268. sdio->des.txconfig(sdio->config->dma_tx.Instance, sdio->config->dma_tx.channel, pkg);
  269. DMA_ChCmd(sdio->config->dma_tx.Instance, sdio->config->dma_tx.channel, ENABLE);
  270. }
  271. else if (data->flags & DATA_DIR_READ)
  272. {
  273. sdio->des.rxconfig(sdio->config->dma_rx.Instance, sdio->config->dma_rx.channel, pkg);
  274. DMA_ChCmd(sdio->config->dma_rx.Instance, sdio->config->dma_rx.channel, ENABLE);
  275. }
  276. }
  277. /**
  278. * @brief Send command.
  279. * @param [in] sdio Pointer to a @ref rthw_sdio structure
  280. * @param [in] pkg Pointer to a @ref sdio_pkg structure
  281. * @retval None
  282. */
  283. static void _sdio_send_command(struct rthw_sdio *sdio, struct sdio_pkg *pkg)
  284. {
  285. rt_int32_t ret;
  286. struct rt_mmcsd_cmd *cmd = pkg->cmd;
  287. struct rt_mmcsd_data *data = cmd->data;
  288. CM_SDIOC_TypeDef *instance = sdio->config->instance;
  289. stc_sdioc_cmd_config_t stcCmdConfig;
  290. stc_sdioc_data_config_t stcDataConfig;
  291. /* save pkg */
  292. sdio->pkg = pkg;
  293. LOG_D("CMD:%d ARG:0x%08x RES:%s%s%s%s%s%s%s%s%s rw:%c len:%d blksize:%d",
  294. cmd->cmd_code,
  295. cmd->arg,
  296. resp_type(cmd) == RESP_NONE ? "NONE" : "",
  297. resp_type(cmd) == RESP_R1 ? "R1" : "",
  298. resp_type(cmd) == RESP_R1B ? "R1B" : "",
  299. resp_type(cmd) == RESP_R2 ? "R2" : "",
  300. resp_type(cmd) == RESP_R3 ? "R3" : "",
  301. resp_type(cmd) == RESP_R4 ? "R4" : "",
  302. resp_type(cmd) == RESP_R5 ? "R5" : "",
  303. resp_type(cmd) == RESP_R6 ? "R6" : "",
  304. resp_type(cmd) == RESP_R7 ? "R7" : "",
  305. data ? (data->flags & DATA_DIR_WRITE ? 'w' : 'r') : '-',
  306. data ? data->blks * data->blksize : 0,
  307. data ? data->blksize : 0);
  308. /* config command */
  309. stcCmdConfig.u16CmdIndex = cmd->cmd_code;
  310. /* config command argument */
  311. stcCmdConfig.u32Argument = cmd->arg;
  312. /* config command type */
  313. stcCmdConfig.u16CmdType = SDIOC_CMD_TYPE_NORMAL;
  314. /* config response type */
  315. stcCmdConfig.u16ResponseType = _sdio_get_cmd_resptype(resp_type(cmd));
  316. if (data != RT_NULL)
  317. {
  318. /* config data */
  319. stcDataConfig.u16BlockSize = data->blksize;
  320. stcDataConfig.u16BlockCount = data->blks;
  321. stcDataConfig.u16TransDir = (data->flags & DATA_DIR_READ) ? SDIOC_TRANS_DIR_TO_HOST : SDIOC_TRANS_DIR_TO_CARD;
  322. stcDataConfig.u16AutoCmd12 = SDIOC_AUTO_SEND_CMD12_DISABLE;
  323. stcDataConfig.u16DataTimeout = SDIOC_DATA_TIMEOUT_CLK_2E27;
  324. stcDataConfig.u16TransMode = (data->blks > 1U) ? SDIOC_TRANS_MD_MULTI : SDIOC_TRANS_MD_SINGLE;
  325. ret = SDIOC_ConfigData(instance, &stcDataConfig);
  326. if (ret != 0)
  327. {
  328. LOG_E("configure data error : %d", ret);
  329. }
  330. /* transfer config */
  331. _sdio_transfer_by_dma(sdio, pkg);
  332. stcCmdConfig.u16DataLine = SDIOC_DATA_LINE_ENABLE;;
  333. }
  334. else
  335. {
  336. stcCmdConfig.u16DataLine = SDIOC_DATA_LINE_DISABLE;
  337. }
  338. /* send cmd */
  339. ret = SDIOC_SendCommand(instance, &stcCmdConfig);
  340. if (ret != 0)
  341. {
  342. LOG_E("send command error : %d", ret);
  343. }
  344. /* wait completed */
  345. _sdio_wait_completed(sdio);
  346. /* clear pkg */
  347. sdio->pkg = RT_NULL;
  348. }
  349. /**
  350. * @brief Send sdio request.
  351. * @param [in] host Pointer to a @ref rt_mmcsd_host structure
  352. * @param [in] req Pointer to a @ref rt_mmcsd_req structure
  353. * @retval None
  354. */
  355. static void _sdio_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
  356. {
  357. rt_uint32_t mask;
  358. struct sdio_pkg pkg;
  359. struct rt_mmcsd_data *data;
  360. struct rthw_sdio *sdio = host->private_data;
  361. if ((NULL == host) || (NULL == req) || (NULL == sdio) || (NULL == sdio->config))
  362. {
  363. LOG_E("%s function arguments error: %s %s %s %s",
  364. __func__,
  365. (host == RT_NULL ? "host is NULL" : ""),
  366. (req == RT_NULL ? "req is NULL" : ""),
  367. (sdio == RT_NULL ? "sdio is NULL" : ""),
  368. (sdio ? (sdio->config == RT_NULL ? "sdio->config is NULL" : "") : "")
  369. );
  370. return;
  371. }
  372. RTHW_SDIO_LOCK(sdio);
  373. if (req->cmd != RT_NULL)
  374. {
  375. rt_memset(&pkg, 0, sizeof(pkg));
  376. data = req->cmd->data;
  377. pkg.cmd = req->cmd;
  378. if (SD_SEND_IF_COND == pkg.cmd->cmd_code)
  379. {
  380. mask = (CM_SDIOC1 == sdio->config->instance) ? PERIC_SDIOC_SYCTLREG_SELMMC1 : PERIC_SDIOC_SYCTLREG_SELMMC2;
  381. if (data == RT_NULL)
  382. {
  383. CM_PERIC->SDIOC_SYCTLREG &= ~mask;
  384. }
  385. else
  386. {
  387. CM_PERIC->SDIOC_SYCTLREG |= mask;
  388. }
  389. }
  390. if (data != RT_NULL)
  391. {
  392. rt_uint32_t size = data->blks * data->blksize;
  393. RT_ASSERT(size <= SDIO_BUFF_SIZE);
  394. /* buffer unaligned */
  395. if ((rt_uint32_t)data->buf & (SDIO_ALIGN_LEN - 1))
  396. {
  397. if (data->flags & DATA_DIR_WRITE)
  398. {
  399. rt_memcpy(sdio->cache_buf, data->buf, size);
  400. }
  401. pkg.buf = sdio->cache_buf;
  402. }
  403. else
  404. {
  405. pkg.buf = data->buf;
  406. }
  407. }
  408. _sdio_send_command(sdio, &pkg);
  409. if ((data != RT_NULL) && (data->flags & DATA_DIR_READ) && ((rt_uint32_t)data->buf & (SDIO_ALIGN_LEN - 1)))
  410. {
  411. rt_memcpy(data->buf, sdio->cache_buf, data->blksize * data->blks);
  412. }
  413. }
  414. if (req->stop != RT_NULL)
  415. {
  416. rt_memset(&pkg, 0, sizeof(pkg));
  417. pkg.cmd = req->stop;
  418. _sdio_send_command(sdio, &pkg);
  419. }
  420. RTHW_SDIO_UNLOCK(sdio);
  421. mmcsd_req_complete(sdio->host);
  422. }
  423. /**
  424. * @brief Config sdio.
  425. * @param [in] host Pointer to a @ref rt_mmcsd_host structure
  426. * @param [in] io_cfg Pointer to a @ref rt_mmcsd_io_cfg structure
  427. * @retval None
  428. */
  429. static void _sdio_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
  430. {
  431. rt_int32_t ret;
  432. rt_uint32_t clk;
  433. rt_uint16_t clk_div;
  434. rt_uint32_t clk_src;
  435. struct rthw_sdio *sdio = host->private_data;
  436. CM_SDIOC_TypeDef *instance;
  437. if ((NULL == host) || (NULL == io_cfg) || (NULL == sdio) || (NULL == sdio->config))
  438. {
  439. LOG_E("%s function arguments error: %s %s %s %s",
  440. __func__,
  441. (host == RT_NULL ? "host is NULL" : ""),
  442. (io_cfg == RT_NULL ? "io_cfg is NULL" : ""),
  443. (sdio == RT_NULL ? "sdio_des is NULL" : ""),
  444. (sdio ? (sdio->config == RT_NULL ? "sdio->config is NULL" : "") : "")
  445. );
  446. return;
  447. }
  448. instance = sdio->config->instance;
  449. clk_src = sdio->des.clk_get(instance);
  450. if (clk_src < 400 * 1000)
  451. {
  452. LOG_E("clock rate is too low! rate:%d", clk_src);
  453. return;
  454. }
  455. clk = io_cfg->clock;
  456. if (clk > host->freq_max)
  457. {
  458. clk = host->freq_max;
  459. }
  460. if (clk > clk_src)
  461. {
  462. LOG_W("setting rate is greater than clock source rate.");
  463. clk = clk_src;
  464. }
  465. LOG_D("clk:%d width:%s%s%s power:%s%s%s",
  466. clk,
  467. io_cfg->bus_width == MMCSD_BUS_WIDTH_8 ? "8" : "",
  468. io_cfg->bus_width == MMCSD_BUS_WIDTH_4 ? "4" : "",
  469. io_cfg->bus_width == MMCSD_BUS_WIDTH_1 ? "1" : "",
  470. io_cfg->power_mode == MMCSD_POWER_OFF ? "OFF" : "",
  471. io_cfg->power_mode == MMCSD_POWER_UP ? "UP" : "",
  472. io_cfg->power_mode == MMCSD_POWER_ON ? "ON" : "");
  473. RTHW_SDIO_LOCK(sdio);
  474. switch (io_cfg->bus_width)
  475. {
  476. case MMCSD_BUS_WIDTH_1:
  477. SDIOC_SetBusWidth(instance, SDIOC_BUS_WIDTH_1BIT);
  478. break;
  479. case MMCSD_BUS_WIDTH_4:
  480. SDIOC_SetBusWidth(instance, SDIOC_BUS_WIDTH_4BIT);
  481. break;
  482. case MMCSD_BUS_WIDTH_8:
  483. SDIOC_SetBusWidth(instance, SDIOC_BUS_WIDTH_8BIT);
  484. break;
  485. default:
  486. LOG_E("unknown bus width: %d", io_cfg->bus_width);
  487. break;
  488. }
  489. switch (io_cfg->power_mode)
  490. {
  491. case MMCSD_POWER_OFF:
  492. SDIOC_PowerCmd(instance, DISABLE);
  493. break;
  494. case MMCSD_POWER_UP:
  495. case MMCSD_POWER_ON:
  496. SDIOC_PowerCmd(instance, ENABLE);
  497. break;
  498. default:
  499. LOG_W("unknown power_mode %d", io_cfg->power_mode);
  500. break;
  501. }
  502. instance->CLKCON = 0;
  503. if (clk > 0)
  504. {
  505. ret = SDIOC_GetOptimumClockDiv(clk, &clk_div);
  506. if (ret != LL_OK)
  507. {
  508. LOG_E("clock division error");
  509. }
  510. else
  511. {
  512. SDIOC_SetClockDiv(instance, clk_div);
  513. if ((clk << 1) <= host->freq_max)
  514. {
  515. SDIOC_SetSpeedMode(instance, SDIOC_SPEED_MD_NORMAL);
  516. }
  517. else
  518. {
  519. SDIOC_SetSpeedMode(instance, SDIOC_SPEED_MD_HIGH);
  520. }
  521. instance->CLKCON = (clk_div | SDIOC_CLKCON_ICE | SDIOC_CLKCON_CE);
  522. }
  523. }
  524. RTHW_SDIO_UNLOCK(sdio);
  525. }
  526. /**
  527. * @brief Update the sdio interrupt.
  528. * @param [in] host Pointer to a @ref rt_mmcsd_host structure
  529. * @param [in] enable Enable interrupt when value is non-zero
  530. * @retval None
  531. */
  532. static void _sdio_enable_sdio_irq(struct rt_mmcsd_host *host, rt_int32_t enable)
  533. {
  534. struct rthw_sdio *sdio = host->private_data;
  535. CM_SDIOC_TypeDef *instance = sdio->config->instance;
  536. if (enable)
  537. {
  538. LOG_D("enable sdio interrupt");
  539. SDIOC_IntStatusCmd(instance, SDIOC_INT_CINTSEN, ENABLE);
  540. SDIOC_IntCmd(instance, SDIOC_INT_CINTSEN, ENABLE);
  541. }
  542. else
  543. {
  544. LOG_D("disable sdio interrupt");
  545. SDIOC_IntStatusCmd(instance, SDIOC_INT_CINTSEN, DISABLE);
  546. SDIOC_IntCmd(instance, SDIOC_INT_CINTSEN, DISABLE);
  547. }
  548. }
  549. /**
  550. * @brief update all of the using interrupt.
  551. * @param [in] host Pointer to a @ref rt_mmcsd_host structure
  552. * @param [in] enable Enable interrupt when value is non-zero
  553. * @retval None
  554. */
  555. static void _sdio_update_irq(struct rt_mmcsd_host *host, rt_int32_t enable)
  556. {
  557. struct rthw_sdio *sdio = host->private_data;
  558. CM_SDIOC_TypeDef *instance = sdio->config->instance;
  559. const rt_uint32_t int_type = (SDIOC_INT_CCSEN | SDIOC_INT_TCSEN | SDIOC_ERR_INT_ALL);
  560. if (enable)
  561. {
  562. LOG_D("enable all of the using interrupt");
  563. SDIOC_IntStatusCmd(instance, (int_type | SDIOC_INT_BRRSEN | SDIOC_INT_BWRSEN), ENABLE);
  564. SDIOC_IntCmd(instance, int_type, ENABLE);
  565. }
  566. else
  567. {
  568. LOG_D("disable all of the using interrupt");
  569. SDIOC_IntStatusCmd(instance, (int_type | SDIOC_INT_BRRSEN | SDIOC_INT_BWRSEN), DISABLE);
  570. SDIOC_IntCmd(instance, int_type, DISABLE);
  571. }
  572. }
  573. /**
  574. * @brief Get card status.
  575. * @param [in] host Pointer to a @ref rt_mmcsd_host structure
  576. * @retval rt_int32_t:
  577. * - 0: No card
  578. * - 1: Card inserted
  579. */
  580. static rt_int32_t _sdio_get_card_status(struct rt_mmcsd_host *host)
  581. {
  582. struct rthw_sdio *sdio = host->private_data;
  583. LOG_D("try to detect device");
  584. return (rt_int32_t)SDIOC_GetHostStatus(sdio->config->instance, SDIOC_HOST_FLAG_CIN);
  585. }
  586. static const struct rt_mmcsd_host_ops _mmcsd_host_ops =
  587. {
  588. _sdio_request,
  589. _sdio_iocfg,
  590. _sdio_get_card_status,
  591. _sdio_enable_sdio_irq,
  592. };
  593. /**
  594. * @brief Get SDIO clock source frequency.
  595. * @param [in] SDIOCx Pointer to SDIOC unit instance
  596. * @retval SDIO clock source frequency
  597. */
  598. static rt_uint32_t _sdio_clock_get(CM_SDIOC_TypeDef *SDIOCx)
  599. {
  600. rt_uint32_t clk;
  601. (void)SDIOCx;
  602. #if defined (HC32F4A0) || defined (HC32F4A8)
  603. clk = CLK_GetBusClockFreq(CLK_BUS_PCLK1);
  604. #elif defined (HC32F460)
  605. clk = CLK_GetBusClockFreq(CLK_BUS_EXCLK);
  606. #endif
  607. return clk;
  608. }
  609. /**
  610. * @brief Initialize DMA for SDIO.
  611. * @param [in] config Pointer to hc32_sdio_config structure
  612. * @retval None
  613. */
  614. static void _sdio_dma_init(struct hc32_sdio_config *config)
  615. {
  616. stc_dma_init_t stcDmaInit;
  617. /* Enable DMA and AOS clock */
  618. FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_AOS, ENABLE);
  619. FCG_Fcg0PeriphClockCmd(config->dma_rx.clock, ENABLE);
  620. FCG_Fcg0PeriphClockCmd(config->dma_tx.clock, ENABLE);
  621. /* Initialize DMA config structure */
  622. (void)DMA_StructInit(&stcDmaInit);
  623. stcDmaInit.u32BlockSize = 512UL;
  624. stcDmaInit.u32DataWidth = DMA_DATAWIDTH_32BIT;
  625. /* Configure DMA_RX Transfer */
  626. stcDmaInit.u32SrcAddr = (uint32_t)(&config->instance->BUF0);
  627. stcDmaInit.u32DestAddr = 0UL;
  628. stcDmaInit.u32SrcAddrInc = DMA_SRC_ADDR_FIX;
  629. stcDmaInit.u32DestAddrInc = DMA_DEST_ADDR_INC;
  630. if (LL_OK != DMA_Init(config->dma_rx.Instance, config->dma_rx.channel, &stcDmaInit))
  631. {
  632. LOG_E("DMA_RX initialization fail");
  633. }
  634. AOS_SetTriggerEventSrc(config->dma_rx.trigger_select, config->dma_rx.trigger_event);
  635. /* Configure DMA_TX Transfer */
  636. stcDmaInit.u32SrcAddr = 0UL;
  637. stcDmaInit.u32DestAddr = (uint32_t)(&config->instance->BUF0);
  638. stcDmaInit.u32SrcAddrInc = DMA_SRC_ADDR_INC;
  639. stcDmaInit.u32DestAddrInc = DMA_DEST_ADDR_FIX;
  640. if (LL_OK != DMA_Init(config->dma_tx.Instance, config->dma_tx.channel, &stcDmaInit))
  641. {
  642. LOG_E("DMA_TX initialization fail");
  643. }
  644. AOS_SetTriggerEventSrc(config->dma_tx.trigger_select, config->dma_tx.trigger_event);
  645. /* Enable DMA */
  646. DMA_Cmd(config->dma_rx.Instance, ENABLE);
  647. DMA_Cmd(config->dma_tx.Instance, ENABLE);
  648. }
  649. /**
  650. * @brief Configure DMA for SDIO receiving.
  651. * @param [in] instance Pointer to DMA instance register base
  652. * @param [in] ch DMA channel
  653. * @param [in] pkg Pointer to sdio_pkg structure
  654. * @retval RT_EOK
  655. */
  656. static rt_err_t _sdio_dma_rxconfig(CM_DMA_TypeDef *instance, rt_uint8_t ch, struct sdio_pkg *pkg)
  657. {
  658. struct rt_mmcsd_cmd *cmd = pkg->cmd;
  659. struct rt_mmcsd_data *data = cmd->data;
  660. DMA_ClearTransCompleteStatus(instance, (DMA_INTSTAT1_BTC_0 | DMA_INTSTAT1_TC_0) << ch);
  661. DMA_SetDestAddr(instance, ch, (rt_uint32_t)pkg->buf);
  662. DMA_SetBlockSize(instance, ch, (rt_uint16_t)(data->blksize >> 2));
  663. DMA_SetTransCount(instance, ch, (rt_uint16_t)data->blks);
  664. return RT_EOK;
  665. }
  666. /**
  667. * @brief Configure DMA for SDIO transmitting.
  668. * @param [in] instance Pointer to DMA instance register base
  669. * @param [in] ch DMA channel
  670. * @param [in] pkg Pointer to sdio_pkg structure
  671. * @retval RT_EOK
  672. */
  673. static rt_err_t _sdio_dma_txconfig(CM_DMA_TypeDef *instance, rt_uint8_t ch, struct sdio_pkg *pkg)
  674. {
  675. struct rt_mmcsd_cmd *cmd = pkg->cmd;
  676. struct rt_mmcsd_data *data = cmd->data;
  677. DMA_ClearTransCompleteStatus(instance, (DMA_INTSTAT1_BTC_0 | DMA_INTSTAT1_TC_0) << ch);
  678. DMA_SetSrcAddr(instance, ch, (rt_uint32_t)pkg->buf);
  679. DMA_SetBlockSize(instance, ch, (rt_uint16_t)(data->blksize >> 2));
  680. DMA_SetTransCount(instance, ch, (rt_uint16_t)data->blks);
  681. return RT_EOK;
  682. }
  683. /**
  684. * @brief This function interrupt process function.
  685. * @param [in] host Pointer to rt_mmcsd_host structure
  686. * @retval None
  687. */
  688. static void _sdio_irq_process(struct rt_mmcsd_host *host)
  689. {
  690. int complete = 0;
  691. struct rthw_sdio *sdio = host->private_data;
  692. CM_SDIOC_TypeDef *instance = sdio->config->instance;
  693. rt_uint32_t norint_status = (rt_uint32_t)instance->NORINTST;
  694. rt_uint32_t errint_status = (rt_uint32_t)instance->ERRINTST;
  695. rt_uint32_t status = (errint_status << 16) | norint_status;
  696. LOG_D("[%s] sta=0x%08X, cmd %d, arg=0x%08X", __func__, status, sdio->pkg->cmd->cmd_code, sdio->pkg->cmd->arg);
  697. if (norint_status & (SDIOC_INT_FLAG_CRM | SDIOC_INT_FLAG_CIST))
  698. {
  699. SDIOC_ClearIntStatus(instance, SDIOC_INT_FLAG_CLR_ALL);
  700. /* ready to change */
  701. mmcsd_change(host);
  702. LOG_D("[%s] card insert or remove", __func__);
  703. complete = 1;
  704. }
  705. else
  706. {
  707. if (norint_status & SDIOC_INT_FLAG_EI)
  708. {
  709. SDIOC_ClearIntStatus(instance, SDIOC_INT_FLAG_CLR_ALL);
  710. complete = 1;
  711. LOG_D("[%s] error", __func__);
  712. }
  713. else
  714. {
  715. if (norint_status & SDIOC_INT_FLAG_CC)
  716. {
  717. SDIOC_ClearIntStatus(instance, SDIOC_INT_FLAG_CC);
  718. if (sdio->pkg != RT_NULL)
  719. {
  720. if ((!sdio->pkg->cmd->data) && (resp_type(sdio->pkg->cmd) != RESP_R1B))
  721. {
  722. complete = 1;
  723. }
  724. }
  725. }
  726. if (norint_status & SDIOC_INT_FLAG_TC)
  727. {
  728. SDIOC_ClearIntStatus(instance, SDIOC_INT_FLAG_TC);
  729. complete = 1;
  730. }
  731. }
  732. }
  733. if (norint_status & SDIOC_INT_FLAG_CINT)
  734. {
  735. SDIOC_ClearIntStatus(instance, SDIOC_INT_FLAG_CINT);
  736. sdio_irq_wakeup(host);
  737. }
  738. if (complete)
  739. {
  740. rt_event_send(&sdio->event, status);
  741. LOG_D("[%s] complete", __func__);
  742. }
  743. }
  744. #ifdef BSP_USING_SDIO1
  745. /**
  746. * @brief SDIOC1 irq handler.
  747. * @param None
  748. * @retval None
  749. */
  750. static void _sdio1_handler(void)
  751. {
  752. /* enter interrupt */
  753. rt_interrupt_enter();
  754. /* process all SDIO interrupt sources */
  755. _sdio_irq_process(_sdio_host[0]);
  756. /* leave interrupt */
  757. rt_interrupt_leave();
  758. }
  759. #endif
  760. #ifdef BSP_USING_SDIO2
  761. /**
  762. * @brief SDIOC2 irq handler.
  763. * @param None
  764. * @retval None
  765. */
  766. static void _sdio2_handler(void)
  767. {
  768. /* enter interrupt */
  769. rt_interrupt_enter();
  770. /* process all SDIO interrupt sources */
  771. _sdio_irq_process(_sdio_host[1]);
  772. /* leave interrupt */
  773. rt_interrupt_leave();
  774. }
  775. #endif
  776. /**
  777. * @brief verify bus clock frequency.
  778. * @param [in] config Pointer to hc32_sdio_config structure
  779. * @retval RT_EOK pass to verify
  780. * -RT_ERROR fail to verify
  781. */
  782. static rt_err_t _sdio_verify_bus_clock_frequency(struct hc32_sdio_config *config)
  783. {
  784. rt_err_t ret = RT_EOK;
  785. #if defined (HC32F4A0)
  786. rt_uint32_t pclk1;
  787. rt_uint32_t exlck;
  788. (void)config;
  789. /* ensure bus frequency condition: EXCLK >= PCLK1 */
  790. pclk1 = CLK_GetBusClockFreq(CLK_BUS_PCLK1);
  791. exlck = CLK_GetBusClockFreq(CLK_BUS_EXCLK);
  792. if (exlck < pclk1)
  793. {
  794. LOG_E("bus frequency error: EXCLK < PCLK1. Please meet the bus frequency condition: EXCLK >= PCLK1");
  795. ret = -RT_ERROR;
  796. }
  797. #endif
  798. return ret;
  799. }
  800. /**
  801. * @brief Enable SDIO clock.
  802. * @param [in] config Pointer to hc32_sdio_config structure
  803. * @retval RT_EOK pass to enable SDIO clock
  804. * -RT_ERROR fail to enable SDIO clock
  805. */
  806. static rt_err_t _sdio_clock_enable(struct hc32_sdio_config *config)
  807. {
  808. /* verify bus clock frequency */
  809. if (_sdio_verify_bus_clock_frequency(config) != RT_EOK)
  810. {
  811. LOG_E("[%s] fail to verify bus clock frequency", __func__);
  812. return -RT_ERROR;
  813. }
  814. FCG_Fcg1PeriphClockCmd(config->clock, ENABLE);
  815. return RT_EOK;
  816. }
  817. /**
  818. * @brief Create mmcsd host.
  819. * @param [in] config Pointer to a @ref hc32_sdio_config structure
  820. * @param [in] cache_buf Pointer to cache buffer
  821. * @param [in] sdio_des Pointer to a @ref hc32_sdio_des structure
  822. * @retval rt_mmcsd_host
  823. */
  824. static struct rt_mmcsd_host *_sdio_host_create(struct hc32_sdio_config *config,
  825. uint8_t *cache_buf,
  826. const struct hc32_sdio_des *sdio_des)
  827. {
  828. struct rt_mmcsd_host *host;
  829. struct rthw_sdio *sdio = RT_NULL;
  830. if ((config == RT_NULL) || (cache_buf == RT_NULL) || \
  831. (sdio_des == RT_NULL) || (sdio_des->txconfig == RT_NULL) || (sdio_des->rxconfig == RT_NULL))
  832. {
  833. LOG_E("function arguments error: %s %s %s %s %s",
  834. (config == RT_NULL ? "config is NULL" : ""),
  835. (cache_buf == RT_NULL ? "cache_buf is NULL" : ""),
  836. (sdio_des == RT_NULL ? "sdio_des is NULL" : ""),
  837. (sdio_des ? (sdio_des->txconfig ? "txconfig is NULL" : "") : ""),
  838. (sdio_des ? (sdio_des->rxconfig ? "rxconfig is NULL" : "") : "")
  839. );
  840. return RT_NULL;
  841. }
  842. /* malloc rthw_sdio */
  843. sdio = rt_malloc(sizeof(struct rthw_sdio));
  844. if (sdio == RT_NULL)
  845. {
  846. LOG_E("malloc rthw_sdio fail");
  847. return RT_NULL;
  848. }
  849. rt_memset(sdio, 0, sizeof(struct rthw_sdio));
  850. /* malloc mmcsd_alloc_host */
  851. host = mmcsd_alloc_host();
  852. if (host == RT_NULL)
  853. {
  854. LOG_E("mmcsd_alloc_host fail");
  855. rt_free(sdio);
  856. return RT_NULL;
  857. }
  858. rt_memcpy(&sdio->des, sdio_des, sizeof(struct hc32_sdio_des));
  859. rt_event_init(&sdio->event, "sdio", RT_IPC_FLAG_FIFO);
  860. rt_mutex_init(&sdio->mutex, "sdio", RT_IPC_FLAG_FIFO);
  861. /* set host default attributes */
  862. host->ops = &_mmcsd_host_ops;
  863. host->freq_min = 400 * 1000;
  864. host->freq_max = SDIO_MAX_FREQ;
  865. host->valid_ocr = VDD_32_33 | VDD_33_34;
  866. #ifndef SDIO_USING_1_BIT
  867. host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ;
  868. #else
  869. host->flags = MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ;
  870. #endif
  871. host->max_seg_size = SDIO_BUFF_SIZE;
  872. host->max_dma_segs = 1;
  873. host->max_blk_size = 512;
  874. host->max_blk_count = (SDIO_BUFF_SIZE / host->max_blk_size);
  875. /* link up host, config, cache_buf and sdio */
  876. sdio->host = host;
  877. sdio->config = config;
  878. sdio->cache_buf = cache_buf;
  879. host->private_data = sdio;
  880. /* enable interrupt */
  881. _sdio_update_irq(host, 1);
  882. /* ready to change */
  883. mmcsd_change(host);
  884. return host;
  885. }
  886. int rt_hw_sdio_init(void)
  887. {
  888. struct rt_mmcsd_host *host;
  889. struct hc32_sdio_config *sdio_config;
  890. rt_size_t obj_num = sizeof(_sdio_config) / sizeof(struct hc32_sdio_config);
  891. const struct hc32_sdio_des sdio_des =
  892. {
  893. .clk_get = _sdio_clock_get,
  894. .rxconfig = _sdio_dma_rxconfig,
  895. .txconfig = _sdio_dma_txconfig,
  896. };
  897. for (rt_size_t i = 0; i < obj_num; i++)
  898. {
  899. sdio_config = &_sdio_config[i];
  900. if (_sdio_clock_enable(sdio_config) != RT_EOK)
  901. {
  902. LOG_E("clock enable fail");
  903. return -1;
  904. }
  905. host = _sdio_host_create(sdio_config, _sdio_cache_buf[i], &sdio_des);
  906. if (host == RT_NULL)
  907. {
  908. LOG_E("host create fail");
  909. return -1;
  910. }
  911. else
  912. {
  913. /* link host */
  914. _sdio_host[i] = host;
  915. /* init board pin */
  916. rt_hw_board_sdio_init(sdio_config->instance);
  917. /* init DMA */
  918. _sdio_dma_init(sdio_config);
  919. /* register the irq handler */
  920. hc32_install_irq_handler(&sdio_config->irq_config, _sdio_irq_handler[i], RT_TRUE);
  921. }
  922. }
  923. return RT_EOK;
  924. }
  925. INIT_DEVICE_EXPORT(rt_hw_sdio_init);
  926. #endif /* BSP_USING_SDIO */
  927. #endif /* RT_USING_SDIO */