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