/* * The Clear BSD License * Copyright 2013-2016 Freescale Semiconductor, Inc. * Copyright 2016-2018 NXP * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted (subject to the limitations in the * disclaimer below) provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "fsl_ftfx_controller.h" /******************************************************************************* * Definitions ******************************************************************************/ /*! * @name Flash controller command numbers * @{ */ #define FTFx_VERIFY_BLOCK 0x00U /*!< RD1BLK*/ #define FTFx_VERIFY_SECTION 0x01U /*!< RD1SEC*/ #define FTFx_PROGRAM_CHECK 0x02U /*!< PGMCHK*/ #define FTFx_READ_RESOURCE 0x03U /*!< RDRSRC*/ #define FTFx_PROGRAM_LONGWORD 0x06U /*!< PGM4*/ #define FTFx_PROGRAM_PHRASE 0x07U /*!< PGM8*/ #define FTFx_ERASE_BLOCK 0x08U /*!< ERSBLK*/ #define FTFx_ERASE_SECTOR 0x09U /*!< ERSSCR*/ #define FTFx_PROGRAM_SECTION 0x0BU /*!< PGMSEC*/ #define FTFx_GENERATE_CRC 0x0CU /*!< CRCGEN*/ #define FTFx_VERIFY_ALL_BLOCK 0x40U /*!< RD1ALL*/ #define FTFx_READ_ONCE 0x41U /*!< RDONCE or RDINDEX*/ #define FTFx_PROGRAM_ONCE 0x43U /*!< PGMONCE or PGMINDEX*/ #define FTFx_ERASE_ALL_BLOCK 0x44U /*!< ERSALL*/ #define FTFx_SECURITY_BY_PASS 0x45U /*!< VFYKEY*/ #define FTFx_SWAP_CONTROL 0x46U /*!< SWAP*/ #define FTFx_ERASE_ALL_BLOCK_UNSECURE 0x49U /*!< ERSALLU*/ #define FTFx_VERIFY_ALL_EXECUTE_ONLY_SEGMENT 0x4AU /*!< RD1XA*/ #define FTFx_ERASE_ALL_EXECUTE_ONLY_SEGMENT 0x4BU /*!< ERSXA*/ #define FTFx_PROGRAM_PARTITION 0x80U /*!< PGMPART*/ #define FTFx_SET_FLEXRAM_FUNCTION 0x81U /*!< SETRAM*/ /*@}*/ /*! * @brief Constants for execute-in-RAM flash function. */ enum _ftfx_ram_func_constants { kFTFx_RamFuncMaxSizeInWords = 16U, /*!< The maximum size of execute-in-RAM function.*/ }; /*! @brief A function pointer used to point to relocated flash_run_command() */ typedef void (*callFtfxRunCommand_t)(FTFx_REG8_ACCESS_TYPE ftfx_fstat); /*! * @name Enumeration for Flash security register code * @{ */ enum _ftfx_fsec_register_code { kFTFx_FsecRegCode_KEYEN_Enabled = 0x80U, kFTFx_FsecRegCode_SEC_Unsecured = 0x02U }; /*@}*/ /*! * @brief Enumeration for flash config area. */ enum _ftfx_pflash_config_area_range { kFTFx_PflashConfigAreaStart = 0x400U, kFTFx_PflashConfigAreaEnd = 0x40FU }; /******************************************************************************* * Prototypes ******************************************************************************/ /*! @brief Init IFR memory related info */ static status_t ftfx_init_ifr(ftfx_config_t *config); #if FTFx_DRIVER_IS_FLASH_RESIDENT /*! @brief Copy flash_run_command() to RAM*/ static void ftfx_copy_run_command_to_ram(uint32_t *ftfxRunCommand); #endif /* FTFx_DRIVER_IS_FLASH_RESIDENT */ /*! @brief Internal function Flash command sequence. Called by driver APIs only*/ static status_t ftfx_command_sequence(ftfx_config_t *config); /*! @brief Validates the range and alignment of the given address range.*/ static status_t ftfx_check_mem_range(ftfx_config_t *config, uint32_t startAddress, uint32_t lengthInBytes, uint8_t alignmentBaseline); /*! @brief Validates the given user key for flash erase APIs.*/ static status_t ftfx_check_user_key(uint32_t key); /*! @brief Reads word from byte address.*/ static uint32_t ftfx_read_word_from_byte_address(const uint8_t *src); /*! @brief Writes word to byte address.*/ static void ftfx_write_word_to_byte_address(uint8_t *dst, uint32_t word); #if defined(FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD) && FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD /*! @brief Validates the range of the given resource address.*/ static status_t ftfx_check_resource_range(ftfx_config_t *config, uint32_t start, uint32_t lengthInBytes, uint32_t alignmentBaseline, ftfx_read_resource_opt_t option); #endif /* FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD */ #if defined(FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD) && FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD /*! @brief Validates the gived flexram function option.*/ static inline status_t ftfx_check_flexram_function_option(ftfx_flexram_func_opt_t option); #endif /* FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD */ #if defined(FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD) && FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD /*! @brief Validates the gived swap control option.*/ static status_t ftfx_check_swap_control_option(ftfx_swap_control_opt_t option); #endif /* FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD */ /******************************************************************************* * Variables ******************************************************************************/ #if FTFx_DRIVER_IS_FLASH_RESIDENT /*! * @brief Position independent code of flash_run_command() * * Note1: The prototype of C function is shown as below: * @code * void flash_run_command(FTFx_REG8_ACCESS_TYPE ftfx_fstat) * { * // clear CCIF bit * *ftfx_fstat = FTFx_FSTAT_CCIF_MASK; * * // Check CCIF bit of the flash status register, wait till it is set. * // IP team indicates that this loop will always complete. * while (!((*ftfx_fstat) & FTFx_FSTAT_CCIF_MASK)) * { * } * } * @endcode * Note2: The binary code is generated by IAR 7.70.1 */ static const uint16_t s_ftfxRunCommandFunctionCode[] = { 0x2180, /* MOVS R1, #128 ; 0x80 */ 0x7001, /* STRB R1, [R0] */ /* @4: */ 0x7802, /* LDRB R2, [R0] */ 0x420a, /* TST R2, R1 */ 0xd0fc, /* BEQ.N @4 */ 0x4770 /* BX LR */ }; #if (!FTFx_DRIVER_IS_EXPORTED) /*! @brief A static buffer used to hold flash_run_command() */ static uint32_t s_ftfxRunCommand[kFTFx_RamFuncMaxSizeInWords]; #endif /* (!FTFx_DRIVER_IS_EXPORTED) */ #endif /* FTFx_DRIVER_IS_FLASH_RESIDENT */ /*! @brief Access to FTFx Registers */ static volatile uint32_t *const kFCCOBx = (volatile uint32_t *)&FTFx_FCCOB3_REG; #if FSL_FEATURE_FLASH_HAS_FLEX_NVM /*! @brief Table of eeprom sizes. */ static const uint16_t kEepromDensities[16] = { FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0000, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0001, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0010, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0011, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0100, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0101, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0110, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0111, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1000, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1001, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1010, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1011, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1100, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1101, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1110, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1111 }; /*! @brief Table of dflash sizes. */ static const uint32_t kDflashDensities[16] = { FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0000, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0001, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0010, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0011, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0100, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0101, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0110, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0111, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1000, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1001, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1010, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1011, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1100, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1101, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1110, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1111 }; #endif /* FSL_FEATURE_FLASH_HAS_FLEX_NVM */ /******************************************************************************* * Code ******************************************************************************/ status_t FTFx_API_Init(ftfx_config_t *config) { if (config == NULL) { return kStatus_FTFx_InvalidArgument; } config->flexramBlockBase = FSL_FEATURE_FLASH_FLEX_RAM_START_ADDRESS; config->flexramTotalSize = FSL_FEATURE_FLASH_FLEX_RAM_SIZE; /* copy required flash command to RAM */ #if FTFx_DRIVER_IS_FLASH_RESIDENT if (NULL == config->runCmdFuncAddr) { #if FTFx_DRIVER_IS_EXPORTED return kStatus_FTFx_ExecuteInRamFunctionNotReady; #else config->runCmdFuncAddr = s_ftfxRunCommand; #endif /* FTFx_DRIVER_IS_EXPORTED */ } ftfx_copy_run_command_to_ram(config->runCmdFuncAddr); #endif /* FTFx_DRIVER_IS_FLASH_RESIDENT */ ftfx_init_ifr(config); return kStatus_FTFx_Success; } #if FSL_FEATURE_FLASH_HAS_FLEX_NVM status_t FTFx_API_UpdateFlexnvmPartitionStatus(ftfx_config_t *config) { struct _dflash_ifr_field_config { uint32_t reserved0; uint8_t FlexNVMPartitionCode; uint8_t EEPROMDataSetSize; uint16_t reserved1; } dataIFRReadOut; uint32_t flexnvmInfoIfrAddr; status_t returnCode; if (config == NULL) { return kStatus_FTFx_InvalidArgument; } flexnvmInfoIfrAddr = config->ifrDesc.resRange.dflashIfrStart + config->ifrDesc.resRange.ifrMemSize - sizeof(dataIFRReadOut); #if defined(FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD) && FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD /* Get FlexNVM memory partition info from data flash IFR */ returnCode = FTFx_CMD_ReadResource(config, flexnvmInfoIfrAddr, (uint8_t *)&dataIFRReadOut, sizeof(dataIFRReadOut), kFTFx_ResourceOptionFlashIfr); if (returnCode != kStatus_FTFx_Success) { return kStatus_FTFx_PartitionStatusUpdateFailure; } #else #error "Cannot get FlexNVM memory partition info" #endif /* Fill out partitioned EEPROM size */ dataIFRReadOut.EEPROMDataSetSize &= 0x0FU; config->eepromTotalSize = kEepromDensities[dataIFRReadOut.EEPROMDataSetSize]; /* Fill out partitioned DFlash size */ dataIFRReadOut.FlexNVMPartitionCode &= 0x0FU; config->flashDesc.totalSize = kDflashDensities[dataIFRReadOut.FlexNVMPartitionCode]; return kStatus_FTFx_Success; } #endif /* FSL_FEATURE_FLASH_HAS_FLEX_NVM */ status_t FTFx_CMD_Erase(ftfx_config_t *config, uint32_t start, uint32_t lengthInBytes, uint32_t key) { uint32_t sectorSize; uint32_t endAddress; /* storing end address */ uint32_t numberOfSectors; /* number of sectors calculated by endAddress */ status_t returnCode; /* Check the supplied address range. */ returnCode = ftfx_check_mem_range(config, start, lengthInBytes, config->opsConfig.addrAligment.sectorCmd); if (returnCode) { return returnCode; } /* Validate the user key */ returnCode = ftfx_check_user_key(key); if (returnCode) { return returnCode; } start = config->opsConfig.convertedAddress; sectorSize = config->flashDesc.sectorSize; /* calculating Flash end address */ endAddress = start + lengthInBytes - 1; /* re-calculate the endAddress and align it to the start of the next sector * which will be used in the comparison below */ if (endAddress % sectorSize) { numberOfSectors = endAddress / sectorSize + 1; endAddress = numberOfSectors * sectorSize - 1; } /* the start address will increment to the next sector address * until it reaches the endAdddress */ while (start <= endAddress) { /* preparing passing parameter to erase a flash block */ kFCCOBx[0] = BYTE2WORD_1_3(FTFx_ERASE_SECTOR, start); /* calling flash command sequence function to execute the command */ returnCode = ftfx_command_sequence(config); /* checking the success of command execution */ if (kStatus_FTFx_Success != returnCode) { break; } else { /* Increment to the next sector */ start += sectorSize; } } return (returnCode); } status_t FTFx_CMD_EraseAll(ftfx_config_t *config, uint32_t key) { status_t returnCode; if (config == NULL) { return kStatus_FTFx_InvalidArgument; } /* preparing passing parameter to erase all flash blocks */ kFCCOBx[0] = BYTE2WORD_1_3(FTFx_ERASE_ALL_BLOCK, 0xFFFFFFU); /* Validate the user key */ returnCode = ftfx_check_user_key(key); if (returnCode) { return returnCode; } /* calling flash command sequence function to execute the command */ returnCode = ftfx_command_sequence(config); #if FSL_FEATURE_FLASH_HAS_FLEX_NVM /* Data flash IFR will be erased by erase all command, so we need to * update FlexNVM memory partition status synchronously */ if (returnCode == kStatus_FTFx_Success) { returnCode = FTFx_API_UpdateFlexnvmPartitionStatus(config); } #endif return returnCode; } #if defined(FSL_FEATURE_FLASH_HAS_ERASE_ALL_BLOCKS_UNSECURE_CMD) && FSL_FEATURE_FLASH_HAS_ERASE_ALL_BLOCKS_UNSECURE_CMD status_t FTFx_CMD_EraseAllUnsecure(ftfx_config_t *config, uint32_t key) { status_t returnCode; if (config == NULL) { return kStatus_FTFx_InvalidArgument; } /* Prepare passing parameter to erase all flash blocks (unsecure). */ kFCCOBx[0] = BYTE2WORD_1_3(FTFx_ERASE_ALL_BLOCK_UNSECURE, 0xFFFFFFU); /* Validate the user key */ returnCode = ftfx_check_user_key(key); if (returnCode) { return returnCode; } /* calling flash command sequence function to execute the command */ returnCode = ftfx_command_sequence(config); #if FSL_FEATURE_FLASH_HAS_FLEX_NVM /* Data flash IFR will be erased by erase all unsecure command, so we need to * update FlexNVM memory partition status synchronously */ if (returnCode == kStatus_FTFx_Success) { returnCode = FTFx_API_UpdateFlexnvmPartitionStatus(config); } #endif return returnCode; } #endif /* FSL_FEATURE_FLASH_HAS_ERASE_ALL_BLOCKS_UNSECURE_CMD */ status_t FTFx_CMD_EraseAllExecuteOnlySegments(ftfx_config_t *config, uint32_t key) { status_t returnCode; if (config == NULL) { return kStatus_FTFx_InvalidArgument; } /* preparing passing parameter to erase all execute-only segments * 1st element for the FCCOB register */ kFCCOBx[0] = BYTE2WORD_1_3(FTFx_ERASE_ALL_EXECUTE_ONLY_SEGMENT, 0xFFFFFFU); /* Validate the user key */ returnCode = ftfx_check_user_key(key); if (returnCode) { return returnCode; } /* calling flash command sequence function to execute the command */ returnCode = ftfx_command_sequence(config); return returnCode; } status_t FTFx_CMD_Program(ftfx_config_t *config, uint32_t start, uint8_t *src, uint32_t lengthInBytes) { status_t returnCode; uint8_t blockWriteUnitSize = config->opsConfig.addrAligment.blockWriteUnitSize; if (src == NULL) { return kStatus_FTFx_InvalidArgument; } /* Check the supplied address range. */ returnCode = ftfx_check_mem_range(config, start, lengthInBytes, blockWriteUnitSize); if (returnCode) { return returnCode; } start = config->opsConfig.convertedAddress; while (lengthInBytes > 0) { /* preparing passing parameter to program the flash block */ kFCCOBx[1] = ftfx_read_word_from_byte_address((const uint8_t*)src); src += 4; if (4 == blockWriteUnitSize) { kFCCOBx[0] = BYTE2WORD_1_3(FTFx_PROGRAM_LONGWORD, start); } else if (8 == blockWriteUnitSize) { kFCCOBx[2] = ftfx_read_word_from_byte_address((const uint8_t*)src); src += 4; kFCCOBx[0] = BYTE2WORD_1_3(FTFx_PROGRAM_PHRASE, start); } else { } /* calling flash command sequence function to execute the command */ returnCode = ftfx_command_sequence(config); /* checking for the success of command execution */ if (kStatus_FTFx_Success != returnCode) { break; } else { /* update start address for next iteration */ start += blockWriteUnitSize; /* update lengthInBytes for next iteration */ lengthInBytes -= blockWriteUnitSize; } } return (returnCode); } status_t FTFx_CMD_ProgramOnce(ftfx_config_t *config, uint32_t index, uint8_t *src, uint32_t lengthInBytes) { status_t returnCode; if ((config == NULL) || (src == NULL)) { return kStatus_FTFx_InvalidArgument; } /* pass paramters to FTFx */ kFCCOBx[0] = BYTE2WORD_1_1_2(FTFx_PROGRAM_ONCE, index, 0xFFFFU); kFCCOBx[1] = ftfx_read_word_from_byte_address((const uint8_t*)src); /* Note: Have to seperate the first index from the rest if it equals 0 * to avoid a pointless comparison of unsigned int to 0 compiler warning */ if (config->ifrDesc.feature.has8ByteIdxSupport) { if (config->ifrDesc.feature.has4ByteIdxSupport) { if (((index == config->ifrDesc.idxInfo.mix8byteIdxStart) || ((index >= config->ifrDesc.idxInfo.mix8byteIdxStart + 1) && (index <= config->ifrDesc.idxInfo.mix8byteIdxStart))) && (lengthInBytes == 8)) { kFCCOBx[2] = ftfx_read_word_from_byte_address((const uint8_t*)src + 4); } } else { kFCCOBx[2] = ftfx_read_word_from_byte_address((const uint8_t*)src + 4); } } /* calling flash command sequence function to execute the command */ returnCode = ftfx_command_sequence(config); return returnCode; } #if defined(FSL_FEATURE_FLASH_HAS_PROGRAM_SECTION_CMD) && FSL_FEATURE_FLASH_HAS_PROGRAM_SECTION_CMD status_t FTFx_CMD_ProgramSection(ftfx_config_t *config, uint32_t start, uint8_t *src, uint32_t lengthInBytes) { status_t returnCode; uint32_t sectorSize; uint8_t aligmentInBytes = config->opsConfig.addrAligment.sectionCmd; #if defined(FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD) && FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD bool needSwitchFlexRamMode = false; #endif /* FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD */ if (src == NULL) { return kStatus_FTFx_InvalidArgument; } /* Check the supplied address range. */ returnCode = ftfx_check_mem_range(config, start, lengthInBytes, aligmentInBytes); if (returnCode) { return returnCode; } start = config->opsConfig.convertedAddress; sectorSize = config->flashDesc.sectorSize; #if defined(FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD) && FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD /* Switch function of FlexRAM if needed */ if (!(FTFx->FCNFG & FTFx_FCNFG_RAMRDY_MASK)) { needSwitchFlexRamMode = true; returnCode = FTFx_CMD_SetFlexramFunction(config, kFTFx_FlexramFuncOptAvailableAsRam); if (returnCode != kStatus_FTFx_Success) { return kStatus_FTFx_SetFlexramAsRamError; } } #endif /* FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD */ while (lengthInBytes > 0) { /* Make sure the write operation doesn't span two sectors */ uint32_t endAddressOfCurrentSector = ALIGN_UP(start, sectorSize); uint32_t lengthTobeProgrammedOfCurrentSector; uint32_t currentOffset = 0; if (endAddressOfCurrentSector == start) { endAddressOfCurrentSector += sectorSize; } if (lengthInBytes + start > endAddressOfCurrentSector) { lengthTobeProgrammedOfCurrentSector = endAddressOfCurrentSector - start; } else { lengthTobeProgrammedOfCurrentSector = lengthInBytes; } /* Program Current Sector */ while (lengthTobeProgrammedOfCurrentSector > 0) { /* Make sure the program size doesn't exceeds Acceleration RAM size */ uint32_t programSizeOfCurrentPass; uint32_t numberOfPhases; if (lengthTobeProgrammedOfCurrentSector > config->flexramTotalSize) { programSizeOfCurrentPass = config->flexramTotalSize; } else { programSizeOfCurrentPass = lengthTobeProgrammedOfCurrentSector; } /* Copy data to FlexRAM */ memcpy((void *)config->flexramBlockBase, src + currentOffset, programSizeOfCurrentPass); /* Set start address of the data to be programmed */ kFCCOBx[0] = BYTE2WORD_1_3(FTFx_PROGRAM_SECTION, start + currentOffset); /* Set program size in terms of FEATURE_FLASH_SECTION_CMD_ADDRESS_ALIGMENT */ numberOfPhases = programSizeOfCurrentPass / aligmentInBytes; kFCCOBx[1] = BYTE2WORD_2_2(numberOfPhases, 0xFFFFU); /* Peform command sequence */ returnCode = ftfx_command_sequence(config); if (returnCode != kStatus_FTFx_Success) { return returnCode; } lengthTobeProgrammedOfCurrentSector -= programSizeOfCurrentPass; currentOffset += programSizeOfCurrentPass; } src += currentOffset; start += currentOffset; lengthInBytes -= currentOffset; } #if defined(FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD) && FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD /* Restore function of FlexRAM if needed. */ if (needSwitchFlexRamMode) { returnCode = FTFx_CMD_SetFlexramFunction(config, kFTFx_FlexramFuncOptAvailableForEeprom); if (returnCode != kStatus_FTFx_Success) { return kStatus_FTFx_RecoverFlexramAsEepromError; } } #endif /* FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD */ return returnCode; } #endif /* FSL_FEATURE_FLASH_HAS_PROGRAM_SECTION_CMD */ #if defined(FSL_FEATURE_FLASH_HAS_PROGRAM_PARTITION_CMD) && FSL_FEATURE_FLASH_HAS_PROGRAM_PARTITION_CMD status_t FTFx_CMD_ProgramPartition(ftfx_config_t *config, ftfx_partition_flexram_load_opt_t option, uint32_t eepromDataSizeCode, uint32_t flexnvmPartitionCode) { status_t returnCode; if (config == NULL) { return kStatus_FTFx_InvalidArgument; } /* eepromDataSizeCode[7:6], flexnvmPartitionCode[7:4] should be all 1'b0 * or it will cause access error. */ /* eepromDataSizeCode &= 0x3FU; */ /* flexnvmPartitionCode &= 0x0FU; */ /* preparing passing parameter to program the flash block */ kFCCOBx[0] = BYTE2WORD_1_2_1(FTFx_PROGRAM_PARTITION, 0xFFFFU, option); kFCCOBx[1] = BYTE2WORD_1_1_2(eepromDataSizeCode, flexnvmPartitionCode, 0xFFFFU); /* calling flash command sequence function to execute the command */ returnCode = ftfx_command_sequence(config); #if FSL_FEATURE_FLASH_HAS_FLEX_NVM /* Data flash IFR will be updated by program partition command during reset sequence, * so we just set reserved values for partitioned FlexNVM size here */ config->eepromTotalSize = 0xFFFFU; config->flashDesc.totalSize = 0xFFFFFFFFU; #endif return (returnCode); } #endif /* FSL_FEATURE_FLASH_HAS_PROGRAM_PARTITION_CMD */ status_t FTFx_CMD_ReadOnce(ftfx_config_t *config, uint32_t index, uint8_t *dst, uint32_t lengthInBytes) { status_t returnCode; if ((config == NULL) || (dst == NULL)) { return kStatus_FTFx_InvalidArgument; } /* pass paramters to FTFx */ kFCCOBx[0] = BYTE2WORD_1_1_2(FTFx_READ_ONCE, index, 0xFFFFU); /* calling flash command sequence function to execute the command */ returnCode = ftfx_command_sequence(config); if (kStatus_FTFx_Success == returnCode) { ftfx_write_word_to_byte_address(dst, kFCCOBx[1]); /* Note: Have to seperate the first index from the rest if it equals 0 * to avoid a pointless comparison of unsigned int to 0 compiler warning */ if (config->ifrDesc.feature.has8ByteIdxSupport) { if (config->ifrDesc.feature.has4ByteIdxSupport) { if (((index == config->ifrDesc.idxInfo.mix8byteIdxStart) || ((index >= config->ifrDesc.idxInfo.mix8byteIdxStart + 1) && (index <= config->ifrDesc.idxInfo.mix8byteIdxStart))) && (lengthInBytes == 8)) { ftfx_write_word_to_byte_address(dst + 4, kFCCOBx[2]); } } else { ftfx_write_word_to_byte_address(dst + 4, kFCCOBx[2]); } } } return returnCode; } #if defined(FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD) && FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD status_t FTFx_CMD_ReadResource(ftfx_config_t *config, uint32_t start, uint8_t *dst, uint32_t lengthInBytes, ftfx_read_resource_opt_t option) { status_t returnCode; if ((config == NULL) || (dst == NULL)) { return kStatus_FTFx_InvalidArgument; } uint8_t aligmentInBytes = config->opsConfig.addrAligment.resourceCmd; /* Check the supplied address range. */ returnCode = ftfx_check_resource_range(config, start, lengthInBytes, aligmentInBytes, option); if (returnCode != kStatus_FTFx_Success) { return returnCode; } while (lengthInBytes > 0) { /* preparing passing parameter */ kFCCOBx[0] = BYTE2WORD_1_3(FTFx_READ_RESOURCE, start); if (aligmentInBytes == 4) { kFCCOBx[2] = BYTE2WORD_1_3(option, 0xFFFFFFU); } else if (aligmentInBytes == 8) { kFCCOBx[1] = BYTE2WORD_1_3(option, 0xFFFFFFU); } else { } /* calling flash command sequence function to execute the command */ returnCode = ftfx_command_sequence(config); if (kStatus_FTFx_Success != returnCode) { break; } /* fetch data */ ftfx_write_word_to_byte_address(dst, kFCCOBx[1]); dst += 4; if (aligmentInBytes == 8) { ftfx_write_word_to_byte_address(dst, kFCCOBx[2]); dst += 4; } /* update start address for next iteration */ start += aligmentInBytes; /* update lengthInBytes for next iteration */ lengthInBytes -= aligmentInBytes; } return (returnCode); } #endif /* FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD */ status_t FTFx_CMD_VerifyErase(ftfx_config_t *config, uint32_t start, uint32_t lengthInBytes, ftfx_margin_value_t margin) { /* Check arguments. */ uint32_t blockSize; uint32_t nextBlockStartAddress; uint32_t remainingBytes; uint8_t aligmentInBytes = config->opsConfig.addrAligment.sectionCmd; status_t returnCode; returnCode = ftfx_check_mem_range(config, start, lengthInBytes, aligmentInBytes); if (returnCode) { return returnCode; } start = config->opsConfig.convertedAddress; blockSize = config->flashDesc.totalSize / config->flashDesc.blockCount; nextBlockStartAddress = ALIGN_UP(start, blockSize); if (nextBlockStartAddress == start) { nextBlockStartAddress += blockSize; } remainingBytes = lengthInBytes; while (remainingBytes) { uint32_t numberOfPhrases; uint32_t verifyLength = nextBlockStartAddress - start; if (verifyLength > remainingBytes) { verifyLength = remainingBytes; } numberOfPhrases = verifyLength / aligmentInBytes; /* Fill in verify section command parameters. */ kFCCOBx[0] = BYTE2WORD_1_3(FTFx_VERIFY_SECTION, start); kFCCOBx[1] = BYTE2WORD_2_1_1(numberOfPhrases, margin, 0xFFU); /* calling flash command sequence function to execute the command */ returnCode = ftfx_command_sequence(config); if (returnCode) { return returnCode; } remainingBytes -= verifyLength; start += verifyLength; nextBlockStartAddress += blockSize; } return kStatus_FTFx_Success; } status_t FTFx_CMD_VerifyEraseAll(ftfx_config_t *config, ftfx_margin_value_t margin) { if (config == NULL) { return kStatus_FTFx_InvalidArgument; } /* preparing passing parameter to verify all block command */ kFCCOBx[0] = BYTE2WORD_1_1_2(FTFx_VERIFY_ALL_BLOCK, margin, 0xFFFFU); /* calling flash command sequence function to execute the command */ return ftfx_command_sequence(config); } status_t FTFx_CMD_VerifyEraseAllExecuteOnlySegments(ftfx_config_t *config, ftfx_margin_value_t margin) { if (config == NULL) { return kStatus_FTFx_InvalidArgument; } /* preparing passing parameter to verify erase all execute-only segments command */ kFCCOBx[0] = BYTE2WORD_1_1_2(FTFx_VERIFY_ALL_EXECUTE_ONLY_SEGMENT, margin, 0xFFFFU); /* calling flash command sequence function to execute the command */ return ftfx_command_sequence(config); } status_t FTFx_CMD_VerifyProgram(ftfx_config_t *config, uint32_t start, uint32_t lengthInBytes, const uint8_t *expectedData, ftfx_margin_value_t margin, uint32_t *failedAddress, uint32_t *failedData) { status_t returnCode; uint8_t aligmentInBytes = config->opsConfig.addrAligment.checkCmd; if (expectedData == NULL) { return kStatus_FTFx_InvalidArgument; } returnCode = ftfx_check_mem_range(config, start, lengthInBytes, aligmentInBytes); if (returnCode) { return returnCode; } start = config->opsConfig.convertedAddress; while (lengthInBytes) { /* preparing passing parameter to program check the flash block */ kFCCOBx[0] = BYTE2WORD_1_3(FTFx_PROGRAM_CHECK, start); kFCCOBx[1] = BYTE2WORD_1_3(margin, 0xFFFFFFU); kFCCOBx[2] = ftfx_read_word_from_byte_address((const uint8_t*)expectedData); /* calling flash command sequence function to execute the command */ returnCode = ftfx_command_sequence(config); /* checking for the success of command execution */ if (kStatus_FTFx_Success != returnCode) { if (failedAddress) { *failedAddress = start; } if (failedData) { *failedData = 0; } break; } lengthInBytes -= aligmentInBytes; expectedData += aligmentInBytes; start += aligmentInBytes; } return (returnCode); } status_t FTFx_CMD_SecurityBypass(ftfx_config_t *config, const uint8_t *backdoorKey) { uint8_t registerValue; /* registerValue */ status_t returnCode; /* return code variable */ if ((config == NULL) || (backdoorKey == NULL)) { return kStatus_FTFx_InvalidArgument; } /* set the default return code as kStatus_Success */ returnCode = kStatus_FTFx_Success; /* Get flash security register value */ registerValue = FTFx->FSEC; /* Check to see if flash is in secure state (any state other than 0x2) * If not, then skip this since flash is not secure */ if (0x02 != (registerValue & 0x03)) { /* preparing passing parameter to erase a flash block */ kFCCOBx[0] = BYTE2WORD_1_3(FTFx_SECURITY_BY_PASS, 0xFFFFFFU); kFCCOBx[1] = BYTE2WORD_1_1_1_1(backdoorKey[0], backdoorKey[1], backdoorKey[2], backdoorKey[3]); kFCCOBx[2] = BYTE2WORD_1_1_1_1(backdoorKey[4], backdoorKey[5], backdoorKey[6], backdoorKey[7]); /* calling flash command sequence function to execute the command */ returnCode = ftfx_command_sequence(config); } return (returnCode); } status_t FTFx_REG_GetSecurityState(ftfx_config_t *config, ftfx_security_state_t *state) { /* store data read from flash register */ uint8_t registerValue; if ((config == NULL) || (state == NULL)) { return kStatus_FTFx_InvalidArgument; } /* Get flash security register value */ registerValue = FTFx->FSEC; /* check the status of the flash security bits in the security register */ if (kFTFx_FsecRegCode_SEC_Unsecured == (registerValue & FTFx_FSEC_SEC_MASK)) { /* Flash in unsecured state */ *state = kFTFx_SecurityStateNotSecure; } else { /* Flash in secured state * check for backdoor key security enable bit */ if (kFTFx_FsecRegCode_KEYEN_Enabled == (registerValue & FTFx_FSEC_KEYEN_MASK)) { /* Backdoor key security enabled */ *state = kFTFx_SecurityStateBackdoorEnabled; } else { /* Backdoor key security disabled */ *state = kFTFx_SecurityStateBackdoorDisabled; } } return (kStatus_FTFx_Success); } #if defined(FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD) && FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD status_t FTFx_CMD_SetFlexramFunction(ftfx_config_t *config, ftfx_flexram_func_opt_t option) { status_t status; if (config == NULL) { return kStatus_FTFx_InvalidArgument; } status = ftfx_check_flexram_function_option(option); if (status != kStatus_FTFx_Success) { return status; } /* preparing passing parameter to verify all block command */ kFCCOBx[0] = BYTE2WORD_1_1_2(FTFx_SET_FLEXRAM_FUNCTION, option, 0xFFFFU); /* calling flash command sequence function to execute the command */ return ftfx_command_sequence(config); } #endif /* FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD */ #if defined(FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD) && FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD status_t FTFx_CMD_SwapControl(ftfx_config_t *config, uint32_t address, ftfx_swap_control_opt_t option, ftfx_swap_state_config_t *returnInfo) { status_t returnCode; if ((config == NULL) || (returnInfo == NULL)) { return kStatus_FTFx_InvalidArgument; } if (address & (FSL_FEATURE_FLASH_PFLASH_SWAP_CONTROL_CMD_ADDRESS_ALIGMENT - 1)) { return kStatus_FTFx_AlignmentError; } /* Make sure address provided is in the lower half of Program flash but not in the Flash Configuration Field */ if ((address >= (config->flashDesc.totalSize / 2)) || ((address >= kFTFx_PflashConfigAreaStart) && (address <= kFTFx_PflashConfigAreaEnd))) { return kStatus_FTFx_SwapIndicatorAddressError; } /* Check the option. */ returnCode = ftfx_check_swap_control_option(option); if (returnCode) { return returnCode; } kFCCOBx[0] = BYTE2WORD_1_3(FTFx_SWAP_CONTROL, address); kFCCOBx[1] = BYTE2WORD_1_3(option, 0xFFFFFFU); returnCode = ftfx_command_sequence(config); returnInfo->flashSwapState = (ftfx_swap_state_t)FTFx_FCCOB5_REG; returnInfo->currentSwapBlockStatus = (ftfx_swap_block_status_t)FTFx_FCCOB6_REG; returnInfo->nextSwapBlockStatus = (ftfx_swap_block_status_t)FTFx_FCCOB7_REG; return returnCode; } #endif /* FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD */ static status_t ftfx_init_ifr(ftfx_config_t *config) { if (config == NULL) { return kStatus_FTFx_InvalidArgument; } #if FSL_FEATURE_FLASH_IS_FTFA /* FTFA parts(eg. K80, KL80, L5K) support both 4-bytes and 8-bytes unit size */ config->ifrDesc.feature.has4ByteIdxSupport = 1; config->ifrDesc.feature.has8ByteIdxSupport = 1; config->ifrDesc.idxInfo.mix8byteIdxStart = 0x10U; config->ifrDesc.idxInfo.mix8byteIdxEnd = 0x13U; #elif FSL_FEATURE_FLASH_IS_FTFE /* FTFE parts(eg. K65, KE18) only support 8-bytes unit size */ config->ifrDesc.feature.has4ByteIdxSupport = 0; config->ifrDesc.feature.has8ByteIdxSupport = 1; #elif FSL_FEATURE_FLASH_IS_FTFL /* FTFL parts(eg. K20) only support 4-bytes unit size */ config->ifrDesc.feature.has4ByteIdxSupport = 1; config->ifrDesc.feature.has8ByteIdxSupport = 0; #endif config->ifrDesc.resRange.pflashIfrStart = 0x0000U; config->ifrDesc.resRange.versionIdSize = 0x08U; #if FSL_FEATURE_FLASH_IS_FTFE config->ifrDesc.resRange.versionIdStart = 0x08U; config->ifrDesc.resRange.ifrMemSize = 0x0400U; #else /* FSL_FEATURE_FLASH_IS_FTFL == 1 or FSL_FEATURE_FLASH_IS_FTFA = =1 */ config->ifrDesc.resRange.versionIdStart = 0x00U; config->ifrDesc.resRange.ifrMemSize = 0x0100U; #endif #if FSL_FEATURE_FLASH_HAS_FLEX_NVM config->ifrDesc.resRange.dflashIfrStart = 0x800000U; #endif #if FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD #if FSL_FEATURE_FLASH_IS_FTFE config->ifrDesc.resRange.pflashSwapIfrStart = 0x40000U; #else /* FSL_FEATURE_FLASH_IS_FTFL == 1 or FSL_FEATURE_FLASH_IS_FTFA == 1 */ config->ifrDesc.resRange.pflashSwapIfrStart = config->flashDesc.totalSize / 4; #endif #endif /* FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD */ return kStatus_FTFx_Success; } #if FTFx_DRIVER_IS_FLASH_RESIDENT /*! * @brief Copy PIC of flash_run_command() to RAM */ static void ftfx_copy_run_command_to_ram(uint32_t *ftfxRunCommand) { assert(sizeof(s_ftfxRunCommandFunctionCode) <= (kFTFx_RamFuncMaxSizeInWords * 4)); /* Since the value of ARM function pointer is always odd, but the real start address * of function memory should be even, that's why +1 operation exist. */ memcpy((uint8_t *)ftfxRunCommand, (const uint8_t *)s_ftfxRunCommandFunctionCode, sizeof(s_ftfxRunCommandFunctionCode)); } #endif /* FTFx_DRIVER_IS_FLASH_RESIDENT */ /*! * @brief FTFx Command Sequence * * This function is used to perform the command write sequence to the flash. * * @param driver Pointer to storage for the driver runtime state. * @return An error code or kStatus_FTFx_Success */ static status_t ftfx_command_sequence(ftfx_config_t *config) { uint8_t registerValue; #if FTFx_DRIVER_IS_FLASH_RESIDENT /* clear RDCOLERR & ACCERR & FPVIOL flag in flash status register */ FTFx->FSTAT = FTFx_FSTAT_RDCOLERR_MASK | FTFx_FSTAT_ACCERR_MASK | FTFx_FSTAT_FPVIOL_MASK; /* Since the value of ARM function pointer is always odd, but the real start address * of function memory should be even, that's why +1 operation exist. */ callFtfxRunCommand_t callFtfxRunCommand = (callFtfxRunCommand_t)((uint32_t)config->runCmdFuncAddr + 1); /* We pass the ftfx_fstat address as a parameter to flash_run_comamnd() instead of using * pre-processed MICRO sentences or operating global variable in flash_run_comamnd() * to make sure that flash_run_command() will be compiled into position-independent code (PIC). */ callFtfxRunCommand((FTFx_REG8_ACCESS_TYPE)(&FTFx->FSTAT)); #else /* clear RDCOLERR & ACCERR & FPVIOL flag in flash status register */ FTFx->FSTAT = FTFx_FSTAT_RDCOLERR_MASK | FTFx_FSTAT_ACCERR_MASK | FTFx_FSTAT_FPVIOL_MASK; /* clear CCIF bit */ FTFx->FSTAT = FTFx_FSTAT_CCIF_MASK; /* Check CCIF bit of the flash status register, wait till it is set. * IP team indicates that this loop will always complete. */ while (!(FTFx->FSTAT & FTFx_FSTAT_CCIF_MASK)) { } #endif /* FTFx_DRIVER_IS_FLASH_RESIDENT */ /* Check error bits */ /* Get flash status register value */ registerValue = FTFx->FSTAT; /* checking access error */ if (registerValue & FTFx_FSTAT_ACCERR_MASK) { return kStatus_FTFx_AccessError; } /* checking protection error */ else if (registerValue & FTFx_FSTAT_FPVIOL_MASK) { return kStatus_FTFx_ProtectionViolation; } /* checking MGSTAT0 non-correctable error */ else if (registerValue & FTFx_FSTAT_MGSTAT0_MASK) { return kStatus_FTFx_CommandFailure; } else { return kStatus_FTFx_Success; } } /*! @brief Validates the range and alignment of the given address range.*/ static status_t ftfx_check_mem_range(ftfx_config_t *config, uint32_t startAddress, uint32_t lengthInBytes, uint8_t alignmentBaseline) { if (config == NULL) { return kStatus_FTFx_InvalidArgument; } /* Verify the start and length are alignmentBaseline aligned. */ if ((startAddress & (alignmentBaseline - 1)) || (lengthInBytes & (alignmentBaseline - 1))) { return kStatus_FTFx_AlignmentError; } /* check for valid range of the target addresses */ if ((startAddress >= config->flashDesc.blockBase) && ((startAddress + lengthInBytes) <= (config->flashDesc.blockBase + config->flashDesc.totalSize))) { return kStatus_FTFx_Success; } return kStatus_FTFx_AddressError; } /*! @brief Validates the given user key for flash erase APIs.*/ static status_t ftfx_check_user_key(uint32_t key) { /* Validate the user key */ if (key != kFTFx_ApiEraseKey) { return kStatus_FTFx_EraseKeyError; } return kStatus_FTFx_Success; } /*! @brief Reads word from byte address.*/ static uint32_t ftfx_read_word_from_byte_address(const uint8_t *src) { uint32_t word = 0; if (!((uint32_t)src % 4)) { word = *(const uint32_t *)src; } else { for (uint32_t i = 0; i < 4; i++) { word |= (uint32_t)(*src) << (i * 8); src++; } } return word; } /*! @brief Writes word to byte address.*/ static void ftfx_write_word_to_byte_address(uint8_t *dst, uint32_t word) { if (!((uint32_t)dst % 4)) { *(uint32_t *)dst = word; } else { for (uint32_t i = 0; i < 4; i++) { *dst = (uint8_t)((word >> (i * 8)) & 0xFFU); dst++; } } } #if defined(FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD) && FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD /*! @brief Validates the range of the given resource address.*/ static status_t ftfx_check_resource_range(ftfx_config_t *config, uint32_t start, uint32_t lengthInBytes, uint32_t alignmentBaseline, ftfx_read_resource_opt_t option) { status_t status; uint32_t maxReadbleAddress; if ((start & (alignmentBaseline - 1)) || (lengthInBytes & (alignmentBaseline - 1))) { return kStatus_FTFx_AlignmentError; } status = kStatus_FTFx_Success; maxReadbleAddress = start + lengthInBytes - 1; if (option == kFTFx_ResourceOptionVersionId) { if ((start != config->ifrDesc.resRange.versionIdStart) || (lengthInBytes != config->ifrDesc.resRange.versionIdSize)) { status = kStatus_FTFx_InvalidArgument; } } else if (option == kFTFx_ResourceOptionFlashIfr) { if ((start >= config->ifrDesc.resRange.pflashIfrStart) && (maxReadbleAddress < (config->ifrDesc.resRange.pflashIfrStart + config->ifrDesc.resRange.ifrMemSize))) { } #if FSL_FEATURE_FLASH_HAS_FLEX_NVM else if ((start >= config->ifrDesc.resRange.dflashIfrStart) && (maxReadbleAddress < (config->ifrDesc.resRange.dflashIfrStart + config->ifrDesc.resRange.ifrMemSize))) { } #endif #if FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD else if ((start >= config->ifrDesc.resRange.pflashSwapIfrStart) && (maxReadbleAddress < (config->ifrDesc.resRange.pflashSwapIfrStart + config->ifrDesc.resRange.ifrMemSize))) { } #endif else { status = kStatus_FTFx_InvalidArgument; } } else { status = kStatus_FTFx_InvalidArgument; } return status; } #endif /* FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD */ #if defined(FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD) && FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD /*! @brief Validates the gived flexram function option.*/ static inline status_t ftfx_check_flexram_function_option(ftfx_flexram_func_opt_t option) { if ((option != kFTFx_FlexramFuncOptAvailableAsRam) && (option != kFTFx_FlexramFuncOptAvailableForEeprom)) { return kStatus_FTFx_InvalidArgument; } return kStatus_FTFx_Success; } #endif /* FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD */ #if defined(FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD) && FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD /*! @brief Validates the gived swap control option.*/ static status_t ftfx_check_swap_control_option(ftfx_swap_control_opt_t option) { if ((option == kFTFx_SwapControlOptionIntializeSystem) || (option == kFTFx_SwapControlOptionSetInUpdateState) || (option == kFTFx_SwapControlOptionSetInCompleteState) || (option == kFTFx_SwapControlOptionReportStatus) || (option == kFTFx_SwapControlOptionDisableSystem)) { return kStatus_FTFx_Success; } return kStatus_FTFx_InvalidArgument; } #endif /* FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD */