/***************************************************************************//** * @file bl_flash.c * @brief This file provides the flash APIs. * @version V1.0.0 * @date May-2021 * @author Zhixin Semiconductor * * @note * Copyright (C) 2021 Zhixin Semiconductor Ltd. All rights reserved. * ******************************************************************************/ #include "bl_flash.h" /*#include "bootloader.h"*/ #define DRIVER_ADDR_START 0x20000000 #define MEM_DRIVER_LEN 0x800 #ifdef BL_FLASH_DRV_FROM_HOST typedef ResultStatus_t (*tpfFLASH_DRV_EraseSector)(uint32_t addr, const FLASH_CmdConfig_t *config); typedef ResultStatus_t (*tpfFLASH_DRV_VerifySector)(uint32_t addr,const FLASH_CmdConfig_t *config); typedef ResultStatus_t (*tpfFLASH_DRV_Program)(uint32_t flashAddr, uint32_t len, const uint8_t *dataP,flash_cb_t callBack); typedef ResultStatus_t (*tpfFLASH_DRV_VerifyPhrase)(uint32_t addr, const FLASH_CmdConfig_t *config); typedef struct { tpfFLASH_DRV_EraseSector pfFLASH_DRV_EraseSector; tpfFLASH_DRV_VerifySector pfFLASH_DRV_VerifySector; tpfFLASH_DRV_Program pfFLASH_DRV_Program; tpfFLASH_DRV_VerifyPhrase pfFLASH_DRV_VerifyPhrase; } tFlashDriverAPIInfo; tFlashDriverAPIInfo *g_pstFlashOptInfo = (void *)0; static flash_reg_t *const flsRegPtr = (flash_reg_t *) FLASHC_BASE_ADDR; /* Init Flash API g_pstFlashOptInfo pointer */ void InitFlashDrvAPI(void) { uint32_t flashDriverStartAdd = 0; uint32_t flashDriverLength = 0; FLASH_HAL_GetFlashDriverInfo(&flashDriverStartAdd, &flashDriverLength); g_pstFlashOptInfo = (tFlashDriverAPIInfo *)flashDriverStartAdd; g_pstFlashOptInfo->pfFLASH_DRV_EraseSector = (tpfFLASH_DRV_EraseSector) ((uint32_t)flashDriverStartAdd + (uint32_t)(g_pstFlashOptInfo->pfFLASH_DRV_EraseSector)); g_pstFlashOptInfo->pfFLASH_DRV_VerifySector = (tpfFLASH_DRV_VerifySector) ((uint32_t)flashDriverStartAdd + (uint32_t)(g_pstFlashOptInfo->pfFLASH_DRV_VerifySector)); g_pstFlashOptInfo->pfFLASH_DRV_Program = (tpfFLASH_DRV_Program) ((uint32_t)flashDriverStartAdd + (uint32_t)(g_pstFlashOptInfo->pfFLASH_DRV_Program)); g_pstFlashOptInfo->pfFLASH_DRV_VerifyPhrase = (tpfFLASH_DRV_VerifyPhrase) ((uint32_t)flashDriverStartAdd + (uint32_t)(g_pstFlashOptInfo->pfFLASH_DRV_VerifyPhrase)); } #endif /* Flash driver config */ const BlockInfo_t gs_astFlashDriverBlock[] = { {DRIVER_ADDR_START, MEM_DRIVER_LEN}, }; static FLASH_CmdConfig_t flashCfg = { .act = FLASH_CMD_ACT_WAIT, #ifdef WATCHDOG_ENABLE .callBack = FeedWatchdog #else .callBack = NULL #endif }; ResultStatus_t FlashVerifyPhrase(uint32_t addr) { ResultStatus_t res; BlInterruptsDisable(); #ifdef BL_FLASH_DRV_FROM_HOST /* MISRA 2012 11.1 */ res = g_pstFlashOptInfo->pfFLASH_DRV_VerifyPhrase(addr,&flashCfg); #else res = FLASH_VerifyPhrase(addr,&flashCfg); #endif BlInterruptsEnable(); return res; } ResultStatus_t FlashEraseSector(uint32_t addr) { ResultStatus_t res; BlInterruptsDisable(); #ifdef BL_FLASH_DRV_FROM_HOST /* MISRA 2012 11.1 */ res = g_pstFlashOptInfo->pfFLASH_DRV_EraseSector(addr,&flashCfg); #else res = FLASH_EraseSector(addr,&flashCfg); #endif BlInterruptsEnable(); return res; } ResultStatus_t FlashWriteWithPadding(const uint8_t data[], uint32_t len, uint32_t addr) { ResultStatus_t res = SUCC; uint32_t alignedLen; uint32_t remained; uint32_t writeAddr = addr; uint8_t lastData[FLASH_PHRASE_LEN]; if(addr%FLASH_PHRASE_LEN != 0U) { res = ERR; } else { alignedLen = (len/FLASH_PHRASE_LEN)*FLASH_PHRASE_LEN; remained = len%FLASH_PHRASE_LEN; BlInterruptsDisable(); if(alignedLen != 0U) { #ifdef BL_FLASH_DRV_FROM_HOST /* MISRA 2012 11.1 */ if(ERR == g_pstFlashOptInfo->pfFLASH_DRV_Program(writeAddr, alignedLen, data, flashCfg.callBack)) { res = ERR; } #else if(ERR == FLASH_Program(writeAddr, alignedLen, data, flashCfg.callBack)) { res = ERR; } #endif } if(res == SUCC) { writeAddr += alignedLen; if(remained != 0U) { for(uint32_t i = 0U; i < FLASH_PHRASE_LEN; i++) { if(i < remained) { lastData[i] = data[alignedLen+i]; } else { lastData[i] = 0xFFU; } } #ifdef BL_FLASH_DRV_FROM_HOST /* MISRA 2012 11.1 */ if(ERR == g_pstFlashOptInfo->pfFLASH_DRV_Program(writeAddr, FLASH_PHRASE_LEN, (const uint8_t *)lastData, flashCfg.callBack)) { res = ERR; } #else if(ERR == FLASH_Program(writeAddr, FLASH_PHRASE_LEN, (const uint8_t *)lastData, flashCfg.callBack)) { res = ERR; } #endif } } BlInterruptsEnable(); } return res; } /* check if the address is in flash and can be programmed */ FlagStatus_t FlashCheckValidAddr(uint32_t addr, uint32_t len) { FlagStatus_t res = RESET; if((addr >= FLASH_CODE_BASE_ADDR)&&(addr <= BL_PFLASH_END_ADDR)) { if((addr+len-1U >= FLASH_CODE_BASE_ADDR) && (addr +len-1U <= BL_PFLASH_END_ADDR)) { /* program into PFLASH */ res = SET; } } if((addr >= FLASH_DATA_BASE_ADDR)&&(addr <= BL_DFLASH_END_ADDR)) { if((addr+len-1U >= FLASH_DATA_BASE_ADDR) && (addr +len-1U <= BL_DFLASH_END_ADDR)) { /* program into DFLASH */ res = SET; } } if((addr >= FLASH_IFR_BASE_ADDR) && (addr <= BL_FLASH_IFR_END_ADDR)) { if((addr+len-1U >= FLASH_IFR_BASE_ADDR) && (addr +len-1U <= BL_FLASH_IFR_END_ADDR)) { /* program into FLASH ISR */ res = SET; } } return res; } /* check if flash driver has been downloaded from host */ FlagStatus_t FlashCheckFlashDrvValid(void) { FlagStatus_t retVal = RESET; #ifdef BL_FLASH_DRV_FROM_HOST uint32_t *validFlag = (uint32_t *)BL_FLASH_DRV_VALID_FLAG_ADDR; if(*validFlag == BL_FLASH_DRV_VALID_FLAG_VALUE) { retVal = SET; } #else /* flash driver is always valid if flash driver is not downloaded from host */ retVal = SET; #endif return retVal; } #ifdef BL_FLASH_DRV_FROM_HOST /* make the flash driver flag to invalid status */ void FlashSetFlashDrvFlag(FlagStatus_t flag) { uint32_t *validFlag = (uint32_t *)BL_FLASH_DRV_VALID_FLAG_ADDR; if(flag == SET) { *validFlag = BL_FLASH_DRV_VALID_FLAG_VALUE; } else { *validFlag = 0U; } } #endif /* check flash init */ ResultStatus_t FlashInit(void) { ResultStatus_t ret = SUCC; #ifdef BL_FLASH_DRV_FROM_HOST if(1U == flsRegPtr->FLASH_FSTAT.FAIL) { ret = ERR; } #else if(ERR == FLASH_Init()) { ret = ERR; } #endif return ret; } void FeedWatchdog(void) { uint32_t tmp; __asm volatile( "MRS %0, PRIMASK " : "=r"(tmp)); if(tmp == 0U) { BlInterruptsDisable(); } WDOG->WDOG_CNT.CNT = 0xA0C4B1D6U; WDOG->WDOG_CNT.CNT = 0x1E0D0C7BU; if(tmp == 0U) { BlInterruptsEnable(); } } /* Get flash driver start and length */ bool FLASH_HAL_GetFlashDriverInfo(uint32_t *o_pFlashDriverAddrStart, uint32_t *o_pFlashDriverLength) { ASSERT(NULL_PTR == o_pFlashDriverAddrStart); ASSERT(NULL_PTR == o_pFlashDriverLength); *o_pFlashDriverAddrStart = gs_astFlashDriverBlock[0u].xBlockStartLogicalAddr; *o_pFlashDriverLength = gs_astFlashDriverBlock[0u].xBlockLength; return true; }