drv_sdio.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. /*
  2. * Copyright (c) 2022-2023 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. * 2023-07-27 HPMicro Fixed clock setting issue
  11. * 2023-08-02 HPMicro Add speed mode setting
  12. */
  13. #include <rtthread.h>
  14. #ifdef BSP_USING_SDXC
  15. #include <rthw.h>
  16. #include <rtdevice.h>
  17. #include <rtdbg.h>
  18. #include "board.h"
  19. #include "hpm_sdxc_drv.h"
  20. #include "hpm_l1c_drv.h"
  21. #define CACHE_LINESIZE HPM_L1C_CACHELINE_SIZE
  22. #define SDXC_ADMA_TABLE_WORDS (2U)
  23. #define SDXC_AMDA2_ADDR_ALIGN (4U)
  24. #define SDXC_DATA_TIMEOUT (0xFU)
  25. #define SDXC_CACHELINE_ALIGN_DOWN(x) HPM_L1C_CACHELINE_ALIGN_DOWN(x)
  26. #define SDXC_CACHELINE_ALIGN_UP(x) HPM_L1C_CACHELINE_ALIGN_UP(x)
  27. #define SDXC_IS_CACHELINE_ALIGNED(n) ((uint32_t)(n) % (uint32_t)(CACHE_LINESIZE) == 0U)
  28. struct hpm_mmcsd
  29. {
  30. struct rt_mmcsd_host *host;
  31. struct rt_mmcsd_req *req;
  32. struct rt_mmcsd_cmd *cmd;
  33. struct rt_timer *timer;
  34. rt_uint32_t *buf;
  35. SDXC_Type *sdxc_base;
  36. int32_t irq_num;
  37. uint32_t *sdxc_adma2_table;
  38. uint8_t power_mode;
  39. uint8_t bus_width;
  40. uint8_t timing;
  41. uint8_t bus_mode;
  42. uint32_t freq;
  43. };
  44. static void hpm_sdmmc_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req);
  45. static void hpm_sdmmc_set_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg);
  46. static void hpm_sdmmc_enable_sdio_irq(struct rt_mmcsd_host *host, rt_int32_t en);
  47. static void hpm_sdmmc_host_recovery(SDXC_Type *base);
  48. static int hpm_sdmmc_transfer(SDXC_Type *base, sdxc_adma_config_t *dma_config, sdxc_xfer_t *xfer);
  49. static const struct rt_mmcsd_host_ops hpm_mmcsd_host_ops =
  50. {
  51. .request = hpm_sdmmc_request,
  52. .set_iocfg = hpm_sdmmc_set_iocfg,
  53. .get_card_status = NULL,
  54. .enable_sdio_irq = NULL, // Do not use the interrupt mode, use DMA instead
  55. };
  56. /* Place the ADMA2 table to non-cacheable region */
  57. ATTR_PLACE_AT_NONCACHEABLE static uint32_t s_sdxc_adma2_table[SDXC_ADMA_TABLE_WORDS];
  58. static int hpm_sdmmc_transfer(SDXC_Type *base, sdxc_adma_config_t *dma_config, sdxc_xfer_t *xfer)
  59. {
  60. hpm_stat_t status;
  61. sdxc_command_t *cmd = xfer->command;
  62. sdxc_data_t *data = xfer->data;
  63. status = sdxc_transfer_nonblocking(base, dma_config, xfer);
  64. if (status != status_success)
  65. {
  66. return -RT_ERROR;
  67. }
  68. /* Wait until idle */
  69. volatile uint32_t interrupt_status = sdxc_get_interrupt_status(base);
  70. while (!IS_HPM_BITMASK_SET(interrupt_status, SDXC_INT_STAT_CMD_COMPLETE_MASK))
  71. {
  72. interrupt_status = sdxc_get_interrupt_status(base);
  73. status = sdxc_parse_interrupt_status(base);
  74. HPM_BREAK_IF(status != status_success);
  75. }
  76. sdxc_clear_interrupt_status(base, SDXC_INT_STAT_CMD_COMPLETE_MASK);
  77. if (status == status_success)
  78. {
  79. status = sdxc_receive_cmd_response(base, cmd);
  80. }
  81. if ((status == status_success) && (data != RT_NULL))
  82. {
  83. interrupt_status = sdxc_get_interrupt_status(base);
  84. while (!IS_HPM_BITMASK_SET(interrupt_status, SDXC_INT_STAT_XFER_COMPLETE_MASK | SDXC_STS_ERROR))
  85. {
  86. interrupt_status = sdxc_get_interrupt_status(base);
  87. status = sdxc_parse_interrupt_status(base);
  88. HPM_BREAK_IF(status != status_success);
  89. }
  90. }
  91. return (status == status_success) ? RT_EOK : -RT_ERROR;
  92. }
  93. /**
  94. * !@brief SDMMC request implementation based on HPMicro SDXC Host
  95. */
  96. static void hpm_sdmmc_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
  97. {
  98. RT_ASSERT(host != RT_NULL);
  99. RT_ASSERT(host->private_data != RT_NULL);
  100. RT_ASSERT(req != RT_NULL);
  101. RT_ASSERT(req->cmd != RT_NULL);
  102. sdxc_adma_config_t adma_config = { 0 };
  103. sdxc_xfer_t xfer = { 0 };
  104. sdxc_command_t sdxc_cmd = { 0 };
  105. sdxc_data_t sdxc_data = { 0 };
  106. uint32_t *aligned_buf = NULL;
  107. hpm_stat_t err = status_invalid_argument;
  108. struct hpm_mmcsd *mmcsd = (struct hpm_mmcsd *) host->private_data;
  109. struct rt_mmcsd_cmd *cmd = req->cmd;
  110. struct rt_mmcsd_data *data = cmd->data;
  111. /* configure command */
  112. sdxc_cmd.cmd_index = cmd->cmd_code;
  113. sdxc_cmd.cmd_argument = cmd->arg;
  114. sdxc_cmd.cmd_type = (cmd->cmd_code == STOP_TRANSMISSION) ? sdxc_cmd_type_abort_cmd : sdxc_cmd_type_normal_cmd;
  115. switch (cmd->flags & RESP_MASK)
  116. {
  117. case RESP_NONE:
  118. sdxc_cmd.resp_type = sdxc_dev_resp_none;
  119. break;
  120. case RESP_R1:
  121. sdxc_cmd.resp_type = sdxc_dev_resp_r1;
  122. break;
  123. case RESP_R1B:
  124. sdxc_cmd.resp_type = sdxc_dev_resp_r1b;
  125. break;
  126. case RESP_R2:
  127. sdxc_cmd.resp_type = sdxc_dev_resp_r2;
  128. break;
  129. case RESP_R3:
  130. sdxc_cmd.resp_type = sdxc_dev_resp_r3;
  131. break;
  132. case RESP_R4:
  133. sdxc_cmd.resp_type = sdxc_dev_resp_r4;
  134. break;
  135. case RESP_R6:
  136. sdxc_cmd.resp_type = sdxc_dev_resp_r6;
  137. break;
  138. case RESP_R7:
  139. sdxc_cmd.resp_type = sdxc_dev_resp_r7;
  140. break;
  141. case RESP_R5:
  142. sdxc_cmd.resp_type = sdxc_dev_resp_r5;
  143. break;
  144. default:
  145. RT_ASSERT(NULL);
  146. break;
  147. }
  148. sdxc_cmd.cmd_flags = 0UL;
  149. xfer.command = &sdxc_cmd;
  150. if (data != NULL)
  151. {
  152. sdxc_data.enable_auto_cmd12 = false;
  153. sdxc_data.enable_auto_cmd23 = false;
  154. sdxc_data.enable_ignore_error = false;
  155. sdxc_data.data_type = sdxc_xfer_data_normal;
  156. sdxc_data.block_size = data->blksize;
  157. sdxc_data.block_cnt = data->blks;
  158. /* configure adma2 */
  159. adma_config.dma_type = sdxc_dmasel_adma2;
  160. adma_config.adma_table = (uint32_t*) core_local_mem_to_sys_address(BOARD_RUNNING_CORE,
  161. (uint32_t) mmcsd->sdxc_adma2_table);
  162. adma_config.adma_table_words = SDXC_ADMA_TABLE_WORDS;
  163. if ((req->data->flags & DATA_DIR_WRITE) != 0U)
  164. {
  165. uint32_t write_size = data->blks * data->blksize;
  166. if (!SDXC_IS_CACHELINE_ALIGNED(data->buf) || !SDXC_IS_CACHELINE_ALIGNED(write_size))
  167. {
  168. write_size = SDXC_CACHELINE_ALIGN_UP(write_size);
  169. aligned_buf = (uint32_t *) rt_malloc_align(write_size, CACHE_LINESIZE);
  170. rt_memcpy(aligned_buf, data->buf, write_size);
  171. sdxc_data.tx_data = aligned_buf;
  172. rt_enter_critical();
  173. l1c_dc_flush((uint32_t) sdxc_data.tx_data, write_size);
  174. rt_exit_critical();
  175. }
  176. else
  177. {
  178. sdxc_data.tx_data = (uint32_t const *) core_local_mem_to_sys_address(BOARD_RUNNING_CORE,
  179. (uint32_t) data->buf);
  180. rt_enter_critical();
  181. l1c_dc_flush((uint32_t) data->buf, write_size);
  182. rt_exit_critical();
  183. }
  184. sdxc_data.rx_data = NULL;
  185. }
  186. else
  187. {
  188. uint32_t read_size = data->blks * data->blksize;
  189. if (!SDXC_IS_CACHELINE_ALIGNED(data->buf) || !SDXC_IS_CACHELINE_ALIGNED(read_size))
  190. {
  191. uint32_t aligned_read_size = SDXC_CACHELINE_ALIGN_UP(read_size);
  192. aligned_buf = (uint32_t *) rt_malloc_align(aligned_read_size, CACHE_LINESIZE);
  193. sdxc_data.rx_data = aligned_buf;
  194. }
  195. else
  196. {
  197. sdxc_data.rx_data = (uint32_t*) core_local_mem_to_sys_address(BOARD_RUNNING_CORE, (uint32_t) data->buf);
  198. }
  199. sdxc_data.tx_data = NULL;
  200. }
  201. xfer.data = &sdxc_data;
  202. }
  203. else
  204. {
  205. xfer.data = NULL;
  206. }
  207. if ((req->data->blks > 1) && ((cmd->cmd_code == READ_MULTIPLE_BLOCK) || ((cmd->cmd_code == WRITE_MULTIPLE_BLOCK))))
  208. {
  209. xfer.data->enable_auto_cmd12 = true;
  210. }
  211. err = hpm_sdmmc_transfer(mmcsd->sdxc_base, &adma_config, &xfer);
  212. LOG_I("cmd=%d, arg=%x\n", cmd->cmd_code, cmd->arg);
  213. if (err != status_success)
  214. {
  215. hpm_sdmmc_host_recovery(mmcsd->sdxc_base);
  216. LOG_E(" ***hpm_sdmmc_transfer error: %d*** -->\n", err);
  217. cmd->err = -RT_ERROR;
  218. }
  219. else
  220. {
  221. LOG_I(" ***hpm_sdmmc_transfer passed: %d*** -->\n", err);
  222. if (sdxc_cmd.resp_type == sdxc_dev_resp_r2)
  223. {
  224. LOG_I("resp:0x%08x 0x%08x 0x%08x 0x%08x\n", sdxc_cmd.response[0],
  225. sdxc_cmd.response[1], sdxc_cmd.response[2], sdxc_cmd.response[3]);
  226. }
  227. else
  228. {
  229. LOG_I("resp:0x%08x\n", sdxc_cmd.response[0]);
  230. }
  231. }
  232. if ((sdxc_data.rx_data != NULL) && (cmd->err == RT_EOK))
  233. {
  234. uint32_t read_size = data->blks * data->blksize;
  235. if (aligned_buf != NULL)
  236. {
  237. uint32_t aligned_read_size = SDXC_CACHELINE_ALIGN_UP(read_size);
  238. rt_enter_critical();
  239. l1c_dc_invalidate((uint32_t) aligned_buf, aligned_read_size);
  240. rt_exit_critical();
  241. rt_memcpy(data->buf, aligned_buf, read_size);
  242. }
  243. else
  244. {
  245. rt_enter_critical();
  246. l1c_dc_invalidate((uint32_t) data->buf, read_size);
  247. rt_exit_critical();
  248. }
  249. }
  250. if (aligned_buf != NULL)
  251. {
  252. rt_free_align(aligned_buf);
  253. aligned_buf = NULL;
  254. }
  255. if ((cmd->flags & RESP_MASK) == RESP_R2)
  256. {
  257. cmd->resp[3] = sdxc_cmd.response[0];
  258. cmd->resp[2] = sdxc_cmd.response[1];
  259. cmd->resp[1] = sdxc_cmd.response[2];
  260. cmd->resp[0] = sdxc_cmd.response[3];
  261. }
  262. else
  263. {
  264. cmd->resp[0] = sdxc_cmd.response[0];
  265. }
  266. mmcsd_req_complete(host);
  267. }
  268. /**
  269. * !@brief Set IO Configuration for HPMicro IO and SDXC Host
  270. */
  271. static void hpm_sdmmc_set_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
  272. {
  273. RT_ASSERT(host != RT_NULL);
  274. RT_ASSERT(host->private_data != RT_NULL);
  275. RT_ASSERT(io_cfg != RT_NULL);
  276. struct hpm_mmcsd *mmcsd = (struct hpm_mmcsd *) host->private_data;
  277. uint32_t vdd = io_cfg->vdd;
  278. if (io_cfg->power_mode != mmcsd->power_mode)
  279. {
  280. switch(io_cfg->power_mode)
  281. {
  282. case MMCSD_POWER_OFF:
  283. board_sd_power_switch(mmcsd->sdxc_base, false);
  284. break;
  285. case MMCSD_POWER_ON:
  286. board_sd_power_switch(mmcsd->sdxc_base, true);
  287. break;
  288. case MMCSD_POWER_UP:
  289. board_sd_power_switch(mmcsd->sdxc_base, false);
  290. rt_thread_mdelay(10);
  291. board_sd_power_switch(mmcsd->sdxc_base, true);
  292. break;
  293. default:
  294. /* Do nothing */
  295. break;
  296. }
  297. mmcsd->power_mode = io_cfg->power_mode;
  298. }
  299. if (mmcsd->bus_width != io_cfg->bus_width)
  300. {
  301. switch (io_cfg->bus_width)
  302. {
  303. case MMCSD_BUS_WIDTH_4:
  304. sdxc_set_data_bus_width(mmcsd->sdxc_base, sdxc_bus_width_4bit);
  305. break;
  306. case MMCSD_BUS_WIDTH_8:
  307. sdxc_set_data_bus_width(mmcsd->sdxc_base, sdxc_bus_width_8bit);
  308. break;
  309. default:
  310. sdxc_set_data_bus_width(mmcsd->sdxc_base, sdxc_bus_width_1bit);
  311. break;
  312. }
  313. mmcsd->bus_width = io_cfg->bus_width;
  314. }
  315. if (mmcsd->timing != io_cfg->timing)
  316. {
  317. switch (io_cfg->timing)
  318. {
  319. case MMCSD_TIMING_LEGACY:
  320. sdxc_set_speed_mode(mmcsd->sdxc_base, sdxc_sd_speed_normal);
  321. break;
  322. case MMCSD_TIMING_SD_HS:
  323. case MMCSD_TIMING_MMC_HS:
  324. sdxc_set_speed_mode(mmcsd->sdxc_base, sdxc_sd_speed_high);
  325. break;
  326. case MMCSD_TIMING_UHS_SDR12:
  327. sdxc_set_speed_mode(mmcsd->sdxc_base, sdxc_sd_speed_sdr12);
  328. break;
  329. case MMCSD_TIMING_UHS_SDR25:
  330. sdxc_set_speed_mode(mmcsd->sdxc_base, sdxc_sd_speed_sdr25);
  331. break;
  332. case MMCSD_TIMING_UHS_SDR50:
  333. sdxc_set_speed_mode(mmcsd->sdxc_base, sdxc_sd_speed_sdr50);
  334. break;
  335. case MMCSD_TIMING_UHS_SDR104:
  336. sdxc_set_speed_mode(mmcsd->sdxc_base, sdxc_sd_speed_sdr104);
  337. break;
  338. case MMCSD_TIMING_UHS_DDR50:
  339. sdxc_set_speed_mode(mmcsd->sdxc_base, sdxc_sd_speed_ddr50);
  340. break;
  341. case MMCSD_TIMING_MMC_DDR52:
  342. sdxc_set_speed_mode(mmcsd->sdxc_base, sdxc_emmc_speed_high_speed_ddr);
  343. break;
  344. case MMCSD_TIMING_MMC_HS200:
  345. sdxc_set_speed_mode(mmcsd->sdxc_base, sdxc_emmc_speed_hs200);
  346. break;
  347. case MMCSD_TIMING_MMC_HS400:
  348. sdxc_set_speed_mode(mmcsd->sdxc_base, sdxc_emmc_speed_hs400);
  349. break;
  350. }
  351. mmcsd->timing = io_cfg->timing;
  352. }
  353. board_init_sd_pins(mmcsd->sdxc_base);
  354. uint32_t sdxc_clock = io_cfg->clock;
  355. if (sdxc_clock != 0U)
  356. {
  357. if (mmcsd->freq != sdxc_clock)
  358. {
  359. /* Ensure request frequency from mmcsd stack level doesn't exceed maximum supported frequency by host */
  360. uint32_t clock_freq = MIN(mmcsd->host->freq_max, sdxc_clock);
  361. board_sd_configure_clock(mmcsd->sdxc_base, clock_freq);
  362. mmcsd->freq = sdxc_clock;
  363. }
  364. }
  365. }
  366. static void hpm_sdmmc_enable_sdio_irq(struct rt_mmcsd_host *host, rt_int32_t en)
  367. {
  368. RT_ASSERT(host != RT_NULL);
  369. RT_ASSERT(host->private_data != RT_NULL);
  370. struct hpm_mmcsd *mmcsd = (struct hpm_mmcsd *) host->private_data;
  371. if (en != 0)
  372. {
  373. intc_m_enable_irq_with_priority(mmcsd->irq_num, 1);
  374. }
  375. else
  376. {
  377. intc_m_disable_irq(mmcsd->irq_num);
  378. }
  379. }
  380. static void hpm_sdmmc_host_recovery(SDXC_Type *base)
  381. {
  382. uint32_t pstate = sdxc_get_present_status(base);
  383. bool need_reset_cmd_line = false;
  384. bool need_reset_data_line = false;
  385. if ((pstate & SDXC_PSTATE_CMD_INHIBIT_MASK) != 0U)
  386. {
  387. /* Reset command line */
  388. need_reset_cmd_line = true;
  389. }
  390. if ((pstate & SDXC_PSTATE_DAT_INHIBIT_MASK) != 0U)
  391. {
  392. /* Reset data line */
  393. need_reset_data_line = true;
  394. }
  395. uint32_t int_stat = sdxc_get_interrupt_status(base);
  396. if ((int_stat & 0xF0000UL) != 0U)
  397. {
  398. need_reset_cmd_line = true;
  399. }
  400. if ((int_stat & 0x700000) != 0U)
  401. {
  402. need_reset_data_line = true;
  403. }
  404. if (need_reset_cmd_line)
  405. {
  406. sdxc_reset(base, sdxc_reset_cmd_line, 0xFFFFUL);
  407. }
  408. if (need_reset_data_line)
  409. {
  410. sdxc_reset(base, sdxc_reset_data_line, 0xFFFFUL);
  411. }
  412. if (need_reset_cmd_line || need_reset_data_line)
  413. {
  414. sdxc_clear_interrupt_status(base, ~0UL);
  415. }
  416. rt_thread_mdelay(10);
  417. LOG_E("%s\n", __func__);
  418. }
  419. int rt_hw_sdio_init(void)
  420. {
  421. rt_err_t err = RT_EOK;
  422. struct rt_mmcsd_host *host = NULL;
  423. struct hpm_mmcsd *mmcsd = NULL;
  424. do
  425. {
  426. host = mmcsd_alloc_host();
  427. if (host == NULL)
  428. {
  429. err = -RT_ERROR;
  430. break;
  431. }
  432. mmcsd = rt_malloc(sizeof(struct hpm_mmcsd));
  433. if (mmcsd == NULL)
  434. {
  435. LOG_E("allocate hpm_mmcsd failed\n");
  436. err = -RT_ERROR;
  437. break;
  438. }
  439. rt_memset(mmcsd, 0, sizeof(struct hpm_mmcsd));
  440. mmcsd->sdxc_base = BOARD_APP_SDCARD_SDXC_BASE;
  441. mmcsd->sdxc_adma2_table = s_sdxc_adma2_table;
  442. host->ops = &hpm_mmcsd_host_ops;
  443. host->freq_min = 375000;
  444. host->freq_max = 50000000;
  445. host->valid_ocr = VDD_30_31 | VDD_31_32 | VDD_32_33 | VDD_33_34;
  446. host->flags = MMCSD_MUTBLKWRITE | MMCSD_BUSWIDTH_4 | MMCSD_SUP_HIGHSPEED | MMCSD_SUP_SDIO_IRQ;
  447. host->max_seg_size = 65535;
  448. host->max_dma_segs = 2;
  449. host->max_blk_size = 512;
  450. host->max_blk_count = 4096;
  451. mmcsd->host = host;
  452. /* Perform necessary initialization */
  453. board_sd_configure_clock(mmcsd->sdxc_base, 375000);
  454. sdxc_config_t sdxc_config = { 0 };
  455. sdxc_config.data_timeout = SDXC_DATA_TIMEOUT;
  456. sdxc_init(mmcsd->sdxc_base, &sdxc_config);
  457. host->private_data = mmcsd;
  458. mmcsd_change(host);
  459. } while (false);
  460. if (err != RT_EOK)
  461. {
  462. if (host != NULL)
  463. {
  464. mmcsd_free_host(host);
  465. host = NULL;
  466. }
  467. }
  468. return err;
  469. }
  470. INIT_DEVICE_EXPORT(rt_hw_sdio_init);
  471. #endif