drv_sdio.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  1. /**************************************************************************//**
  2. *
  3. * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. *
  7. * Change Logs:
  8. * Date Author Notes
  9. * 2022-4-21 Wayne First version
  10. *
  11. ******************************************************************************/
  12. #include "rtconfig.h"
  13. #if defined(BSP_USING_SDH)
  14. #include <rtdevice.h>
  15. #include <drivers/mmcsd_core.h>
  16. #include <drivers/sdio.h>
  17. #include "NuMicro.h"
  18. #define LOG_TAG "drv.sdh"
  19. #undef DBG_ENABLE
  20. #define DBG_SECTION_NAME LOG_TAG
  21. #define DBG_LEVEL LOG_LVL_ASSERT
  22. #define DBG_COLOR
  23. #include <rtdbg.h>
  24. #define SDH_ALIGN_LEN 4
  25. #define SDH_BUFF_SIZE 512
  26. #define SDH_BLOCK_SIZE 512
  27. enum
  28. {
  29. SDH_START = -1,
  30. #if defined(BSP_USING_SDH0)
  31. SDH0_IDX,
  32. #endif
  33. #if defined(BSP_USING_SDH1)
  34. SDH1_IDX,
  35. #endif
  36. SDH_CNT
  37. };
  38. struct nu_sdh
  39. {
  40. struct rt_mmcsd_host *host;
  41. char *name;
  42. SDH_T *base;
  43. IRQn_Type irqn;
  44. uint32_t rstidx;
  45. uint32_t modid;
  46. uint8_t *cachebuf;
  47. uint32_t u32CmdResp0;
  48. uint32_t u32CmdResp1;
  49. uint32_t u32CurClk;
  50. rt_tick_t LastNotice;
  51. };
  52. typedef struct nu_sdh *nu_sdh_t;
  53. /* Private variables ------------------------------------------------------------*/
  54. static struct nu_sdh nu_sdh_arr [] =
  55. {
  56. #if defined(BSP_USING_SDH0)
  57. {
  58. .name = "sdh0",
  59. .base = SDH0,
  60. .irqn = SDH0_IRQn,
  61. .rstidx = SDH0_RST,
  62. .modid = SDH0_MODULE,
  63. .cachebuf = RT_NULL,
  64. },
  65. #endif
  66. #if defined(BSP_USING_SDH1)
  67. {
  68. .name = "sdh1",
  69. .base = SDH1,
  70. .irqn = SDH1_IRQn,
  71. .rstidx = SDH1_RST,
  72. .modid = SDH1_MODULE,
  73. .cachebuf = RT_NULL,
  74. },
  75. #endif
  76. }; /* struct nu_sdh nu_sdh_arr [] */
  77. #define SDH_SetClock SDH_Set_clock
  78. static int SDH_SetBusWidth(SDH_T *sdh, uint32_t bw)
  79. {
  80. if (bw == 4)
  81. {
  82. sdh->CTL |= SDH_CTL_DBW_Msk;
  83. }
  84. else if (bw == 1)
  85. {
  86. sdh->CTL &= ~SDH_CTL_DBW_Msk;
  87. }
  88. else
  89. {
  90. goto exit_SDH_SetBusWidth;
  91. }
  92. return 0;
  93. exit_SDH_SetBusWidth:
  94. return -1;
  95. }
  96. static int SDH_GetBusStatus(SDH_T *sdh, uint32_t mask)
  97. {
  98. int cnt = 0x100000;
  99. while (cnt-- > 0)
  100. {
  101. sdh->CTL |= SDH_CTL_CLK8OEN_Msk;
  102. while (sdh->CTL & SDH_CTL_CLK8OEN_Msk) { }
  103. if (SDH_GET_INT_FLAG(sdh, SDH_INTSTS_DAT0STS_Msk))
  104. break;
  105. }
  106. return (cnt == 0) ? -1 : 0 ;
  107. }
  108. static int SDH_GetCD(SDH_T *sdh)
  109. {
  110. int i32CD = 0;
  111. if ((sdh->GCTL & SDH_GCTL_SDEN_Msk) == SDH_GCTL_SDEN_Msk)
  112. {
  113. if ((sdh->INTEN & SDH_INTEN_CDSRC_Msk) == SDH_INTEN_CDSRC_Msk) /* Card detect pin from GPIO */
  114. {
  115. i32CD = (sdh->INTSTS & SDH_INTSTS_CDSTS_Msk) ? 0 : 1;
  116. }
  117. else /* Card detect pin from DAT3 mode */
  118. {
  119. __IO uint32_t i;
  120. sdh->CTL |= SDH_CTL_CLKKEEP_Msk;
  121. for (i = 0ul; i < 5000ul; i++) { }
  122. i32CD = ((sdh->INTSTS & SDH_INTSTS_CDSTS_Msk) == SDH_INTSTS_CDSTS_Msk) ? 1 : 0;
  123. sdh->CTL &= ~SDH_CTL_CLKKEEP_Msk;
  124. }
  125. }
  126. return i32CD;
  127. }
  128. static void SDH_Enable(SDH_T *sdh)
  129. {
  130. /* Reset sdh and its DMA engine at first. */
  131. sdh->DMACTL |= SDH_DMACTL_DMARST_Msk | SDH_DMACTL_DMAEN_Msk;
  132. while ((sdh->DMACTL & SDH_DMACTL_DMARST_Msk) == SDH_DMACTL_DMARST_Msk) { }
  133. sdh->DMACTL = SDH_DMACTL_DMAEN_Msk;
  134. sdh->DMAINTSTS = SDH_DMAINTSTS_ABORTIF_Msk | SDH_DMAINTSTS_WEOTIF_Msk; // clear all interrupt flag
  135. sdh->GCTL = SDH_GCTL_GCTLRST_Msk;
  136. while ((sdh->GCTL & SDH_GCTL_GCTLRST_Msk) == SDH_GCTL_GCTLRST_Msk) { }// clear all interrupt flag
  137. sdh->GINTSTS = SDH_GINTSTS_DTAIF_Msk;
  138. sdh->GCTL = SDH_GCTL_SDEN_Msk;
  139. sdh->CTL |= SDH_CTL_CTLRST_Msk;
  140. while ((sdh->CTL & SDH_CTL_CTLRST_Msk) == SDH_CTL_CTLRST_Msk) { }
  141. sdh->INTSTS = 0xFFFFFFFF; // clear all interrupt flag
  142. sdh->INTEN |= SDH_INTEN_CDSRC_Msk;
  143. sdh->INTEN |= SDH_INTEN_CDIEN_Msk;
  144. }
  145. /**
  146. * @brief This function get command responding.
  147. * @param sdh SDH instance
  148. * @param cmd rt_mmcsd_cmd
  149. * @retval none
  150. */
  151. static void nu_sdh_sendcmd_done(SDH_T *sdh, struct rt_mmcsd_cmd *cmd)
  152. {
  153. if (resp_type(cmd) == RESP_R2)
  154. {
  155. uint8_t *c = (uint8_t *)&sdh->FB[0];
  156. int i, j, tmp[5];
  157. for (i = 0, j = 0; j < 5; i += 4, j++)
  158. {
  159. tmp[j] = (*(c + i) << 24) | (*(c + i + 1) << 16) | (*(c + i + 2) << 8) | (*(c + i + 3));
  160. }
  161. for (i = 0; i < 4; i++)
  162. {
  163. cmd->resp[i] = ((tmp[i] & 0x00ffffff) << 8) |
  164. ((tmp[i + 1] & 0xff000000) >> 24);
  165. }
  166. }
  167. else
  168. {
  169. cmd->resp[0] = (sdh->RESP0 << 8) | (sdh->RESP1 & 0xff);
  170. cmd->resp[1] = cmd->resp[2] = cmd->resp[3] = 0;
  171. }
  172. }
  173. /**
  174. * @brief This function wait data-sending/receiving.
  175. * @param sdh SDH instance
  176. * @param data rt_mmcsd_data
  177. * @retval error code
  178. */
  179. static int nu_sdh_xfer_data(SDH_T *sdh, struct rt_mmcsd_data *data)
  180. {
  181. while (!SDH_GET_INT_FLAG(sdh, SDH_INTSTS_BLKDIF_Msk)) { }
  182. SDH_CLR_INT_FLAG(sdh, SDH_INTSTS_BLKDIF_Msk);
  183. if (data->flags & DATA_DIR_WRITE)
  184. {
  185. sdh->CTL |= SDH_CTL_CLKKEEP_Msk;
  186. while (!SDH_GET_INT_FLAG(sdh, SDH_INTSTS_DAT0STS_Msk)) { }
  187. sdh->CTL &= ~SDH_CTL_CLKKEEP_Msk;
  188. }
  189. return 0;
  190. }
  191. /**
  192. * @brief This function send command and wait its response.
  193. * @param host rt_mmcsd_host
  194. * @param cmd rt_mmcsd_cmd
  195. * @param data rt_mmcsd_data
  196. * @retval error code
  197. */
  198. static int nu_sdh_sendcmd(struct rt_mmcsd_host *host, struct rt_mmcsd_cmd *cmd, struct rt_mmcsd_data *data)
  199. {
  200. int ret;
  201. nu_sdh_t NuSdh = (nu_sdh_t)host->private_data;
  202. SDH_T *sdh = NuSdh->base;
  203. volatile uint32_t ctl = 0, tout = 0;
  204. switch (host->io_cfg.bus_width)
  205. {
  206. case MMCSD_BUS_WIDTH_1:
  207. ctl &= ~SDH_CTL_DBW_Msk;
  208. break;
  209. case MMCSD_BUS_WIDTH_4:
  210. ctl |= SDH_CTL_DBW_Msk;
  211. break;
  212. case MMCSD_BUS_WIDTH_8:
  213. default:
  214. return -1;
  215. }
  216. /* Reset sdh and its DMA engine at first. */
  217. sdh->DMACTL |= SDH_DMACTL_DMARST_Msk | SDH_DMACTL_DMAEN_Msk;
  218. while ((sdh->DMACTL & SDH_DMACTL_DMARST_Msk) == SDH_DMACTL_DMARST_Msk) { }
  219. sdh->DMACTL = SDH_DMACTL_DMAEN_Msk;
  220. sdh->DMAINTSTS = SDH_DMAINTSTS_ABORTIF_Msk | SDH_DMAINTSTS_WEOTIF_Msk; // clear all interrupt flag
  221. if (resp_type(cmd) != RESP_NONE)
  222. {
  223. if (resp_type(cmd) == RESP_R2)
  224. {
  225. ctl |= SDH_CTL_R2EN_Msk;
  226. }
  227. else
  228. {
  229. ctl |= SDH_CTL_RIEN_Msk;
  230. }
  231. tout = 0xFFFF;
  232. }
  233. /* Set SDNWR and BLK_CNT to 1 */
  234. ctl |= ((9 << SDH_CTL_SDNWR_Pos) | (1 << SDH_CTL_BLKCNT_Pos));
  235. ctl |= ((cmd->cmd_code << SDH_CTL_CMDCODE_Pos) | SDH_CTL_COEN_Msk);
  236. /* Set Transfer mode regarding to data flag */
  237. if (data != RT_NULL)
  238. {
  239. sdh->BLEN = data->blksize - 1;
  240. if (data->blksize <= 0x200)
  241. {
  242. if (data->blks < 256)
  243. {
  244. ctl = (ctl & ~SDH_CTL_BLKCNT_Msk) | (data->blks << SDH_CTL_BLKCNT_Pos);
  245. }
  246. else
  247. {
  248. LOG_E("SD Max block transfer is 255!!");
  249. }
  250. }
  251. if (data->flags & DATA_DIR_READ)
  252. {
  253. tout = 0xFFFFFF;
  254. ctl |= SDH_CTL_DIEN_Msk; // Data-in
  255. sdh->DMASA = (uint32_t)data->buf; // Read from dest
  256. }
  257. else if (data->flags & DATA_DIR_WRITE)
  258. {
  259. ctl |= SDH_CTL_DOEN_Msk; // Data-out
  260. sdh->DMASA = (uint32_t)data->buf; // Write to dest
  261. }
  262. }
  263. else if (resp_type(cmd) == RESP_R1B)
  264. {
  265. }
  266. /* Clear response-timeout flag first for safty and reset new timeout value. */
  267. SDH_CLR_INT_FLAG(sdh, SDH_INTSTS_RTOIF_Msk);
  268. sdh->TOUT = tout;
  269. /* Set argument and start a transaction. */
  270. sdh->CMDARG = cmd->arg;
  271. sdh->CTL = ctl;
  272. /* Wait a command done. */
  273. while ((sdh->CTL & (SDH_CTL_COEN_Msk)) == SDH_CTL_COEN_Msk) { }
  274. if (resp_type(cmd) != RESP_NONE)
  275. {
  276. if (resp_type(cmd) == RESP_R2)
  277. {
  278. /* Wait to receive a response R2 from SD card and store the response data into DMC's Flash buffer (exclude CRC7). */
  279. while (sdh->CTL & SDH_CTL_R2EN_Msk)
  280. {
  281. /* When get a Response timeout, break the polling. */
  282. if (SDH_GET_INT_FLAG(sdh, SDH_INTSTS_RTOIF_Msk))
  283. {
  284. ret = __LINE__;
  285. goto exit_nu_sdh_sendcmd;
  286. }
  287. }
  288. }
  289. else
  290. {
  291. /* Wait to receive a response from SD card. */
  292. while ((sdh->CTL & SDH_CTL_RIEN_Msk))
  293. {
  294. /* When get a Response timeout, break the polling. */
  295. if (SDH_GET_INT_FLAG(sdh, SDH_INTSTS_RTOIF_Msk))
  296. {
  297. ret = __LINE__;
  298. goto exit_nu_sdh_sendcmd;
  299. }
  300. }
  301. /* TOFIX: ISSUE: Sometimes, SDH's RIEN is cleared automatically by controller after host sending CMD5 to SD card. */
  302. /* Workaround: To check previous cmd's response with CMD's. */
  303. if (cmd->cmd_code == 5)
  304. {
  305. if ((NuSdh->u32CmdResp0 == sdh->RESP0) && (NuSdh->u32CmdResp1 == sdh->RESP1))
  306. {
  307. LOG_E("False CMD5-RESP issue occured.\n");
  308. ret = __LINE__;
  309. goto exit_nu_sdh_sendcmd;
  310. }
  311. }
  312. NuSdh->u32CmdResp0 = sdh->RESP0;
  313. NuSdh->u32CmdResp1 = sdh->RESP1;
  314. }
  315. /* Get response from FB or register */
  316. nu_sdh_sendcmd_done(sdh, cmd);
  317. }
  318. if (data != RT_NULL)
  319. {
  320. /* Wait data processing done */
  321. nu_sdh_xfer_data(sdh, data);
  322. ret = SDH_GetBusStatus(sdh, 0);
  323. if (ret)
  324. {
  325. LOG_E("ERROR: Busy %d\n", ret);
  326. ret = __LINE__;
  327. goto exit_nu_sdh_sendcmd;
  328. }
  329. }
  330. /* Handle CRC flag */
  331. if (SDH_GET_INT_FLAG(sdh, SDH_INTSTS_CRCIF_Msk)) // Fault
  332. {
  333. uint32_t u32INTSTS = sdh->INTSTS;
  334. SDH_CLR_INT_FLAG(sdh, SDH_INTSTS_CRCIF_Msk);
  335. ret = __LINE__;
  336. if ((resp_type(cmd) != RESP_R3) && (u32INTSTS & SDH_INTSTS_CRC7_Msk) == 0) //CRC7, Ignore R3
  337. {
  338. LOG_E("CRC7 error! (resp_type=%d)", resp_type(cmd));
  339. goto exit_nu_sdh_sendcmd;
  340. }
  341. if ((u32INTSTS & SDH_INTSTS_CRC16_Msk) == 0) //CRC16
  342. {
  343. LOG_E("CRC16 error! (resp_type=%d)", resp_type(cmd));
  344. goto exit_nu_sdh_sendcmd;
  345. }
  346. }
  347. return 0;
  348. exit_nu_sdh_sendcmd:
  349. LOG_D("[%s %d] cmdid=%d error line=%d", __func__, __LINE__, cmd->cmd_code, ret);
  350. cmd->resp[0] = cmd->resp[1] = cmd->resp[2] = cmd->resp[3] = 0;
  351. sdh->TOUT = 0;
  352. SDH_Enable(sdh);
  353. return -ret;
  354. }
  355. /**
  356. * @brief This function send request.
  357. * @param host rt_mmcsd_host
  358. * @param req request
  359. * @retval None
  360. */
  361. static void nu_sdh_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
  362. {
  363. nu_sdh_t NuSdh;
  364. SDH_T *sdh;
  365. RT_ASSERT(host);
  366. RT_ASSERT(req);
  367. NuSdh = (nu_sdh_t)host->private_data;
  368. sdh = NuSdh->base;
  369. if (!SDH_GetCD(sdh)) // card is not present
  370. {
  371. LOG_E("Card is not present");
  372. req->cmd->err = -RT_EIO;
  373. goto exit_nu_sdh_request;
  374. }
  375. if (req->cmd != RT_NULL)
  376. {
  377. struct rt_mmcsd_cmd *cmd = req->cmd;
  378. struct rt_mmcsd_data *data = req->data;
  379. LOG_D("[%s%s%s%s%s]REQ: CMD:%d ARG:0x%08x RESP_TYPE:%d rw:%c addr:%08x, blks:%d, blksize:%d datalen:%d",
  380. (host->card == RT_NULL) ? "Unknown" : "",
  381. (host->card) && (host->card->card_type == CARD_TYPE_MMC) ? "MMC" : "",
  382. (host->card) && (host->card->card_type == CARD_TYPE_SD) ? "SD" : "",
  383. (host->card) && (host->card->card_type == CARD_TYPE_SDIO) ? "SDIO" : "",
  384. (host->card) && (host->card->card_type == CARD_TYPE_SDIO_COMBO) ? "SDIO_COMBO" : "",
  385. cmd->cmd_code,
  386. cmd->arg,
  387. resp_type(cmd),
  388. data ? (data->flags & DATA_DIR_WRITE ? 'w' : 'r') : '-',
  389. data ? data->buf : 0,
  390. data ? data->blks : 0,
  391. data ? data->blksize : 0,
  392. data ? data->blks * data->blksize : 0);
  393. if (data != RT_NULL)
  394. {
  395. rt_uint32_t size;
  396. rt_int32_t IsNonaligned = 0;
  397. rt_uint32_t *org_data_buf = data->buf;
  398. size = data->blksize * data->blks;
  399. RT_ASSERT(org_data_buf);
  400. IsNonaligned = (((rt_uint32_t)data->buf & (SDH_ALIGN_LEN - 1)) > 0) ? 1 : 0;
  401. if (IsNonaligned)
  402. {
  403. /* Allocate memory temp buffer on demand. */
  404. RT_ASSERT(size <= SDH_BUFF_SIZE);
  405. if (NuSdh->cachebuf == RT_NULL)
  406. {
  407. NuSdh->cachebuf = rt_malloc_align(SDH_BUFF_SIZE, SDH_ALIGN_LEN);
  408. RT_ASSERT(NuSdh->cachebuf);
  409. }
  410. data->buf = (rt_uint32_t *)NuSdh->cachebuf;
  411. if (data->flags & DATA_DIR_WRITE)
  412. {
  413. LOG_D("Un-aligned, prepare into cache buf(%d)", size);
  414. rt_memcpy(data->buf, org_data_buf, size);
  415. }
  416. }
  417. cmd->err = nu_sdh_sendcmd(host, cmd, data);
  418. if (!cmd->err && IsNonaligned)
  419. {
  420. if (data->flags & DATA_DIR_READ)
  421. {
  422. LOG_D("Un-aligned, restore from cache buf(%d)", size);
  423. rt_memcpy(org_data_buf, data->buf, size);
  424. }
  425. }
  426. data->buf = org_data_buf;
  427. LOG_HEX("data.dest", 16, (void *)data->buf, size);
  428. }
  429. else
  430. {
  431. cmd->err = nu_sdh_sendcmd(host, cmd, NULL);
  432. }
  433. if (resp_type(cmd) != RESP_NONE)
  434. LOG_HEX("cmd->resp", 16, (void *)&cmd->resp[0], 16);
  435. }
  436. if (req->stop != RT_NULL)
  437. {
  438. struct rt_mmcsd_cmd *stop = req->stop;
  439. stop->err = nu_sdh_sendcmd(host, stop, NULL);
  440. if (resp_type(stop) != RESP_NONE)
  441. LOG_HEX("stop->resp", 16, (void *)&stop->resp[0], 16);
  442. }
  443. exit_nu_sdh_request:
  444. mmcsd_req_complete(host);
  445. }
  446. /**
  447. * @brief This function config.
  448. * @param host rt_mmcsd_host
  449. * @param io_cfg rt_mmcsd_io_cfg
  450. * @retval None
  451. */
  452. static void nu_sdh_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
  453. {
  454. nu_sdh_t NuSdh;
  455. rt_uint32_t clk;
  456. SDH_T *sdh;
  457. RT_ASSERT(host);
  458. RT_ASSERT(io_cfg);
  459. NuSdh = (nu_sdh_t)host->private_data;
  460. sdh = NuSdh->base;
  461. clk = io_cfg->clock;
  462. LOG_D("[%s]clk:%d width(%d):%s%s%s power:%s%s%s",
  463. NuSdh->name,
  464. clk,
  465. io_cfg->bus_width,
  466. (io_cfg->bus_width) == MMCSD_BUS_WIDTH_8 ? "8" : "",
  467. (io_cfg->bus_width) == MMCSD_BUS_WIDTH_4 ? "4" : "",
  468. (io_cfg->bus_width) == MMCSD_BUS_WIDTH_1 ? "1" : "",
  469. io_cfg->power_mode == MMCSD_POWER_OFF ? "OFF" : "",
  470. io_cfg->power_mode == MMCSD_POWER_UP ? "UP" : "",
  471. io_cfg->power_mode == MMCSD_POWER_ON ? "ON" : "");
  472. /* Clock */
  473. if (clk > host->freq_max)
  474. clk = host->freq_max;
  475. if (clk < host->freq_min)
  476. clk = host->freq_min;
  477. LOG_D("[%s] ExceptedFreq: %d kHz", NuSdh->name, clk / 1000);
  478. if (NuSdh->u32CurClk != (clk / 1000))
  479. {
  480. SDH_SetClock(sdh, clk / 1000);
  481. NuSdh->u32CurClk = (clk / 1000);
  482. }
  483. switch (io_cfg->power_mode)
  484. {
  485. case MMCSD_POWER_UP:
  486. if (clk <= 400000)
  487. {
  488. /* power ON 74 clock */
  489. sdh->CTL |= SDH_CTL_CLK74OEN_Msk;
  490. while ((sdh->CTL & SDH_CTL_CLK74OEN_Msk) == SDH_CTL_CLK74OEN_Msk)
  491. {
  492. }
  493. }
  494. break;
  495. case MMCSD_POWER_ON:
  496. break;
  497. case MMCSD_POWER_OFF:
  498. break;
  499. default:
  500. break;
  501. }
  502. /* Bus width */
  503. switch ((io_cfg->bus_width))
  504. {
  505. case MMCSD_BUS_WIDTH_1:
  506. SDH_SetBusWidth(sdh, 1);
  507. break;
  508. case MMCSD_BUS_WIDTH_4:
  509. SDH_SetBusWidth(sdh, 4);
  510. break;
  511. case MMCSD_BUS_WIDTH_8:
  512. default:
  513. break;
  514. }
  515. }
  516. /**
  517. * @brief This function detect sdcard.
  518. * @param host rt_mmcsd_host
  519. * @retval card detection status
  520. */
  521. static rt_int32_t nu_sdh_card_detect(struct rt_mmcsd_host *host)
  522. {
  523. nu_sdh_t NuSdh;
  524. RT_ASSERT(host);
  525. NuSdh = (nu_sdh_t)host->private_data;
  526. SDH_T *sdh = NuSdh->base;
  527. LOG_D("try to detect device");
  528. return SDH_GetCD(sdh);
  529. }
  530. static void nu_sdh_isr(nu_sdh_t NuSdh)
  531. {
  532. SDH_T *sdh = NuSdh->base;
  533. uint32_t isr = sdh->INTSTS;
  534. /* card detected */
  535. if (isr & SDH_INTSTS_CDIF_Msk)
  536. {
  537. rt_tick_t cur_tick = rt_tick_get();
  538. rt_tick_t diff_tick;
  539. /* ready to change */
  540. if (cur_tick >= NuSdh->LastNotice)
  541. diff_tick = (cur_tick - NuSdh->LastNotice);
  542. else
  543. diff_tick = ((rt_tick_t) -1) - NuSdh->LastNotice + cur_tick;
  544. if (!NuSdh->LastNotice || (diff_tick > (RT_TICK_PER_SECOND / 5))) // Debounce 200ms
  545. {
  546. NuSdh->LastNotice = cur_tick;
  547. mmcsd_change(NuSdh->host);
  548. }
  549. /* Clear CDIF interrupt flag */
  550. SDH_CLR_INT_FLAG(sdh, SDH_INTSTS_CDIF_Msk);
  551. }
  552. }
  553. #if defined(BSP_USING_SDH0)
  554. void SDH0_IRQHandler(void)
  555. {
  556. /* enter interrupt */
  557. rt_interrupt_enter();
  558. nu_sdh_isr(&nu_sdh_arr[SDH0_IDX]);
  559. /* leave interrupt */
  560. rt_interrupt_leave();
  561. }
  562. #endif
  563. #if defined(BSP_USING_SDH1)
  564. void SDH1_IRQHandler(void)
  565. {
  566. /* enter interrupt */
  567. rt_interrupt_enter();
  568. nu_sdh_isr(&nu_sdh_arr[SDH1_IDX]);
  569. /* leave interrupt */
  570. rt_interrupt_leave();
  571. }
  572. #endif
  573. /**
  574. * @brief This function update sdh interrupt.
  575. * @param host rt_mmcsd_host
  576. * @param enable
  577. * @retval None
  578. */
  579. void nu_sdh_irq_update(struct rt_mmcsd_host *host, rt_int32_t enable)
  580. {
  581. nu_sdh_t NuSdh = (nu_sdh_t)host->private_data;
  582. SDH_T *sdh = NuSdh->base;
  583. if (enable)
  584. {
  585. LOG_D("Enable %s irq", NuSdh->name);
  586. SDH_ENABLE_INT(sdh, SDH_INTSTS_CDIF_Msk);
  587. }
  588. else
  589. {
  590. LOG_D("Disable %s irq", NuSdh->name);
  591. SDH_DISABLE_INT(sdh, SDH_INTSTS_CDIF_Msk);
  592. }
  593. }
  594. static const struct rt_mmcsd_host_ops ops =
  595. {
  596. nu_sdh_request,
  597. nu_sdh_iocfg,
  598. nu_sdh_card_detect,
  599. nu_sdh_irq_update,
  600. };
  601. /**
  602. * @brief This function create mmcsd host.
  603. * @param sdh nu_sdh_t
  604. * @retval nuvton
  605. */
  606. void nu_sdh_host_init(nu_sdh_t sdh)
  607. {
  608. struct rt_mmcsd_host *host = mmcsd_alloc_host();
  609. RT_ASSERT(host);
  610. /* set host default attributes */
  611. host->ops = &ops;
  612. host->freq_min = 300 * 1000;
  613. host->freq_max = 48 * 1000 * 1000;
  614. host->valid_ocr = VDD_26_27 | VDD_27_28 | VDD_28_29 | VDD_29_30 | VDD_30_31 | VDD_31_32 | VDD_32_33 | VDD_33_34;
  615. host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_HIGHSPEED;
  616. host->max_seg_size = SDH_BUFF_SIZE;
  617. host->max_dma_segs = 1;
  618. host->max_blk_size = SDH_BLOCK_SIZE;
  619. host->max_blk_count = (SDH_BUFF_SIZE / SDH_BLOCK_SIZE);
  620. /* link up host and sdio */
  621. host->private_data = sdh;
  622. sdh->host = host;
  623. /* Enable DMA engine at first. */
  624. SDH_Enable(sdh->base);
  625. /* Install ISR. */
  626. NVIC_EnableIRQ(sdh->irqn);
  627. /* ready to change */
  628. //mmcsd_change(host);
  629. }
  630. static int rt_hw_sdh_init(void)
  631. {
  632. int i;
  633. for (i = (SDH_START + 1); i < SDH_CNT; i++)
  634. {
  635. CLK_EnableModuleClock(nu_sdh_arr[i].modid);
  636. SYS_ResetModule(nu_sdh_arr[i].rstidx);
  637. nu_sdh_host_init(&nu_sdh_arr[i]);
  638. }
  639. return 0;
  640. }
  641. INIT_DEVICE_EXPORT(rt_hw_sdh_init);
  642. void nu_sd_attach(void)
  643. {
  644. int i;
  645. /* ready to change */
  646. for (i = (SDH_START + 1); i < SDH_CNT; i++)
  647. {
  648. if (nu_sdh_arr[i].host)
  649. mmcsd_change(nu_sdh_arr[i].host);
  650. }
  651. }
  652. MSH_CMD_EXPORT(nu_sd_attach, attach card);
  653. void nu_sd_regdump(void)
  654. {
  655. int i;
  656. for (i = (SDH_START + 1); i < SDH_CNT; i++)
  657. {
  658. if (nu_sdh_arr[i].host)
  659. LOG_HEX("sdh_reg", 16, (void *)nu_sdh_arr[i].base, sizeof(SDH_T));
  660. }
  661. }
  662. MSH_CMD_EXPORT(nu_sd_regdump, dump sdh registers);
  663. #endif