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