1 /**************************************************************************//**
2 * @file fmc.c
3 * @version V1.00
4 * @brief M480 series FMC driver source file
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 * @copyright (C) 2016-2020 Nuvoton Technology Corp. All rights reserved.
8 *****************************************************************************/
9
10 #include <stdio.h>
11
12 #include "NuMicro.h"
13
14
15 /** @addtogroup Standard_Driver Standard Driver
16 @{
17 */
18
19 /** @addtogroup FMC_Driver FMC Driver
20 @{
21 */
22
23
24 /** @addtogroup FMC_EXPORTED_FUNCTIONS FMC Exported Functions
25 @{
26 */
27
28
29 /**
30 * @brief Disable FMC ISP function.
31 * @return None
32 */
FMC_Close(void)33 void FMC_Close(void)
34 {
35 FMC->ISPCTL &= ~FMC_ISPCTL_ISPEN_Msk;
36 }
37
38 /**
39 * @brief Config XOM Region
40 * @param[in] u32XomNum The XOM number(0~3)
41 * @param[in] u32XomBase The XOM region base address.
42 * @param[in] u8XomPage The XOM page number of region size.
43 *
44 * @retval 0 Success
45 * @retval 1 XOM is has already actived.
46 * @retval -1 Program failed.
47 * @retval -2 Invalid XOM number.
48 *
49 * @details Program XOM base address and XOM size(page)
50 */
FMC_ConfigXOM(uint32_t u32XomNum,uint32_t u32XomBase,uint8_t u8XomPage)51 int32_t FMC_ConfigXOM(uint32_t u32XomNum, uint32_t u32XomBase, uint8_t u8XomPage)
52 {
53 int32_t ret = 0;
54
55 if(u32XomNum >= 4UL)
56 {
57 ret = -2;
58 }
59
60 if(ret == 0)
61 {
62 ret = FMC_GetXOMState(u32XomNum);
63 }
64
65 if(ret == 0)
66 {
67 FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
68 FMC->ISPADDR = FMC_XOM_BASE + (u32XomNum * 0x10u);
69 FMC->ISPDAT = u32XomBase;
70 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
71 while(FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) {}
72
73 if(FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
74 {
75 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
76 ret = -1;
77 }
78 }
79
80 if(ret == 0)
81 {
82 FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
83 FMC->ISPADDR = FMC_XOM_BASE + (u32XomNum * 0x10u + 0x04u);
84 FMC->ISPDAT = u8XomPage;
85 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
86 while(FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) {}
87
88 if(FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
89 {
90 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
91 ret = -1;
92 }
93 }
94
95 if(ret == 0)
96 {
97 FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
98 FMC->ISPADDR = FMC_XOM_BASE + (u32XomNum * 0x10u + 0x08u);
99 FMC->ISPDAT = 0u;
100 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
101 while(FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) {}
102
103 if(FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
104 {
105 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
106 ret = -1;
107 }
108 }
109
110 return ret;
111 }
112
113 /**
114 * @brief Execute FMC_ISPCMD_PAGE_ERASE command to erase a flash page. The page size is 4096 bytes.
115 * @param[in] u32PageAddr Address of the flash page to be erased.
116 * It must be a 4096 bytes aligned address.
117 * @return ISP page erase success or not.
118 * @retval 0 Success
119 * @retval -1 Erase failed
120 */
FMC_Erase(uint32_t u32PageAddr)121 int32_t FMC_Erase(uint32_t u32PageAddr)
122 {
123 int32_t ret = 0;
124
125 if (u32PageAddr == FMC_SPROM_BASE)
126 {
127 ret = FMC_Erase_SPROM();
128 }
129
130 if (ret == 0)
131 {
132 FMC->ISPCMD = FMC_ISPCMD_PAGE_ERASE;
133 FMC->ISPADDR = u32PageAddr;
134 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
135
136 while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
137
138 if (FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk)
139 {
140 FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
141 ret = -1;
142 }
143 }
144 return ret;
145 }
146
147
148 /**
149 * @brief Execute FMC_ISPCMD_PAGE_ERASE command to erase SPROM. The page size is 4096 bytes.
150 * @return SPROM page erase success or not.
151 * @retval 0 Success
152 * @retval -1 Erase failed
153 */
FMC_Erase_SPROM(void)154 int32_t FMC_Erase_SPROM(void)
155 {
156 int32_t ret = 0;
157
158 FMC->ISPCMD = FMC_ISPCMD_PAGE_ERASE;
159 FMC->ISPADDR = FMC_SPROM_BASE;
160 FMC->ISPDAT = 0x0055AA03UL;
161 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
162
163 while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
164
165 if (FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk)
166 {
167 FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
168 ret = -1;
169 }
170 return ret;
171 }
172
173 /**
174 * @brief Execute FMC_ISPCMD_BLOCK_ERASE command to erase a flash block. The block size is 4 pages.
175 * @param[in] u32BlockAddr Address of the flash block to be erased.
176 * It must be a 4 pages aligned address.
177 * @return ISP page erase success or not.
178 * @retval 0 Success
179 * @retval -1 Erase failed
180 */
FMC_Erase_Block(uint32_t u32BlockAddr)181 int32_t FMC_Erase_Block(uint32_t u32BlockAddr)
182 {
183 int32_t ret = 0;
184
185 FMC->ISPCMD = FMC_ISPCMD_BLOCK_ERASE;
186 FMC->ISPADDR = u32BlockAddr;
187 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
188
189 while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
190
191 if (FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk)
192 {
193 FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
194 ret = -1;
195 }
196 return ret;
197 }
198
199 /**
200 * @brief Execute FMC_ISPCMD_BANK_ERASE command to erase a flash block.
201 * @param[in] u32BankAddr Base address of the flash bank to be erased.
202 * @return ISP page erase success or not.
203 * @retval 0 Success
204 * @retval -1 Erase failed
205 */
FMC_Erase_Bank(uint32_t u32BankAddr)206 int32_t FMC_Erase_Bank(uint32_t u32BankAddr)
207 {
208 int32_t ret = 0;
209
210 FMC->ISPCMD = FMC_ISPCMD_BANK_ERASE;
211 FMC->ISPADDR = u32BankAddr;
212 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
213
214 while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
215
216 if (FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk)
217 {
218 FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
219 ret = -1;
220 }
221 return ret;
222 }
223
224 /**
225 * @brief Execute Erase XOM Region
226 *
227 * @param[in] u32XomNum The XOMRn(n=0~3)
228 *
229 * @return XOM erase success or not.
230 * @retval 0 Success
231 * @retval -1 Erase failed
232 * @retval -2 Invalid XOM number.
233 *
234 * @details Execute FMC_ISPCMD_PAGE_ERASE command to erase XOM.
235 */
FMC_EraseXOM(uint32_t u32XomNum)236 int32_t FMC_EraseXOM(uint32_t u32XomNum)
237 {
238 uint32_t u32Addr;
239 int32_t i32Active, err = 0;
240
241 if(u32XomNum >= 4UL)
242 {
243 err = -2;
244 }
245
246 if(err == 0)
247 {
248 i32Active = FMC_GetXOMState(u32XomNum);
249
250 if(i32Active)
251 {
252 switch(u32XomNum)
253 {
254 case 0u:
255 u32Addr = (FMC->XOMR0STS & 0xFFFFFF00u) >> 8u;
256 break;
257 case 1u:
258 u32Addr = (FMC->XOMR1STS & 0xFFFFFF00u) >> 8u;
259 break;
260 case 2u:
261 u32Addr = (FMC->XOMR2STS & 0xFFFFFF00u) >> 8u;
262 break;
263 case 3u:
264 u32Addr = (FMC->XOMR3STS & 0xFFFFFF00u) >> 8u;
265 break;
266 default:
267 break;
268 }
269 FMC->ISPCMD = FMC_ISPCMD_PAGE_ERASE;
270 FMC->ISPADDR = u32Addr;
271 FMC->ISPDAT = 0x55aa03u;
272 FMC->ISPTRG = 0x1u;
273 #if ISBEN
274 __ISB();
275 #endif
276 while(FMC->ISPTRG) {}
277
278 /* Check ISPFF flag to know whether erase OK or fail. */
279 if(FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk)
280 {
281 FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
282 err = -1;
283 }
284 }
285 else
286 {
287 err = -1;
288 }
289 }
290 return err;
291 }
292
293 /**
294 * @brief Check the XOM is actived or not.
295 *
296 * @param[in] u32XomNum The xom number(0~3).
297 *
298 * @retval 1 XOM is actived.
299 * @retval 0 XOM is not actived.
300 * @retval -2 Invalid XOM number.
301 *
302 * @details To get specify XOMRn(n=0~3) active status
303 */
FMC_GetXOMState(uint32_t u32XomNum)304 int32_t FMC_GetXOMState(uint32_t u32XomNum)
305 {
306 uint32_t u32act;
307 int32_t ret = 0;
308
309 if(u32XomNum >= 4UL)
310 {
311 ret = -2;
312 }
313
314 if(ret >= 0)
315 {
316 u32act = (((FMC->XOMSTS) & 0xful) & (1ul << u32XomNum)) >> u32XomNum;
317 ret = (int32_t)u32act;
318 }
319 return ret;
320 }
321
322 /**
323 * @brief Get the current boot source.
324 * @return The current boot source.
325 * @retval 0 Is boot from APROM.
326 * @retval 1 Is boot from LDROM.
327 * @retval 2 Is boot from Boot Loader.
328 */
FMC_GetBootSource(void)329 int32_t FMC_GetBootSource (void)
330 {
331 if (FMC->ISPCTL & FMC_ISPCTL_BL_Msk)
332 {
333 return 2;
334 }
335 if (FMC->ISPCTL & FMC_ISPCTL_BS_Msk)
336 {
337 return 1;
338 }
339 return 0;
340 }
341
342
343 /**
344 * @brief Enable FMC ISP function
345 * @return None
346 */
FMC_Open(void)347 void FMC_Open(void)
348 {
349 FMC->ISPCTL |= FMC_ISPCTL_ISPEN_Msk;
350 }
351
352
353 /**
354 * @brief Execute FMC_ISPCMD_READ command to read a word from flash.
355 * @param[in] u32Addr Address of the flash location to be read.
356 * It must be a word aligned address.
357 * @return The word data read from specified flash address.
358 */
FMC_Read(uint32_t u32Addr)359 uint32_t FMC_Read(uint32_t u32Addr)
360 {
361 FMC->ISPCMD = FMC_ISPCMD_READ;
362 FMC->ISPADDR = u32Addr;
363 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
364 while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
365
366 return FMC->ISPDAT;
367 }
368
369
370 /**
371 * @brief Execute FMC_ISPCMD_READ_64 command to read a double-word from flash.
372 * @param[in] u32addr Address of the flash location to be read.
373 * It must be a double-word aligned address.
374 * @param[out] u32data0 Place holder of word 0 read from flash address u32addr.
375 * @param[out] u32data1 Place holder of word 0 read from flash address u32addr+4.
376 * @return 0 Success
377 * @return -1 Failed
378 */
FMC_Read_64(uint32_t u32addr,uint32_t * u32data0,uint32_t * u32data1)379 int32_t FMC_Read_64(uint32_t u32addr, uint32_t * u32data0, uint32_t * u32data1)
380 {
381 int32_t ret = 0;
382
383 FMC->ISPCMD = FMC_ISPCMD_READ_64;
384 FMC->ISPADDR = u32addr;
385 FMC->ISPDAT = 0x0UL;
386 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
387
388 while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
389
390 if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
391 {
392 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
393 ret = -1;
394 }
395 else
396 {
397 *u32data0 = FMC->MPDAT0;
398 *u32data1 = FMC->MPDAT1;
399 }
400 return ret;
401 }
402
403
404 /**
405 * @brief Get the base address of Data Flash if enabled.
406 * @retval The base address of Data Flash
407 */
FMC_ReadDataFlashBaseAddr(void)408 uint32_t FMC_ReadDataFlashBaseAddr(void)
409 {
410 return FMC->DFBA;
411 }
412
413 /**
414 * @brief Set boot source from LDROM or APROM after next software reset
415 * @param[in] i32BootSrc
416 * 1: Boot from LDROM
417 * 0: Boot from APROM
418 * @return None
419 * @details This function is used to switch APROM boot or LDROM boot. User need to call
420 * FMC_SetBootSource to select boot source first, then use CPU reset or
421 * System Reset Request to reset system.
422 */
FMC_SetBootSource(int32_t i32BootSrc)423 void FMC_SetBootSource(int32_t i32BootSrc)
424 {
425 if(i32BootSrc)
426 {
427 FMC->ISPCTL |= FMC_ISPCTL_BS_Msk; /* Boot from LDROM */
428 }
429 else
430 {
431 FMC->ISPCTL &= ~FMC_ISPCTL_BS_Msk;/* Boot from APROM */
432 }
433 }
434
435 /**
436 * @brief Execute ISP FMC_ISPCMD_PROGRAM to program a word to flash.
437 * @param[in] u32Addr Address of the flash location to be programmed.
438 * It must be a word aligned address.
439 * @param[in] u32Data The word data to be programmed.
440 * @return None
441 */
FMC_Write(uint32_t u32Addr,uint32_t u32Data)442 void FMC_Write(uint32_t u32Addr, uint32_t u32Data)
443 {
444 FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
445 FMC->ISPADDR = u32Addr;
446 FMC->ISPDAT = u32Data;
447 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
448 while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
449 }
450
451 /**
452 * @brief Execute ISP FMC_ISPCMD_PROGRAM_64 to program a double-word to flash.
453 * @param[in] u32addr Address of the flash location to be programmed.
454 * It must be a double-word aligned address.
455 * @param[in] u32data0 The word data to be programmed to flash address u32addr.
456 * @param[in] u32data1 The word data to be programmed to flash address u32addr+4.
457 * @return 0 Success
458 * @return -1 Failed
459 */
FMC_Write8Bytes(uint32_t u32addr,uint32_t u32data0,uint32_t u32data1)460 int32_t FMC_Write8Bytes(uint32_t u32addr, uint32_t u32data0, uint32_t u32data1)
461 {
462 int32_t ret = 0;
463
464 FMC->ISPCMD = FMC_ISPCMD_PROGRAM_64;
465 FMC->ISPADDR = u32addr;
466 FMC->MPDAT0 = u32data0;
467 FMC->MPDAT1 = u32data1;
468 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
469
470 while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
471
472 if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
473 {
474 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
475 ret = -1;
476 }
477 return ret;
478 }
479
480
481 /**
482 * @brief Program Multi-Word data into specified address of flash.
483 * @param[in] u32Addr Start flash address in APROM where the data chunk to be programmed into.
484 * This address must be 8-bytes aligned to flash address.
485 * @param[in] pu32Buf Buffer that carry the data chunk.
486 * @param[in] u32Len Length of the data chunk in bytes.
487 * @retval >=0 Number of data bytes were programmed.
488 * @return -1 Invalid address.
489 */
FMC_WriteMultiple(uint32_t u32Addr,uint32_t pu32Buf[],uint32_t u32Len)490 int32_t FMC_WriteMultiple(uint32_t u32Addr, uint32_t pu32Buf[], uint32_t u32Len)
491 {
492 int i, idx, retval = 0;
493
494 if ((u32Addr >= FMC_APROM_END) || ((u32Addr % 8) != 0))
495 {
496 return -1;
497 }
498
499 u32Len = u32Len - (u32Len % 8); /* u32Len must be multiple of 8. */
500
501 idx = 0;
502
503 while (u32Len >= 8)
504 {
505 FMC->ISPADDR = u32Addr;
506 FMC->MPDAT0 = pu32Buf[idx++];
507 FMC->MPDAT1 = pu32Buf[idx++];
508 FMC->MPDAT2 = pu32Buf[idx++];
509 FMC->MPDAT3 = pu32Buf[idx++];
510 FMC->ISPCMD = FMC_ISPCMD_PROGRAM_MUL;
511 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
512
513 for (i = 16; i < FMC_MULTI_WORD_PROG_LEN; )
514 {
515 while (FMC->MPSTS & (FMC_MPSTS_D0_Msk | FMC_MPSTS_D1_Msk))
516 ;
517 retval += 8;
518 u32Len -= 8;
519 if (u32Len < 8)
520 {
521 return retval;
522 }
523
524 if (!(FMC->MPSTS & FMC_MPSTS_MPBUSY_Msk))
525 {
526 /* printf(" [WARNING] busy cleared after D0D1 cleared!\n"); */
527 i += 8;
528 break;
529 }
530
531 FMC->MPDAT0 = pu32Buf[idx++];
532 FMC->MPDAT1 = pu32Buf[idx++];
533
534 if (i == FMC_MULTI_WORD_PROG_LEN/4)
535 break; // done
536
537 while (FMC->MPSTS & (FMC_MPSTS_D2_Msk | FMC_MPSTS_D3_Msk))
538 ;
539 retval += 8;
540 u32Len -= 8;
541 if (u32Len < 8)
542 {
543 return retval;
544 }
545
546 if (!(FMC->MPSTS & FMC_MPSTS_MPBUSY_Msk))
547 {
548 /* printf(" [WARNING] busy cleared after D2D3 cleared!\n"); */
549 i += 8;
550 break;
551 }
552
553 FMC->MPDAT2 = pu32Buf[idx++];
554 FMC->MPDAT3 = pu32Buf[idx++];
555 }
556
557 if (i != FMC_MULTI_WORD_PROG_LEN)
558 {
559 /* printf(" [WARNING] Multi-word program interrupted at 0x%x !!\n", i); */
560 return retval;
561 }
562
563 while (FMC->MPSTS & FMC_MPSTS_MPBUSY_Msk) ;
564
565 u32Addr += FMC_MULTI_WORD_PROG_LEN;
566 }
567 return retval;
568 }
569
570
571 /**
572 * @brief Program a 64-bits data to the specified OTP.
573 * @param[in] otp_num The OTP number.
574 * @param[in] low_word Low word of the 64-bits data.
575 * @param[in] high_word Low word of the 64-bits data.
576 * @retval 0 Success
577 * @retval -1 Program failed.
578 * @retval -2 Invalid OTP number.
579 */
FMC_Write_OTP(uint32_t otp_num,uint32_t low_word,uint32_t high_word)580 int32_t FMC_Write_OTP(uint32_t otp_num, uint32_t low_word, uint32_t high_word)
581 {
582 int32_t ret = 0;
583
584 if (otp_num > 255UL)
585 {
586 ret = -2;
587 }
588
589 if (ret == 0)
590 {
591 FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
592 FMC->ISPADDR = FMC_OTP_BASE + otp_num * 8UL;
593 FMC->ISPDAT = low_word;
594 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
595
596 while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
597
598 if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
599 {
600 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
601 ret = -1;
602 }
603 }
604
605 if (ret == 0)
606 {
607 FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
608 FMC->ISPADDR = FMC_OTP_BASE + otp_num * 8UL + 4UL;
609 FMC->ISPDAT = high_word;
610 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
611
612 while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
613
614 if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
615 {
616 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
617 ret = -1;
618 }
619 }
620
621 return ret;
622 }
623
624 /**
625 * @brief Read the 64-bits data from the specified OTP.
626 * @param[in] otp_num The OTP number.
627 * @param[in] low_word Low word of the 64-bits data.
628 * @param[in] high_word Low word of the 64-bits data.
629 * @retval 0 Success
630 * @retval -1 Read failed.
631 * @retval -2 Invalid OTP number.
632 */
FMC_Read_OTP(uint32_t otp_num,uint32_t * low_word,uint32_t * high_word)633 int32_t FMC_Read_OTP(uint32_t otp_num, uint32_t *low_word, uint32_t *high_word)
634 {
635 int32_t ret = 0;
636
637 if (otp_num > 255UL)
638 {
639 ret = -2;
640 }
641
642 if (ret == 0)
643 {
644 FMC->ISPCMD = FMC_ISPCMD_READ_64;
645 FMC->ISPADDR = FMC_OTP_BASE + otp_num * 8UL ;
646 FMC->ISPDAT = 0x0UL;
647 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
648
649 while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
650
651 if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
652 {
653 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
654 ret = -1;
655 }
656 else
657 {
658 *low_word = FMC->MPDAT0;
659 *high_word = FMC->MPDAT1;
660 }
661 }
662 return ret;
663 }
664
665 /**
666 * @brief Lock the specified OTP.
667 * @param[in] otp_num The OTP number.
668 * @retval 0 Success
669 * @retval -1 Failed to write OTP lock bits.
670 * @retval -2 Invalid OTP number.
671 */
FMC_Lock_OTP(uint32_t otp_num)672 int32_t FMC_Lock_OTP(uint32_t otp_num)
673 {
674 int32_t ret = 0;
675
676 if (otp_num > 255UL)
677 {
678 ret = -2;
679 }
680
681 if (ret == 0)
682 {
683 FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
684 FMC->ISPADDR = FMC_OTP_BASE + 0x800UL + otp_num * 4UL;
685 FMC->ISPDAT = 0UL;
686 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
687
688 while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
689
690 if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
691 {
692 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
693 ret = -1;
694 }
695 }
696 return ret;
697 }
698
699 /**
700 * @brief Check the OTP is locked or not.
701 * @param[in] otp_num The OTP number.
702 * @retval 1 OTP is locked.
703 * @retval 0 OTP is not locked.
704 * @retval -1 Failed to read OTP lock bits.
705 * @retval -2 Invalid OTP number.
706 */
FMC_Is_OTP_Locked(uint32_t otp_num)707 int32_t FMC_Is_OTP_Locked(uint32_t otp_num)
708 {
709 int32_t ret = 0;
710
711 if (otp_num > 255UL)
712 {
713 ret = -2;
714 }
715
716 if (ret == 0)
717 {
718 FMC->ISPCMD = FMC_ISPCMD_READ;
719 FMC->ISPADDR = FMC_OTP_BASE + 0x800UL + otp_num * 4UL;
720 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
721
722 while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
723
724 if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
725 {
726 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
727 ret = -1;
728 }
729 else
730 {
731 if (FMC->ISPDAT != 0xFFFFFFFFUL)
732 {
733 ret = 1; /* Lock work was progrmmed. OTP was locked. */
734 }
735 }
736 }
737 return ret;
738 }
739
740 /**
741 * @brief Execute FMC_ISPCMD_READ command to read User Configuration.
742 * @param[out] u32Config A two-word array.
743 * u32Config[0] holds CONFIG0, while u32Config[1] holds CONFIG1.
744 * @param[in] u32Count Available word count in u32Config.
745 * @return Success or not.
746 * @retval 0 Success.
747 * @retval -1 Invalid parameter.
748 */
FMC_ReadConfig(uint32_t u32Config[],uint32_t u32Count)749 int32_t FMC_ReadConfig(uint32_t u32Config[], uint32_t u32Count)
750 {
751 int32_t ret = 0;
752
753 u32Config[0] = FMC_Read(FMC_CONFIG_BASE);
754
755 if (u32Count < 2UL)
756 {
757 ret = -1;
758 }
759 else
760 {
761 u32Config[1] = FMC_Read(FMC_CONFIG_BASE+4UL);
762 }
763 return ret;
764 }
765
766
767 /**
768 * @brief Execute ISP commands to erase then write User Configuration.
769 * @param[in] u32Config A two-word array.
770 * u32Config[0] holds CONFIG0, while u32Config[1] holds CONFIG1.
771 * @param[in] u32Count The number of User Configuration words to be written.
772 * @return Success or not.
773 * @retval 0 Success
774 * @retval -1 Failed
775 */
FMC_WriteConfig(uint32_t u32Config[],uint32_t u32Count)776 int32_t FMC_WriteConfig(uint32_t u32Config[], uint32_t u32Count)
777 {
778 int i;
779
780 FMC_ENABLE_CFG_UPDATE();
781 FMC_Erase(FMC_CONFIG_BASE);
782
783 if ((FMC_Read(FMC_CONFIG_BASE) != 0xFFFFFFFF) || (FMC_Read(FMC_CONFIG_BASE+4) != 0xFFFFFFFF) ||
784 (FMC_Read(FMC_CONFIG_BASE+8) != 0xFFFF5A5A))
785 {
786 FMC_DISABLE_CFG_UPDATE();
787 return -1;
788 }
789
790 for (i = 0; i < u32Count; i++)
791 {
792 FMC_Write(FMC_CONFIG_BASE+i*4UL, u32Config[1]);
793
794 if (FMC_Read(FMC_CONFIG_BASE+i*4UL) != u32Config[1])
795 {
796 FMC_DISABLE_CFG_UPDATE();
797 return -1;
798 }
799 }
800
801 FMC_DISABLE_CFG_UPDATE();
802 return 0;
803 }
804
805
806 /**
807 * @brief Run CRC32 checksum calculation and get result.
808 * @param[in] u32addr Starting flash address. It must be a page aligned address.
809 * @param[in] u32count Byte count of flash to be calculated. It must be multiple of 512 bytes.
810 * @return Success or not.
811 * @retval 0 Success.
812 * @retval 0xFFFFFFFF Invalid parameter.
813 */
FMC_GetChkSum(uint32_t u32addr,uint32_t u32count)814 uint32_t FMC_GetChkSum(uint32_t u32addr, uint32_t u32count)
815 {
816 uint32_t ret;
817
818 if ((u32addr % 512UL) || (u32count % 512UL))
819 {
820 ret = 0xFFFFFFFF;
821 }
822 else
823 {
824 FMC->ISPCMD = FMC_ISPCMD_RUN_CKS;
825 FMC->ISPADDR = u32addr;
826 FMC->ISPDAT = u32count;
827 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
828
829 while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
830
831 FMC->ISPCMD = FMC_ISPCMD_READ_CKS;
832 FMC->ISPADDR = u32addr;
833 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
834
835 while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
836
837 ret = FMC->ISPDAT;
838 }
839
840 return ret;
841 }
842
843
844 /**
845 * @brief Run flash all one verification and get result.
846 * @param[in] u32addr Starting flash address. It must be a page aligned address.
847 * @param[in] u32count Byte count of flash to be calculated. It must be multiple of 512 bytes.
848 * @retval READ_ALLONE_YES The contents of verified flash area are 0xFFFFFFFF.
849 * @retval READ_ALLONE_NOT Some contents of verified flash area are not 0xFFFFFFFF.
850 * @retval READ_ALLONE_CMD_FAIL Unexpected error occurred.
851 */
FMC_CheckAllOne(uint32_t u32addr,uint32_t u32count)852 uint32_t FMC_CheckAllOne(uint32_t u32addr, uint32_t u32count)
853 {
854 uint32_t ret = READ_ALLONE_CMD_FAIL;
855
856 FMC->ISPSTS = 0x80UL; /* clear check all one bit */
857
858 FMC->ISPCMD = FMC_ISPCMD_RUN_ALL1;
859 FMC->ISPADDR = u32addr;
860 FMC->ISPDAT = u32count;
861 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
862
863 while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
864
865 do
866 {
867 FMC->ISPCMD = FMC_ISPCMD_READ_ALL1;
868 FMC->ISPADDR = u32addr;
869 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
870 while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
871 }
872 while (FMC->ISPDAT == 0UL);
873
874 if (FMC->ISPDAT == READ_ALLONE_YES)
875 {
876 ret = FMC->ISPDAT;
877 }
878
879 if (FMC->ISPDAT == READ_ALLONE_NOT)
880 {
881 ret = FMC->ISPDAT;
882 }
883
884 return ret;
885 }
886
887
888 /**
889 * @brief Setup security key.
890 * @param[in] key Key 0~2 to be setup.
891 * @param[in] kpmax Maximum unmatched power-on counting number.
892 * @param[in] kemax Maximum unmatched counting number.
893 * @param[in] lock_CONFIG 1: Security key lock CONFIG to write-protect. 0: Don't lock CONFIG.
894 * @param[in] lock_SPROM 1: Security key lock SPROM to write-protect. 0: Don't lock SPROM.
895 * @retval 0 Success.
896 * @retval -1 Key is locked. Cannot overwrite the current key.
897 * @retval -2 Failed to erase flash.
898 * @retval -3 Failed to program key.
899 * @retval -4 Key lock function failed.
900 * @retval -5 CONFIG lock function failed.
901 * @retval -6 SPROM lock function failed.
902 * @retval -7 KPMAX function failed.
903 * @retval -8 KEMAX function failed.
904 */
FMC_SetSPKey(uint32_t key[3],uint32_t kpmax,uint32_t kemax,const int32_t lock_CONFIG,const int32_t lock_SPROM)905 int32_t FMC_SetSPKey(uint32_t key[3], uint32_t kpmax, uint32_t kemax,
906 const int32_t lock_CONFIG, const int32_t lock_SPROM)
907 {
908 uint32_t lock_ctrl = 0UL;
909 uint32_t u32KeySts;
910 int32_t ret = 0;
911
912 if (FMC->KPKEYSTS != 0x200UL)
913 {
914 ret = -1;
915 }
916
917 if (FMC_Erase(FMC_KPROM_BASE))
918 {
919 ret = -2;
920 }
921
922 if (FMC_Erase(FMC_KPROM_BASE+0x200UL))
923 {
924 ret = -3;
925 }
926
927 if (!lock_CONFIG)
928 {
929 lock_ctrl |= 0x1UL;
930 }
931
932 if (!lock_SPROM)
933 {
934 lock_ctrl |= 0x2UL;
935 }
936
937 if (ret == 0)
938 {
939 FMC_Write(FMC_KPROM_BASE, key[0]);
940 FMC_Write(FMC_KPROM_BASE+0x4UL, key[1]);
941 FMC_Write(FMC_KPROM_BASE+0x8UL, key[2]);
942 FMC_Write(FMC_KPROM_BASE+0xCUL, kpmax);
943 FMC_Write(FMC_KPROM_BASE+0x10UL, kemax);
944 FMC_Write(FMC_KPROM_BASE+0x14UL, lock_ctrl);
945
946 while (FMC->KPKEYSTS & FMC_KPKEYSTS_KEYBUSY_Msk) { }
947
948 u32KeySts = FMC->KPKEYSTS;
949
950 if (!(u32KeySts & FMC_KPKEYSTS_KEYLOCK_Msk))
951 {
952 /* Security key lock failed! */
953 ret = -4;
954 }
955 else if ((lock_CONFIG && (!(u32KeySts & FMC_KPKEYSTS_CFGFLAG_Msk))) ||
956 ((!lock_CONFIG) && (u32KeySts & FMC_KPKEYSTS_CFGFLAG_Msk)))
957 {
958 /* CONFIG lock failed! */
959 ret = -5;
960 }
961 else if ((lock_SPROM && (!(u32KeySts & FMC_KPKEYSTS_SPFLAG_Msk))) ||
962 ((!lock_SPROM) && (u32KeySts & FMC_KPKEYSTS_SPFLAG_Msk)))
963 {
964 /* CONFIG lock failed! */
965 ret = -6;
966 }
967 else if (((FMC->KPCNT & FMC_KPCNT_KPMAX_Msk) >> FMC_KPCNT_KPMAX_Pos) != kpmax)
968 {
969 /* KPMAX failed! */
970 ret = -7;
971 }
972 else if (((FMC->KPKEYCNT & FMC_KPKEYCNT_KPKEMAX_Msk) >> FMC_KPKEYCNT_KPKEMAX_Pos) != kemax)
973 {
974 /* KEMAX failed! */
975 ret = -8;
976 }
977 }
978 return ret;
979 }
980
981
982 /**
983 * @brief Execute security key comparison.
984 * @param[in] key Key 0~2 to be compared.
985 * @retval 0 Key matched.
986 * @retval -1 Forbidden. Times of key comparison mismatch reach the maximum count.
987 * @retval -2 Key mismatched.
988 * @retval -3 No security key lock. Key comparison is not required.
989 */
FMC_CompareSPKey(uint32_t key[3])990 int32_t FMC_CompareSPKey(uint32_t key[3])
991 {
992 uint32_t u32KeySts;
993 int32_t ret = 0;
994
995 if (FMC->KPKEYSTS & FMC_KPKEYSTS_FORBID_Msk)
996 {
997 /* FMC_CompareSPKey - FORBID! */
998 ret = -1;
999 }
1000
1001 if (!(FMC->KPKEYSTS & FMC_KPKEYSTS_KEYLOCK_Msk))
1002 {
1003 /* FMC_CompareSPKey - key is not locked! */
1004 ret = -3;
1005 }
1006
1007 if (ret == 0)
1008 {
1009 FMC->KPKEY0 = key[0];
1010 FMC->KPKEY1 = key[1];
1011 FMC->KPKEY2 = key[2];
1012 FMC->KPKEYTRG = FMC_KPKEYTRG_KPKEYGO_Msk | FMC_KPKEYTRG_TCEN_Msk;
1013
1014 while (FMC->KPKEYSTS & FMC_KPKEYSTS_KEYBUSY_Msk) { }
1015
1016 u32KeySts = FMC->KPKEYSTS;
1017
1018 if (!(u32KeySts & FMC_KPKEYSTS_KEYMATCH_Msk))
1019 {
1020 /* Key mismatched! */
1021 ret = -2;
1022 }
1023 else if (u32KeySts & FMC_KPKEYSTS_KEYLOCK_Msk)
1024 {
1025 /* Key matched, but still be locked! */
1026 ret = -2;
1027 }
1028 }
1029 return ret;
1030 }
1031
1032
1033 /*@}*/ /* end of group FMC_EXPORTED_FUNCTIONS */
1034
1035 /*@}*/ /* end of group FMC_Driver */
1036
1037 /*@}*/ /* end of group Standard_Driver */
1038
1039 /*** (C) COPYRIGHT 2016 Nuvoton Technology Corp. ***/
1040
1041
1042