drv_sdh.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-05-28 flyingcys the first version
  9. */
  10. #include <rtdevice.h>
  11. #include "board.h"
  12. #ifdef RT_USING_DFS
  13. #define LOG_TAG "drv.sdh"
  14. #ifdef BSP_DRIVER_DEBUG
  15. #define DBG_LEVEL DBG_LOG
  16. #else
  17. #define DBG_LEVEL DBG_INFO
  18. #endif
  19. #include <rtdbg.h>
  20. #include <drivers/dev_mmcsd_core.h>
  21. #include <drivers/dev_sdio.h>
  22. #include "drv_sdh.h"
  23. #if defined(BL808)
  24. #include "bl808_common.h"
  25. #include "bl808_glb.h"
  26. #include "bl808_sdh.h"
  27. #elif defined(BL606P)
  28. #include "bl606p_common.h"
  29. #include "bl606p_glb.h"
  30. #include "bl606p_sdh.h"
  31. #elif defined(BL616)
  32. #include "bl616_common.h"
  33. #include "bl616_glb.h"
  34. #include "bl616_sdh.h"
  35. #elif defined(BL628)
  36. #include "bl628_common.h"
  37. #include "bl628_glb.h"
  38. #include "bl628_smih.h"
  39. #endif
  40. #include "bflb_mtimer.h"
  41. #include "bflb_l1c.h"
  42. #define SDIO_BUFF_SIZE 512
  43. static uint8_t sdh_buffer[SDIO_BUFF_SIZE] __attribute__ ((aligned (8)));
  44. #define SDIO_CMDTIMEOUT_MS (1000)
  45. static uint32_t sdhClockInit = 100ul;
  46. static uint32_t sdhClockSrc = 100ul;
  47. static SDH_Cfg_Type SDH_Cfg_Type_Instance;
  48. static SDH_DMA_Cfg_Type SDH_DMA_Cfg_TypeInstance;
  49. /*causion: ADMA related variables must on OCRAM or shared ram*/
  50. static __attribute__((aligned(32), section(".noncacheable"))) SDH_ADMA2_Desc_Type adma2Entries[16];
  51. typedef enum {
  52. SD_OK = 0,
  53. SD_CMD_ERROR,
  54. SD_DataCfg_ERROR,
  55. SD_WAITING,
  56. } SD_Error;
  57. #ifdef BSP_USING_BL808
  58. static void sdh_clock_init(void)
  59. {
  60. PERIPHERAL_CLOCK_SDH_ENABLE();
  61. uint32_t tmp_val;
  62. tmp_val = BL_RD_REG(PDS_BASE, PDS_CTL5);
  63. uint32_t tmp_val2 = BL_GET_REG_BITS_VAL(tmp_val, PDS_CR_PDS_GPIO_KEEP_EN);
  64. tmp_val2 &= ~(1 << 0);
  65. tmp_val = BL_SET_REG_BITS_VAL(tmp_val, PDS_CR_PDS_GPIO_KEEP_EN, tmp_val2);
  66. BL_WR_REG(PDS_BASE, PDS_CTL5, tmp_val);
  67. GLB_AHB_MCU_Software_Reset(GLB_AHB_MCU_SW_SDH);
  68. }
  69. static void sdh_gpio_init(void)
  70. {
  71. struct bflb_device_s *gpio;
  72. gpio = bflb_device_get_by_name("gpio");
  73. bflb_gpio_init(gpio, GPIO_PIN_0, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
  74. bflb_gpio_init(gpio, GPIO_PIN_1, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
  75. bflb_gpio_init(gpio, GPIO_PIN_2, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
  76. bflb_gpio_init(gpio, GPIO_PIN_3, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
  77. bflb_gpio_init(gpio, GPIO_PIN_4, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
  78. bflb_gpio_init(gpio, GPIO_PIN_5, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
  79. }
  80. #elif defined(BSP_USING_BL61X)
  81. static void sdh_clock_init(void)
  82. {
  83. PERIPHERAL_CLOCK_SDH_ENABLE();
  84. GLB_AHB_MCU_Software_Reset(GLB_AHB_MCU_SW_EXT_SDH);
  85. }
  86. static void sdh_gpio_init(void)
  87. {
  88. struct bflb_device_s *gpio;
  89. gpio = bflb_device_get_by_name("gpio");
  90. bflb_gpio_init(gpio, GPIO_PIN_10, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
  91. bflb_gpio_init(gpio, GPIO_PIN_11, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
  92. bflb_gpio_init(gpio, GPIO_PIN_12, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
  93. bflb_gpio_init(gpio, GPIO_PIN_13, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
  94. bflb_gpio_init(gpio, GPIO_PIN_14, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
  95. bflb_gpio_init(gpio, GPIO_PIN_15, GPIO_FUNC_SDH | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_2);
  96. }
  97. #else
  98. #error "The Current Chip Does Not Support SDH!"
  99. #endif
  100. static void sdh_set_bus_width(SDH_Data_Bus_Width_Type width)
  101. {
  102. SDH_Cfg_Type_Instance.vlot18Enable = DISABLE;
  103. SDH_Cfg_Type_Instance.highSpeed = ENABLE;
  104. SDH_Cfg_Type_Instance.dataWidth = width;
  105. SDH_Cfg_Type_Instance.volt = SDH_VOLTAGE_3P3V;
  106. SDH_Cfg_Type_Instance.srcClock = sdhClockSrc;
  107. SDH_Cfg_Type_Instance.busClock = sdhClockInit;
  108. SDH_Ctrl_Init(&SDH_Cfg_Type_Instance);
  109. }
  110. static void sdio_host_init(void)
  111. {
  112. GLB_Set_SDH_CLK(ENABLE, GLB_SDH_CLK_WIFIPLL_96M, 7);
  113. /* initialise SDH controller*/
  114. SDH_Cfg_Type_Instance.vlot18Enable = DISABLE;
  115. SDH_Cfg_Type_Instance.highSpeed = ENABLE;
  116. SDH_Cfg_Type_Instance.dataWidth = SDH_DATA_BUS_WIDTH_1BIT;
  117. SDH_Cfg_Type_Instance.volt = SDH_VOLTAGE_3P3V;
  118. SDH_Cfg_Type_Instance.srcClock = sdhClockSrc;
  119. SDH_Cfg_Type_Instance.busClock = sdhClockInit;
  120. SDH_Ctrl_Init(&SDH_Cfg_Type_Instance);
  121. /*setup timeout counter*/
  122. SDH_Set_Timeout(0x0e);
  123. }
  124. static SDH_Resp_Type sdio_host_get_resp_type(struct rt_mmcsd_cmd *cmd)
  125. {
  126. SDH_Resp_Type respType;
  127. switch (resp_type(cmd))
  128. {
  129. case RESP_NONE:
  130. respType = SDH_RESP_NONE;
  131. break;
  132. case RESP_R1:
  133. respType = SDH_RESP_R1;
  134. break;
  135. case RESP_R1B:
  136. respType = SDH_RESP_R1B;
  137. break;
  138. case RESP_R2:
  139. respType = SDH_RESP_R2;
  140. break;
  141. case RESP_R3:
  142. respType = SDH_RESP_R3;
  143. break;
  144. case RESP_R4:
  145. respType = SDH_RESP_R4;
  146. break;
  147. case RESP_R5:
  148. respType = SDH_RESP_R5;
  149. break;
  150. case RESP_R6:
  151. respType = SDH_RESP_R6;
  152. break;
  153. case RESP_R7:
  154. respType = SDH_RESP_R7;
  155. break;
  156. default:
  157. respType = SDH_RESP_NONE;
  158. break;
  159. }
  160. return respType;
  161. }
  162. static rt_err_t sdio_host_send_command(SDH_CMD_Cfg_Type *SDH_CMD_Cfg_TypeInstance)
  163. {
  164. SD_Error sd_status;
  165. uint32_t time_node;
  166. SDH_ClearIntStatus(SDH_INT_CMD_COMPLETED | SDH_INT_CMD_ERRORS);
  167. SDH_SendCommand(SDH_CMD_Cfg_TypeInstance);
  168. time_node = (uint32_t)bflb_mtimer_get_time_ms();
  169. uint32_t intFlag;
  170. while (1)
  171. {
  172. intFlag = SDH_GetIntStatus();
  173. if (intFlag & SDH_INT_CMD_ERRORS)
  174. {
  175. sd_status = SD_CMD_ERROR;
  176. break;
  177. }
  178. else if (intFlag & SDH_INT_CMD_COMPLETED)
  179. {
  180. sd_status = SD_OK;
  181. break;
  182. }
  183. else if ((uint32_t)bflb_mtimer_get_time_ms() - time_node > SDIO_CMDTIMEOUT_MS)
  184. {
  185. LOG_D("SDH send CMD%ld timeout: %ld ms", SDH_CMD_Cfg_TypeInstance->index, (uint32_t)bflb_mtimer_get_time_ms() - time_node);
  186. return -RT_ETIMEOUT;
  187. }
  188. BL_DRV_DUMMY;
  189. BL_DRV_DUMMY;
  190. }
  191. SDH_ClearIntStatus(intFlag & (SDH_INT_CMD_ERRORS | SDH_INT_CMD_COMPLETED));
  192. if (sd_status != SD_OK)
  193. {
  194. LOG_E("SDH send CMD%ld error", SDH_CMD_Cfg_TypeInstance->index);
  195. return -RT_ERROR;
  196. }
  197. else
  198. {
  199. LOG_D("SDH send CMD%ld success", SDH_CMD_Cfg_TypeInstance->index);
  200. SDH_CMD_Cfg_TypeInstance->response[0] = BL_RD_REG(SDH_BASE, SDH_SD_RESP_0);
  201. SDH_CMD_Cfg_TypeInstance->response[1] = BL_RD_REG(SDH_BASE, SDH_SD_RESP_2);
  202. SDH_CMD_Cfg_TypeInstance->response[2] = BL_RD_REG(SDH_BASE, SDH_SD_RESP_4);
  203. SDH_CMD_Cfg_TypeInstance->response[3] = BL_RD_REG(SDH_BASE, SDH_SD_RESP_6);
  204. }
  205. return RT_EOK;
  206. }
  207. static rt_err_t SDH_CardTransferNonBlocking(SDH_DMA_Cfg_Type *dmaCfg, SDH_Trans_Cfg_Type *transfer)
  208. {
  209. rt_err_t ret = RT_EOK;
  210. SDH_Stat_Type stat = SDH_STAT_SUCCESS;
  211. stat = SDH_TransferNonBlocking(dmaCfg, transfer);
  212. if (stat != SDH_STAT_SUCCESS) {
  213. LOG_E("SDH_TransferNonBlocking error:%d", stat);
  214. return -RT_ERROR;
  215. }
  216. /* Flush ADMA2-descriptor-table to RAM, Otherwise ADMA2 will fail */
  217. bflb_l1c_dcache_clean_range((void *)(dmaCfg->admaEntries), dmaCfg->maxEntries * sizeof(SDH_ADMA2_Desc_Type));
  218. ret = sdio_host_send_command(transfer->cmdCfg);
  219. if (ret != RT_EOK)
  220. {
  221. LOG_E("sdio_host_send_command error:%d", transfer->cmdCfg->index);
  222. return ret;
  223. }
  224. rt_uint32_t intFlag;
  225. SD_Error sd_status;
  226. rt_uint32_t time_node;
  227. time_node = (uint32_t)bflb_mtimer_get_time_ms();
  228. while (1)
  229. {
  230. intFlag = SDH_GetIntStatus();
  231. if (intFlag & SDH_INT_DATA_ERRORS || intFlag & SDH_INT_DMA_ERROR || intFlag & SDH_INT_AUTO_CMD12_ERROR)
  232. {
  233. sd_status = SD_CMD_ERROR;
  234. break;
  235. }
  236. else if (intFlag & SDH_INT_DATA_COMPLETED)
  237. {
  238. sd_status = SD_OK;
  239. break;
  240. }
  241. else if ((uint32_t)bflb_mtimer_get_time_ms() - time_node > SDIO_CMDTIMEOUT_MS)
  242. {
  243. LOG_E("SDH Transfer data timeout: %ld ms", (uint32_t)bflb_mtimer_get_time_ms() - time_node);
  244. return -RT_ETIMEOUT;
  245. }
  246. BL_DRV_DUMMY;
  247. BL_DRV_DUMMY;
  248. }
  249. SDH_ClearIntStatus(intFlag);
  250. if (sd_status != SD_OK)
  251. {
  252. LOG_E("sd_status :%d", sd_status);
  253. return -RT_ERROR;
  254. }
  255. LOG_D("Transfer data used time: %ld ms", (uint32_t)bflb_mtimer_get_time_ms() - time_node);
  256. return RT_EOK;
  257. }
  258. static rt_err_t rt_hw_sdh_data_transfer(struct rt_mmcsd_host *host, struct rt_mmcsd_cmd *cmd, struct rt_mmcsd_data *data)
  259. {
  260. rt_err_t ret = RT_EOK;
  261. SDH_Data_Cfg_Type SDH_Data_Cfg_TypeInstance;
  262. SDH_CMD_Cfg_Type SDH_CMD_Cfg_TypeInstance;
  263. SDH_Trans_Cfg_Type SDH_Trans_Cfg_TypeInstance = { &SDH_Data_Cfg_TypeInstance, &SDH_CMD_Cfg_TypeInstance };
  264. SDH_CMD_Cfg_TypeInstance.index = cmd->cmd_code;
  265. SDH_CMD_Cfg_TypeInstance.argument = cmd->arg;
  266. SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
  267. SDH_CMD_Cfg_TypeInstance.respType = sdio_host_get_resp_type(cmd);
  268. SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_DATA_PRESENT;
  269. /*set data parameter */
  270. SDH_Data_Cfg_TypeInstance.enableAutoCommand12 = DISABLE;
  271. SDH_Data_Cfg_TypeInstance.enableAutoCommand23 = DISABLE;
  272. SDH_Data_Cfg_TypeInstance.enableIgnoreError = DISABLE;
  273. SDH_Data_Cfg_TypeInstance.dataType = SDH_TRANS_DATA_NORMAL;
  274. SDH_Data_Cfg_TypeInstance.blockSize = data->blksize;
  275. SDH_Data_Cfg_TypeInstance.blockCount = data->blks;
  276. if (cmd->cmd_code == READ_SINGLE_BLOCK || cmd->cmd_code == READ_MULTIPLE_BLOCK)
  277. {
  278. SDH_Data_Cfg_TypeInstance.rxDataLen = 0;
  279. SDH_Data_Cfg_TypeInstance.rxData = (rt_uint32_t *)sdh_buffer;
  280. // SDH_Data_Cfg_TypeInstance.rxData = (rt_uint32_t *)data->buf;
  281. SDH_Data_Cfg_TypeInstance.txDataLen = 0;
  282. SDH_Data_Cfg_TypeInstance.txData = NULL;
  283. }
  284. else
  285. {
  286. rt_memcpy((void *)sdh_buffer, (void *)data->buf, data->blksize);
  287. SDH_Data_Cfg_TypeInstance.rxDataLen = 0;
  288. SDH_Data_Cfg_TypeInstance.rxData = NULL;
  289. SDH_Data_Cfg_TypeInstance.txDataLen = 0;
  290. // SDH_Data_Cfg_TypeInstance.txData = (rt_uint32_t *)data->buf;
  291. SDH_Data_Cfg_TypeInstance.txData = (rt_uint32_t *)sdh_buffer;
  292. }
  293. /*set parameters for SDH_DMA_Cfg_TypeInstance*/
  294. SDH_DMA_Cfg_TypeInstance.dmaMode = SDH_DMA_MODE_ADMA2;
  295. SDH_DMA_Cfg_TypeInstance.burstSize = SDH_BURST_SIZE_128_BYTES;
  296. SDH_DMA_Cfg_TypeInstance.fifoThreshold = SDH_FIFO_THRESHOLD_256_BYTES;
  297. SDH_DMA_Cfg_TypeInstance.admaEntries = (rt_uint32_t *)adma2Entries;
  298. SDH_DMA_Cfg_TypeInstance.maxEntries = sizeof(adma2Entries) / sizeof(adma2Entries[0]);
  299. if (data->flags & DATA_DIR_WRITE)
  300. {
  301. bflb_l1c_dcache_clean_range((void *)(sdh_buffer), data->blksize * data->blks);
  302. }
  303. ret = SDH_CardTransferNonBlocking(&SDH_DMA_Cfg_TypeInstance, &SDH_Trans_Cfg_TypeInstance);
  304. if (ret != RT_EOK)
  305. {
  306. LOG_E("SDH_CardTransferNonBlocking error:%d", ret);
  307. return ret;
  308. }
  309. if (resp_type(cmd) != RESP_NONE)
  310. {
  311. cmd->resp[0] = SDH_CMD_Cfg_TypeInstance.response[0];
  312. LOG_D("resp[0]: %08x", cmd->resp[0]);
  313. }
  314. if (data->flags & DATA_DIR_READ)
  315. {
  316. bflb_l1c_dcache_invalidate_range((void *)(sdh_buffer), data->blksize * data->blks);
  317. rt_memcpy(data->buf, sdh_buffer, data->blks * data->blksize);
  318. }
  319. return RT_EOK;
  320. }
  321. static rt_err_t rt_hw_sdh_cmd_transfer(struct rt_mmcsd_host *host, struct rt_mmcsd_cmd *cmd, struct rt_mmcsd_data *data)
  322. {
  323. rt_err_t ret = RT_EOK;
  324. SDH_Stat_Type stat = SDH_STAT_SUCCESS;
  325. SDH_Data_Cfg_Type SDH_Data_Cfg_TypeInstance;
  326. SDH_CMD_Cfg_Type SDH_CMD_Cfg_TypeInstance;
  327. if (data != RT_NULL)
  328. {
  329. SDH_Data_Cfg_TypeInstance.enableAutoCommand12 = DISABLE;
  330. SDH_Data_Cfg_TypeInstance.enableAutoCommand23 = DISABLE;
  331. SDH_Data_Cfg_TypeInstance.enableIgnoreError = DISABLE;
  332. SDH_Data_Cfg_TypeInstance.dataType = SDH_TRANS_DATA_NORMAL;
  333. SDH_Data_Cfg_TypeInstance.blockSize = data->blksize;
  334. SDH_Data_Cfg_TypeInstance.blockCount = data->blks;
  335. SDH_Data_Cfg_TypeInstance.rxDataLen = 0;
  336. SDH_Data_Cfg_TypeInstance.rxData = (rt_uint32_t *)data->buf;
  337. SDH_Data_Cfg_TypeInstance.txDataLen = 0;
  338. SDH_Data_Cfg_TypeInstance.txData = NULL;
  339. /* Config the data transfer parameter */
  340. stat = SDH_ConfigDataTranfer(&SDH_Data_Cfg_TypeInstance);
  341. if (stat != SDH_STAT_SUCCESS)
  342. {
  343. return -RT_ERROR;
  344. }
  345. SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_DATA_PRESENT;
  346. }
  347. else
  348. {
  349. SDH_CMD_Cfg_TypeInstance.flag = SDH_TRANS_FLAG_NONE;
  350. }
  351. SDH_CMD_Cfg_TypeInstance.index = cmd->cmd_code;
  352. SDH_CMD_Cfg_TypeInstance.argument = cmd->arg;
  353. SDH_CMD_Cfg_TypeInstance.type = SDH_CMD_NORMAL;
  354. SDH_CMD_Cfg_TypeInstance.respType = sdio_host_get_resp_type(cmd);
  355. ret = sdio_host_send_command(&SDH_CMD_Cfg_TypeInstance);
  356. if (ret != RT_EOK)
  357. {
  358. memset(cmd->resp, 0, sizeof(cmd->resp));
  359. return ret;
  360. }
  361. if (resp_type(cmd) != RESP_NONE)
  362. {
  363. if (resp_type(cmd) == RESP_R2)
  364. {
  365. cmd->resp[0] = ((SDH_CMD_Cfg_TypeInstance.response[3] << 8) & ~0xff);
  366. cmd->resp[0] |= ((SDH_CMD_Cfg_TypeInstance.response[2] >> 24) & 0xff);
  367. cmd->resp[1] = ((SDH_CMD_Cfg_TypeInstance.response[2] << 8) & ~0xff);
  368. cmd->resp[1] |= ((SDH_CMD_Cfg_TypeInstance.response[1] >> 24) & 0xff);
  369. cmd->resp[2] = ((SDH_CMD_Cfg_TypeInstance.response[1] << 8) & ~0xff);
  370. cmd->resp[2] |= ((SDH_CMD_Cfg_TypeInstance.response[0] >> 24) & 0xff);
  371. cmd->resp[3] = ((SDH_CMD_Cfg_TypeInstance.response[3] << 8) & ~0xff);
  372. LOG_D("resp[0]: %08x %08x %08x %08x", cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
  373. }
  374. else
  375. {
  376. cmd->resp[0] = SDH_CMD_Cfg_TypeInstance.response[0];
  377. LOG_D("resp[0]: %08x", cmd->resp[0]);
  378. }
  379. }
  380. if (data != RT_NULL)
  381. {
  382. SD_Error sd_status;
  383. uint32_t time_node;
  384. time_node = (uint32_t)bflb_mtimer_get_time_ms();
  385. uint32_t intFlag;
  386. while (1)
  387. {
  388. intFlag = SDH_GetIntStatus();
  389. if (intFlag & SDH_INT_DATA_ERRORS || intFlag & SDH_INT_DMA_ERROR)
  390. {
  391. sd_status = SD_DataCfg_ERROR;
  392. break;
  393. }
  394. else if (intFlag & SDH_INT_BUFFER_READ_READY || intFlag & SDH_INT_DATA_COMPLETED)
  395. {
  396. sd_status = SD_OK;
  397. break;
  398. }
  399. else if ((uint32_t)bflb_mtimer_get_time_ms() - time_node > SDIO_CMDTIMEOUT_MS)
  400. {
  401. LOG_E("SDH get csr data timeout: %ld ms", (uint32_t)bflb_mtimer_get_time_ms() - time_node);
  402. return -RT_ETIMEOUT;
  403. }
  404. BL_DRV_DUMMY;
  405. BL_DRV_DUMMY;
  406. }
  407. SDH_ClearIntStatus(intFlag);
  408. if (sd_status != SD_OK)
  409. {
  410. return -RT_ERROR;
  411. }
  412. if (data->flags & DATA_DIR_READ)
  413. {
  414. rt_uint32_t ret = SDH_ReadDataPort(&SDH_Data_Cfg_TypeInstance);
  415. if (ret <= 0)
  416. return -RT_ERROR;
  417. }
  418. }
  419. return RT_EOK;
  420. }
  421. static void rt_hw_sdh_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
  422. {
  423. RT_ASSERT(host != RT_NULL);
  424. RT_ASSERT(req != RT_NULL);
  425. if (req->cmd != RT_NULL)
  426. {
  427. struct rt_mmcsd_cmd *cmd = req->cmd;
  428. struct rt_mmcsd_data *data = req->data;
  429. LOG_D("[%s%s%s%s%s]REQ: CMD:%d ARG:0x%08x RES:%s%s%s%s%s%s%s%s%s rw:%c addr:%08x, blks:%d, blksize:%d datalen:%d",
  430. (host->card == RT_NULL) ? "Unknown" : "",
  431. (host->card) && (host->card->card_type == CARD_TYPE_MMC) ? "MMC" : "",
  432. (host->card) && (host->card->card_type == CARD_TYPE_SD) ? "SD" : "",
  433. (host->card) && (host->card->card_type == CARD_TYPE_SDIO) ? "SDIO" : "",
  434. (host->card) && (host->card->card_type == CARD_TYPE_SDIO_COMBO) ? "SDIO_COMBO" : "",
  435. cmd->cmd_code,
  436. cmd->arg,
  437. resp_type(cmd) == RESP_NONE ? "NONE" : "",
  438. resp_type(cmd) == RESP_R1 ? "R1" : "",
  439. resp_type(cmd) == RESP_R1B ? "R1B" : "",
  440. resp_type(cmd) == RESP_R2 ? "R2" : "",
  441. resp_type(cmd) == RESP_R3 ? "R3" : "",
  442. resp_type(cmd) == RESP_R4 ? "R4" : "",
  443. resp_type(cmd) == RESP_R5 ? "R5" : "",
  444. resp_type(cmd) == RESP_R6 ? "R6" : "",
  445. resp_type(cmd) == RESP_R7 ? "R7" : "",
  446. data ? (data->flags & DATA_DIR_WRITE ? 'w' : 'r') : '-',
  447. data ? data->buf : 0,
  448. data ? data->blks : 0,
  449. data ? data->blksize : 0,
  450. data ? data->blks * data->blksize : 0);
  451. if (cmd->cmd_code == READ_SINGLE_BLOCK || cmd->cmd_code == READ_MULTIPLE_BLOCK || \
  452. cmd->cmd_code == WRITE_BLOCK || cmd->cmd_code == WRITE_MULTIPLE_BLOCK)
  453. {
  454. cmd->err = rt_hw_sdh_data_transfer(host, cmd, data);
  455. }
  456. else
  457. {
  458. cmd->err = rt_hw_sdh_cmd_transfer(host, cmd, data);
  459. if (cmd->cmd_code == SD_SEND_IF_COND && cmd->err != RT_EOK)
  460. {
  461. LOG_D("retry cmd: %d", SD_SEND_IF_COND);
  462. struct rt_mmcsd_cmd user_cmd;
  463. rt_uint8_t retries = 0;
  464. rt_err_t ret = RT_EOK;
  465. do
  466. {
  467. rt_memset(&user_cmd, 0, sizeof(struct rt_mmcsd_cmd));
  468. user_cmd.cmd_code = GO_IDLE_STATE;
  469. user_cmd.arg = 0;
  470. user_cmd.flags = RESP_SPI_R1 | RESP_NONE | CMD_BC;
  471. rt_hw_sdh_cmd_transfer(host, &user_cmd, RT_NULL);
  472. rt_thread_mdelay(1);
  473. cmd->err = rt_hw_sdh_cmd_transfer(host, cmd, data);
  474. if(cmd->err == RT_EOK)
  475. {
  476. break;
  477. }
  478. retries ++;
  479. LOG_D("cmd: %d retries: %d", SD_SEND_IF_COND, retries);
  480. }
  481. while (retries < 3);
  482. }
  483. }
  484. }
  485. if (req->stop != RT_NULL)
  486. {
  487. struct rt_mmcsd_cmd *stop = req->stop;
  488. stop->err = rt_hw_sdh_cmd_transfer(host, stop, RT_NULL);
  489. }
  490. mmcsd_req_complete(host);
  491. }
  492. static void rt_hw_sdh_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
  493. {
  494. rt_uint32_t clk;
  495. RT_ASSERT(host != RT_NULL);
  496. RT_ASSERT(io_cfg != RT_NULL);
  497. clk = io_cfg->clock;
  498. LOG_D("clk:%d width:%s%s%s power:%s%s%s",
  499. clk,
  500. io_cfg->bus_width == MMCSD_BUS_WIDTH_8 ? "8" : "",
  501. io_cfg->bus_width == MMCSD_BUS_WIDTH_4 ? "4" : "",
  502. io_cfg->bus_width == MMCSD_BUS_WIDTH_1 ? "1" : "",
  503. io_cfg->power_mode == MMCSD_POWER_OFF ? "OFF" : "",
  504. io_cfg->power_mode == MMCSD_POWER_UP ? "UP" : "",
  505. io_cfg->power_mode == MMCSD_POWER_ON ? "ON" : ""
  506. );
  507. /* clock */
  508. if (clk > host->freq_max)
  509. clk = host->freq_max;
  510. if (clk < host->freq_min)
  511. clk = host->freq_min;
  512. /* power mode */
  513. switch (io_cfg->power_mode)
  514. {
  515. case MMCSD_POWER_UP:
  516. break;
  517. case MMCSD_POWER_ON:
  518. SDH_Powon();
  519. break;
  520. case MMCSD_POWER_OFF:
  521. break;
  522. default:
  523. break;
  524. }
  525. /* bus width */
  526. switch (io_cfg->bus_width)
  527. {
  528. case MMCSD_BUS_WIDTH_1:
  529. sdh_set_bus_width(SDH_DATA_BUS_WIDTH_1BIT);
  530. break;
  531. case MMCSD_BUS_WIDTH_4:
  532. sdh_set_bus_width(SDH_DATA_BUS_WIDTH_4BITS);
  533. break;
  534. case MMCSD_BUS_WIDTH_8:
  535. sdh_set_bus_width(SDH_DATA_BUS_WIDTH_8BITS);
  536. break;
  537. default:
  538. LOG_E("nonsupport bus width: %d", io_cfg->bus_width);
  539. break;
  540. }
  541. }
  542. static const struct rt_mmcsd_host_ops ops =
  543. {
  544. rt_hw_sdh_request,
  545. rt_hw_sdh_iocfg,
  546. RT_NULL,
  547. RT_NULL,
  548. };
  549. int rt_hw_sdh_init(void)
  550. {
  551. struct rt_mmcsd_host *host;
  552. host = mmcsd_alloc_host();
  553. RT_ASSERT(host != RT_NULL);
  554. sdh_clock_init();
  555. sdh_gpio_init();
  556. /* reset SDH controller*/
  557. SDH_Reset();
  558. sdio_host_init();
  559. /* set host default attributes */
  560. host->ops = &ops;
  561. host->freq_min = 40 * 1000;
  562. host->freq_max = 50 * 1000 * 1000;
  563. host->valid_ocr = VDD_31_32 | VDD_32_33 | VDD_33_34;
  564. host->flags = MMCSD_MUTBLKWRITE | MMCSD_SUP_HIGHSPEED | MMCSD_BUSWIDTH_4;
  565. host->max_seg_size = SDIO_BUFF_SIZE;
  566. host->max_dma_segs = 1;
  567. host->max_blk_size = 512;
  568. host->max_blk_count = 512;
  569. /* link up host and sdio */
  570. host->private_data = host;
  571. mmcsd_change(host);
  572. return 0;
  573. }
  574. INIT_DEVICE_EXPORT(rt_hw_sdh_init);
  575. #endif /* RT_USING_DFS */