1 /**************************************************************************//**
2  * @file     fmc.c
3  * @version  V3.00
4  * $Revision: 1 $
5  * $Date: 19/11/27 7:50p $
6  * @brief    Flash Memory Controller(FMC) driver source file
7  *
8  * @copyright SPDX-License-Identifier: Apache-2.0
9  * @copyright Copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
10  *****************************************************************************/
11 #include <stdio.h>
12 #include "NuMicro.h"
13 
14 /** @addtogroup Standard_Driver Standard Driver
15   @{
16 */
17 
18 /** @addtogroup FMC_Driver FMC Driver
19   @{
20 */
21 
22 /** @addtogroup FMC_EXPORTED_FUNCTIONS FMC Exported Functions
23   @{
24 */
25 
26 /**
27   * @brief Run flash all one verification and get result.
28   *
29   * @param[in] u32addr   Starting flash address. It must be a page aligned address.
30   * @param[in] u32count  Byte count of flash to be calculated. It must be multiple of 512 bytes.
31   *
32   * @retval   READ_ALLONE_YES       The contents of verified flash area are 0xA11FFFFF.
33   * @retval   READ_ALLONE_NOT       Some contents of verified flash area are not 0xA1100000.
34   * @retval   READ_ALLONE_CMD_FAIL  Unexpected error occurred.
35   *
36   * @details  Run ISP check all one command to check specify area is all one or not.
37   */
FMC_CheckAllOne(uint32_t u32addr,uint32_t u32count)38 uint32_t  FMC_CheckAllOne(uint32_t u32addr, uint32_t u32count)
39 {
40     uint32_t  ret = READ_ALLONE_CMD_FAIL;
41 
42     FMC_ISP->ISPSTS = 0x80UL;   /* clear check all one bit */
43 
44     FMC_ISP->ISPCMD   = FMC_ISPCMD_RUN_ALL1;
45     FMC_ISP->ISPADDR  = u32addr;
46     FMC_ISP->ISPDAT   = u32count;
47     FMC_ISP->ISPTRG   = FMC_ISPTRG_ISPGO_Msk;
48 
49     while(FMC_ISP->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
50 
51     do
52     {
53         FMC_ISP->ISPCMD = FMC_ISPCMD_READ_ALL1;
54         FMC_ISP->ISPADDR    = u32addr;
55         FMC_ISP->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
56         while(FMC_ISP->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
57     }
58     while(FMC_ISP->ISPDAT == 0UL);
59 
60     if(FMC_ISP->ISPDAT == READ_ALLONE_YES)
61     {
62         ret = FMC_ISP->ISPDAT;
63     }
64 
65     if(FMC_ISP->ISPDAT == READ_ALLONE_NOT)
66     {
67         ret = FMC_ISP->ISPDAT;
68     }
69 
70     return ret;
71 }
72 
73 
74 /**
75   * @brief    Disable ISP Functions
76   *
77   * @param    None
78   *
79   * @return   None
80   *
81   * @details  This function will clear ISPEN bit of ISPCON to disable ISP function
82   *
83   */
FMC_Close(void)84 void FMC_Close(void)
85 {
86     FMC->ISPCTL &= ~FMC_ISPCTL_ISPEN_Msk;
87 }
88 
89 /**
90   * @brief     Config XOM Region
91   * @param[in] u32XomNum    The XOM number(0~3)
92   * @param[in] u32XomBase   The XOM region base address.
93   * @param[in] u8XomPage   The XOM page number of region size.
94   *
95   * @retval   0   Success
96   * @retval   1   XOM is has already actived.
97   * @retval   -1  Program failed.
98   * @retval   -2  Invalid XOM number.
99   *
100   * @details  Program XOM base address and XOM size(page)
101   */
FMC_ConfigXOM(uint32_t u32XomNum,uint32_t u32XomBase,uint8_t u8XomPage)102 int32_t FMC_ConfigXOM(uint32_t u32XomNum, uint32_t u32XomBase, uint8_t u8XomPage)
103 {
104     int32_t  ret = 0;
105 
106     if(u32XomNum >= 4UL)
107     {
108         ret = -2;
109     }
110 
111     if(ret == 0)
112     {
113         ret = FMC_GetXOMState(u32XomNum);
114     }
115 
116     if(ret == 0)
117     {
118         FMC_ISP->ISPCMD = FMC_ISPCMD_PROGRAM;
119         FMC_ISP->ISPADDR = FMC_XOM_BASE + (u32XomNum * 0x10u);
120         FMC_ISP->ISPDAT = u32XomBase;
121         FMC_ISP->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
122         while(FMC_ISP->ISPTRG & FMC_ISPTRG_ISPGO_Msk) {}
123 
124         if(FMC_ISP->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
125         {
126             FMC_ISP->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
127             ret = -1;
128         }
129     }
130 
131     if(ret == 0)
132     {
133         FMC_ISP->ISPCMD = FMC_ISPCMD_PROGRAM;
134         FMC_ISP->ISPADDR = FMC_XOM_BASE + (u32XomNum * 0x10u + 0x04u);
135         FMC_ISP->ISPDAT = u8XomPage;
136         FMC_ISP->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
137         while(FMC_ISP->ISPTRG & FMC_ISPTRG_ISPGO_Msk) {}
138 
139         if(FMC_ISP->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
140         {
141             FMC_ISP->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
142             ret = -1;
143         }
144     }
145 
146     if(ret == 0)
147     {
148         FMC_ISP->ISPCMD = FMC_ISPCMD_PROGRAM;
149         FMC_ISP->ISPADDR = FMC_XOM_BASE + (u32XomNum * 0x10u + 0x08u);
150         FMC_ISP->ISPDAT = 0u;
151         FMC_ISP->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
152         while(FMC_ISP->ISPTRG & FMC_ISPTRG_ISPGO_Msk) {}
153 
154         if(FMC_ISP->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
155         {
156             FMC_ISP->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
157             ret = -1;
158         }
159     }
160 
161     return ret;
162 }
163 
164 /**
165   * @brief      Execute Flash Page erase
166   *
167   * @param[in]  u32PageAddr Address of the flash page to be erased.
168   *             It must be a 2048 bytes aligned address.
169   *
170   * @return     ISP page erase success or not.
171   * @retval     0  Success
172   * @retval     -1  Erase failed
173   *
174   * @details    Execute FMC_ISPCMD_PAGE_ERASE command to erase a flash page. The page size is 2048 bytes.
175   */
FMC_Erase(uint32_t u32PageAddr)176 int32_t FMC_Erase(uint32_t u32PageAddr)
177 {
178     int32_t  ret = 0;
179 
180     if(ret == 0)
181     {
182         FMC_ISP->ISPCMD = FMC_ISPCMD_PAGE_ERASE;
183         FMC_ISP->ISPADDR = u32PageAddr;
184         FMC_ISP->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
185 
186         while(FMC_ISP->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
187 
188         if(FMC_ISP->ISPCTL & FMC_ISPCTL_ISPFF_Msk)
189         {
190             FMC_ISP->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
191             ret = -1;
192         }
193     }
194     return ret;
195 }
196 
197 /**
198   * @brief      Execute Flash Bank erase
199   *
200   * @param[in]  u32BankAddr Base address of the flash bank to be erased.
201   *
202   * @return     ISP bank erase success or not.
203   * @retval     0  Success
204   * @retval     -1  Erase failed
205   *
206   * @details  Execute FMC_ISPCMD_BANK_ERASE command to erase a flash block.
207   */
FMC_EraseBank(uint32_t u32BankAddr)208 int32_t FMC_EraseBank(uint32_t u32BankAddr)
209 {
210     int32_t  ret = 0;
211 
212     FMC->ISPCMD = FMC_ISPCMD_BANK_ERASE;
213     FMC->ISPADDR = u32BankAddr;
214     FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
215 
216     while(FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) {}
217 
218     if(FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk)
219     {
220         FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
221         ret = -1;
222     }
223     return ret;
224 }
225 
226 
227 /**
228   * @brief  Execute Erase XOM Region
229   *
230   * @param[in]  u32XomNum  The XOMRn(n=0~3)
231   *
232   * @return   XOM erase success or not.
233   * @retval    0  Success
234   * @retval   -1  Erase failed
235   * @retval   -2  Invalid XOM number.
236   *
237   * @details Execute FMC_ISPCMD_PAGE_ERASE command to erase XOM.
238   */
FMC_EraseXOM(uint32_t u32XomNum)239 int32_t FMC_EraseXOM(uint32_t u32XomNum)
240 {
241     uint32_t u32Addr;
242     int32_t i32Active, err = 0;
243 
244     if(u32XomNum >= 4UL)
245     {
246         err = -2;
247     }
248 
249     if(err == 0)
250     {
251         i32Active = FMC_GetXOMState(u32XomNum);
252 
253         if(i32Active)
254         {
255             u32Addr = (((uint32_t)(&FMC->XOMR0STS)[u32XomNum]) & 0xFFFFFF00u) >> 8u;
256 
257             FMC->ISPCMD = FMC_ISPCMD_PAGE_ERASE;
258             FMC->ISPADDR = u32Addr;
259             FMC->ISPDAT = 0x55aa03u;
260             FMC->ISPTRG = 0x1u;
261 #if ISBEN
262             __ISB();
263 #endif
264             while(FMC->ISPTRG) {}
265 
266             /* Check ISPFF flag to know whether erase OK or fail. */
267             if(FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk)
268             {
269                 FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
270                 err = -1;
271             }
272         }
273         else
274         {
275             err = -1;
276         }
277     }
278     return err;
279 }
280 
281 /**
282   * @brief     Run CRC32 checksum calculation and get result.
283   *
284   * @param[in] u32addr   Starting flash address. It must be a page aligned address.
285   * @param[in] u32count  Byte count of flash to be calculated. It must be multiple of 2048bytes.
286   *
287   * @return    Success or not.
288   * @retval    0           Success.
289   * @retval    0xFFFFFFFF  Invalid parameter.
290   *
291   * @details  Run ISP CRC32 checksum command to calculate checksum then get and return checksum data.
292   */
FMC_GetChkSum(uint32_t u32addr,uint32_t u32count)293 uint32_t  FMC_GetChkSum(uint32_t u32addr, uint32_t u32count)
294 {
295     uint32_t   ret;
296 
297     if((u32addr % 2048UL) || (u32count % 2048UL))
298     {
299         ret = 0xFFFFFFFF;
300     }
301     else
302     {
303         FMC_ISP->ISPCMD  = FMC_ISPCMD_RUN_CKS;
304         FMC_ISP->ISPADDR = u32addr;
305         FMC_ISP->ISPDAT  = u32count;
306         FMC_ISP->ISPTRG  = FMC_ISPTRG_ISPGO_Msk;
307 
308         while(FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
309 
310         FMC_ISP->ISPCMD = FMC_ISPCMD_READ_CKS;
311         FMC_ISP->ISPADDR    = u32addr;
312         FMC_ISP->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
313 
314         while(FMC_ISP->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
315 
316         ret = FMC_ISP->ISPDAT;
317     }
318 
319     return ret;
320 }
321 
322 /**
323   * @brief  Check the OTP is locked or not.
324   *
325   * @param[in] u32OtpNum    The OTP number.
326   *
327   * @retval   1   OTP is locked.
328   * @retval   0   OTP is not locked.
329   * @retval   -1  Failed to read OTP lock bits.
330   * @retval   -2  Invalid OTP number.
331   *
332   * @details To get specify OTP lock status
333   */
FMC_IsOTPLocked(uint32_t u32OtpNum)334 int32_t FMC_IsOTPLocked(uint32_t u32OtpNum)
335 {
336     int32_t  ret = 0;
337 
338     if(u32OtpNum > 255UL)
339     {
340         ret = -2;
341     }
342 
343     if(ret == 0)
344     {
345         FMC->ISPCMD = FMC_ISPCMD_READ;
346         FMC->ISPADDR = FMC_OTP_BASE + 0x800UL + u32OtpNum * 4UL;
347         FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
348 
349         while(FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
350 
351         if(FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
352         {
353             FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
354             ret = -1;
355         }
356         else
357         {
358             if(FMC->ISPDAT != 0xFFFFFFFFUL)
359             {
360                 ret = 1;   /* Lock work was progrmmed. OTP was locked. */
361             }
362         }
363     }
364     return ret;
365 }
366 
367 /**
368   * @brief  Check the XOM is actived or not.
369   *
370   * @param[in] u32XomNum    The xom number(0~3).
371   *
372   * @retval   1   XOM is actived.
373   * @retval   0   XOM is not actived.
374   * @retval   -2  Invalid XOM number.
375   *
376   * @details To get specify XOMRn(n=0~3) active status
377   */
FMC_GetXOMState(uint32_t u32XomNum)378 int32_t FMC_GetXOMState(uint32_t u32XomNum)
379 {
380     uint32_t u32act;
381     int32_t  ret = 0;
382 
383     if(u32XomNum >= 4UL)
384     {
385         ret = -2;
386     }
387 
388     if(ret >= 0)
389     {
390         u32act = (((FMC_ISP->XOMSTS) & 0xful) & (1ul << u32XomNum)) >> u32XomNum;
391         ret = (int32_t)u32act;
392     }
393     return ret;
394 }
395 
396 /**
397   * @brief  Lock the specified OTP.
398   *
399   * @param[in] u32OtpNum    The OTP number.
400   *
401   * @retval    0   Success
402   * @retval   -1  Failed to write OTP lock bits.
403   * @retval   -2  Invalid OTP number.
404   *
405   * @details  To lock specified OTP number
406   */
FMC_LockOTP(uint32_t u32OtpNum)407 int32_t FMC_LockOTP(uint32_t u32OtpNum)
408 {
409     int32_t  ret = 0;
410 
411     if(u32OtpNum > 255UL)
412     {
413         ret = -2;
414     }
415 
416     if(ret == 0)
417     {
418         FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
419         FMC->ISPADDR = FMC_OTP_BASE + 0x800UL + u32OtpNum * 4UL;
420         FMC->ISPDAT = 0UL;
421         FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
422 
423         while(FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
424 
425         if(FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
426         {
427             FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
428             ret = -1;
429         }
430     }
431     return ret;
432 }
433 
434 /**
435   * @brief    Enable FMC ISP function
436   *
437   * @param    None
438   *
439   * @return   None
440   *
441   * @details  ISPEN bit of ISPCON must be set before we can use ISP commands.
442   *           Therefore, To use all FMC function APIs, user needs to call FMC_Open() first to enable ISP functions.
443   *
444   * @note     ISP functions are write-protected. user also needs to unlock it by calling SYS_UnlockReg() before using all ISP functions.
445   *
446   */
FMC_Open(void)447 void FMC_Open(void)
448 {
449     FMC_ISP->ISPCTL |=  FMC_ISPCTL_ISPEN_Msk;
450 }
451 
452 
453 /**
454   * @brief      Read a word bytes from flash
455   *
456   * @param[in]  u32Addr Address of the flash location to be read.
457   *             It must be a word aligned address.
458   *
459   * @return     The word data read from specified flash address.
460   *
461   * @details    Execute FMC_ISPCMD_READ command to read a word from flash.
462   */
FMC_Read(uint32_t u32Addr)463 uint32_t FMC_Read(uint32_t u32Addr)
464 {
465     FMC_ISP->ISPCMD = FMC_ISPCMD_READ;
466     FMC_ISP->ISPADDR = u32Addr;
467     FMC_ISP->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
468     while(FMC_ISP->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
469 
470     return FMC_ISP->ISPDAT;
471 }
472 
473 /**
474   * @brief      Read a double-word bytes from flash
475   *
476   * @param[in]  u32addr   Address of the flash location to be read.
477   *             It must be a double-word aligned address.
478   *
479   * @param[out] u32data0  Place holder of word 0 read from flash address u32addr.
480   * @param[out] u32data1  Place holder of word 0 read from flash address u32addr+4.
481   *
482   * @return     0   Success
483   * @return     -1  Failed
484   *
485   * @details    Execute FMC_ISPCMD_READ_64 command to read a double-word from flash.
486   */
FMC_Read64(uint32_t u32addr,uint32_t * u32data0,uint32_t * u32data1)487 int32_t FMC_Read64(uint32_t u32addr, uint32_t * u32data0, uint32_t * u32data1)
488 {
489     int32_t  ret = 0;
490 
491     FMC->ISPCMD = FMC_ISPCMD_READ_64;
492     FMC->ISPADDR    = u32addr;
493     FMC->ISPDAT = 0x0UL;
494     FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
495 
496     while(FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
497 
498     if(FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
499     {
500         FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
501         ret = -1;
502     }
503     else
504     {
505         *u32data0 = FMC->MPDAT0;
506         *u32data1 = FMC->MPDAT1;
507     }
508     return ret;
509 }
510 
511 /**
512   * @brief  Read data from OTP
513   *
514   * @param[in] u32OtpNum    The OTP number(0~255).
515   * @param[in] u32LowWord   Low word of the 64-bits data.
516   * @param[in] u32HighWord   High word of the 64-bits data.
517   *
518   * @retval    0   Success
519   * @retval   -1  Read failed.
520   * @retval   -2  Invalid OTP number.
521   *
522   * @details  Read the 64-bits data from the specified OTP.
523   */
FMC_ReadOTP(uint32_t u32OtpNum,uint32_t * u32LowWord,uint32_t * u32HighWord)524 int32_t FMC_ReadOTP(uint32_t u32OtpNum, uint32_t *u32LowWord, uint32_t *u32HighWord)
525 {
526     int32_t  ret = 0;
527 
528     if(u32OtpNum > 255UL)
529     {
530         ret = -2;
531     }
532 
533     if(ret == 0)
534     {
535         FMC->ISPCMD = FMC_ISPCMD_READ_64;
536         FMC->ISPADDR    = FMC_OTP_BASE + u32OtpNum * 8UL ;
537         FMC->ISPDAT = 0x0UL;
538         FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
539 
540         while(FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) {}
541 
542         if(FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
543         {
544             FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
545             ret = -1;
546         }
547         else
548         {
549             *u32LowWord = FMC->MPDAT0;
550             *u32HighWord = FMC->MPDAT1;
551         }
552     }
553     return ret;
554 }
555 
556 /**
557   * @brief       Read the User Configuration words.
558   *
559   * @param[out]  u32Config[]  The word buffer to store the User Configuration data.
560   * @param[in]   u32Count   The word count to be read.
561   *
562   * @return      Success or not.
563   * @retval       0 Success
564   * @retval      -1 Failed
565   *
566   * @details     This function is used to read the settings of user configuration.
567   *              if u32Count = 1, Only CONFIG0 will be returned to the buffer specified by u32Config.
568   *              if u32Count = 2, Both CONFIG0 and CONFIG1 will be returned.
569   */
FMC_ReadConfig(uint32_t u32Config[],uint32_t u32Count)570 int32_t FMC_ReadConfig(uint32_t u32Config[], uint32_t u32Count)
571 {
572     uint32_t i;
573 
574     for(i = 0u; i < u32Count; i++)
575     {
576         u32Config[i] = FMC_Read(FMC_CONFIG_BASE + i * 4u);
577     }
578     return 0;
579 }
580 
581 /**
582   * @brief      Write a word bytes to flash.
583   *
584   * @param[in]  u32Addr Address of the flash location to be programmed.
585   *             It must be a word aligned address.
586   * @param[in]  u32Data The word data to be programmed.
587   *
588   * @return     None
589   *
590   * @ details   Execute ISP FMC_ISPCMD_PROGRAM to program a word to flash.
591   */
FMC_Write(uint32_t u32Addr,uint32_t u32Data)592 void FMC_Write(uint32_t u32Addr, uint32_t u32Data)
593 {
594     FMC_ISP->ISPCMD = FMC_ISPCMD_PROGRAM;
595     FMC_ISP->ISPADDR = u32Addr;
596     FMC_ISP->ISPDAT = u32Data;
597     FMC_ISP->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
598     while(FMC_ISP->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
599 }
600 
601 /**
602   * @brief      Write a double-word bytes to flash
603   *
604   * @param[in]  u32addr Address of the flash location to be programmed.
605   *             It must be a double-word aligned address.
606   * @param[in]  u32data0   The word data to be programmed to flash address u32addr.
607   * @param[in]  u32data1   The word data to be programmed to flash address u32addr+4.
608   *
609   * @return     0   Success
610   * @return     -1  Failed
611   *
612   * @ details   Execute ISP FMC_ISPCMD_PROGRAM_64 to program a double-word to flash.
613   */
FMC_Write8Bytes(uint32_t u32addr,uint32_t u32data0,uint32_t u32data1)614 int32_t FMC_Write8Bytes(uint32_t u32addr, uint32_t u32data0, uint32_t u32data1)
615 {
616     int32_t  ret = 0;
617 
618     FMC->ISPCMD  = FMC_ISPCMD_PROGRAM_64;
619     FMC->ISPADDR = u32addr;
620     FMC->MPDAT0  = u32data0;
621     FMC->MPDAT1  = u32data1;
622     FMC->ISPTRG  = FMC_ISPTRG_ISPGO_Msk;
623 
624     while(FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
625 
626     if(FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
627     {
628         FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
629         ret = -1;
630     }
631     return ret;
632 }
633 
634 /**
635   * @brief    Write User Configuration
636   *
637   * @param[in]  au32Config[] The word buffer to store the User Configuration data.
638   * @param[in]  u32Count The word count to program to User Configuration.
639   *
640   * @retval     0 Success
641   * @retval    -1 Failed
642   *
643   * @details  User must enable User Configuration update before writing it.
644   *           User must erase User Configuration before writing it.
645   *           User Configuration is also be page erase. User needs to backup necessary data
646   *           before erase User Configuration.
647   */
FMC_WriteConfig(uint32_t au32Config[],uint32_t u32Count)648 int32_t FMC_WriteConfig(uint32_t au32Config[], uint32_t u32Count)
649 {
650     int32_t  ret = 0;
651     uint32_t i;
652 
653     FMC_ENABLE_CFG_UPDATE();
654     for(i = 0u; i < u32Count; i++)
655     {
656         FMC_Write(FMC_CONFIG_BASE + i * 4u, au32Config[i]);
657         if(FMC_Read(FMC_CONFIG_BASE + i * 4u) != au32Config[i])
658         {
659             ret = -1;
660         }
661     }
662     FMC_DISABLE_CFG_UPDATE();
663     return ret;
664 }
665 
666 /**
667   * @brief      Write Multi-Word bytes to flash
668   *
669   * @param[in]  u32Addr    Start flash address in APROM where the data chunk to be programmed into.
670   *                        This address must be 8-bytes aligned to flash address.
671   * @param[in]  pu32Buf    Buffer that carry the data chunk.
672   * @param[in]  u32Len     Length of the data chunk in bytes.
673   *
674   * @retval     >=0  Number of data bytes were programmed.
675   * @return     -1   Invalid address.
676   *
677   * @details     Program Multi-Word data into specified address of flash.
678   */
679 
FMC_WriteMultiple(uint32_t u32Addr,uint32_t pu32Buf[],uint32_t u32Len)680 int32_t FMC_WriteMultiple(uint32_t u32Addr, uint32_t pu32Buf[], uint32_t u32Len)
681 {
682 
683     uint32_t i, idx, u32OnProg;
684     int32_t err,  retval = 0;
685 
686     if((u32Addr >= FMC_APROM_END) || ((u32Addr % 8) != 0))
687     {
688         return -1;
689     }
690 
691     idx = 0u;
692     FMC->ISPCMD = FMC_ISPCMD_PROGRAM_MUL;
693     FMC->ISPADDR = u32Addr;
694     retval += 16;
695     do
696     {
697         err = 0;
698         u32OnProg = 1u;
699         FMC->MPDAT0 = pu32Buf[idx + 0u];
700         FMC->MPDAT1 = pu32Buf[idx + 1u];
701         FMC->MPDAT2 = pu32Buf[idx + 2u];
702         FMC->MPDAT3 = pu32Buf[idx + 3u];
703         FMC->ISPTRG = 0x1u;
704         idx += 4u;
705 
706         for(i = idx; i < (u32Len / 4u); i += 4u) /* Max data length is 256 bytes (512/4 words)*/
707         {
708             __set_PRIMASK(1u); /* Mask interrupt to avoid status check coherence error*/
709             do
710             {
711                 if((FMC->MPSTS & FMC_MPSTS_MPBUSY_Msk) == 0u)
712                 {
713                     __set_PRIMASK(0u);
714 
715                     FMC->ISPADDR = FMC->MPADDR & (~0xful);
716                     idx = (FMC->ISPADDR - u32Addr) / 4u;
717                     err = -1;
718                 }
719             }
720             while((FMC->MPSTS & (3u << FMC_MPSTS_D0_Pos)) && (err == 0));
721 
722             if(err == 0)
723             {
724                 retval += 8;
725 
726                 /* Update new data for D0 */
727                 FMC->MPDAT0 = pu32Buf[i];
728                 FMC->MPDAT1 = pu32Buf[i + 1u];
729                 do
730                 {
731                     if((FMC->MPSTS & FMC_MPSTS_MPBUSY_Msk) == 0u)
732                     {
733                         __set_PRIMASK(0u);
734                         FMC->ISPADDR = FMC->MPADDR & (~0xful);
735                         idx = (FMC->ISPADDR - u32Addr) / 4u;
736                         err = -1;
737                     }
738                 }
739                 while((FMC->MPSTS & (3u << FMC_MPSTS_D2_Pos)) && (err == 0));
740 
741                 if(err == 0)
742                 {
743                     retval += 8;
744 
745                     /* Update new data for D2*/
746                     FMC->MPDAT2 = pu32Buf[i + 2u];
747                     FMC->MPDAT3 = pu32Buf[i + 3u];
748                     __set_PRIMASK(0u);
749                 }
750             }
751 
752             if(err < 0)
753             {
754                 break;
755             }
756         }
757         if(err == 0)
758         {
759             u32OnProg = 0u;
760             while(FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) {}
761         }
762     }
763     while(u32OnProg);
764 
765     return retval;
766 }
767 
768 /**
769   * @brief     Write data to OTP
770   *
771   * @param[in] u32OtpNum    The OTP number(0~255).
772   * @param[in] u32LowWord   Low word of the 64-bits data.
773   * @param[in] u32HighWord   High word of the 64-bits data.
774   *
775   * @retval    0   Success
776   * @retval    -1  Program failed.
777   * @retval    -2  Invalid OTP number.
778   *
779   * @details  Program a 64-bits data to the specified OTP.
780   */
FMC_WriteOTP(uint32_t u32OtpNum,uint32_t u32LowWord,uint32_t u32HighWord)781 int32_t FMC_WriteOTP(uint32_t u32OtpNum, uint32_t u32LowWord, uint32_t u32HighWord)
782 {
783     int32_t  ret = 0;
784 
785     if(u32OtpNum > 255UL)
786     {
787         ret = -2;
788     }
789 
790     if(ret == 0)
791     {
792         FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
793         FMC->ISPADDR = FMC_OTP_BASE + u32OtpNum * 8UL;
794         FMC->ISPDAT = u32LowWord;
795         FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
796 
797         while(FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
798 
799         if(FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
800         {
801             FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
802             ret = -1;
803         }
804     }
805 
806     if(ret == 0)
807     {
808         FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
809         FMC->ISPADDR = FMC_OTP_BASE + u32OtpNum * 8UL + 4UL;
810         FMC->ISPDAT = u32HighWord;
811         FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
812 
813         while(FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
814 
815         if(FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
816         {
817             FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
818             ret = -1;
819         }
820     }
821 
822     return ret;
823 }
824 
825 /**
826   * @brief     Swap Bank0/Bank1
827   *
828   * @param[in] u32Bank    Bank Num which will swap to.
829   *
830   * @retval    0   Success
831   * @retval    -1  Program failed.
832   *
833   * @details  Swap Bank0/Bank1
834   */
FMC_SwapBank(uint32_t u32Bank)835 int32_t FMC_SwapBank(uint32_t u32Bank)
836 {
837     int32_t  ret = 0;
838 
839     FMC->ISPCMD = FMC_ISPCMD_BANK_SWAP;
840     FMC->ISPADDR = u32Bank;
841     FMC->ISPDAT = 0x5AA55AA5UL;
842     FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
843 
844     while(FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
845 
846     if(FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk)
847     {
848         FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
849         ret = -1;
850     }
851     return ret;
852 }
853 
854 /**@}*/ /* end of group FMC_EXPORTED_FUNCTIONS */
855 
856 /**@}*/ /* end of group FMC_Driver */
857 
858 /**@}*/ /* end of group Standard_Driver */
859