Arrow / Mbed OS DAPLink Reset
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers m480_fmc.c Source File

m480_fmc.c

00001 /**************************************************************************//**
00002  * @file     fmc.c
00003  * @version  V1.00
00004  * @brief    M480 series FMC driver source file
00005  *
00006  * @copyright (C) 2016 Nuvoton Technology Corp. All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without modification,
00009  * are permitted provided that the following conditions are met:
00010  *   1. Redistributions of source code must retain the above copyright notice,
00011  *      this list of conditions and the following disclaimer.
00012  *   2. Redistributions in binary form must reproduce the above copyright notice,
00013  *      this list of conditions and the following disclaimer in the documentation
00014  *      and/or other materials provided with the distribution.
00015  *   3. Neither the name of Nuvoton Technology Corp. nor the names of its contributors
00016  *      may be used to endorse or promote products derived from this software
00017  *      without specific prior written permission.
00018  * 
00019  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00020  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00021  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
00023  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00024  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00025  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00026  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00027  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00028  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029 *****************************************************************************/
00030 
00031 #include <stdio.h>
00032 
00033 #include "NuMicro.h"
00034 
00035 
00036 /** @addtogroup Standard_Driver Standard Driver
00037   @{
00038 */
00039 
00040 /** @addtogroup FMC_Driver FMC Driver
00041   @{
00042 */
00043 
00044 
00045 /** @addtogroup FMC_EXPORTED_FUNCTIONS FMC Exported Functions
00046   @{
00047 */
00048 
00049 
00050 /**
00051   * @brief Disable FMC ISP function.
00052   * @return None
00053   */
00054 void FMC_Close(void)
00055 {
00056     FMC->ISPCTL &= ~FMC_ISPCTL_ISPEN_Msk;
00057 }
00058 
00059 
00060 /**
00061   * @brief Execute FMC_ISPCMD_PAGE_ERASE command to erase a flash page. The page size is 4096 bytes.
00062   * @param[in]  u32PageAddr Address of the flash page to be erased.
00063   *             It must be a 4096 bytes aligned address.
00064   * @return ISP page erase success or not.
00065   * @retval   0  Success
00066   * @retval   -1  Erase failed
00067   */
00068 int32_t FMC_Erase(uint32_t u32PageAddr)
00069 {
00070     int32_t  ret = 0;
00071 
00072     if (u32PageAddr == FMC_SPROM_BASE) {
00073         ret = FMC_Erase_SPROM();
00074     }
00075 
00076     if (ret == 0) {
00077         FMC->ISPCMD = FMC_ISPCMD_PAGE_ERASE;
00078         FMC->ISPADDR = u32PageAddr;
00079         FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
00080 
00081         while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
00082 
00083         if (FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk) {
00084             FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
00085             ret = -1;
00086         }
00087     }
00088 
00089     return ret;
00090 }
00091 
00092 
00093 /**
00094   * @brief Execute FMC_ISPCMD_PAGE_ERASE command to erase SPROM. The page size is 4096 bytes.
00095   * @return   SPROM page erase success or not.
00096   * @retval   0  Success
00097   * @retval   -1  Erase failed
00098   */
00099 int32_t FMC_Erase_SPROM(void)
00100 {
00101     int32_t  ret = 0;
00102     FMC->ISPCMD = FMC_ISPCMD_PAGE_ERASE;
00103     FMC->ISPADDR = FMC_SPROM_BASE;
00104     FMC->ISPDAT = 0x0055AA03UL;
00105     FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
00106 
00107     while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
00108 
00109     if (FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk) {
00110         FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
00111         ret = -1;
00112     }
00113 
00114     return ret;
00115 }
00116 
00117 /**
00118   * @brief Execute FMC_ISPCMD_BLOCK_ERASE command to erase a flash block. The block size is 4 pages.
00119   * @param[in]  u32BlockAddr  Address of the flash block to be erased.
00120   *             It must be a 4 pages aligned address.
00121   * @return ISP page erase success or not.
00122   * @retval   0  Success
00123   * @retval   -1  Erase failed
00124   */
00125 int32_t FMC_Erase_Block(uint32_t u32BlockAddr)
00126 {
00127     int32_t  ret = 0;
00128     FMC->ISPCMD = FMC_ISPCMD_BLOCK_ERASE;
00129     FMC->ISPADDR = u32BlockAddr;
00130     FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
00131 
00132     while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
00133 
00134     if (FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk) {
00135         FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
00136         ret = -1;
00137     }
00138 
00139     return ret;
00140 }
00141 
00142 /**
00143   * @brief Execute FMC_ISPCMD_BANK_ERASE command to erase a flash block.
00144   * @param[in]  u32BankAddr Base address of the flash bank to be erased.
00145   * @return ISP page erase success or not.
00146   * @retval   0  Success
00147   * @retval   -1  Erase failed
00148   */
00149 int32_t FMC_Erase_Bank(uint32_t u32BankAddr)
00150 {
00151     int32_t  ret = 0;
00152     FMC->ISPCMD = FMC_ISPCMD_BANK_ERASE;
00153     FMC->ISPADDR = u32BankAddr;
00154     FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
00155 
00156     while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
00157 
00158     if (FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk) {
00159         FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
00160         ret = -1;
00161     }
00162 
00163     return ret;
00164 }
00165 
00166 /**
00167   * @brief Get the current boot source.
00168   * @return The current boot source.
00169   * @retval   0  Is boot from APROM.
00170   * @retval   1  Is boot from LDROM.
00171   */
00172 int32_t FMC_GetBootSource(void)
00173 {
00174     int32_t  ret = 0;
00175 
00176     if (FMC->ISPCTL & FMC_ISPCTL_BS_Msk) {
00177         ret = 1;
00178     }
00179 
00180     return ret;
00181 }
00182 
00183 
00184 /**
00185   * @brief Enable FMC ISP function
00186   * @return None
00187   */
00188 void FMC_Open(void)
00189 {
00190     FMC->ISPCTL |=  FMC_ISPCTL_ISPEN_Msk;
00191 }
00192 
00193 
00194 /**
00195   * @brief Execute FMC_ISPCMD_READ command to read a word from flash.
00196   * @param[in]  u32Addr Address of the flash location to be read.
00197   *             It must be a word aligned address.
00198   * @return The word data read from specified flash address.
00199   */
00200 uint32_t FMC_Read(uint32_t u32Addr)
00201 {
00202     FMC->ISPCMD = FMC_ISPCMD_READ;
00203     FMC->ISPADDR = u32Addr;
00204     FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
00205 
00206     while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
00207 
00208     return FMC->ISPDAT;
00209 }
00210 
00211 
00212 /**
00213   * @brief Execute FMC_ISPCMD_READ_64 command to read a double-word from flash.
00214   * @param[in]  u32addr   Address of the flash location to be read.
00215   *             It must be a double-word aligned address.
00216   * @param[out] u32data0  Place holder of word 0 read from flash address u32addr.
00217   * @param[out] u32data1  Place holder of word 0 read from flash address u32addr+4.
00218   * @return   0   Success
00219   * @return   -1  Failed
00220   */
00221 int32_t FMC_Read_64(uint32_t u32addr, uint32_t *u32data0, uint32_t *u32data1)
00222 {
00223     int32_t  ret = 0;
00224     FMC->ISPCMD = FMC_ISPCMD_READ_64;
00225     FMC->ISPADDR    = u32addr;
00226     FMC->ISPDAT = 0x0UL;
00227     FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
00228 
00229     while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
00230 
00231     if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk) {
00232         FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
00233         ret = -1;
00234     } else {
00235         *u32data0 = FMC->MPDAT0;
00236         *u32data1 = FMC->MPDAT1;
00237     }
00238 
00239     return ret;
00240 }
00241 
00242 
00243 /**
00244   * @brief    Get the base address of Data Flash if enabled.
00245   * @retval   The base address of Data Flash
00246   */
00247 uint32_t FMC_ReadDataFlashBaseAddr(void)
00248 {
00249     return FMC->DFBA;
00250 }
00251 
00252 /**
00253   * @brief      Set boot source from LDROM or APROM after next software reset
00254   * @param[in]  i32BootSrc
00255   *                1: Boot from LDROM
00256   *                0: Boot from APROM
00257   * @return    None
00258   * @details   This function is used to switch APROM boot or LDROM boot. User need to call
00259   *            FMC_SetBootSource to select boot source first, then use CPU reset or
00260   *            System Reset Request to reset system.
00261   */
00262 void FMC_SetBootSource(int32_t i32BootSrc)
00263 {
00264     if (i32BootSrc) {
00265         FMC->ISPCTL |= FMC_ISPCTL_BS_Msk; /* Boot from LDROM */
00266     } else {
00267         FMC->ISPCTL &= ~FMC_ISPCTL_BS_Msk;/* Boot from APROM */
00268     }
00269 }
00270 
00271 /**
00272   * @brief Execute ISP FMC_ISPCMD_PROGRAM to program a word to flash.
00273   * @param[in]  u32Addr Address of the flash location to be programmed.
00274   *             It must be a word aligned address.
00275   * @param[in]  u32Data The word data to be programmed.
00276   * @return None
00277   */
00278 void FMC_Write(uint32_t u32Addr, uint32_t u32Data)
00279 {
00280     FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
00281     FMC->ISPADDR = u32Addr;
00282     FMC->ISPDAT = u32Data;
00283     FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
00284 
00285     while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
00286 }
00287 
00288 /**
00289   * @brief Execute ISP FMC_ISPCMD_PROGRAM_64 to program a double-word to flash.
00290   * @param[in]  u32addr Address of the flash location to be programmed.
00291   *             It must be a double-word aligned address.
00292   * @param[in]  u32data0   The word data to be programmed to flash address u32addr.
00293   * @param[in]  u32data1   The word data to be programmed to flash address u32addr+4.
00294   * @return   0   Success
00295   * @return   -1  Failed
00296   */
00297 int32_t FMC_Write8Bytes(uint32_t u32addr, uint32_t u32data0, uint32_t u32data1)
00298 {
00299     int32_t  ret = 0;
00300     FMC->ISPCMD  = FMC_ISPCMD_PROGRAM_64;
00301     FMC->ISPADDR = u32addr;
00302     FMC->MPDAT0  = u32data0;
00303     FMC->MPDAT1  = u32data1;
00304     FMC->ISPTRG  = FMC_ISPTRG_ISPGO_Msk;
00305 
00306     while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
00307 
00308     if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk) {
00309         FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
00310         ret = -1;
00311     }
00312 
00313     return ret;
00314 }
00315 
00316 
00317 /**
00318   * @brief   Program Multi-Word data into specified address of flash.
00319   * @param[in]  u32Addr    Start flash address in APROM where the data chunk to be programmed into.
00320   *                        This address must be 8-bytes aligned to flash address.
00321   * @param[in]  pu32Buf    Buffer that carry the data chunk.
00322   * @param[in]  u32Len     Length of the data chunk in bytes.
00323   * @retval   >=0  Number of data bytes were programmed.
00324   * @return   -1   Invalid address.
00325   */
00326 int32_t FMC_WriteMultiple(uint32_t u32Addr, uint32_t pu32Buf[], uint32_t u32Len)
00327 {
00328     int   i, idx, retval = 0;
00329 
00330     if ((u32Addr >= FMC_APROM_END) || ((u32Addr % 8) != 0)) {
00331         return -1;
00332     }
00333 
00334     u32Len = u32Len - (u32Len % 8);         /* u32Len must be multiple of 8. */
00335     idx = 0;
00336 
00337     while (u32Len >= 8) {
00338         FMC->ISPADDR = u32Addr;
00339         FMC->MPDAT0  = pu32Buf[idx++];
00340         FMC->MPDAT1  = pu32Buf[idx++];
00341         FMC->MPDAT2  = pu32Buf[idx++];
00342         FMC->MPDAT3  = pu32Buf[idx++];
00343         FMC->ISPCMD  = FMC_ISPCMD_PROGRAM_MUL;
00344         FMC->ISPTRG  = FMC_ISPTRG_ISPGO_Msk;
00345 
00346         for (i = 16; i < FMC_MULTI_WORD_PROG_LEN;) {
00347             while (FMC->MPSTS & (FMC_MPSTS_D0_Msk | FMC_MPSTS_D1_Msk))
00348                 ;
00349 
00350             retval += 8;
00351             u32Len -= 8;
00352 
00353             if (u32Len < 8) {
00354                 return retval;
00355             }
00356 
00357             if (!(FMC->MPSTS & FMC_MPSTS_MPBUSY_Msk)) {
00358                 /* printf("    [WARNING] busy cleared after D0D1 cleared!\n"); */
00359                 i += 8;
00360                 break;
00361             }
00362 
00363             FMC->MPDAT0 = pu32Buf[idx++];
00364             FMC->MPDAT1 = pu32Buf[idx++];
00365 
00366             if (i == FMC_MULTI_WORD_PROG_LEN / 4) {
00367                 break;    // done
00368             }
00369 
00370             while (FMC->MPSTS & (FMC_MPSTS_D2_Msk | FMC_MPSTS_D3_Msk))
00371                 ;
00372 
00373             retval += 8;
00374             u32Len -= 8;
00375 
00376             if (u32Len < 8) {
00377                 return retval;
00378             }
00379 
00380             if (!(FMC->MPSTS & FMC_MPSTS_MPBUSY_Msk)) {
00381                 /* printf("    [WARNING] busy cleared after D2D3 cleared!\n"); */
00382                 i += 8;
00383                 break;
00384             }
00385 
00386             FMC->MPDAT2 = pu32Buf[idx++];
00387             FMC->MPDAT3 = pu32Buf[idx++];
00388         }
00389 
00390         if (i != FMC_MULTI_WORD_PROG_LEN) {
00391             /* printf("    [WARNING] Multi-word program interrupted at 0x%x !!\n", i); */
00392             return retval;
00393         }
00394 
00395         while (FMC->MPSTS & FMC_MPSTS_MPBUSY_Msk) ;
00396 
00397         u32Addr += FMC_MULTI_WORD_PROG_LEN;
00398     }
00399 
00400     return retval;
00401 }
00402 
00403 
00404 /**
00405   * @brief Program a 64-bits data to the specified OTP.
00406   * @param[in] otp_num    The OTP number.
00407   * @param[in] low_word   Low word of the 64-bits data.
00408   * @param[in] high_word   Low word of the 64-bits data.
00409   * @retval   0   Success
00410   * @retval   -1  Program failed.
00411   * @retval   -2  Invalid OTP number.
00412   */
00413 int32_t FMC_Write_OTP(uint32_t otp_num, uint32_t low_word, uint32_t high_word)
00414 {
00415     int32_t  ret = 0;
00416 
00417     if (otp_num > 255UL) {
00418         ret = -2;
00419     }
00420 
00421     if (ret == 0) {
00422         FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
00423         FMC->ISPADDR = FMC_OTP_BASE + otp_num * 8UL;
00424         FMC->ISPDAT = low_word;
00425         FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
00426 
00427         while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
00428 
00429         if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk) {
00430             FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
00431             ret = -1;
00432         }
00433     }
00434 
00435     if (ret == 0) {
00436         FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
00437         FMC->ISPADDR = FMC_OTP_BASE + otp_num * 8UL + 4UL;
00438         FMC->ISPDAT = high_word;
00439         FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
00440 
00441         while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
00442 
00443         if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk) {
00444             FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
00445             ret = -1;
00446         }
00447     }
00448 
00449     return ret;
00450 }
00451 
00452 /**
00453   * @brief  Read the 64-bits data from the specified OTP.
00454   * @param[in] otp_num    The OTP number.
00455   * @param[in] low_word   Low word of the 64-bits data.
00456   * @param[in] high_word   Low word of the 64-bits data.
00457   * @retval   0   Success
00458   * @retval   -1  Read failed.
00459   * @retval   -2  Invalid OTP number.
00460   */
00461 int32_t FMC_Read_OTP(uint32_t otp_num, uint32_t *low_word, uint32_t *high_word)
00462 {
00463     int32_t  ret = 0;
00464 
00465     if (otp_num > 255UL) {
00466         ret = -2;
00467     }
00468 
00469     if (ret == 0) {
00470         FMC->ISPCMD = FMC_ISPCMD_READ_64;
00471         FMC->ISPADDR    = FMC_OTP_BASE + otp_num * 8UL ;
00472         FMC->ISPDAT = 0x0UL;
00473         FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
00474 
00475         while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
00476 
00477         if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk) {
00478             FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
00479             ret = -1;
00480         } else {
00481             *low_word = FMC->MPDAT0;
00482             *high_word = FMC->MPDAT1;
00483         }
00484     }
00485 
00486     return ret;
00487 }
00488 
00489 /**
00490   * @brief  Lock the specified OTP.
00491   * @param[in] otp_num    The OTP number.
00492   * @retval   0   Success
00493   * @retval   -1  Failed to write OTP lock bits.
00494   * @retval   -2  Invalid OTP number.
00495   */
00496 int32_t FMC_Lock_OTP(uint32_t otp_num)
00497 {
00498     int32_t  ret = 0;
00499 
00500     if (otp_num > 255UL) {
00501         ret = -2;
00502     }
00503 
00504     if (ret == 0) {
00505         FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
00506         FMC->ISPADDR = FMC_OTP_BASE + 0x800UL + otp_num * 4UL;
00507         FMC->ISPDAT = 0UL;
00508         FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
00509 
00510         while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
00511 
00512         if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk) {
00513             FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
00514             ret = -1;
00515         }
00516     }
00517 
00518     return ret;
00519 }
00520 
00521 /**
00522   * @brief  Check the OTP is locked or not.
00523   * @param[in] otp_num    The OTP number.
00524   * @retval   1   OTP is locked.
00525   * @retval   0   OTP is not locked.
00526   * @retval   -1  Failed to read OTP lock bits.
00527   * @retval   -2  Invalid OTP number.
00528   */
00529 int32_t FMC_Is_OTP_Locked(uint32_t otp_num)
00530 {
00531     int32_t  ret = 0;
00532 
00533     if (otp_num > 255UL) {
00534         ret = -2;
00535     }
00536 
00537     if (ret == 0) {
00538         FMC->ISPCMD = FMC_ISPCMD_READ;
00539         FMC->ISPADDR = FMC_OTP_BASE + 0x800UL + otp_num * 4UL;
00540         FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
00541 
00542         while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk) { }
00543 
00544         if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk) {
00545             FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
00546             ret = -1;
00547         } else {
00548             if (FMC->ISPDAT != 0xFFFFFFFFUL) {
00549                 ret = 1;   /* Lock work was progrmmed. OTP was locked. */
00550             }
00551         }
00552     }
00553 
00554     return ret;
00555 }
00556 
00557 /**
00558   * @brief Execute FMC_ISPCMD_READ command to read User Configuration.
00559   * @param[out]  u32Config A two-word array.
00560   *              u32Config[0] holds CONFIG0, while u32Config[1] holds CONFIG1.
00561   * @param[in] u32Count Available word count in u32Config.
00562   * @return Success or not.
00563   * @retval   0  Success.
00564   * @retval   -1  Invalid parameter.
00565   */
00566 int32_t FMC_ReadConfig(uint32_t u32Config[], uint32_t u32Count)
00567 {
00568     int32_t   ret = 0;
00569     u32Config[0] = FMC_Read(FMC_CONFIG_BASE);
00570 
00571     if (u32Count < 2UL) {
00572         ret = -1;
00573     } else {
00574         u32Config[1] = FMC_Read(FMC_CONFIG_BASE + 4UL);
00575     }
00576 
00577     return ret;
00578 }
00579 
00580 
00581 /**
00582   * @brief Execute ISP commands to erase then write User Configuration.
00583   * @param[in] u32Config   A two-word array.
00584   *            u32Config[0] holds CONFIG0, while u32Config[1] holds CONFIG1.
00585   * @param[in] u32Count  Always be 2 in this BSP.
00586   * @return Success or not.
00587   * @retval   0  Success.
00588   * @retval   -1  Invalid parameter.
00589   */
00590 int32_t FMC_WriteConfig(uint32_t u32Config[], uint32_t u32Count)
00591 {
00592     FMC_ENABLE_CFG_UPDATE();
00593     FMC_Erase(FMC_CONFIG_BASE);
00594     FMC_Write(FMC_CONFIG_BASE, u32Config[0]);
00595     FMC_Write(FMC_CONFIG_BASE + 4UL, u32Config[1]);
00596     FMC_DISABLE_CFG_UPDATE();
00597     return 0;
00598 }
00599 
00600 
00601 /**
00602   * @brief Run CRC32 checksum calculation and get result.
00603   * @param[in] u32addr   Starting flash address. It must be a page aligned address.
00604   * @param[in] u32count  Byte count of flash to be calculated. It must be multiple of 512 bytes.
00605   * @return Success or not.
00606   * @retval   0           Success.
00607   * @retval   0xFFFFFFFF  Invalid parameter.
00608   */
00609 uint32_t  FMC_GetChkSum(uint32_t u32addr, uint32_t u32count)
00610 {
00611     uint32_t   ret;
00612 
00613     if ((u32addr % 512UL) || (u32count % 512UL)) {
00614         ret = 0xFFFFFFFF;
00615     } else {
00616         FMC->ISPCMD  = FMC_ISPCMD_RUN_CKS;
00617         FMC->ISPADDR = u32addr;
00618         FMC->ISPDAT  = u32count;
00619         FMC->ISPTRG  = FMC_ISPTRG_ISPGO_Msk;
00620 
00621         while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
00622 
00623         FMC->ISPCMD = FMC_ISPCMD_READ_CKS;
00624         FMC->ISPADDR    = u32addr;
00625         FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
00626 
00627         while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
00628 
00629         ret = FMC->ISPDAT;
00630     }
00631 
00632     return ret;
00633 }
00634 
00635 
00636 /**
00637   * @brief Run flash all one verification and get result.
00638   * @param[in] u32addr   Starting flash address. It must be a page aligned address.
00639   * @param[in] u32count  Byte count of flash to be calculated. It must be multiple of 512 bytes.
00640   * @retval   READ_ALLONE_YES      The contents of verified flash area are 0xFFFFFFFF.
00641   * @retval   READ_ALLONE_NOT  Some contents of verified flash area are not 0xFFFFFFFF.
00642   * @retval   READ_ALLONE_CMD_FAIL  Unexpected error occurred.
00643   */
00644 uint32_t  FMC_CheckAllOne(uint32_t u32addr, uint32_t u32count)
00645 {
00646     uint32_t  ret = READ_ALLONE_CMD_FAIL;
00647     FMC->ISPSTS = 0x80UL;   /* clear check all one bit */
00648     FMC->ISPCMD   = FMC_ISPCMD_RUN_ALL1;
00649     FMC->ISPADDR  = u32addr;
00650     FMC->ISPDAT   = u32count;
00651     FMC->ISPTRG   = FMC_ISPTRG_ISPGO_Msk;
00652 
00653     while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
00654 
00655     do {
00656         FMC->ISPCMD = FMC_ISPCMD_READ_ALL1;
00657         FMC->ISPADDR    = u32addr;
00658         FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
00659 
00660         while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk) { }
00661     } while (FMC->ISPDAT == 0UL);
00662 
00663     if (FMC->ISPDAT == READ_ALLONE_YES) {
00664         ret = FMC->ISPDAT;
00665     }
00666 
00667     if (FMC->ISPDAT == READ_ALLONE_NOT) {
00668         ret = FMC->ISPDAT;
00669     }
00670 
00671     return ret;
00672 }
00673 
00674 
00675 /**
00676   * @brief    Setup security key.
00677   * @param[in] key      Key 0~2 to be setup.
00678   * @param[in] kpmax    Maximum unmatched power-on counting number.
00679   * @param[in] kemax    Maximum unmatched counting number.
00680   * @param[in] lock_CONFIG   1: Security key lock CONFIG to write-protect. 0: Don't lock CONFIG.
00681   * @param[in] lock_SPROM    1: Security key lock SPROM to write-protect. 0: Don't lock SPROM.
00682   * @retval   0     Success.
00683   * @retval   -1    Key is locked. Cannot overwrite the current key.
00684   * @retval   -2    Failed to erase flash.
00685   * @retval   -3    Failed to program key.
00686   * @retval   -4    Key lock function failed.
00687   * @retval   -5    CONFIG lock function failed.
00688   * @retval   -6    SPROM lock function failed.
00689   * @retval   -7    KPMAX function failed.
00690   * @retval   -8    KEMAX function failed.
00691   */
00692 int32_t  FMC_SetSPKey(uint32_t key[3], uint32_t kpmax, uint32_t kemax,
00693                       const int32_t lock_CONFIG, const int32_t lock_SPROM)
00694 {
00695     uint32_t  lock_ctrl = 0UL;
00696     uint32_t  u32KeySts;
00697     int32_t   ret = 0;
00698 
00699     if (FMC->KPKEYSTS != 0x200UL) {
00700         ret = -1;
00701     }
00702 
00703     if (FMC_Erase(FMC_KPROM_BASE)) {
00704         ret = -2;
00705     }
00706 
00707     if (FMC_Erase(FMC_KPROM_BASE + 0x200UL)) {
00708         ret = -3;
00709     }
00710 
00711     if (!lock_CONFIG) {
00712         lock_ctrl |= 0x1UL;
00713     }
00714 
00715     if (!lock_SPROM) {
00716         lock_ctrl |= 0x2UL;
00717     }
00718 
00719     if (ret == 0) {
00720         FMC_Write(FMC_KPROM_BASE, key[0]);
00721         FMC_Write(FMC_KPROM_BASE + 0x4UL, key[1]);
00722         FMC_Write(FMC_KPROM_BASE + 0x8UL, key[2]);
00723         FMC_Write(FMC_KPROM_BASE + 0xCUL, kpmax);
00724         FMC_Write(FMC_KPROM_BASE + 0x10UL, kemax);
00725         FMC_Write(FMC_KPROM_BASE + 0x14UL, lock_ctrl);
00726 
00727         while (FMC->KPKEYSTS & FMC_KPKEYSTS_KEYBUSY_Msk) { }
00728 
00729         u32KeySts = FMC->KPKEYSTS;
00730 
00731         if (!(u32KeySts & FMC_KPKEYSTS_KEYLOCK_Msk)) {
00732             /* Security key lock failed! */
00733             ret = -4;
00734         } else if ((lock_CONFIG && (!(u32KeySts & FMC_KPKEYSTS_CFGFLAG_Msk))) ||
00735                    ((!lock_CONFIG) && (u32KeySts & FMC_KPKEYSTS_CFGFLAG_Msk))) {
00736             /* CONFIG lock failed! */
00737             ret = -5;
00738         } else if ((lock_SPROM && (!(u32KeySts & FMC_KPKEYSTS_SPFLAG_Msk))) ||
00739                    ((!lock_SPROM) && (u32KeySts & FMC_KPKEYSTS_SPFLAG_Msk))) {
00740             /* CONFIG lock failed! */
00741             ret = -6;
00742         } else if (((FMC->KPCNT & FMC_KPCNT_KPMAX_Msk) >> FMC_KPCNT_KPMAX_Pos) != kpmax) {
00743             /* KPMAX failed! */
00744             ret = -7;
00745         } else if (((FMC->KPKEYCNT & FMC_KPKEYCNT_KPKEMAX_Msk) >> FMC_KPKEYCNT_KPKEMAX_Pos) != kemax) {
00746             /* KEMAX failed! */
00747             ret = -8;
00748         }
00749     }
00750 
00751     return ret;
00752 }
00753 
00754 
00755 /**
00756   * @brief    Execute security key comparison.
00757   * @param[in] key  Key 0~2 to be compared.
00758   * @retval   0     Key matched.
00759   * @retval   -1    Forbidden. Times of key comparison mismatch reach the maximum count.
00760   * @retval   -2    Key mismatched.
00761   * @retval   -3    No security key lock. Key comparison is not required.
00762   */
00763 int32_t  FMC_CompareSPKey(uint32_t key[3])
00764 {
00765     uint32_t  u32KeySts;
00766     int32_t   ret = 0;
00767 
00768     if (FMC->KPKEYSTS & FMC_KPKEYSTS_FORBID_Msk) {
00769         /* FMC_CompareSPKey - FORBID!  */
00770         ret = -1;
00771     }
00772 
00773     if (!(FMC->KPKEYSTS & FMC_KPKEYSTS_KEYLOCK_Msk)) {
00774         /* FMC_CompareSPKey - key is not locked!  */
00775         ret = -3;
00776     }
00777 
00778     if (ret == 0) {
00779         FMC->KPKEY0 = key[0];
00780         FMC->KPKEY1 = key[1];
00781         FMC->KPKEY2 = key[2];
00782         FMC->KPKEYTRG = FMC_KPKEYTRG_KPKEYGO_Msk | FMC_KPKEYTRG_TCEN_Msk;
00783 
00784         while (FMC->KPKEYSTS & FMC_KPKEYSTS_KEYBUSY_Msk) { }
00785 
00786         u32KeySts = FMC->KPKEYSTS;
00787 
00788         if (!(u32KeySts & FMC_KPKEYSTS_KEYMATCH_Msk)) {
00789             /* Key mismatched! */
00790             ret = -2;
00791         } else if (u32KeySts & FMC_KPKEYSTS_KEYLOCK_Msk) {
00792             /* Key matched, but still be locked! */
00793             ret = -2;
00794         }
00795     }
00796 
00797     return ret;
00798 }
00799 
00800 
00801 /*@}*/ /* end of group FMC_EXPORTED_FUNCTIONS */
00802 
00803 /*@}*/ /* end of group FMC_Driver */
00804 
00805 /*@}*/ /* end of group Standard_Driver */
00806 
00807 /*** (C) COPYRIGHT 2016 Nuvoton Technology Corp. ***/
00808 
00809