nu_fmc.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. /**************************************************************************//**
  2. * @file fmc.c
  3. * @version V1.00
  4. * $Revision: 3 $
  5. * $Date: 18/04/24 3:05p $
  6. * @brief M031 series FMC driver source file
  7. *
  8. * @note
  9. * SPDX-License-Identifier: Apache-2.0
  10. * Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved.
  11. *****************************************************************************/
  12. #include <stdio.h>
  13. #include "NuMicro.h"
  14. /** @addtogroup Standard_Driver Standard Driver
  15. @{
  16. */
  17. /** @addtogroup FMC_Driver FMC Driver
  18. @{
  19. */
  20. /** @addtogroup FMC_EXPORTED_FUNCTIONS FMC Exported Functions
  21. @{
  22. */
  23. /**
  24. * @brief Disable FMC ISP function.
  25. * @return None
  26. */
  27. void FMC_Close(void)
  28. {
  29. FMC->ISPCTL &= ~FMC_ISPCTL_ISPEN_Msk;
  30. }
  31. /**
  32. * @brief Execute FMC_ISPCMD_PAGE_ERASE command to erase a flash page. The page size is 4096 bytes.
  33. * @param[in] u32PageAddr Address of the flash page to be erased.
  34. * It must be a 4096 bytes aligned address.
  35. * @return ISP page erase success or not.
  36. * @retval 0 Success
  37. * @retval -1 Erase failed
  38. */
  39. int32_t FMC_Erase(uint32_t u32PageAddr)
  40. {
  41. int32_t ret = 0;
  42. if (u32PageAddr == FMC_SPROM_BASE)
  43. {
  44. ret = FMC_Erase_SPROM();
  45. }
  46. else
  47. {
  48. FMC->ISPCMD = FMC_ISPCMD_PAGE_ERASE;
  49. FMC->ISPADDR = u32PageAddr;
  50. FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
  51. while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
  52. if (FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk)
  53. {
  54. FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
  55. ret = -1;
  56. }
  57. }
  58. return ret;
  59. }
  60. /**
  61. * @brief Execute Flash Bank erase
  62. *
  63. * @param[in] u32BankAddr Base address of the flash bank to be erased.
  64. *
  65. * @return ISP bank erase success or not.
  66. * @retval 0 Success
  67. * @retval -1 Erase failed
  68. *
  69. * @details Execute FMC_ISPCMD_BANK_ERASE command to erase a flash bank.
  70. */
  71. int32_t FMC_Erase_Bank(uint32_t u32BankAddr)
  72. {
  73. int32_t ret = 0;
  74. FMC->ISPCMD = FMC_ISPCMD_BANK_ERASE;
  75. FMC->ISPADDR = u32BankAddr;
  76. FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
  77. while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
  78. if (FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk)
  79. {
  80. FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
  81. ret = -1;
  82. }
  83. return ret;
  84. }
  85. /**
  86. * @brief Execute FMC_ISPCMD_PAGE_ERASE command to erase SPROM. The page size is 4096 bytes.
  87. * @return SPROM page erase success or not.
  88. * @retval 0 Success
  89. * @retval -1 Erase failed
  90. */
  91. int32_t FMC_Erase_SPROM(void)
  92. {
  93. int32_t ret = 0;
  94. FMC->ISPCMD = FMC_ISPCMD_PAGE_ERASE;
  95. FMC->ISPADDR = FMC_SPROM_BASE;
  96. FMC->ISPDAT = 0x0055AA03UL;
  97. FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
  98. while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
  99. if (FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk)
  100. {
  101. FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
  102. ret = -1;
  103. }
  104. return ret;
  105. }
  106. /**
  107. * @brief Execute FMC_ISPCMD_BANK_REMAP command to remap bank.
  108. * @return Bank remap success or not.
  109. * @retval 0 Success
  110. * @retval -1 Erase failed
  111. */
  112. int32_t FMC_RemapBank(uint32_t u32BankIdx)
  113. {
  114. int32_t ret = 0;
  115. FMC->ISPCMD = FMC_ISPCMD_BANK_REMAP;
  116. FMC->ISPADDR = u32BankIdx;
  117. FMC->ISPDAT = 0x5AA55AA5UL;
  118. FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
  119. while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
  120. if (FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk)
  121. {
  122. FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
  123. ret = -1;
  124. }
  125. return ret;
  126. }
  127. /**
  128. * @brief Get the current boot source.
  129. * @return The current boot source.
  130. * @retval 0 Is boot from APROM.
  131. * @retval 1 Is boot from LDROM.
  132. */
  133. int32_t FMC_GetBootSource (void)
  134. {
  135. int32_t ret = 0;
  136. if (FMC->ISPCTL & FMC_ISPCTL_BS_Msk)
  137. {
  138. ret = 1;
  139. }
  140. return ret;
  141. }
  142. /**
  143. * @brief Enable FMC ISP function
  144. * @return None
  145. */
  146. void FMC_Open(void)
  147. {
  148. FMC->ISPCTL |= FMC_ISPCTL_ISPEN_Msk;
  149. }
  150. /**
  151. * @brief Execute FMC_ISPCMD_READ command to read a word from flash.
  152. * @param[in] u32Addr Address of the flash location to be read.
  153. * It must be a word aligned address.
  154. * @return The word data read from specified flash address.
  155. */
  156. uint32_t FMC_Read(uint32_t u32Addr)
  157. {
  158. FMC->ISPCMD = FMC_ISPCMD_READ;
  159. FMC->ISPADDR = u32Addr;
  160. FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
  161. while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
  162. return FMC->ISPDAT;
  163. }
  164. /**
  165. * @brief Get the base address of Data Flash if enabled.
  166. * @retval The base address of Data Flash
  167. */
  168. uint32_t FMC_ReadDataFlashBaseAddr(void)
  169. {
  170. return FMC->DFBA;
  171. }
  172. /**
  173. * @brief Set boot source from LDROM or APROM after next software reset
  174. * @param[in] i32BootSrc
  175. * 1: Boot from LDROM
  176. * 0: Boot from APROM
  177. * @return None
  178. * @details This function is used to switch APROM boot or LDROM boot. User need to call
  179. * FMC_SetBootSource to select boot source first, then use CPU reset or
  180. * System Reset Request to reset system.
  181. */
  182. void FMC_SetBootSource(int32_t i32BootSrc)
  183. {
  184. if(i32BootSrc)
  185. {
  186. FMC->ISPCTL |= FMC_ISPCTL_BS_Msk; /* Boot from LDROM */
  187. }
  188. else
  189. {
  190. FMC->ISPCTL &= ~FMC_ISPCTL_BS_Msk;/* Boot from APROM */
  191. }
  192. }
  193. /**
  194. * @brief Execute ISP FMC_ISPCMD_PROGRAM to program a word to flash.
  195. * @param[in] u32Addr Address of the flash location to be programmed.
  196. * It must be a word aligned address.
  197. * @param[in] u32Data The word data to be programmed.
  198. * @return None
  199. */
  200. void FMC_Write(uint32_t u32Addr, uint32_t u32Data)
  201. {
  202. FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
  203. FMC->ISPADDR = u32Addr;
  204. FMC->ISPDAT = u32Data;
  205. FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
  206. while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
  207. }
  208. /**
  209. * @brief Execute ISP FMC_ISPCMD_PROGRAM_64 to program a double-word to flash.
  210. * @param[in] u32addr Address of the flash location to be programmed.
  211. * It must be a double-word aligned address.
  212. * @param[in] u32data0 The word data to be programmed to flash address u32addr.
  213. * @param[in] u32data1 The word data to be programmed to flash address u32addr+4.
  214. * @return 0 Success
  215. * @return -1 Failed
  216. */
  217. int32_t FMC_Write8Bytes(uint32_t u32addr, uint32_t u32data0, uint32_t u32data1)
  218. {
  219. int32_t ret = 0;
  220. FMC->ISPCMD = FMC_ISPCMD_PROGRAM_64;
  221. FMC->ISPADDR = u32addr;
  222. FMC->MPDAT0 = u32data0;
  223. FMC->MPDAT1 = u32data1;
  224. FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
  225. while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
  226. if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
  227. {
  228. FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
  229. ret = -1;
  230. }
  231. return ret;
  232. }
  233. /**
  234. * @brief Execute FMC_ISPCMD_READ command to read User Configuration.
  235. * @param[out] u32Config A three-word array.
  236. * u32Config[0] holds CONFIG0, while u32Config[1] holds CONFIG1.
  237. * @param[in] u32Count Available word count in u32Config.
  238. * @return Success or not.
  239. * @retval 0 Success.
  240. * @retval -1 Invalid parameter.
  241. */
  242. int32_t FMC_ReadConfig(uint32_t u32Config[], uint32_t u32Count)
  243. {
  244. int32_t ret = 0;
  245. u32Config[0] = FMC_Read(FMC_CONFIG_BASE);
  246. if (u32Count > 3UL)
  247. {
  248. ret = -1;
  249. }
  250. else
  251. {
  252. if(u32Count > 1UL)
  253. {
  254. u32Config[1] = FMC_Read(FMC_CONFIG_BASE+4UL);
  255. }
  256. if(u32Count > 2UL)
  257. {
  258. u32Config[2] = FMC_Read(FMC_CONFIG_BASE+8UL);
  259. }
  260. }
  261. return ret;
  262. }
  263. /**
  264. * @brief Execute ISP commands to erase then write User Configuration.
  265. * @param[in] u32Config A two-word array.
  266. * u32Config[0] holds CONFIG0, while u32Config[1] holds CONFIG1.
  267. * @param[in] u32Count Always be 2 in this BSP.
  268. * @return Success or not.
  269. * @retval 0 Success.
  270. * @retval -1 Invalid parameter.
  271. */
  272. int32_t FMC_WriteConfig(uint32_t u32Config[], uint32_t u32Count)
  273. {
  274. int32_t ret = 0;
  275. uint32_t i;
  276. for (i = 0u; i < u32Count; i++)
  277. {
  278. FMC_Write(FMC_CONFIG_BASE + i * 4u, u32Config[i]);
  279. if (FMC_Read(FMC_CONFIG_BASE + i * 4u) != u32Config[i])
  280. {
  281. ret = -1;
  282. }
  283. }
  284. return ret;
  285. }
  286. /**
  287. * @brief Run CRC32 checksum calculation and get result.
  288. * @param[in] u32addr Starting flash address. It must be a page aligned address.
  289. * @param[in] u32count Byte count of flash to be calculated. It must be multiple of 512 bytes.
  290. * @return Success or not.
  291. * @retval 0 Success.
  292. * @retval 0xFFFFFFFF Invalid parameter.
  293. */
  294. uint32_t FMC_GetChkSum(uint32_t u32addr, uint32_t u32count)
  295. {
  296. uint32_t ret;
  297. if ((u32addr % 512UL) || (u32count % 512UL))
  298. {
  299. ret = 0xFFFFFFFF;
  300. }
  301. else
  302. {
  303. FMC->ISPCMD = FMC_ISPCMD_RUN_CKS;
  304. FMC->ISPADDR = u32addr;
  305. FMC->ISPDAT = u32count;
  306. FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
  307. while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
  308. FMC->ISPCMD = FMC_ISPCMD_READ_CKS;
  309. FMC->ISPADDR = u32addr;
  310. FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
  311. while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
  312. ret = FMC->ISPDAT;
  313. }
  314. return ret;
  315. }
  316. /**
  317. * @brief Run flash all one verification and get result.
  318. *
  319. * @param[in] u32addr Starting flash address. It must be a page aligned address.
  320. * @param[in] u32count Byte count of flash to be calculated. It must be multiple of 512 bytes.
  321. *
  322. * @retval READ_ALLONE_YES The contents of verified flash area are 0xFFFFFFFF.
  323. * @retval READ_ALLONE_NOT Some contents of verified flash area are not 0xFFFFFFFF.
  324. * @retval READ_ALLONE_CMD_FAIL Unexpected error occurred.
  325. *
  326. * @details Run ISP check all one command to check specify area is all one or not.
  327. */
  328. #define FMC_APROM_BANK1_BASE (0x40000)
  329. #define FMC_CHECKALLONE_UNIT (512)
  330. uint32_t FMC_CheckAllOne(uint32_t u32addr, uint32_t u32count)
  331. {
  332. uint32_t ret = READ_ALLONE_CMD_FAIL;
  333. /** Workaround solution for M031 with 512KB Flash uses FMC Read command instead of FMC All-One-Verification command to
  334. * check the Flash content from 0x40000 to 0x401FF.
  335. */
  336. if(u32addr == FMC_APROM_BANK1_BASE)
  337. {
  338. uint32_t i;
  339. u32count = u32count - FMC_CHECKALLONE_UNIT;
  340. for(i = FMC_APROM_BANK1_BASE; i < (FMC_APROM_BANK1_BASE + FMC_CHECKALLONE_UNIT); i = i+4)
  341. {
  342. if( FMC_Read(i) != 0xFFFFFFFF)
  343. return READ_ALLONE_NOT;
  344. }
  345. if(u32count == 0)
  346. return READ_ALLONE_YES;
  347. else
  348. u32addr = u32addr + FMC_CHECKALLONE_UNIT;
  349. }
  350. FMC->ISPSTS = 0x80UL; /* clear check all one bit */
  351. FMC->ISPCMD = FMC_ISPCMD_RUN_ALL1;
  352. FMC->ISPADDR = u32addr;
  353. FMC->ISPDAT = u32count;
  354. FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
  355. while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
  356. do
  357. {
  358. FMC->ISPCMD = FMC_ISPCMD_READ_ALL1;
  359. FMC->ISPADDR = u32addr;
  360. FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
  361. while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
  362. }
  363. while (FMC->ISPDAT == 0UL);
  364. if (FMC->ISPDAT == READ_ALLONE_YES)
  365. {
  366. ret = FMC->ISPDAT;
  367. }
  368. if (FMC->ISPDAT == READ_ALLONE_NOT)
  369. {
  370. ret = FMC->ISPDAT;
  371. }
  372. return ret;
  373. }
  374. /**
  375. * @brief Write Multi-Word bytes to flash
  376. *
  377. * @param[in] u32Addr Start flash address in APROM where the data chunk to be programmed into.
  378. * This address must be 8-bytes aligned to flash address.
  379. * @param[in] pu32Buf Buffer that carry the data chunk.
  380. * @param[in] u32Len Length of the data chunk in bytes.
  381. *
  382. * @retval >=0 Number of data bytes were programmed.
  383. * @return -1 Invalid address.
  384. *
  385. * @detail Program Multi-Word data into specified address of flash.
  386. */
  387. #if defined ( __CC_ARM )
  388. #pragma arm section code="fastcode"
  389. int32_t FMC_WriteMultiple(uint32_t u32Addr, uint32_t pu32Buf[], uint32_t u32Len)
  390. #elif defined ( __ICCARM__ )
  391. int32_t FMC_WriteMultiple(uint32_t u32Addr, uint32_t pu32Buf[], uint32_t u32Len) @ "fastcode"
  392. #elif defined ( __GNUC__ )
  393. #pragma GCC push_options
  394. #pragma GCC optimize ("O0")
  395. __attribute__ ((used, long_call, section(".fastcode"))) int32_t FMC_WriteMultiple(uint32_t u32Addr, uint32_t pu32Buf[], uint32_t u32Len)
  396. #else
  397. int32_t FMC_WriteMultiple(uint32_t u32Addr, uint32_t pu32Buf[], uint32_t u32Len)
  398. #endif
  399. {
  400. uint32_t i, idx, u32OnProg, retval = 0;
  401. int32_t err;
  402. if ((u32Addr % 8) != 0)
  403. {
  404. return -1;
  405. }
  406. idx = 0u;
  407. FMC->ISPCMD = FMC_ISPCMD_MULTI_PROG;
  408. FMC->ISPADDR = u32Addr;
  409. retval += 16;
  410. do
  411. {
  412. err = 0;
  413. u32OnProg = 1u;
  414. FMC->MPDAT0 = pu32Buf[idx + 0u];
  415. FMC->MPDAT1 = pu32Buf[idx + 1u];
  416. FMC->MPDAT2 = pu32Buf[idx + 2u];
  417. FMC->MPDAT3 = pu32Buf[idx + 3u];
  418. FMC->ISPTRG = 0x1u;
  419. idx += 4u;
  420. for (i = idx; i < (FMC_MULTI_WORD_PROG_LEN / 4u); i += 4u) /* Max data length is 256 bytes (512/4 words)*/
  421. {
  422. __set_PRIMASK(1u); /* Mask interrupt to avoid status check coherence error*/
  423. do
  424. {
  425. if ((FMC->MPSTS & FMC_MPSTS_MPBUSY_Msk) == 0u)
  426. {
  427. __set_PRIMASK(0u);
  428. FMC->ISPADDR = FMC->MPADDR & (~0xful);
  429. idx = (FMC->ISPADDR - u32Addr) / 4u;
  430. err = -1;
  431. }
  432. }
  433. while ((FMC->MPSTS & (3u << FMC_MPSTS_D0_Pos)) && (err == 0));
  434. if (err == 0)
  435. {
  436. retval += 8;
  437. /* Update new data for D0 */
  438. FMC->MPDAT0 = pu32Buf[i];
  439. FMC->MPDAT1 = pu32Buf[i + 1u];
  440. do
  441. {
  442. if ((FMC->MPSTS & FMC_MPSTS_MPBUSY_Msk) == 0u)
  443. {
  444. __set_PRIMASK(0u);
  445. FMC->ISPADDR = FMC->MPADDR & (~0xful);
  446. idx = (FMC->ISPADDR - u32Addr) / 4u;
  447. err = -1;
  448. }
  449. }
  450. while ((FMC->MPSTS & (3u << FMC_MPSTS_D2_Pos)) && (err == 0));
  451. if (err == 0)
  452. {
  453. retval += 8;
  454. /* Update new data for D2*/
  455. FMC->MPDAT2 = pu32Buf[i + 2u];
  456. FMC->MPDAT3 = pu32Buf[i + 3u];
  457. __set_PRIMASK(0u);
  458. }
  459. }
  460. if (err < 0)
  461. {
  462. break;
  463. }
  464. }
  465. if (err == 0)
  466. {
  467. u32OnProg = 0u;
  468. while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
  469. }
  470. }
  471. while (u32OnProg);
  472. return retval;
  473. }
  474. #if defined ( __CC_ARM )
  475. #pragma arm section
  476. #elif defined ( __GNUC__ )
  477. #pragma GCC pop_options
  478. #endif
  479. /*@}*/ /* end of group FMC_EXPORTED_FUNCTIONS */
  480. /*@}*/ /* end of group FMC_Driver */
  481. /*@}*/ /* end of group Standard_Driver */
  482. /*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/