drv_sdio.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /*
  2. * Copyright (c) 2022 hpmicro
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-02-23 hpmicro First version
  9. * 2022-07-19 hpmicro Fixed the multi-block read/write issue
  10. */
  11. #include <rtthread.h>
  12. #ifdef BSP_USING_SDXC
  13. #include <rthw.h>
  14. #include <rtdevice.h>
  15. #include <rtdbg.h>
  16. #include "board.h"
  17. #include "hpm_sdxc_drv.h"
  18. #include "hpm_l1c_drv.h"
  19. #define CACHE_LINESIZE HPM_L1C_CACHELINE_SIZE
  20. #define SDXC_ADMA_TABLE_WORDS (2U)
  21. #define SDXC_AMDA2_ADDR_ALIGN (4U)
  22. #define SDXC_DATA_TIMEOUT (0xFU)
  23. #define SDXC_CACHELINE_ALIGN_DOWN(x) ((uint32_t)(x) & ~((uint32_t)(CACHE_LINESIZE) - 1UL))
  24. #define SDXC_CACHELINE_ALIGN_UP(x) SDXC_CACHELINE_ALIGN_DOWN((uint32_t)(x) + (uint32_t)(CACHE_LINESIZE) - 1U)
  25. #define SDXC_IS_CACHELINE_ALIGNED(n) ((uint32_t)(n) % (uint32_t)(CACHE_LINESIZE) == 0U)
  26. struct hpm_mmcsd
  27. {
  28. struct rt_mmcsd_host *host;
  29. struct rt_mmcsd_req *req;
  30. struct rt_mmcsd_cmd *cmd;
  31. struct rt_timer *timer;
  32. rt_uint32_t *buf;
  33. SDXC_Type *sdxc_base;
  34. int32_t irq_num;
  35. uint32_t *sdxc_adma2_table;
  36. };
  37. static void hpm_sdmmc_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req);
  38. static void hpm_sdmmc_set_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg);
  39. static void hpm_sdmmc_enable_sdio_irq(struct rt_mmcsd_host *host, rt_int32_t en);
  40. static void hpm_sdmmc_host_recovery(SDXC_Type *base);
  41. static const struct rt_mmcsd_host_ops hpm_mmcsd_host_ops =
  42. {
  43. .request = hpm_sdmmc_request,
  44. .set_iocfg = hpm_sdmmc_set_iocfg,
  45. .get_card_status = NULL,
  46. .enable_sdio_irq = NULL, // Do not use the interrupt mode, use DMA instead
  47. };
  48. /* Place the ADMA2 table to non-cacheable region */
  49. ATTR_PLACE_AT_NONCACHEABLE static uint32_t s_sdxc_adma2_table[SDXC_ADMA_TABLE_WORDS];
  50. /**
  51. * !@brief SDMMC request implementation based on HPMicro SDXC Host
  52. */
  53. static void hpm_sdmmc_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
  54. {
  55. struct hpm_mmcsd *mmcsd;
  56. struct rt_mmcsd_cmd *cmd;
  57. struct rt_mmcsd_data *data;
  58. sdxc_adma_config_t adma_config = { 0 };
  59. sdxc_xfer_t xfer = { 0 };
  60. sdxc_command_t sdxc_cmd = { 0 };
  61. sdxc_data_t sdxc_data = { 0 };
  62. uint32_t *aligned_buf = NULL;
  63. hpm_stat_t err = status_invalid_argument;
  64. RT_ASSERT(host != RT_NULL);
  65. RT_ASSERT(host->private_data != RT_NULL);
  66. RT_ASSERT(req != RT_NULL);
  67. RT_ASSERT(req->cmd != RT_NULL);
  68. mmcsd = (struct hpm_mmcsd *) host->private_data;
  69. cmd = req->cmd;
  70. data = cmd->data;
  71. /* configure command */
  72. sdxc_cmd.cmd_index = cmd->cmd_code;
  73. sdxc_cmd.cmd_argument = cmd->arg;
  74. if (cmd->cmd_code == STOP_TRANSMISSION)
  75. {
  76. sdxc_cmd.cmd_type = sdxc_cmd_type_abort_cmd;
  77. }
  78. else
  79. {
  80. sdxc_cmd.cmd_type = sdxc_cmd_type_normal_cmd;
  81. }
  82. switch (cmd->flags & RESP_MASK)
  83. {
  84. case RESP_NONE:
  85. sdxc_cmd.resp_type = sdxc_dev_resp_none;
  86. break;
  87. case RESP_R1:
  88. sdxc_cmd.resp_type = sdxc_dev_resp_r1;
  89. break;
  90. case RESP_R1B:
  91. sdxc_cmd.resp_type = sdxc_dev_resp_r1b;
  92. break;
  93. case RESP_R2:
  94. sdxc_cmd.resp_type = sdxc_dev_resp_r2;
  95. break;
  96. case RESP_R3:
  97. sdxc_cmd.resp_type = sdxc_dev_resp_r3;
  98. break;
  99. case RESP_R4:
  100. sdxc_cmd.resp_type = sdxc_dev_resp_r4;
  101. break;
  102. case RESP_R6:
  103. sdxc_cmd.resp_type = sdxc_dev_resp_r6;
  104. break;
  105. case RESP_R7:
  106. sdxc_cmd.resp_type = sdxc_dev_resp_r7;
  107. break;
  108. case RESP_R5:
  109. sdxc_cmd.resp_type = sdxc_dev_resp_r5;
  110. break;
  111. default:
  112. RT_ASSERT(NULL);
  113. break;
  114. }
  115. sdxc_cmd.cmd_flags = 0UL;
  116. xfer.command = &sdxc_cmd;
  117. if (data != NULL)
  118. {
  119. sdxc_data.enable_auto_cmd12 = false;
  120. sdxc_data.enable_auto_cmd23 = false;
  121. sdxc_data.enable_ignore_error = false;
  122. sdxc_data.data_type = sdxc_xfer_data_normal;
  123. sdxc_data.block_size = data->blksize;
  124. sdxc_data.block_cnt = data->blks;
  125. /* configure adma2 */
  126. adma_config.dma_type = sdxc_dmasel_adma2;
  127. adma_config.adma_table = (uint32_t*) core_local_mem_to_sys_address(BOARD_RUNNING_CORE,
  128. (uint32_t) mmcsd->sdxc_adma2_table);
  129. adma_config.adma_table_words = SDXC_ADMA_TABLE_WORDS;
  130. if ((req->data->flags & DATA_DIR_WRITE) != 0U)
  131. {
  132. uint32_t write_size = data->blks * data->blksize;
  133. if (!SDXC_IS_CACHELINE_ALIGNED(data->buf) || !SDXC_IS_CACHELINE_ALIGNED(write_size))
  134. {
  135. write_size = SDXC_CACHELINE_ALIGN_UP(write_size);
  136. aligned_buf = (uint32_t *) rt_malloc_align(write_size, CACHE_LINESIZE);
  137. memcpy(aligned_buf, data->buf, write_size);
  138. sdxc_data.tx_data = aligned_buf;
  139. rt_enter_critical();
  140. l1c_dc_flush((uint32_t) sdxc_data.tx_data, write_size);
  141. rt_exit_critical();
  142. }
  143. else
  144. {
  145. sdxc_data.tx_data = (uint32_t const *) core_local_mem_to_sys_address(BOARD_RUNNING_CORE,
  146. (uint32_t) data->buf);
  147. rt_enter_critical();
  148. l1c_dc_flush((uint32_t) data->buf, write_size);
  149. rt_exit_critical();
  150. }
  151. sdxc_data.rx_data = NULL;
  152. }
  153. else
  154. {
  155. uint32_t read_size = data->blks * data->blksize;
  156. if (!SDXC_IS_CACHELINE_ALIGNED(data->buf) || !SDXC_IS_CACHELINE_ALIGNED(read_size))
  157. {
  158. uint32_t aligned_read_size = SDXC_CACHELINE_ALIGN_UP(read_size);
  159. aligned_buf = (uint32_t *) rt_malloc_align(aligned_read_size, CACHE_LINESIZE);
  160. sdxc_data.rx_data = aligned_buf;
  161. }
  162. else
  163. {
  164. sdxc_data.rx_data = (uint32_t*) core_local_mem_to_sys_address(BOARD_RUNNING_CORE, (uint32_t) data->buf);
  165. }
  166. sdxc_data.tx_data = NULL;
  167. }
  168. xfer.data = &sdxc_data;
  169. }
  170. else
  171. {
  172. xfer.data = NULL;
  173. }
  174. if ((req->data->blks > 1) && ((cmd->cmd_code == READ_MULTIPLE_BLOCK) || ((cmd->cmd_code == WRITE_MULTIPLE_BLOCK))))
  175. {
  176. xfer.data->enable_auto_cmd12 = true;
  177. }
  178. err = sdxc_transfer_blocking(mmcsd->sdxc_base, &adma_config, &xfer);
  179. LOG_I("cmd=%d, arg=%x\n", cmd->cmd_code, cmd->arg);
  180. if (err != status_success)
  181. {
  182. hpm_sdmmc_host_recovery(mmcsd->sdxc_base);
  183. LOG_E(" ***sdxc_transfer_blocking error: %d*** -->\n", err);
  184. cmd->err = -RT_ERROR;
  185. }
  186. else
  187. {
  188. LOG_I(" ***sdxc_transfer_blocking passed: %d*** -->\n", err);
  189. if (sdxc_cmd.resp_type == sdxc_dev_resp_r2)
  190. {
  191. LOG_I("resp:0x%08x 0x%08x 0x%08x 0x%08x\n", sdxc_cmd.response[0],
  192. sdxc_cmd.response[1], sdxc_cmd.response[2], sdxc_cmd.response[3]);
  193. }
  194. else
  195. {
  196. LOG_I("resp:0x%08x\n", sdxc_cmd.response[0]);
  197. }
  198. }
  199. if ((sdxc_data.rx_data != NULL) && (cmd->err == RT_EOK))
  200. {
  201. uint32_t read_size = data->blks * data->blksize;
  202. if (aligned_buf != NULL)
  203. {
  204. uint32_t aligned_read_size = SDXC_CACHELINE_ALIGN_UP(read_size);
  205. rt_enter_critical();
  206. l1c_dc_invalidate((uint32_t) aligned_buf, aligned_read_size);
  207. rt_exit_critical();
  208. memcpy(data->buf, aligned_buf, read_size);
  209. }
  210. else
  211. {
  212. rt_enter_critical();
  213. l1c_dc_invalidate((uint32_t) data->buf, read_size);
  214. rt_exit_critical();
  215. }
  216. }
  217. if (aligned_buf != NULL)
  218. {
  219. rt_free_align(aligned_buf);
  220. aligned_buf = NULL;
  221. }
  222. if ((cmd->flags & RESP_MASK) == RESP_R2)
  223. {
  224. cmd->resp[3] = sdxc_cmd.response[0];
  225. cmd->resp[2] = sdxc_cmd.response[1];
  226. cmd->resp[1] = sdxc_cmd.response[2];
  227. cmd->resp[0] = sdxc_cmd.response[3];
  228. }
  229. else
  230. {
  231. cmd->resp[0] = sdxc_cmd.response[0];
  232. }
  233. mmcsd_req_complete(host);
  234. }
  235. /**
  236. * !@brief Set IO Configuration for HPMicro IO and SDXC Host
  237. */
  238. static void hpm_sdmmc_set_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
  239. {
  240. struct hpm_mmcsd *mmcsd;
  241. uint32_t sdxc_clk;
  242. uint32_t vdd;
  243. RT_ASSERT(host != RT_NULL);RT_ASSERT(host->private_data != RT_NULL);RT_ASSERT(io_cfg != RT_NULL);
  244. mmcsd = (struct hpm_mmcsd *) host->private_data;
  245. vdd = io_cfg->vdd;
  246. static bool has_init = false;
  247. init_sdxc_pins(mmcsd->sdxc_base, false);
  248. uint32_t sdxc_clock = io_cfg->clock;
  249. if (sdxc_clock != 0U)
  250. {
  251. switch (io_cfg->bus_width)
  252. {
  253. case MMCSD_BUS_WIDTH_4:
  254. sdxc_set_data_bus_width(mmcsd->sdxc_base, sdxc_bus_width_4bit);
  255. break;
  256. case MMCSD_BUS_WIDTH_8:
  257. sdxc_set_data_bus_width(mmcsd->sdxc_base, sdxc_bus_width_8bit);
  258. break;
  259. default:
  260. sdxc_set_data_bus_width(mmcsd->sdxc_base, sdxc_bus_width_1bit);
  261. break;
  262. }
  263. board_sd_configure_clock(mmcsd->sdxc_base, sdxc_clk);
  264. }
  265. rt_thread_mdelay(5);
  266. }
  267. static void hpm_sdmmc_enable_sdio_irq(struct rt_mmcsd_host *host, rt_int32_t en)
  268. {
  269. RT_ASSERT(host != RT_NULL);RT_ASSERT(host->private_data != RT_NULL);
  270. struct hpm_mmcsd *mmcsd = (struct hpm_mmcsd *) host->private_data;
  271. if (en != 0)
  272. {
  273. intc_m_enable_irq_with_priority(mmcsd->irq_num, 1);
  274. }
  275. else
  276. {
  277. intc_m_disable_irq(mmcsd->irq_num);
  278. }
  279. }
  280. static void hpm_sdmmc_host_recovery(SDXC_Type *base)
  281. {
  282. uint32_t pstate = sdxc_get_present_status(base);
  283. bool need_reset_cmd_line = false;
  284. bool need_reset_data_line = false;
  285. if ((pstate & SDXC_PSTATE_CMD_INHIBIT_MASK) != 0U)
  286. {
  287. /* Reset command line */
  288. need_reset_cmd_line = true;
  289. }
  290. if ((pstate & SDXC_PSTATE_DAT_INHIBIT_MASK) != 0U)
  291. {
  292. /* Reset data line */
  293. need_reset_data_line = true;
  294. }
  295. uint32_t int_stat = sdxc_get_interrupt_status(base);
  296. if ((int_stat & 0xF0000UL) != 0U)
  297. {
  298. need_reset_cmd_line = true;
  299. }
  300. if ((int_stat & 0x700000) != 0U)
  301. {
  302. need_reset_data_line = true;
  303. }
  304. if (need_reset_cmd_line)
  305. {
  306. sdxc_reset(base, sdxc_reset_cmd_line, 0xFFFFUL);
  307. }
  308. if (need_reset_data_line)
  309. {
  310. sdxc_reset(base, sdxc_reset_data_line, 0xFFFFUL);
  311. }
  312. if (need_reset_cmd_line || need_reset_data_line)
  313. {
  314. sdxc_clear_interrupt_status(base, ~0UL);
  315. }
  316. rt_thread_mdelay(10);
  317. LOG_E("%s\n", __func__);
  318. }
  319. int rt_hw_sdio_init(void)
  320. {
  321. rt_err_t err = RT_EOK;
  322. struct rt_mmcsd_host *host = NULL;
  323. struct hpm_mmcsd *mmcsd = NULL;
  324. do
  325. {
  326. host = mmcsd_alloc_host();
  327. if (host == NULL)
  328. {
  329. err = -RT_ERROR;
  330. break;
  331. }
  332. mmcsd = rt_malloc(sizeof(struct hpm_mmcsd));
  333. if (mmcsd == NULL)
  334. {
  335. LOG_E("allocate hpm_mmcsd failed\n");
  336. err = -RT_ERROR;
  337. break;
  338. }
  339. rt_memset(mmcsd, 0, sizeof(struct hpm_mmcsd));
  340. mmcsd->sdxc_base = BOARD_APP_SDCARD_SDXC_BASE;
  341. mmcsd->sdxc_adma2_table = s_sdxc_adma2_table;
  342. host->ops = &hpm_mmcsd_host_ops;
  343. host->freq_min = 375000;
  344. host->freq_max = 50000000;
  345. host->valid_ocr = VDD_30_31 | VDD_31_32 | VDD_32_33 | VDD_33_34;
  346. host->flags = MMCSD_MUTBLKWRITE | MMCSD_BUSWIDTH_4 | MMCSD_SUP_HIGHSPEED | MMCSD_SUP_SDIO_IRQ;
  347. host->max_seg_size = 65535;
  348. host->max_dma_segs = 2;
  349. host->max_blk_size = 512;
  350. host->max_blk_count = 4096;
  351. mmcsd->host = host;
  352. /* Perform necessary initialization */
  353. board_sd_configure_clock(mmcsd->sdxc_base, 375000);
  354. sdxc_config_t sdxc_config = { 0 };
  355. sdxc_config.data_timeout = SDXC_DATA_TIMEOUT;
  356. sdxc_init(mmcsd->sdxc_base, &sdxc_config);
  357. host->private_data = mmcsd;
  358. mmcsd_change(host);
  359. } while (false);
  360. if (err != RT_EOK)
  361. {
  362. if (host != NULL)
  363. {
  364. mmcsd_free_host(host);
  365. host = NULL;
  366. }
  367. }
  368. return err;
  369. }
  370. INIT_DEVICE_EXPORT(rt_hw_sdio_init);
  371. #endif