drv_sdio.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. /*
  2. * Copyright (c) 2006-2024, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2024-11-06 QT-one first version
  9. */
  10. #include <rtdbg.h>
  11. #include "drv_sdio.h"
  12. #ifdef BSP_USING_SDIO
  13. #if !defined (BSP_USING_SDIO)
  14. #error "Please define at least one SDIOx"
  15. #endif
  16. #define RT_HW_SDIO_LOCK(_sdio) rt_mutex_take(&_sdio->mutex, RT_WAITING_FOREVER)
  17. #define RT_HW_SDIO_UNLOCK(_sdio) rt_mutex_release(&_sdio->mutex);
  18. typedef rt_err_t (*dma_txconfig)(rt_uint32_t *src, rt_uint32_t *dst, int size);
  19. typedef rt_err_t (*dma_rxconfig)(rt_uint32_t *src, rt_uint32_t *dst, int size);
  20. typedef rt_uint32_t (*sdio_clk_get)(HT_SDIO_TypeDef *hw_sdio);
  21. struct ht32_sdio_config
  22. {
  23. SDIO_InitTypeDef sdio_cfg; /* SDIO Configuration Structure */
  24. PDMACH_InitTypeDef dma_tx_cfg; /* TX DMA Configuration Structure */
  25. PDMACH_InitTypeDef dma_rx_cfg; /* RX DMA Configuration Structure */
  26. };
  27. struct ht32_sdio_des
  28. {
  29. HT_SDIO_TypeDef *hw_sdio; /* Pointer to sdio hardware structure */
  30. dma_txconfig txconfig; /* Pointer to the configuration function for the TX DMA */
  31. dma_rxconfig rxconfig; /* Pointer to the configuration function for the RX DMA */
  32. sdio_clk_get clk_get; /* Pointer to get sdio clock function */
  33. };
  34. struct sdio_pkg
  35. {
  36. struct rt_mmcsd_cmd *cmd; /* RTT-defined mmcsd command structure */
  37. void *buff; /* Pointer to hold data */
  38. SDIO_CmdInitTypeDef sdio_cmd_str; /* Send Command Configuration */
  39. SDIO_DataInitTypeDef sdio_dat_str; /* Send Data Configuration */
  40. };
  41. struct rt_hw_sdio
  42. {
  43. struct rt_mmcsd_host *host; /* mmcsd host structure */
  44. struct ht32_sdio_des sdio_des; /* Configuration information for sdio */
  45. struct rt_event dat_event; /* data event variable */
  46. struct rt_event cmd_event; /* command event variable */
  47. struct rt_mutex mutex; /* mutually exclusive variable */
  48. struct sdio_pkg *pkg; /* package structure */
  49. };
  50. rt_align(SDIO_ALIGN_LEN) /* Ensure data alignment */
  51. static rt_uint8_t cache_buf[SDIO_BUFF_SIZE]; /* Buff caches allocated to SDIOs */
  52. static struct rt_mmcsd_host *host;
  53. static struct ht32_sdio_config sdio_cfg;
  54. static void sdio_delay(rt_uint32_t ms)
  55. {
  56. while (ms > 0)
  57. ms--;
  58. }
  59. static rt_uint32_t ht32_sdio_clk_get(HT_SDIO_TypeDef *hw_sdio)
  60. {
  61. return SDIO_CLOCK_FREQ;
  62. }
  63. /**
  64. * @brief this function transfer data by dma.
  65. * @param sdio rt_hw_sdio
  66. * @param pkg sdio package
  67. * @retval none
  68. */
  69. static void rt_hw_sdio_transfer_by_dma(struct rt_hw_sdio *sdio, struct sdio_pkg *pkg)
  70. {
  71. struct rt_mmcsd_data *data;
  72. void *buff;
  73. HT_SDIO_TypeDef *hw_sdio;
  74. if ((RT_NULL == pkg) || (RT_NULL == sdio))
  75. {
  76. LOG_E("rt_hw_sdio_transfer_by_dma invalid args");
  77. return;
  78. }
  79. data = pkg->cmd->data;
  80. if (RT_NULL == data)
  81. {
  82. LOG_E("rt_hw_sdio_transfer_by_dma invalid args");
  83. return;
  84. }
  85. buff = pkg->buff;
  86. if (RT_NULL == buff)
  87. {
  88. LOG_E("rt_hw_sdio_transfer_by_dma invalid args");
  89. return;
  90. }
  91. hw_sdio = sdio->sdio_des.hw_sdio;
  92. if (data->flags & DATA_DIR_WRITE)
  93. {
  94. LOG_D("SDIO write!");
  95. sdio->sdio_des.txconfig((rt_uint32_t *)buff, (rt_uint32_t *)&hw_sdio->DR, (data->blks * data->blksize));
  96. }
  97. else if (data->flags & DATA_DIR_READ)
  98. {
  99. LOG_D("SDIO read!");
  100. sdio->sdio_des.rxconfig((rt_uint32_t *)&hw_sdio->DR, (rt_uint32_t *)buff, (data->blks * data->blksize));
  101. }
  102. }
  103. /**
  104. * @brief this function send command.
  105. * @param sdio rt_hw_sdio
  106. * @param pkg sdio package
  107. * @retval none
  108. */
  109. static void rt_hw_sdio_send_command(struct rt_hw_sdio *sdio, struct sdio_pkg *pkg)
  110. {
  111. rt_uint32_t status = 0;
  112. struct rt_mmcsd_cmd *cmd = pkg->cmd;
  113. struct rt_mmcsd_data *data = cmd->data;
  114. HT_SDIO_TypeDef *hw_sdio = sdio->sdio_des.hw_sdio;
  115. /* save pkg */
  116. sdio->pkg = pkg;
  117. LOG_D("CMD:%d ARG:0x%08x RES:%s%s%s%s%s%s%s%s%s rw:%c len:%d blksize:%d",
  118. cmd->cmd_code,
  119. cmd->arg,
  120. resp_type(cmd) == RESP_NONE ? "NONE" : "",
  121. resp_type(cmd) == RESP_R1 ? "R1" : "",
  122. resp_type(cmd) == RESP_R1B ? "R1B" : "",
  123. resp_type(cmd) == RESP_R2 ? "R2" : "",
  124. resp_type(cmd) == RESP_R3 ? "R3" : "",
  125. resp_type(cmd) == RESP_R4 ? "R4" : "",
  126. resp_type(cmd) == RESP_R5 ? "R5" : "",
  127. resp_type(cmd) == RESP_R6 ? "R6" : "",
  128. resp_type(cmd) == RESP_R7 ? "R7" : "",
  129. data ? (data->flags & DATA_DIR_WRITE ? 'w' : 'r') : '-',
  130. data ? data->blks * data->blksize : 0,
  131. data ? data->blksize : 0
  132. );
  133. /* config cmd reg */
  134. pkg->sdio_cmd_str.SDIO_DatPresent = SDIO_Data_Present_No;
  135. /* config data reg */
  136. if (data != RT_NULL)
  137. {
  138. rt_uint32_t dir = 0;
  139. dir = (data->flags & DATA_DIR_READ) ? SDIO_TransferDir_ToSDIO : SDIO_TransferDir_ToCard;
  140. if (SDIO_TransferDir_ToSDIO == dir) /* read */
  141. SDIO_FlagConfig(SDIO_FLAG_BUF_OVERFLOW | SDIO_FLAG_DATA_CRCERR | SDIO_FLAG_DATA_TIMEOUT | SDIO_FLAG_TRANS_END, ENABLE);
  142. else if (SDIO_TransferDir_ToCard == dir) /* write */
  143. SDIO_FlagConfig(SDIO_FLAG_BUF_UNDERFLOW | SDIO_FLAG_DATA_CRCERR | SDIO_FLAG_DATA_TIMEOUT | SDIO_FLAG_TRANS_END, ENABLE);
  144. if (data->blksize > 2048)
  145. LOG_E("Block length out of range!");
  146. pkg->sdio_dat_str.SDIO_DataBlockCount = data->blks; /* Specify the number of data blocks to be transferred 1~65535 */
  147. pkg->sdio_dat_str.SDIO_DataBlockSize = data->blksize; /* Specify the size of the data block to be transferred 1~2048 */
  148. pkg->sdio_dat_str.SDIO_DataTimeOut = HW_SDIO_DATATIMEOUT; /* Specify the data timeout period 0x1 ~ 0x00ffffff */
  149. pkg->sdio_dat_str.SDIO_TransferDir = dir; /* Specify the direction of data transmission r/w */
  150. if (data->blks > 1)
  151. pkg->sdio_dat_str.SDIO_TransferMode = SDIO_MultiBlock_DMA_Transfer; /* multiblock transfer mode */
  152. else
  153. pkg->sdio_dat_str.SDIO_TransferMode = SDIO_SingleBlock_DMA_Transfer; /* single-block transfer mode */
  154. SDIO_DataConfig(&pkg->sdio_dat_str);
  155. pkg->sdio_cmd_str.SDIO_DatPresent = SDIO_Data_Present_Yes;
  156. rt_hw_sdio_transfer_by_dma(sdio, pkg);
  157. }
  158. /* Configuring Response Mode */
  159. if (resp_type(cmd) == RESP_NONE)
  160. pkg->sdio_cmd_str.SDIO_Response = SDIO_Response_No;
  161. else if (resp_type(cmd) == RESP_R2)
  162. pkg->sdio_cmd_str.SDIO_Response = SDIO_Response_Long;
  163. else
  164. pkg->sdio_cmd_str.SDIO_Response = SDIO_Response_Short;
  165. if (resp_type(cmd) & (RESP_R1 | RESP_R6))
  166. pkg->sdio_cmd_str.SDIO_CmdIdxChk = SDIO_CmdIdxChk_Yes;
  167. else
  168. pkg->sdio_cmd_str.SDIO_CmdIdxChk = SDIO_Data_Present_No;
  169. if (resp_type(cmd) & (RESP_R3))
  170. pkg->sdio_cmd_str.SDIO_CmdCrcChk = SDIO_CmdCrcChk_No;
  171. else
  172. pkg->sdio_cmd_str.SDIO_CmdCrcChk = SDIO_CmdCrcChk_Yes;
  173. /* send cmd */
  174. pkg->sdio_cmd_str.SDIO_Argument = cmd->arg; /* sdio Command Parameters */
  175. pkg->sdio_cmd_str.SDIO_CmdIndex = (cmd->cmd_code << 8); /* Index of sdio commands 0x01 ~ 0x40*/
  176. /* open irq */
  177. SDIO_FlagConfig(HW_SDIO_CMD_FLAG, ENABLE);
  178. SDIO_IntConfig(HW_SDIO_CMD_FLAG, ENABLE);
  179. SDIO_SendCommand(&pkg->sdio_cmd_str);
  180. /* wait completed */
  181. if (rt_event_recv(&sdio->cmd_event, 0xffffffff, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
  182. rt_tick_from_millisecond(5000), &status) != RT_EOK)
  183. {
  184. LOG_E("wait completed timeout");
  185. cmd->err = -RT_ETIMEOUT;
  186. return;
  187. }
  188. SDIO_IntConfig(HW_SDIO_CMD_FLAG, DISABLE);
  189. if (cmd->err != RT_EOK)
  190. LOG_D("cmd err!");
  191. /* waiting for data to be sent to completion */
  192. if (data != RT_NULL)
  193. {
  194. status = 0;
  195. SDIO_IntConfig(SDIO_INT_BUF_OVERFLOW | SDIO_INT_DATA_CRCERR | SDIO_INT_DATA_TIMEOUT | SDIO_INT_TRANS_END, ENABLE);
  196. if (rt_event_recv(&sdio->dat_event, 0xffffffff, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
  197. rt_tick_from_millisecond(5000), &status) != RT_EOK)
  198. {
  199. LOG_E("wait completed timeout");
  200. data->err = -RT_ETIMEOUT;
  201. return;
  202. }
  203. SDIO_IntConfig(SDIO_INT_BUF_OVERFLOW | SDIO_INT_DATA_CRCERR | SDIO_INT_DATA_TIMEOUT | SDIO_INT_TRANS_END, DISABLE);
  204. if (data->err != RT_EOK)
  205. LOG_D("data err!");
  206. }
  207. /* close irq, keep sdio irq */
  208. hw_sdio->IER = 0x00;
  209. /* clear pkg */
  210. sdio->pkg = RT_NULL;
  211. }
  212. /**
  213. * @brief this function send sdio request.
  214. * @param sdio rt_hw_sdio
  215. * @param req request
  216. * @retval none
  217. */
  218. static void rt_hw_sdio_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
  219. {
  220. struct sdio_pkg pkg;
  221. struct rt_hw_sdio *sdio = host->private_data;
  222. struct rt_mmcsd_data *data;
  223. RT_HW_SDIO_LOCK(sdio);
  224. /* Send commands and data */
  225. if (req->cmd != RT_NULL)
  226. {
  227. memset(&pkg, 0, sizeof(pkg));
  228. data = req->cmd->data;
  229. pkg.cmd = req->cmd;
  230. if (data != RT_NULL)
  231. {
  232. rt_uint32_t size = data->blks * data->blksize;
  233. RT_ASSERT(size <= SDIO_BUFF_SIZE);
  234. pkg.buff = data->buf;
  235. if ((rt_uint32_t)data->buf & (SDIO_ALIGN_LEN - 1))
  236. {
  237. pkg.buff = cache_buf;
  238. if (data->flags & DATA_DIR_WRITE)
  239. {
  240. memcpy(cache_buf, data->buf, size);
  241. }
  242. }
  243. }
  244. rt_hw_sdio_send_command(sdio, &pkg);
  245. if ((data != RT_NULL) && (data->flags & DATA_DIR_READ) && ((rt_uint32_t)data->buf & (SDIO_ALIGN_LEN - 1)))
  246. {
  247. memcpy(data->buf, cache_buf, data->blksize * data->blks);
  248. }
  249. }
  250. /* Send stop command */
  251. if (req->stop != RT_NULL)
  252. {
  253. memset(&pkg, 0, sizeof(pkg));
  254. pkg.cmd = req->stop;
  255. rt_hw_sdio_send_command(sdio, &pkg);
  256. }
  257. RT_HW_SDIO_UNLOCK(sdio);
  258. mmcsd_req_complete(sdio->host);
  259. }
  260. /**
  261. * @brief this function config sdio.
  262. * @param host rt_mmcsd_host
  263. * @param io_cfg rt_mmcsd_io_cfg
  264. * @retval none
  265. */
  266. static void rt_hw_sdio_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
  267. {
  268. rt_uint32_t div, clk_src;
  269. rt_uint32_t clk = io_cfg->clock;
  270. struct rt_hw_sdio *sdio = host->private_data;
  271. /* SDIO Clock Acquisition and Limiting */
  272. clk_src = sdio->sdio_des.clk_get(sdio->sdio_des.hw_sdio);
  273. if (clk_src < 400 * 1000)
  274. {
  275. LOG_E("Chip clock frequency too low! fre:%d", clk_src);
  276. return;
  277. }
  278. if (clk > host->freq_max) clk = host->freq_max;
  279. if (clk > clk_src)
  280. {
  281. LOG_W("Setting rate is greater than clock source rate.");
  282. clk = clk_src;
  283. }
  284. LOG_D("clk:%d width:%s%s%s power:%s%s%s",
  285. clk,
  286. io_cfg->bus_width == MMCSD_BUS_WIDTH_8 ? "8" : "",
  287. io_cfg->bus_width == MMCSD_BUS_WIDTH_4 ? "4" : "",
  288. io_cfg->bus_width == MMCSD_BUS_WIDTH_1 ? "1" : "",
  289. io_cfg->power_mode == MMCSD_POWER_OFF ? "OFF" : "",
  290. io_cfg->power_mode == MMCSD_POWER_UP ? "UP" : "",
  291. io_cfg->power_mode == MMCSD_POWER_ON ? "ON" : ""
  292. );
  293. RT_HW_SDIO_LOCK(sdio);
  294. /* SDIO Clock Division Configuration */
  295. div = clk_src / clk;
  296. if ((clk == 0) || (div == 0))
  297. {
  298. div = 1;
  299. }
  300. else
  301. {
  302. if (div < 1)
  303. {
  304. div = 1;
  305. }
  306. else if (div > 0xff)
  307. {
  308. div = 0xff;
  309. }
  310. }
  311. sdio_cfg.sdio_cfg.SDIO_ClockDiv = div;
  312. if (div % 2)
  313. sdio_cfg.sdio_cfg.SDIO_ClockPeriod = SDIO_Clock_LowPeriod_Longer;
  314. else
  315. sdio_cfg.sdio_cfg.SDIO_ClockPeriod = SDIO_Clock_LowPeriod_Shorter;
  316. /* Data bus mode configuration */
  317. if (io_cfg->bus_width == MMCSD_BUS_WIDTH_8)
  318. {
  319. LOG_E("8-bit data width not supported!");
  320. return;
  321. }
  322. else if (io_cfg->bus_width == MMCSD_BUS_WIDTH_4)
  323. {
  324. sdio_cfg.sdio_cfg.SDIO_BusWide = SDIO_BusWide_4b;
  325. sdio_cfg.sdio_cfg.SDIO_BusMode = SDIO_BusMode_HighSpeed;
  326. }
  327. else
  328. {
  329. sdio_cfg.sdio_cfg.SDIO_BusWide = SDIO_BusWide_1b;
  330. sdio_cfg.sdio_cfg.SDIO_BusMode = SDIO_BusMode_NormalSpeed;
  331. }
  332. /* Power Mode Configuration */
  333. switch (io_cfg->power_mode)
  334. {
  335. case MMCSD_POWER_OFF:
  336. sdio_cfg.sdio_cfg.SDIO_ClockPowerSave = SDIO_Clock_PowerSave_Disable;
  337. break;
  338. case MMCSD_POWER_UP:
  339. sdio_cfg.sdio_cfg.SDIO_ClockPowerSave = SDIO_Clock_PowerSave_StopHigh;
  340. break;
  341. case MMCSD_POWER_ON:
  342. sdio_cfg.sdio_cfg.SDIO_ClockPowerSave = SDIO_Clock_PowerSave_StopLow;
  343. break;
  344. default:
  345. LOG_W("unknown power_mode %d", io_cfg->power_mode);
  346. break;
  347. }
  348. SDIO_Init(&sdio_cfg.sdio_cfg);
  349. RT_HW_SDIO_UNLOCK(sdio);
  350. }
  351. /**
  352. * @brief this function update sdio interrupt.
  353. * @param host rt_mmcsd_host
  354. * @param enable
  355. * @retval none
  356. */
  357. void rt_hw_sdio_irq_update(struct rt_mmcsd_host *host, rt_int32_t enable)
  358. {
  359. if (enable)
  360. {
  361. LOG_D("enable sdio irq");
  362. NVIC_EnableIRQ(SDIO_IRQn);
  363. }
  364. else
  365. {
  366. LOG_D("disable sdio irq");
  367. NVIC_DisableIRQ(SDIO_IRQn);
  368. }
  369. }
  370. /**
  371. * @brief this function delect sdcard.
  372. * @param host rt_mmcsd_host
  373. * @retval 0x01
  374. */
  375. static rt_int32_t rt_hw_sd_delect(struct rt_mmcsd_host *host)
  376. {
  377. LOG_D("try to detect device");
  378. return 0x01;
  379. }
  380. /**
  381. * @brief this function interrupt process function.
  382. * @param host rt_mmcsd_host
  383. * @retval none
  384. */
  385. void rt_hw_sdio_irq_process(struct rt_mmcsd_host *host)
  386. {
  387. rt_uint8_t cmd_flag = 0;
  388. rt_uint8_t data_flag = 0;
  389. struct rt_hw_sdio *sdio = host->private_data;
  390. HT_SDIO_TypeDef *hw_sdio = sdio->sdio_des.hw_sdio;
  391. rt_uint32_t intstatus = hw_sdio->SR;
  392. struct rt_mmcsd_cmd *cmd = sdio->pkg->cmd;
  393. struct rt_mmcsd_data *data = cmd->data;
  394. if (sdio->pkg == NULL)
  395. {
  396. SDIO_FlagConfig(HW_SDIO_CMD_FLAG, DISABLE);
  397. SDIO_ClearFlag(HW_SDIO_CMD_FLAG);
  398. SDIO_FlagConfig(HW_SDIO_DATA_FLAG, DISABLE);
  399. SDIO_ClearFlag(HW_SDIO_DATA_FLAG);
  400. return;
  401. }
  402. /* Command Response Processing */
  403. if (cmd != NULL)
  404. {
  405. if (intstatus != 0x00000001)
  406. sdio_delay(10000);
  407. cmd->resp[0] = hw_sdio->RESP0;
  408. cmd->resp[1] = hw_sdio->RESP1;
  409. cmd->resp[2] = hw_sdio->RESP2;
  410. cmd->resp[3] = hw_sdio->RESP3;
  411. cmd->err = RT_EOK;
  412. if (SDIO_GetFlagStatus(SDIO_FLAG_CMD_SEND))
  413. {
  414. SDIO_FlagConfig(HW_SDIO_CMD_FLAG, DISABLE);
  415. SDIO_ClearFlag(SDIO_FLAG_CMD_SEND);
  416. cmd_flag = 1;
  417. }
  418. if (SDIO_GetFlagStatus(SDIO_FLAG_CMD_TIMEOUT))
  419. {
  420. SDIO_FlagConfig(HW_SDIO_CMD_FLAG, DISABLE);
  421. SDIO_ClearFlag(SDIO_FLAG_CMD_TIMEOUT);
  422. RESET_CPSM();
  423. cmd->err = -RT_ETIMEOUT;
  424. cmd_flag = 1;
  425. }
  426. if ((SDIO_GetFlagStatus(SDIO_FLAG_CMD_CRCERR)) && (resp_type(cmd) & (RESP_R3 | RESP_R4)))
  427. {
  428. SDIO_FlagConfig(HW_SDIO_CMD_FLAG, DISABLE);
  429. SDIO_ClearFlag(SDIO_FLAG_CMD_CRCERR);
  430. cmd->err = RT_EOK;
  431. cmd_flag = 1;
  432. }
  433. else if (SDIO_GetFlagStatus(SDIO_FLAG_CMD_CRCERR))
  434. {
  435. SDIO_FlagConfig(HW_SDIO_CMD_FLAG, DISABLE);
  436. SDIO_ClearFlag(SDIO_FLAG_CMD_CRCERR);
  437. cmd->err = -RT_ERROR;
  438. cmd_flag = 1;
  439. }
  440. if ((SDIO_GetFlagStatus(SDIO_FLAG_CMD_IDXERR)) && (resp_type(cmd) & (RESP_R1 | RESP_R6)) && (cmd->err == RT_EOK))
  441. {
  442. SDIO_FlagConfig(HW_SDIO_CMD_FLAG, DISABLE);
  443. SDIO_ClearFlag(SDIO_FLAG_CMD_IDXERR);
  444. cmd->err = RT_EOK;
  445. cmd_flag = 1;
  446. }
  447. else if (SDIO_GetFlagStatus(SDIO_FLAG_CMD_IDXERR))
  448. {
  449. SDIO_FlagConfig(HW_SDIO_CMD_FLAG, DISABLE);
  450. SDIO_ClearFlag(SDIO_FLAG_CMD_IDXERR);
  451. cmd->err = -RT_ERROR;
  452. cmd_flag = 1;
  453. }
  454. if (cmd_flag)
  455. {
  456. rt_event_send(&sdio->cmd_event, intstatus);
  457. }
  458. }
  459. /* Data response processing */
  460. if (data != NULL)
  461. {
  462. data->err = RT_EOK;
  463. if (SDIO_GetFlagStatus(SDIO_FLAG_TRANS_END))
  464. {
  465. SDIO_FlagConfig(HW_SDIO_DATA_FLAG, DISABLE);
  466. SDIO_ClearFlag(SDIO_FLAG_TRANS_END);
  467. data_flag = 1;
  468. }
  469. if (SDIO_GetFlagStatus(SDIO_FLAG_DATA_TIMEOUT))
  470. {
  471. SDIO_FlagConfig(HW_SDIO_DATA_FLAG, DISABLE);
  472. SDIO_ClearFlag(SDIO_FLAG_DATA_TIMEOUT);
  473. data->err = -RT_ETIMEOUT;
  474. data_flag = 1;
  475. }
  476. if (SDIO_GetFlagStatus(SDIO_FLAG_DATA_CRCERR))
  477. {
  478. SDIO_FlagConfig(HW_SDIO_DATA_FLAG, DISABLE);
  479. SDIO_ClearFlag(SDIO_FLAG_DATA_CRCERR);
  480. data->err = -RT_ERROR;
  481. data_flag = 1;
  482. }
  483. if (SDIO_GetFlagStatus(SDIO_FLAG_BUF_OVERFLOW))
  484. {
  485. SDIO_FlagConfig(HW_SDIO_DATA_FLAG, DISABLE);
  486. SDIO_ClearFlag(SDIO_FLAG_BUF_OVERFLOW);
  487. data->err = -RT_ERROR;
  488. data_flag = 1;
  489. }
  490. /* 如果操作完成 */
  491. if (data_flag)
  492. {
  493. rt_event_send(&sdio->dat_event, intstatus); /* 发送事件,通知操作完成 */
  494. }
  495. }
  496. }
  497. static const struct rt_mmcsd_host_ops ops =
  498. {
  499. .request = rt_hw_sdio_request,
  500. .set_iocfg = rt_hw_sdio_iocfg,
  501. .get_card_status = rt_hw_sd_delect,
  502. .enable_sdio_irq = rt_hw_sdio_irq_update,
  503. };
  504. /**
  505. * @brief this function create mmcsd host.
  506. * @param sdio_des at32_sdio_des
  507. * @retval rt_mmcsd_host
  508. */
  509. struct rt_mmcsd_host *sdio_host_create(struct ht32_sdio_des *sdio_des)
  510. {
  511. struct rt_mmcsd_host *host;
  512. struct rt_hw_sdio *sdio = RT_NULL;
  513. /* effective parameter */
  514. if ((sdio_des == RT_NULL) || (sdio_des->txconfig == RT_NULL) || (sdio_des->rxconfig == RT_NULL))
  515. {
  516. LOG_E("L:%d F:%s %s %s %s",
  517. (sdio_des == RT_NULL ? "sdio_des is NULL" : ""),
  518. (sdio_des ? (sdio_des->txconfig ? "txconfig is NULL" : "") : ""),
  519. (sdio_des ? (sdio_des->rxconfig ? "rxconfig is NULL" : "") : "")
  520. );
  521. return RT_NULL;
  522. }
  523. sdio = rt_malloc(sizeof(struct rt_hw_sdio));
  524. if (sdio == RT_NULL)
  525. {
  526. LOG_E("L:%d F:%s malloc rt_hw_sdio fail");
  527. return RT_NULL;
  528. }
  529. rt_memset(sdio, 0, sizeof(struct rt_hw_sdio));
  530. host = mmcsd_alloc_host();
  531. if (host == RT_NULL)
  532. {
  533. LOG_E("L:%d F:%s mmcsd alloc host fail");
  534. rt_free(sdio);
  535. return RT_NULL;
  536. }
  537. rt_memcpy(&sdio->sdio_des, sdio_des, sizeof(struct ht32_sdio_des));
  538. sdio->sdio_des.hw_sdio = (sdio_des->hw_sdio == RT_NULL ? (HT_SDIO_TypeDef *)SDIO_BASE_ADDRESS : sdio_des->hw_sdio);
  539. sdio->sdio_des.clk_get = (sdio_des->clk_get == RT_NULL ? ht32_sdio_clk_get : sdio_des->clk_get);
  540. /* Initialising events and mutexes */
  541. rt_event_init(&sdio->dat_event, "sdio", RT_IPC_FLAG_FIFO);
  542. rt_event_init(&sdio->cmd_event, "sdio_cmd", RT_IPC_FLAG_FIFO);
  543. rt_mutex_init(&sdio->mutex, "sdio", RT_IPC_FLAG_PRIO);
  544. /* set host defautl attributes */
  545. host->ops = &ops;
  546. host->freq_min = 400 * 1000;
  547. host->freq_max = SDIO_MAX_FREQ;
  548. host->valid_ocr = 0X00FFFF80;
  549. #ifndef SDIO_USING_1_BIT
  550. host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ;
  551. #else
  552. host->flags = MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ;
  553. #endif
  554. host->max_seg_size = SDIO_BUFF_SIZE;
  555. host->max_dma_segs = 1;
  556. host->max_blk_size = 512;
  557. host->max_blk_count = 512;
  558. /* link up host and sdio */
  559. sdio->host = host;
  560. host->private_data = sdio;
  561. rt_hw_sdio_irq_update(host, 1);
  562. /* ready to change */
  563. mmcsd_change(host);
  564. return host;
  565. }
  566. /**
  567. * @brief this function configures the dmatx.
  568. * @param src: pointer to the source buffer
  569. * @param dst: pointer to the destination buffer
  570. * @param buffer_size: size of tx buffer
  571. * @retval none
  572. */
  573. void sd_lowlevel_dmatx_config(uint32_t *src, uint32_t *dst, uint32_t buffer_size)
  574. {
  575. PDMACH_InitTypeDef PDMACH_InitStruct;
  576. /* Configure */
  577. PDMACH_InitStruct.PDMACH_SrcAddr = (u32)src;
  578. PDMACH_InitStruct.PDMACH_DstAddr = (u32)dst;
  579. PDMACH_InitStruct.PDMACH_AdrMod = SRC_ADR_LIN_INC | DST_ADR_FIX;
  580. PDMACH_InitStruct.PDMACH_BlkCnt = buffer_size;
  581. PDMACH_InitStruct.PDMACH_BlkLen = 1;
  582. PDMACH_InitStruct.PDMACH_DataSize = WIDTH_32BIT;
  583. PDMACH_InitStruct.PDMACH_Priority = H_PRIO;
  584. PDMA_Config(PDMA_SDIO_TX, &PDMACH_InitStruct);
  585. PDMA_IntConfig(PDMA_SDIO_TX, (PDMA_INT_GE | PDMA_INT_TC | PDMA_INT_TE), ENABLE);
  586. NVIC_EnableIRQ(PDMACH7_IRQn);
  587. PDMA_EnaCmd(PDMA_SDIO_TX, ENABLE);
  588. }
  589. /**
  590. * @brief this function configures the dmarx.
  591. * @param src: pointer to the source buffer
  592. * @param dst: pointer to the destination buffer
  593. * @param buffer_size: size of rx buffer
  594. * @retval none
  595. */
  596. void sd_lowlevel_dmarx_config(uint32_t *src, uint32_t *dst, uint32_t buffer_size)
  597. {
  598. PDMACH_InitTypeDef PDMACH_InitStruct;
  599. /* Configure */
  600. PDMACH_InitStruct.PDMACH_SrcAddr = (u32)src;
  601. PDMACH_InitStruct.PDMACH_DstAddr = (u32)dst;
  602. PDMACH_InitStruct.PDMACH_AdrMod = SRC_ADR_FIX | DST_ADR_LIN_INC;
  603. PDMACH_InitStruct.PDMACH_BlkCnt = buffer_size;
  604. PDMACH_InitStruct.PDMACH_BlkLen = 1;
  605. PDMACH_InitStruct.PDMACH_DataSize = WIDTH_32BIT;
  606. PDMACH_InitStruct.PDMACH_Priority = H_PRIO;
  607. PDMA_Config(PDMA_SDIO_RX, &PDMACH_InitStruct);
  608. PDMA_IntConfig(PDMA_SDIO_RX, (PDMA_INT_GE | PDMA_INT_TC | PDMA_INT_TE), ENABLE);
  609. NVIC_EnableIRQ(PDMACH6_IRQn);
  610. PDMA_EnaCmd(PDMA_SDIO_RX, ENABLE);
  611. }
  612. /**
  613. * @brief this function get at32 sdio clock.
  614. * @param hw_sdio: at32_sdio
  615. * @retval ahb frequency
  616. */
  617. static rt_uint32_t ht32_sdio_clock_get(HT_SDIO_TypeDef *hw_sdio)
  618. {
  619. return SystemCoreClock;
  620. }
  621. static rt_err_t dma_tx_config(rt_uint32_t *src, rt_uint32_t *dst, int size)
  622. {
  623. sd_lowlevel_dmatx_config((uint32_t *)src, (uint32_t *)dst, size / 4);
  624. return RT_EOK;
  625. }
  626. static rt_err_t dma_rx_config(rt_uint32_t *src, rt_uint32_t *dst, int size)
  627. {
  628. sd_lowlevel_dmarx_config((uint32_t *)src, (uint32_t *)dst, size / 4);
  629. return RT_EOK;
  630. }
  631. int rt_hw_sdio_init(void)
  632. {
  633. struct ht32_sdio_des sdio_des;
  634. ht32_sdio_gpio_init((void *)(HT_SDIO));
  635. sdio_des.clk_get = ht32_sdio_clock_get;
  636. sdio_des.hw_sdio = (HT_SDIO_TypeDef *)HT_SDIO;
  637. sdio_des.rxconfig = dma_rx_config;
  638. sdio_des.txconfig = dma_tx_config;
  639. host = sdio_host_create(&sdio_des);
  640. if (host == RT_NULL)
  641. {
  642. LOG_E("host create fail");
  643. return -1;
  644. }
  645. return 0;
  646. }
  647. INIT_DEVICE_EXPORT(rt_hw_sdio_init);
  648. /*********************************************************************************************************//**
  649. * @brief This function handles PDMA_CH6 interrupt.
  650. * @retval None
  651. ************************************************************************************************************/
  652. void PDMA_CH6_IRQHandler(void)
  653. {
  654. if (HT_PDMA->ISR1 & (PDMA_FLAG_TE << ((PDMA_CH6 - 6) * 5)))
  655. {
  656. LOG_E(" TE6");
  657. while (1);
  658. }
  659. HT_PDMA->ISCR1 = PDMA_FLAG_TC << ((PDMA_CH6 - 6) * 5);
  660. PDMA_EnaCmd(PDMA_SDIO_RX, DISABLE);
  661. }
  662. /*********************************************************************************************************//**
  663. * @brief This function handles PDMA_CH7 interrupt.
  664. * @retval None
  665. ************************************************************************************************************/
  666. void PDMA_CH7_IRQHandler(void)
  667. {
  668. if (HT_PDMA->ISR1 & (PDMA_FLAG_TE << ((PDMA_CH7 - 6) * 5)))
  669. {
  670. LOG_E(" TE7");
  671. while (1);
  672. }
  673. HT_PDMA->ISCR1 = PDMA_FLAG_TC << ((PDMA_CH7 - 6) * 5);
  674. PDMA_EnaCmd(PDMA_SDIO_TX, DISABLE);
  675. }
  676. /*********************************************************************************************************//**
  677. * @brief This function handles SDIO interrupt.
  678. * @retval None
  679. ************************************************************************************************************/
  680. void SDIO_IRQHandler(void)
  681. {
  682. /* enter interrupt */
  683. rt_interrupt_enter();
  684. rt_hw_sdio_irq_process(host);
  685. /* leave interrupt */
  686. rt_interrupt_leave();
  687. }
  688. void ht32_mmcsd_change(void)
  689. {
  690. mmcsd_change(host);
  691. }
  692. #endif /* BSP_USING_SDIO */