drv_sdio.c 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061
  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. * 2021-11-19 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. #include "drv_common.h"
  19. #define LOG_TAG "drv.sdio"
  20. #undef DBG_ENABLE
  21. #define DBG_SECTION_NAME LOG_TAG
  22. #define DBG_LEVEL LOG_LVL_INFO
  23. #define DBG_COLOR
  24. #include <rtdbg.h>
  25. #define SDH_ALIGN_LEN 64
  26. #define SDH_BUFF_SIZE (512*1024)
  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. struct rt_event event;
  48. };
  49. typedef struct nu_sdh *nu_sdh_t;
  50. /* Private variables ------------------------------------------------------------*/
  51. #if defined(BSP_USING_SDH0)
  52. rt_align(SDH_ALIGN_LEN)
  53. static uint8_t g_au8CacheBuf_SDH0[SDH_BUFF_SIZE];
  54. #endif
  55. #if defined(BSP_USING_SDH1)
  56. rt_align(SDH_ALIGN_LEN)
  57. static uint8_t g_au8CacheBuf_SDH1[SDH_BUFF_SIZE];
  58. #endif
  59. static struct nu_sdh nu_sdh_arr [] =
  60. {
  61. #if defined(BSP_USING_SDH0)
  62. {
  63. .name = "sdh0",
  64. .base = SDH0,
  65. .irqn = SDH0_IRQn,
  66. .rstidx = SDH0_RST,
  67. .modid = SDH0_MODULE,
  68. .cachebuf = g_au8CacheBuf_SDH0,
  69. },
  70. #endif
  71. #if defined(BSP_USING_SDH1)
  72. {
  73. .name = "sdh1",
  74. .base = SDH1,
  75. .irqn = SDH1_IRQn,
  76. .rstidx = SDH1_RST,
  77. .modid = SDH1_MODULE,
  78. .cachebuf = g_au8CacheBuf_SDH1,
  79. },
  80. #endif
  81. }; /* struct nu_sdh nu_sdh_arr [] */
  82. static uint32_t nu_sdh_get_cmd_resptype(uint32_t rt_resp_type)
  83. {
  84. uint32_t nu_resptype = 0;
  85. switch (rt_resp_type)
  86. {
  87. case RESP_NONE:
  88. nu_resptype = MMC_RSP_NONE;
  89. break;
  90. case RESP_R1:
  91. nu_resptype = MMC_RSP_R1;
  92. break;
  93. case RESP_R1B:
  94. nu_resptype = MMC_RSP_R1b;
  95. break;
  96. case RESP_R2:
  97. nu_resptype = MMC_RSP_R2;
  98. break;
  99. case RESP_R3:
  100. nu_resptype = MMC_RSP_R3;
  101. break;
  102. case RESP_R4:
  103. nu_resptype = MMC_RSP_R4;
  104. break;
  105. case RESP_R6:
  106. nu_resptype = MMC_RSP_R6;
  107. break;
  108. case RESP_R7:
  109. nu_resptype = MMC_RSP_R7;
  110. break;
  111. case RESP_R5:
  112. nu_resptype = MMC_RSP_R5;
  113. break;
  114. default:
  115. nu_resptype = 0xffffffff;
  116. }
  117. return nu_resptype ;
  118. }
  119. static void nu_sdh_send_commanddone(SDH_T *sdh, struct mmc_cmd *cmd)
  120. {
  121. if (cmd->resp_type & MMC_RSP_136)
  122. {
  123. /* CRC is stripped so we need to do some shifting. */
  124. cmd->response[0] = (sdh->RESP67 << 8) | sdh->S_RESP45.B3;
  125. cmd->response[1] = (sdh->RESP45 << 8) | sdh->S_RESP23.B3;
  126. cmd->response[2] = (sdh->RESP23 << 8) | sdh->S_RESP01.B3;
  127. cmd->response[3] = (sdh->RESP01 << 8);
  128. }
  129. else
  130. {
  131. cmd->response[0] = sdh->RESP01;
  132. cmd->response[1] = cmd->response[2] = cmd->response[3] = 0;
  133. }
  134. }
  135. static int nu_sdh_xfer_data(SDH_T *sdh, struct mmc_data *data)
  136. {
  137. uint32_t start_addr, timeout;
  138. if (data->flags & DATA_DIR_READ)
  139. {
  140. start_addr = (uint32_t)data->dest;
  141. }
  142. else
  143. {
  144. start_addr = (uint32_t)data->src;
  145. }
  146. timeout = 1000000;
  147. while (!sdh->S_NORMAL_INT_STAT.XFER_COMPLETE) /* SDHCI_INT_DATA_END? */
  148. {
  149. if (sdh->S_NORMAL_INT_STAT.ERR_INTERRUPT == 1)
  150. return -1;
  151. if (sdh->S_NORMAL_INT_STAT.DMA_INTERRUPT) /* SDHCI_INT_DMA_END */
  152. {
  153. sdh->S_NORMAL_INT_STAT.DMA_INTERRUPT = 1; /* Clear SDHCI_INT_DMA_END */
  154. start_addr &= ~(SDH_BLOCK_SIZE * 1024 - 1);
  155. start_addr += SDH_BLOCK_SIZE * 1024;
  156. sdh->SDMASA = start_addr;
  157. }
  158. if (timeout-- > 0)
  159. rt_hw_us_delay(10);
  160. else
  161. return -2;
  162. }
  163. return 0;
  164. }
  165. static void nu_sdh_list_errors(SDH_T *sdh)
  166. {
  167. if (sdh->S_NORMAL_INT_STAT.ERR_INTERRUPT)
  168. {
  169. LOG_D("Error List:");
  170. if (sdh->S_ERROR_INT_STAT.CMD_TOUT_ERR)
  171. LOG_D("\tCMD_TOUT_ERR.");
  172. if (sdh->S_ERROR_INT_STAT.CMD_CRC_ERR)
  173. LOG_D("\tCMD_CRC_ERR.");
  174. if (sdh->S_ERROR_INT_STAT.CMD_END_BIT_ERR)
  175. LOG_D("\tCMD_END_BIT_ERR.");
  176. if (sdh->S_ERROR_INT_STAT.CMD_IDX_ERR)
  177. LOG_D("\tCMD_IDX_ERR.");
  178. if (sdh->S_ERROR_INT_STAT.DATA_TOUT_ERR)
  179. LOG_D("\tDATA_TOUT_ERR.");
  180. if (sdh->S_ERROR_INT_STAT.DATA_CRC_ERR)
  181. LOG_D("\tDATA_CRC_ERR.");
  182. if (sdh->S_ERROR_INT_STAT.DATA_END_BIT_ERR)
  183. LOG_D("\tDATA_END_BIT_ERR.");
  184. if (sdh->S_ERROR_INT_STAT.CUR_LMT_ERR)
  185. LOG_D("\tCUR_LMT_ERR.");
  186. if (sdh->S_ERROR_INT_STAT.AUTO_CMD_ERR)
  187. LOG_D("\tAUTO_CMD_ERR.");
  188. if (sdh->S_ERROR_INT_STAT.ADMA_ERR)
  189. LOG_D("\tADMA_ERR.");
  190. if (sdh->S_ERROR_INT_STAT.TUNING_ERR)
  191. LOG_D("\tTUNING_ERR.");
  192. if (sdh->S_ERROR_INT_STAT.RESP_ERR)
  193. LOG_D("\tRESP_ERR.");
  194. if (sdh->S_ERROR_INT_STAT.BOOT_ACK_ERR)
  195. LOG_D("\tBOOT_ACK_ERR.");
  196. if (sdh->S_ERROR_INT_STAT.VENDOR_ERR1)
  197. LOG_D("\tVENDOR_ERR1.");
  198. if (sdh->S_ERROR_INT_STAT.VENDOR_ERR2)
  199. LOG_D("\tVENDOR_ERR2.");
  200. if (sdh->S_ERROR_INT_STAT.VENDOR_ERR3)
  201. LOG_D("\tVENDOR_ERR3.");
  202. }
  203. }
  204. /**
  205. * @brief This function send command.
  206. * @param sdio rthw_sdio
  207. * @param pkg sdio package
  208. * @retval None
  209. */
  210. static int nu_sdh_send_command(SDH_T *sdh, struct mmc_cmd *cmd, struct mmc_data *data)
  211. {
  212. int ret;
  213. uint32_t mask, flags, mode;
  214. volatile unsigned int time = 0;
  215. volatile unsigned int cmd_timeout, stat;
  216. LOG_D("[CMD:%d ARG:0x%08x] RESP_TYPE:0x%08x rw:%c addr:0x%08x len:%d blksize:%d",
  217. cmd->cmdidx,
  218. cmd->cmdarg,
  219. cmd->resp_type,
  220. data ? (data->flags & DATA_DIR_WRITE ? 'w' : 'r') : '-',
  221. data ? data->src : 0,
  222. data ? data->blocks * data->blocksize : 0,
  223. data ? data->blocksize : 0);
  224. mask = 0x3; /* SDH_CMD_INHIBIT | SDH_DATA_INHIBIT */
  225. if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
  226. mask &= ~0x2; /* SDH_DATA_INHIBIT */
  227. ret = SD_GetBusStatus(sdh, mask);
  228. if (ret)
  229. {
  230. LOG_E("ERROR: Busy %d\n", ret);
  231. ret = __LINE__;
  232. goto exit_nu_sdh_send_command;
  233. }
  234. /* SDHCI_INT_ALL_MASK */
  235. sdh->NORMAL_INT_STAT = 0xFFFF;
  236. sdh->ERROR_INT_STAT = 0xFFFF;
  237. mask = 0x1; /* SDHCI_INT_RESPONSE */
  238. if (!(cmd->resp_type & MMC_RSP_PRESENT))
  239. flags = SDH_CMD_RESP_NONE;
  240. else if (cmd->resp_type & MMC_RSP_136)
  241. flags = SDH_CMD_RESP_LONG;
  242. else if (cmd->resp_type & MMC_RSP_BUSY)
  243. {
  244. flags = SDH_CMD_RESP_SHORT_BUSY;
  245. if (data)
  246. mask |= 0x2; /* SDHCI_INT_DATA_END */
  247. }
  248. else
  249. flags = SDH_CMD_RESP_SHORT;
  250. if (cmd->resp_type & MMC_RSP_CRC)
  251. flags |= SDH_CMD_CRC;
  252. if (cmd->resp_type & MMC_RSP_OPCODE)
  253. flags |= SDH_CMD_INDEX;
  254. /* Set Transfer mode regarding to data flag */
  255. if (data)
  256. {
  257. flags |= SDH_CMD_DATA;
  258. sdh->S_TOUT_CTRL.TOUT_CNT = 0xE;
  259. mode = 0x2; /* SDHCI_TRNS_BLK_CNT_EN */
  260. if (data->blocks > 1)
  261. mode |= 0x20; /* SDHCI_TRNS_MULTI */
  262. if (data->flags & DATA_DIR_READ)
  263. {
  264. mode |= 0x10; /* SDHCI_TRNS_READ */
  265. sdh->SDMASA = (uint32_t)data->dest;
  266. }
  267. else
  268. {
  269. sdh->SDMASA = (uint32_t)data->src;
  270. }
  271. mode |= 0x1;
  272. sdh->S_HOST_CTRL1.DMA_SEL = 0; //SDMA is selected
  273. /* 512 Kbytes SDMA Buffer Boundary */
  274. sdh->S_BLOCKSIZE.SDMA_BUF_BDARY = 0x7;
  275. /* Set Block Size */
  276. sdh->S_BLOCKSIZE.XFER_BLOCK_SIZE = data->blocksize;
  277. /* Set Block count */
  278. sdh->S_BLOCKCOUNT.BLOCK_CNT = data->blocks;
  279. /* Set transfer mode */
  280. sdh->XFER_MODE = mode;
  281. }
  282. else if (cmd->resp_type & MMC_RSP_BUSY)
  283. {
  284. sdh->S_TOUT_CTRL.TOUT_CNT = 0xE;
  285. }
  286. sdh->ARGUMENT = cmd->cmdarg;
  287. sdh->CMD = ((cmd->cmdidx & 0xff) << 8) | (flags & 0xff);
  288. cmd_timeout = 10000000;
  289. time = 0;
  290. do
  291. {
  292. stat = sdh->NORMAL_INT_STAT;
  293. if (stat & 0x8000) /* SDHCI_INT_ERROR */
  294. break;
  295. if (time > cmd_timeout)
  296. {
  297. ret = __LINE__;
  298. LOG_E("[%s %d] timeout stat=%04x, mask=%04x", __func__, __LINE__, stat, mask);
  299. goto exit_nu_sdh_send_command;
  300. }
  301. time++;
  302. }
  303. while ((stat & mask) != mask);
  304. if ((stat & (0x8000 | mask)) == mask)
  305. {
  306. //LOG_D("[%s %d] Done. cmdid=%d restore", __func__, __LINE__, cmd->cmdidx);
  307. nu_sdh_send_commanddone(sdh, cmd);
  308. nu_sdh_list_errors(sdh);
  309. /* Send data */
  310. if (data)
  311. {
  312. ret = nu_sdh_xfer_data(sdh, data);
  313. }
  314. stat = sdh->ERROR_INT_STAT;
  315. sdh->NORMAL_INT_STAT = mask;
  316. ret = 0;
  317. }
  318. else
  319. {
  320. //LOG_E("[%s %d] Error. cmdid=%d not restored %08x %08x", __func__, __LINE__, cmd->cmdidx, stat, mask);
  321. ret = __LINE__;
  322. nu_sdh_list_errors(sdh);
  323. goto exit_nu_sdh_send_command;
  324. }
  325. /* SDHCI_INT_ALL_MASK */
  326. sdh->NORMAL_INT_STAT = 0xFFFF;
  327. sdh->ERROR_INT_STAT = 0xFFFF;
  328. if (ret)
  329. {
  330. LOG_E("[%s %d] ret=%d cmd->cmdidx=%d, error=0x%x", __func__, __LINE__, ret, cmd->cmdidx, stat);
  331. ret = __LINE__;
  332. goto exit_nu_sdh_send_command;
  333. }
  334. return 0;
  335. exit_nu_sdh_send_command:
  336. SDH_Reset(sdh, SDH_RESET_CMD);
  337. SDH_Reset(sdh, SDH_RESET_DATA);
  338. //LOG_E("[%s %d] cmdid=%d error line=%d", __func__, __LINE__, cmd->cmdidx, ret);
  339. return ret;
  340. }
  341. /**
  342. * @brief This function send sdio request.
  343. * @param host rt_mmcsd_host
  344. * @param req request
  345. * @retval None
  346. */
  347. static void nu_sdh_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req)
  348. {
  349. nu_sdh_t sdh = (nu_sdh_t)host->private_data;
  350. RT_ASSERT(host);
  351. RT_ASSERT(req);
  352. if (host->card)
  353. {
  354. if (host->card->card_type == CARD_TYPE_MMC)
  355. {
  356. sdh->base->S_EMMC_CTRL.CARD_IS_EMMC = 1;
  357. sdh->base->S_EMMC_CTRL.DISABLE_DATA_CRC_CHK = 1;
  358. }
  359. else
  360. {
  361. sdh->base->S_EMMC_CTRL.CARD_IS_EMMC = 0;
  362. sdh->base->S_EMMC_CTRL.DISABLE_DATA_CRC_CHK = 0;
  363. }
  364. }
  365. if (req->cmd != RT_NULL)
  366. {
  367. struct mmc_cmd cmd;
  368. LOG_D("[%s%s%s%s%s]REQ: CMD:%d ARG:0x%08x RESP_TYPE:0x%08x, 0x%08x",
  369. (host->card == RT_NULL) ? "Unknown" : "",
  370. (host->card) && (host->card->card_type == CARD_TYPE_MMC) ? "MMC" : "",
  371. (host->card) && (host->card->card_type == CARD_TYPE_SD) ? "SD" : "",
  372. (host->card) && (host->card->card_type == CARD_TYPE_SDIO) ? "SDIO" : "",
  373. (host->card) && (host->card->card_type == CARD_TYPE_SDIO_COMBO) ? "SDIO_COMBO" : "",
  374. req->cmd->cmd_code,
  375. req->cmd->arg,
  376. resp_type(req->cmd),
  377. nu_sdh_get_cmd_resptype(resp_type(req->cmd)));
  378. rt_memset(&cmd, 0, sizeof(struct mmc_cmd));
  379. cmd.cmdidx = req->cmd->cmd_code;
  380. cmd.cmdarg = req->cmd->arg;
  381. cmd.resp_type = nu_sdh_get_cmd_resptype(resp_type(req->cmd));
  382. if (req->data != RT_NULL)
  383. {
  384. struct mmc_data data;
  385. rt_uint32_t size;
  386. rt_int32_t IsNonaligned = 0;
  387. LOG_D("[%s]REQ: BUF:%08x FLAGS:0x%08x BLKSIZE:%d, BLKCOUNT:%d",
  388. sdh->name,
  389. req->data->buf,
  390. req->data->flags,
  391. req->data->blksize,
  392. req->data->blks);
  393. rt_memset(&data, 0, sizeof(struct mmc_data));
  394. data.dest = (char *)req->data->buf;
  395. data.flags = req->data->flags;
  396. data.blocksize = req->data->blksize;
  397. data.blocks = req->data->blks;
  398. size = data.blocksize * data.blocks;
  399. RT_ASSERT(size <= SDH_BUFF_SIZE);
  400. IsNonaligned = (((rt_uint32_t)data.dest & (SDH_ALIGN_LEN - 1)) > 0) ? 1 : 0;
  401. if (IsNonaligned)
  402. {
  403. data.dest = (char *)sdh->cachebuf;
  404. if (data.flags & DATA_DIR_WRITE)
  405. {
  406. LOG_D("Un-aligned, prepare into cache buf(%d)", size);
  407. rt_memcpy(data.dest, req->data->buf, size);
  408. }
  409. }
  410. rt_hw_cpu_dcache_clean_inv((void *)data.dest, size);
  411. req->cmd->err = nu_sdh_send_command(sdh->base, &cmd, &data);
  412. rt_hw_cpu_dcache_invalidate((void *)data.dest, size);
  413. if (!req->cmd->err && IsNonaligned)
  414. {
  415. if (data.flags & DATA_DIR_READ)
  416. {
  417. LOG_D("Un-aligned, restore from cache buf(%d)", size);
  418. rt_memcpy(req->data->buf, data.dest, size);
  419. }
  420. }
  421. LOG_HEX("data.dest", 16, (void *)data.dest, size);
  422. }
  423. else
  424. {
  425. req->cmd->err = nu_sdh_send_command(sdh->base, &cmd, NULL);
  426. }
  427. /* Report response words */
  428. req->cmd->resp[3] = cmd.response[3];
  429. req->cmd->resp[2] = cmd.response[2];
  430. req->cmd->resp[1] = cmd.response[1];
  431. req->cmd->resp[0] = cmd.response[0];
  432. LOG_HEX("req->cmd->resp", 16, (void *)&req->cmd->resp[0], 16);
  433. }
  434. if (req->stop != RT_NULL)
  435. {
  436. struct mmc_cmd stop;
  437. rt_memset(&stop, 0, sizeof(struct mmc_cmd));
  438. stop.cmdidx = req->stop->cmd_code;
  439. stop.cmdarg = req->stop->arg;
  440. stop.resp_type = nu_sdh_get_cmd_resptype(resp_type(req->stop));
  441. req->stop->err = nu_sdh_send_command(sdh->base, &stop, NULL);
  442. /* Report response words */
  443. req->stop->resp[3] = stop.response[3];
  444. req->stop->resp[2] = stop.response[2];
  445. req->stop->resp[1] = stop.response[1];
  446. req->stop->resp[0] = stop.response[0];
  447. LOG_HEX("req->stop->resp", 16, (void *)&req->stop->resp[0], 16);
  448. }
  449. mmcsd_req_complete(host);
  450. }
  451. /**
  452. * @brief This function config sdio.
  453. * @param host rt_mmcsd_host
  454. * @param io_cfg rt_mmcsd_io_cfg
  455. * @retval None
  456. */
  457. static void nu_sdh_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
  458. {
  459. nu_sdh_t NuSdh;
  460. rt_uint32_t clk = io_cfg->clock;
  461. SDH_T *sdh;
  462. RT_ASSERT(host);
  463. RT_ASSERT(io_cfg);
  464. NuSdh = (nu_sdh_t)host->private_data;
  465. sdh = NuSdh->base;
  466. LOG_D("[%s]clk:%d width:%s%s%s power:%s%s%s",
  467. NuSdh->name,
  468. clk,
  469. io_cfg->bus_width == MMCSD_BUS_WIDTH_8 ? "8" : "",
  470. io_cfg->bus_width == MMCSD_BUS_WIDTH_4 ? "4" : "",
  471. io_cfg->bus_width == MMCSD_BUS_WIDTH_1 ? "1" : "",
  472. io_cfg->power_mode == MMCSD_POWER_OFF ? "OFF" : "",
  473. io_cfg->power_mode == MMCSD_POWER_UP ? "UP" : "",
  474. io_cfg->power_mode == MMCSD_POWER_ON ? "ON" : "");
  475. /* Bus width */
  476. switch (io_cfg->bus_width)
  477. {
  478. case MMCSD_BUS_WIDTH_1:
  479. case MMCSD_BUS_WIDTH_4:
  480. case MMCSD_BUS_WIDTH_8:
  481. SDH_SetBusWidth(sdh, 1 << io_cfg->bus_width);
  482. break;
  483. default:
  484. break;
  485. }
  486. /* Power */
  487. switch (io_cfg->power_mode)
  488. {
  489. case MMCSD_POWER_UP:
  490. case MMCSD_POWER_ON:
  491. SDH_SetPower(sdh, 1);
  492. break;
  493. case MMCSD_POWER_OFF:
  494. SDH_SetPower(sdh, 0);
  495. break;
  496. default:
  497. break;
  498. }
  499. /* Clock */
  500. if (clk > host->freq_max)
  501. clk = host->freq_max;
  502. if (clk < host->freq_min)
  503. clk = host->freq_min;
  504. if (clk)
  505. {
  506. uint32_t u32SrcFreqInHz = 0, u32ModRealFreqInHz;
  507. uint32_t u32ModSrcIdx = CLK_GetModuleClockSource(NuSdh->modid);
  508. switch (u32ModSrcIdx)
  509. {
  510. case 0: // From SYSPLL
  511. u32SrcFreqInHz = CLK_GetPLLClockFreq(SYSPLL);
  512. break;
  513. default: // From APLL
  514. u32SrcFreqInHz = CLK_GetPLLClockFreq(APLL);
  515. break;
  516. }
  517. u32ModRealFreqInHz = SDH_SetClock(sdh, u32SrcFreqInHz, clk);
  518. u32ModRealFreqInHz = u32ModRealFreqInHz; //Avoid warning
  519. LOG_D("[%s] SrcClock: %d kHz, ExceptedFreq: %d kHz, RealFreq: %d kHz", NuSdh->name, u32SrcFreqInHz / 1000, clk / 1000, u32ModRealFreqInHz / 1000);
  520. }
  521. }
  522. /**
  523. * @brief This function detect sdcard.
  524. * @param host rt_mmcsd_host
  525. * @retval 0x01
  526. */
  527. static rt_int32_t nu_sdh_card_detect(struct rt_mmcsd_host *host)
  528. {
  529. LOG_D("try to detect device");
  530. return 0x01;
  531. }
  532. /**
  533. * @brief This function interrupt process function.
  534. * @param host rt_mmcsd_host
  535. * @retval None
  536. */
  537. static void nu_sdh_isr(int vector, void *param)
  538. {
  539. nu_sdh_t sdh = (nu_sdh_t)param;
  540. struct rt_mmcsd_host *host = sdh->host;
  541. SDH_T *base = sdh->base;
  542. volatile unsigned int isr = base->NORMAL_INT_STAT;
  543. /* We just catch card detection here. */
  544. if (isr & 0xc0)
  545. {
  546. /* ready to change */
  547. mmcsd_change(host);
  548. base->NORMAL_INT_STAT = 0xC0;
  549. }
  550. }
  551. /**
  552. * @brief This function update sdh interrupt.
  553. * @param host rt_mmcsd_host
  554. * @param enable
  555. * @retval None
  556. */
  557. void nu_sdh_irq_update(struct rt_mmcsd_host *host, rt_int32_t enable)
  558. {
  559. nu_sdh_t sdh = (nu_sdh_t)host->private_data;
  560. SDH_T *sdh_base = sdh->base;
  561. if (enable)
  562. {
  563. LOG_D("Enable %s irq", sdh->name);
  564. /* Enable only interrupts served by the SD controller */
  565. /* sdh_base->NORMAL_INT_STAT_EN = 0x00FB; */
  566. sdh_base->S_NORMAL_INT_STAT_EN.CMD_COMPLETE_STAT_EN = 1;
  567. sdh_base->S_NORMAL_INT_STAT_EN.XFER_COMPLETE_STAT_EN = 1;
  568. sdh_base->S_NORMAL_INT_STAT_EN.DMA_INTERRUPT_STAT_EN = 1;
  569. sdh_base->S_NORMAL_INT_STAT_EN.BUF_WR_READY_STAT_EN = 1;
  570. sdh_base->S_NORMAL_INT_STAT_EN.BUF_RD_READY_STAT_EN = 1;
  571. sdh_base->S_NORMAL_INT_STAT_EN.CARD_INSERTION_STAT_EN = 1;
  572. sdh_base->S_NORMAL_INT_STAT_EN.CARD_REMOVAL_STAT_EN = 1;
  573. /* sdh_base->ERROR_INT_STAT_EN = 0x0271; */
  574. sdh_base->S_ERROR_INT_STAT_EN.CMD_TOUT_ERR_STAT_EN = 1;
  575. sdh_base->S_ERROR_INT_STAT_EN.DATA_TOUT_ERR_STAT_EN = 1;
  576. sdh_base->S_ERROR_INT_STAT_EN.DATA_CRC_ERR_STAT_EN = 1;
  577. sdh_base->S_ERROR_INT_STAT_EN.DATA_END_BIT_ERR_STAT_EN = 1;
  578. sdh_base->S_ERROR_INT_STAT_EN.ADMA_ERR_STAT_EN = 1;
  579. /* Mask all interrupt sources */
  580. /* sdh_base->NORMAL_INT_SIGNAL_EN = 0xC0; */
  581. sdh_base->S_NORMAL_INT_SIGNAL_EN.CARD_INSERTION_SIGNAL_EN = 1;
  582. sdh_base->S_NORMAL_INT_SIGNAL_EN.CARD_REMOVAL_SIGNAL_EN = 1;
  583. sdh_base->ERROR_INT_SIGNAL_EN = 0;
  584. //sdh_base->NORMAL_INT_STAT_EN = 0x7FFF;
  585. //sdh_base->ERROR_INT_STAT_EN = 0xFFFF;
  586. //sdh_base->NORMAL_INT_SIGNAL_EN=0x7FFF;
  587. //sdh_base->ERROR_INT_SIGNAL_EN=0xFFFF;
  588. }
  589. else
  590. {
  591. LOG_D("Disable %s irq", sdh->name);
  592. sdh_base->NORMAL_INT_STAT_EN = 0x0;
  593. sdh_base->ERROR_INT_STAT_EN = 0x0;
  594. sdh_base->NORMAL_INT_SIGNAL_EN = 0x0;
  595. sdh_base->ERROR_INT_SIGNAL_EN = 0x0;
  596. }
  597. }
  598. static const struct rt_mmcsd_host_ops ops =
  599. {
  600. nu_sdh_request,
  601. nu_sdh_iocfg,
  602. nu_sdh_card_detect,
  603. nu_sdh_irq_update,
  604. };
  605. /**
  606. * @brief This function create mmcsd host.
  607. * @param sdh nu_sdh_t
  608. * @retval nuvton
  609. */
  610. void nu_sdh_host_initial(nu_sdh_t sdh)
  611. {
  612. struct rt_mmcsd_host *host;
  613. rt_err_t ret = RT_EOK;
  614. host = mmcsd_alloc_host();
  615. RT_ASSERT(host != RT_NULL);
  616. ret = rt_event_init(&sdh->event, "sdh_event", RT_IPC_FLAG_FIFO);
  617. RT_ASSERT(ret == RT_EOK);
  618. /* Reset sdh at first. */
  619. SDH_Reset(sdh->base, SDH_RESET_ALL);
  620. /* set host default attributes */
  621. host->ops = &ops;
  622. host->freq_min = 200 * 1000;
  623. host->freq_max = 50 * 1000 * 1000;
  624. host->valid_ocr = VDD_30_31 | VDD_31_32 | VDD_32_33 | VDD_33_34; // | VDD_165_195;
  625. host->flags = MMCSD_BUSWIDTH_4 | MMCSD_MUTBLKWRITE | MMCSD_SUP_SDIO_IRQ | MMCSD_SUP_HIGHSPEED;
  626. host->max_seg_size = SDH_BUFF_SIZE;
  627. host->max_dma_segs = 1;
  628. host->max_blk_size = SDH_BLOCK_SIZE;
  629. host->max_blk_count = (SDH_BUFF_SIZE / SDH_BLOCK_SIZE);
  630. /* link up host and sdio */
  631. host->private_data = sdh;
  632. sdh->host = host;
  633. /* Set initial state: high speed */
  634. sdh->base->S_HOST_CTRL1.HIGH_SPEED_EN = 1;
  635. /* Set SDR50 mode */
  636. sdh->base->S_HOST_CTRL2.UHS_MODE_SEL = 2;
  637. /* Install ISR. */
  638. rt_hw_interrupt_install(sdh->irqn, nu_sdh_isr, (void *)sdh, sdh->name);
  639. rt_hw_interrupt_umask(sdh->irqn);
  640. /* Enable interrupt. */
  641. nu_sdh_irq_update(host, 1);
  642. /* ready to change */
  643. mmcsd_change(host);
  644. }
  645. void nu_sd_attach(void)
  646. {
  647. int i;
  648. /* ready to change */
  649. for (i = (SDH_START + 1); i < SDH_CNT; i++)
  650. {
  651. if (nu_sdh_arr[i].host)
  652. mmcsd_change(nu_sdh_arr[i].host);
  653. }
  654. }
  655. MSH_CMD_EXPORT(nu_sd_attach, attach card);
  656. void nu_sd_regdump(void)
  657. {
  658. int i;
  659. /* ready to change */
  660. for (i = (SDH_START + 1); i < SDH_CNT; i++)
  661. {
  662. if (nu_sdh_arr[i].host)
  663. SDH_DumpReg(nu_sdh_arr[i].base);
  664. }
  665. }
  666. MSH_CMD_EXPORT(nu_sd_regdump, dump sdh registers);
  667. static int rt_hw_sdh_init(void)
  668. {
  669. int i;
  670. for (i = (SDH_START + 1); i < SDH_CNT; i++)
  671. {
  672. CLK_EnableModuleClock(nu_sdh_arr[i].modid);
  673. SYS_ResetModule(nu_sdh_arr[i].rstidx);
  674. nu_sdh_host_initial(&nu_sdh_arr[i]);
  675. }
  676. return 0;
  677. }
  678. INIT_DEVICE_EXPORT(rt_hw_sdh_init);
  679. /* A simple MBR writer. */
  680. struct mbr
  681. {
  682. uint8_t code[440];
  683. union
  684. {
  685. uint32_t disk_signature;
  686. struct
  687. {
  688. uint32_t disk_signature_B0: 8;
  689. uint32_t disk_signature_B1: 8;
  690. uint32_t disk_signature_B2: 8;
  691. uint32_t disk_signature_B3: 8;
  692. } s_disk_signature;
  693. };
  694. uint16_t unused;
  695. struct mbr_partition
  696. {
  697. uint8_t status;
  698. uint8_t first_cylinder;
  699. uint8_t first_head;
  700. uint8_t first_sector;
  701. uint8_t partition_type;
  702. uint8_t last_cylinder;
  703. uint8_t last_head;
  704. uint8_t last_sector;
  705. union
  706. {
  707. uint32_t first_sector_lba;
  708. struct
  709. {
  710. uint32_t first_sector_lba_B0: 8;
  711. uint32_t first_sector_lba_B1: 8;
  712. uint32_t first_sector_lba_B2: 8;
  713. uint32_t first_sector_lba_B3: 8;
  714. } s_first_sector_lba;
  715. };
  716. union
  717. {
  718. uint32_t sectors ;
  719. struct
  720. {
  721. uint32_t sectors_B0: 8;
  722. uint32_t sectors_B1: 8;
  723. uint32_t sectors_B2: 8;
  724. uint32_t sectors_B3: 8;
  725. } s_sectors;
  726. };
  727. } partition[4];
  728. uint16_t mbr_signature;
  729. } __attribute__((packed));
  730. #define MBR_SIGNATURE 0xAA55
  731. #define MBR_STATUS_BOOTABLE 0x80
  732. #define le2(a, o) ((a)[o] << 0 | (a)[(o)+1] << 8)
  733. #define le4(a, o) (le2(a,o) | (a)[(o)+2] << 16 | (a)[(o)+3] << 24)
  734. static int nu_sd_mbr_read(const char *devname)
  735. {
  736. rt_device_t mmc_device = RT_NULL;
  737. rt_err_t ret;
  738. struct rt_device_blk_geometry geo = {0};
  739. struct mbr *psMbr = RT_NULL;
  740. if ((mmc_device = rt_device_find(devname)) == RT_NULL)
  741. {
  742. LOG_E("find device %s failed!\n", devname);
  743. goto fail_nu_sd_mbr_read;
  744. }
  745. if (rt_device_open(mmc_device, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
  746. {
  747. LOG_E("open device %s failed!\n", devname);
  748. mmc_device = RT_NULL;
  749. goto fail_nu_sd_mbr_read;
  750. }
  751. if (rt_device_control(mmc_device, RT_DEVICE_CTRL_BLK_GETGEOME, &geo) != RT_EOK)
  752. {
  753. LOG_E("control device %s failed!\n", devname);
  754. goto fail_nu_sd_mbr_read;
  755. }
  756. LOG_I("device information:\n");
  757. LOG_I("sector size : %d byte\n", geo.bytes_per_sector);
  758. LOG_I("sector count : %d \n", geo.sector_count);
  759. LOG_I("block size : %d byte\n", geo.block_size);
  760. LOG_I("MBR size : %d byte\n", sizeof(struct mbr));
  761. psMbr = rt_malloc(sizeof(struct mbr));
  762. if (psMbr == RT_NULL)
  763. {
  764. LOG_E("no memory for mbr buffer!\n");
  765. goto fail_nu_sd_mbr_read;
  766. }
  767. rt_memset(psMbr, 0, sizeof(struct mbr));
  768. ret = rt_device_read(mmc_device, 0, psMbr, 1);
  769. if (ret != 1)
  770. {
  771. LOG_E("read device %s %d failed!\n", devname, ret);
  772. goto fail_nu_sd_mbr_read;
  773. }
  774. LOG_I("disk_signature = %08x\n", psMbr->disk_signature);
  775. LOG_I("unused = %02x\n", psMbr->unused);
  776. for (int i = 0; i < 4; i++)
  777. {
  778. LOG_I("[%d] status = %02x\n", i, psMbr->partition[i].status);
  779. LOG_I("[%d] first_cylinder = %d\n", i, psMbr->partition[i].first_cylinder);
  780. LOG_I("[%d] first_head = %d\n", i, psMbr->partition[i].first_head);
  781. LOG_I("[%d] first_sector = %d\n", i, psMbr->partition[i].first_sector);
  782. LOG_I("[%d] partition_type = %02x\n", i, psMbr->partition[i].partition_type);
  783. LOG_I("[%d] last_cylinder = %d\n", i, psMbr->partition[i].last_cylinder);
  784. LOG_I("[%d] last_head = %d\n", i, psMbr->partition[i].last_head);
  785. LOG_I("[%d] last_sector = %d\n", i, psMbr->partition[i].last_sector);
  786. LOG_I("[%d] first_sector_lba = %u\n", i, psMbr->partition[i].first_sector_lba);
  787. LOG_I("[%d] sectors = %u\n", i, psMbr->partition[i].sectors);
  788. }
  789. LOG_I("signature = %02x\n", psMbr->mbr_signature);
  790. rt_free(psMbr);
  791. rt_device_close(mmc_device);
  792. return 0;
  793. fail_nu_sd_mbr_read:
  794. if (psMbr != RT_NULL)
  795. rt_free(psMbr);
  796. if (mmc_device != RT_NULL)
  797. rt_device_close(mmc_device);
  798. return -1;
  799. }
  800. int nu_sd_mbr_dump(int argc, char *argv[])
  801. {
  802. // argc=1: string, mmcblk device name.
  803. if (argc != 2)
  804. return -1;
  805. return nu_sd_mbr_read(argv[1]);
  806. }
  807. MSH_CMD_EXPORT(nu_sd_mbr_dump, dump sd card device);
  808. static int nu_sd_mbr_write(const char *devname, int32_t u32Sectors)
  809. {
  810. rt_device_t mmc_device = RT_NULL;
  811. rt_err_t ret;
  812. struct rt_device_blk_geometry geo;
  813. struct mbr *psMbr = RT_NULL;
  814. if ((mmc_device = rt_device_find(devname)) == RT_NULL)
  815. {
  816. LOG_E("find device %s failed!\n", devname);
  817. goto fail_nu_sd_mbr_write;
  818. }
  819. if (rt_device_open(mmc_device, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
  820. {
  821. mmc_device = RT_NULL;
  822. LOG_E("open device %s failed!\n", devname);
  823. goto fail_nu_sd_mbr_write;
  824. }
  825. rt_memset(&geo, 0, sizeof(geo));
  826. ret = rt_device_control(mmc_device, RT_DEVICE_CTRL_BLK_GETGEOME, &geo);
  827. if (ret != RT_EOK)
  828. {
  829. LOG_E("control device %s failed!\n", devname);
  830. goto fail_nu_sd_mbr_write;
  831. }
  832. LOG_I("device information:\n");
  833. LOG_I("sector size : %d byte\n", geo.bytes_per_sector);
  834. LOG_I("sector count : %d \n", geo.sector_count);
  835. LOG_I("block size : %d byte\n", geo.block_size);
  836. if (u32Sectors >= geo.sector_count)
  837. {
  838. LOG_E("no enough sectors for reserved. %s failed!\n", devname);
  839. goto fail_nu_sd_mbr_write;
  840. }
  841. psMbr = rt_malloc(sizeof(struct mbr));
  842. if (psMbr == RT_NULL)
  843. {
  844. LOG_E("no memory for mbr buffer!\n");
  845. goto fail_nu_sd_mbr_write;
  846. }
  847. rt_memset(psMbr, 0, sizeof(struct mbr));
  848. psMbr->disk_signature = 0xa8e7d068;
  849. psMbr->mbr_signature = MBR_SIGNATURE;
  850. psMbr->partition[0].status = 0;
  851. //psMbr->partition[0].first_cylinder = 0x00;
  852. //psMbr->partition[0].first_head = 0x21;
  853. //psMbr->partition[0].first_sector = 0x21;
  854. psMbr->partition[0].partition_type = 0x0C;
  855. //psMbr->partition[0].last_head = 0xFE;
  856. //psMbr->partition[0].last_sector = 0x3F;
  857. //psMbr->partition[0].last_cylinder = 0xFF;
  858. psMbr->partition[0].first_sector_lba = u32Sectors;
  859. psMbr->partition[0].sectors = geo.sector_count - u32Sectors;
  860. ret = rt_device_write(mmc_device, 0, psMbr, 1);
  861. if (ret != 1)
  862. {
  863. LOG_E("write device %s %d failed!\n", devname, ret);
  864. goto fail_nu_sd_mbr_write;
  865. }
  866. fail_nu_sd_mbr_write:
  867. if (psMbr != RT_NULL)
  868. rt_free(psMbr);
  869. if (mmc_device)
  870. rt_device_close(mmc_device);
  871. return -1;
  872. }
  873. int nu_sd_mbr_layout(int argc, char *argv[])
  874. {
  875. // argc=1: string, mmcblk device name.
  876. // argc=2: Reserved sectors for bootable code and remains sectors are for elm mounting.
  877. if (argc != 3)
  878. return -1;
  879. return nu_sd_mbr_write((const char *)argv[1], atoi(argv[2]));
  880. }
  881. MSH_CMD_EXPORT(nu_sd_mbr_layout, layout sd device);
  882. #endif