1 /*
2  * Copyright 2013-2016 Freescale Semiconductor, Inc.
3  * Copyright 2016-2020 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  *
8  */
9 
10 #include "fsl_ftfx_controller.h"
11 
12 /*******************************************************************************
13  * Definitions
14  ******************************************************************************/
15 
16 /* Component ID definition, used by tools. */
17 #ifndef FSL_COMPONENT_ID
18 #define FSL_COMPONENT_ID "platform.drivers.flash"
19 #endif
20 
21 /*!
22  * @name Flash controller command numbers
23  * @{
24  */
25 #define FTFx_VERIFY_BLOCK                    0x00U /*!< RD1BLK*/
26 #define FTFx_VERIFY_SECTION                  0x01U /*!< RD1SEC*/
27 #define FTFx_PROGRAM_CHECK                   0x02U /*!< PGMCHK*/
28 #define FTFx_READ_RESOURCE                   0x03U /*!< RDRSRC*/
29 #define FTFx_PROGRAM_LONGWORD                0x06U /*!< PGM4*/
30 #define FTFx_PROGRAM_PHRASE                  0x07U /*!< PGM8*/
31 #define FTFx_ERASE_BLOCK                     0x08U /*!< ERSBLK*/
32 #define FTFx_ERASE_SECTOR                    0x09U /*!< ERSSCR*/
33 #define FTFx_PROGRAM_SECTION                 0x0BU /*!< PGMSEC*/
34 #define FTFx_GENERATE_CRC                    0x0CU /*!< CRCGEN*/
35 #define FTFx_VERIFY_ALL_BLOCK                0x40U /*!< RD1ALL*/
36 #define FTFx_READ_ONCE                       0x41U /*!< RDONCE or RDINDEX*/
37 #define FTFx_PROGRAM_ONCE                    0x43U /*!< PGMONCE or PGMINDEX*/
38 #define FTFx_ERASE_ALL_BLOCK                 0x44U /*!< ERSALL*/
39 #define FTFx_SECURITY_BY_PASS                0x45U /*!< VFYKEY*/
40 #define FTFx_SWAP_CONTROL                    0x46U /*!< SWAP*/
41 #define FTFx_ERASE_ALL_BLOCK_UNSECURE        0x49U /*!< ERSALLU*/
42 #define FTFx_VERIFY_ALL_EXECUTE_ONLY_SEGMENT 0x4AU /*!< RD1XA*/
43 #define FTFx_ERASE_ALL_EXECUTE_ONLY_SEGMENT  0x4BU /*!< ERSXA*/
44 #define FTFx_PROGRAM_PARTITION               0x80U /*!< PGMPART*/
45 #define FTFx_SET_FLEXRAM_FUNCTION            0x81U /*!< SETRAM*/
46 /*@}*/
47 
48 /*!
49  * @brief Constants for execute-in-RAM flash function.
50  */
51 enum _ftfx_ram_func_constants
52 {
53     kFTFx_RamFuncMaxSizeInWords = 16U, /*!< The maximum size of execute-in-RAM function.*/
54 };
55 
56 /*! @brief A function pointer used to point to relocated flash_run_command() */
57 typedef void (*callFtfxRunCommand_t)(FTFx_REG8_ACCESS_TYPE ftfx_fstat);
58 
59 /*!
60  * @name Enumeration for Flash security register code
61  * @{
62  */
63 enum _ftfx_fsec_register_code
64 {
65     kFTFx_FsecRegCode_KEYEN_Enabled = 0x80U,
66     kFTFx_FsecRegCode_SEC_Unsecured = 0x02U
67 };
68 /*@}*/
69 
70 #if defined(FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD) && FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD
71 /*!
72  * @brief Enumeration for flash config area.
73  */
74 enum _ftfx_pflash_config_area_range
75 {
76     kFTFx_PflashConfigAreaStart = 0x400U,
77     kFTFx_PflashConfigAreaEnd   = 0x40FU
78 };
79 #endif /* FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD */
80 
81 /*******************************************************************************
82  * Prototypes
83  ******************************************************************************/
84 
85 /*! @brief Init IFR memory related info */
86 static void ftfx_init_ifr(ftfx_config_t *config);
87 
88 #if FTFx_DRIVER_IS_FLASH_RESIDENT
89 /*! @brief Copy flash_run_command() to RAM*/
90 static void ftfx_copy_run_command_to_ram(uint32_t *ftfxRunCommand);
91 #endif /* FTFx_DRIVER_IS_FLASH_RESIDENT */
92 
93 /*! @brief Internal function Flash command sequence. Called by driver APIs only*/
94 static status_t ftfx_command_sequence(ftfx_config_t *config);
95 
96 /*! @brief Internal function Flash asynchronous command sequence. Called by driver APIs only*/
97 static void ftfx_command_sequence_non_blocking(ftfx_config_t *config);
98 
99 /*! @brief Validates the range and alignment of the given address range.*/
100 static status_t ftfx_check_mem_range(ftfx_config_t *config,
101                                      uint32_t startAddress,
102                                      uint32_t lengthInBytes,
103                                      uint8_t alignmentBaseline);
104 
105 /*! @brief Validates the given user key for flash erase APIs.*/
106 static status_t ftfx_check_user_key(uint32_t key);
107 
108 /*! @brief Reads word from byte address.*/
109 static uint32_t ftfx_read_word_from_byte_address(const uint8_t *src);
110 
111 /*! @brief Writes word to byte address.*/
112 static void ftfx_write_word_to_byte_address(uint8_t *dst, uint32_t word);
113 
114 #if defined(FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD) && FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD
115 /*! @brief Validates the range of the given resource address.*/
116 static status_t ftfx_check_resource_range(ftfx_config_t *config,
117                                           uint32_t start,
118                                           uint32_t lengthInBytes,
119                                           uint32_t alignmentBaseline,
120                                           ftfx_read_resource_opt_t option);
121 #endif /* FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD */
122 
123 #if defined(FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD) && FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD
124 /*! @brief Validates the given flexram function option.*/
125 static inline status_t ftfx_check_flexram_function_option(ftfx_flexram_func_opt_t option);
126 #endif /* FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD */
127 
128 #if defined(FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD) && FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD
129 /*! @brief Validates the given swap control option.*/
130 static status_t ftfx_check_swap_control_option(ftfx_swap_control_opt_t option);
131 #endif /* FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD */
132 
133 /*******************************************************************************
134  * Variables
135  ******************************************************************************/
136 
137 #if FTFx_DRIVER_IS_FLASH_RESIDENT
138 /*!
139  * @brief Position independent code of flash_run_command
140  *
141  * Note1: The prototype of C function is shown as below:
142  * @code
143  *   void flash_run_command(FTFx_REG8_ACCESS_TYPE ftfx_fstat)
144  *   {
145  *       *ftfx_fstat = FTFx_FSTAT_CCIF_MASK;
146  *
147  *       while (!((*ftfx_fstat) & FTFx_FSTAT_CCIF_MASK))
148  *       {
149  *       }
150  *   }
151  * @endcode
152  * Note2: The binary code is generated by IAR 7.70.1
153  */
154 static const uint32_t s_ftfxRunCommandFunctionCode[] = {
155     0x70012180u,
156     0x420a7802u,
157     0x4770d0fcu,
158 };
159 #if (!FTFx_DRIVER_IS_EXPORTED)
160 /*! @brief A static buffer used to hold flash_run_command() */
161 static uint32_t s_ftfxRunCommand[kFTFx_RamFuncMaxSizeInWords];
162 #endif /* (!FTFx_DRIVER_IS_EXPORTED) */
163 #endif /* FTFx_DRIVER_IS_FLASH_RESIDENT */
164 
165 /*! @brief Access to FTFx Registers */
166 static volatile uint32_t *const kFCCOBx = (volatile uint32_t *)(uint32_t)&FTFx_FCCOB3_REG;
167 
168 #if defined(FSL_FEATURE_FLASH_HAS_FLEX_NVM) && FSL_FEATURE_FLASH_HAS_FLEX_NVM
169 /*! @brief Table of eeprom sizes. */
170 static const uint16_t kEepromDensities[16] = {
171     FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0000, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0001,
172     FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0010, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0011,
173     FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0100, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0101,
174     FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0110, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_0111,
175     FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1000, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1001,
176     FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1010, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1011,
177     FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1100, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1101,
178     FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1110, FSL_FEATURE_FLASH_FLEX_NVM_EEPROM_SIZE_FOR_EEESIZE_1111};
179 /*! @brief Table of dflash sizes. */
180 static const uint32_t kDflashDensities[16] = {
181     FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0000, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0001,
182     FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0010, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0011,
183     FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0100, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0101,
184     FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0110, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_0111,
185     FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1000, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1001,
186     FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1010, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1011,
187     FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1100, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1101,
188     FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1110, FSL_FEATURE_FLASH_FLEX_NVM_DFLASH_SIZE_FOR_DEPART_1111};
189 #endif /* FSL_FEATURE_FLASH_HAS_FLEX_NVM */
190 
191 /*******************************************************************************
192  * Code
193  ******************************************************************************/
194 
195 /*!
196  * @brief Initializes the global flash properties structure members.
197  */
FTFx_API_Init(ftfx_config_t * config)198 void FTFx_API_Init(ftfx_config_t *config)
199 {
200     if (config == NULL)
201     {
202         return;
203     }
204     config->runCmdFuncAddr.callFlashCommand = NULL;
205     config->flexramBlockBase                = FSL_FEATURE_FLASH_FLEX_RAM_START_ADDRESS;
206     config->flexramTotalSize                = FSL_FEATURE_FLASH_FLEX_RAM_SIZE;
207 
208     /* copy required flash command to RAM */
209 #if FTFx_DRIVER_IS_FLASH_RESIDENT
210     config->runCmdFuncAddr.commadAddr = (uint32_t)s_ftfxRunCommand;
211     ftfx_copy_run_command_to_ram((uint32_t *)config->runCmdFuncAddr.commadAddr);
212 #endif /* FTFx_DRIVER_IS_FLASH_RESIDENT */
213 
214     ftfx_init_ifr(config);
215 }
216 
217 #if defined(FSL_FEATURE_FLASH_HAS_FLEX_NVM) && FSL_FEATURE_FLASH_HAS_FLEX_NVM
218 /*!
219  * @brief Updates FlexNVM memory partition status according to data flash 0 IFR.
220  */
FTFx_API_UpdateFlexnvmPartitionStatus(ftfx_config_t * config)221 status_t FTFx_API_UpdateFlexnvmPartitionStatus(ftfx_config_t *config)
222 {
223     struct _dflash_ifr_field_config
224     {
225         uint32_t reserved0;
226         uint8_t FlexNVMPartitionCode;
227         uint8_t EEPROMDataSetSize;
228         uint16_t reserved1;
229     } dataIFRReadOut;
230     uint32_t flexnvmInfoIfrAddr;
231     status_t returnCode;
232 
233     if (config == NULL)
234     {
235         return kStatus_FTFx_InvalidArgument;
236     }
237 
238     flexnvmInfoIfrAddr =
239         config->ifrDesc.resRange.dflashIfrStart + config->ifrDesc.resRange.ifrMemSize - sizeof(dataIFRReadOut);
240 
241 #if defined(FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD) && FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD
242     /* Get FlexNVM memory partition info from data flash IFR */
243     returnCode = FTFx_CMD_ReadResource(config, flexnvmInfoIfrAddr, (uint8_t *)&dataIFRReadOut, sizeof(dataIFRReadOut),
244                                        kFTFx_ResourceOptionFlashIfr);
245     if (returnCode != kStatus_FTFx_Success)
246     {
247         return kStatus_FTFx_PartitionStatusUpdateFailure;
248     }
249 #else
250 #error "Cannot get FlexNVM memory partition info"
251 #endif /* FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD */
252 
253     /* Fill out partitioned EEPROM size */
254     dataIFRReadOut.EEPROMDataSetSize &= 0x0FU;
255     config->eepromTotalSize = kEepromDensities[dataIFRReadOut.EEPROMDataSetSize];
256 
257     /* Fill out partitioned DFlash size */
258     dataIFRReadOut.FlexNVMPartitionCode &= 0x0FU;
259     config->flashDesc.totalSize = kDflashDensities[dataIFRReadOut.FlexNVMPartitionCode];
260 
261     return kStatus_FTFx_Success;
262 }
263 #endif /* FSL_FEATURE_FLASH_HAS_FLEX_NVM */
264 
265 /*!
266  * @brief Erases the flash sectors encompassed by parameters passed into function.
267  */
FTFx_CMD_Erase(ftfx_config_t * config,uint32_t start,uint32_t lengthInBytes,uint32_t key)268 status_t FTFx_CMD_Erase(ftfx_config_t *config, uint32_t start, uint32_t lengthInBytes, uint32_t key)
269 {
270     uint32_t sectorSize;
271     uint32_t endAddress;      /* storing end address */
272     uint32_t numberOfSectors; /* number of sectors calculated by endAddress */
273     status_t returnCode;
274     uint32_t eraseStart;
275 
276     /* Check the supplied address range. */
277     returnCode = ftfx_check_mem_range(config, start, lengthInBytes, config->opsConfig.addrAligment.sectorCmd);
278     if (returnCode != kStatus_FTFx_Success)
279     {
280         return returnCode;
281     }
282 
283     /* Validate the user key */
284     returnCode = ftfx_check_user_key(key);
285     if (returnCode != kStatus_FTFx_Success)
286     {
287         return returnCode;
288     }
289 
290     eraseStart = config->opsConfig.convertedAddress;
291     sectorSize = config->flashDesc.sectorSize;
292 
293     /* Calculate Flash end address */
294     endAddress = eraseStart + lengthInBytes - 1U;
295 
296     /* re-calculate the endAddress and align it to the start of the next sector
297      * which will be used in the comparison below */
298     if (0U != (endAddress % sectorSize))
299     {
300         numberOfSectors = endAddress / sectorSize + 1U;
301         endAddress      = numberOfSectors * sectorSize - 1U;
302     }
303 
304     /* the start address will increment to the next sector address
305      * until it reaches the endAdddress */
306     while (eraseStart <= endAddress)
307     {
308         /* preparing passing parameter to erase a flash block */
309         kFCCOBx[0] = BYTE2WORD_1_3(FTFx_ERASE_SECTOR, eraseStart);
310 
311         /* calling flash command sequence function to execute the command */
312         returnCode = ftfx_command_sequence(config);
313 
314         /* checking the success of command execution */
315         if (kStatus_FTFx_Success != returnCode)
316         {
317             break;
318         }
319         else
320         {
321             /* Increment to the next sector */
322             eraseStart += sectorSize;
323         }
324     }
325 
326     return returnCode;
327 }
328 
329 /*!
330  * @brief erases one flash sector size based on the start address.
331  */
FTFx_CMD_EraseSectorNonBlocking(ftfx_config_t * config,uint32_t start,uint32_t key)332 status_t FTFx_CMD_EraseSectorNonBlocking(ftfx_config_t *config, uint32_t start, uint32_t key)
333 {
334     uint32_t eraseStart;
335     uint8_t aligmentInBytes;
336     status_t returnCode    = kStatus_FTFx_AddressError;
337     aligmentInBytes        = config->opsConfig.addrAligment.sectorCmd;
338     uint32_t lengthInBytes = config->flashDesc.sectorSize;
339 
340     returnCode = ftfx_check_mem_range(config, start, lengthInBytes, aligmentInBytes);
341     if (returnCode != kStatus_FTFx_Success)
342     {
343         return returnCode;
344     }
345     /* Validate the user key */
346     returnCode = ftfx_check_user_key(key);
347     if (returnCode != kStatus_FTFx_Success)
348     {
349         return returnCode;
350     }
351 
352     eraseStart = config->opsConfig.convertedAddress;
353 
354     /* preparing passing parameter to erase a flash block */
355     kFCCOBx[0] = BYTE2WORD_1_3(FTFx_ERASE_SECTOR, eraseStart);
356     /* calling flash command sequence function to execute the command */
357     ftfx_command_sequence_non_blocking(config);
358 
359     return returnCode;
360 }
361 
362 /*!
363  * @brief Erases entire flash
364  */
FTFx_CMD_EraseAll(ftfx_config_t * config,uint32_t key)365 status_t FTFx_CMD_EraseAll(ftfx_config_t *config, uint32_t key)
366 {
367     status_t returnCode;
368 
369     if (config == NULL)
370     {
371         return kStatus_FTFx_InvalidArgument;
372     }
373 
374     /* preparing passing parameter to erase all flash blocks */
375     kFCCOBx[0] = BYTE2WORD_1_3(FTFx_ERASE_ALL_BLOCK, 0xFFFFFFU);
376 
377     /* Validate the user key */
378     returnCode = ftfx_check_user_key(key);
379     if (kStatus_FTFx_Success != returnCode)
380     {
381         return returnCode;
382     }
383 
384     /* calling flash command sequence function to execute the command */
385     returnCode = ftfx_command_sequence(config);
386 
387 #if defined(FSL_FEATURE_FLASH_HAS_FLEX_NVM) && FSL_FEATURE_FLASH_HAS_FLEX_NVM
388     /* Data flash IFR will be erased by erase all command, so we need to
389      *  update FlexNVM memory partition status synchronously */
390     if (returnCode == kStatus_FTFx_Success)
391     {
392         if (config->ifrDesc.resRange.dflashIfrStart != config->ifrDesc.resRange.pflashIfrStart)
393         {
394             returnCode = FTFx_API_UpdateFlexnvmPartitionStatus(config);
395         }
396     }
397 #endif /* FSL_FEATURE_FLASH_HAS_FLEX_NVM */
398 
399     return returnCode;
400 }
401 
402 #if defined(FSL_FEATURE_FLASH_HAS_ERASE_ALL_BLOCKS_UNSECURE_CMD) && FSL_FEATURE_FLASH_HAS_ERASE_ALL_BLOCKS_UNSECURE_CMD
403 /*!
404  * @brief Erases the entire flash, including protected sectors.
405  */
FTFx_CMD_EraseAllUnsecure(ftfx_config_t * config,uint32_t key)406 status_t FTFx_CMD_EraseAllUnsecure(ftfx_config_t *config, uint32_t key)
407 {
408     status_t returnCode;
409 
410     if (config == NULL)
411     {
412         return kStatus_FTFx_InvalidArgument;
413     }
414 
415     /* Prepare passing parameter to erase all flash blocks (unsecure). */
416     kFCCOBx[0] = BYTE2WORD_1_3(FTFx_ERASE_ALL_BLOCK_UNSECURE, 0xFFFFFFU);
417 
418     /* Validate the user key */
419     returnCode = ftfx_check_user_key(key);
420     if (returnCode != kStatus_FTFx_Success)
421     {
422         return returnCode;
423     }
424 
425     /* calling flash command sequence function to execute the command */
426     returnCode = ftfx_command_sequence(config);
427 
428 #if defined(FSL_FEATURE_FLASH_HAS_FLEX_NVM) && FSL_FEATURE_FLASH_HAS_FLEX_NVM
429     /* Data flash IFR will be erased by erase all unsecure command, so we need to
430      *  update FlexNVM memory partition status synchronously */
431     if (returnCode == kStatus_FTFx_Success)
432     {
433         if (config->ifrDesc.resRange.dflashIfrStart != config->ifrDesc.resRange.pflashIfrStart)
434         {
435             returnCode = FTFx_API_UpdateFlexnvmPartitionStatus(config);
436         }
437     }
438 #endif /* FSL_FEATURE_FLASH_HAS_FLEX_NVM */
439 
440     return returnCode;
441 }
442 #endif /* FSL_FEATURE_FLASH_HAS_ERASE_ALL_BLOCKS_UNSECURE_CMD */
443 
444 /*!
445  * @brief Erases all program flash execute-only segments defined by the FXACC registers.
446  */
FTFx_CMD_EraseAllExecuteOnlySegments(ftfx_config_t * config,uint32_t key)447 status_t FTFx_CMD_EraseAllExecuteOnlySegments(ftfx_config_t *config, uint32_t key)
448 {
449     status_t returnCode;
450 
451     if (config == NULL)
452     {
453         return kStatus_FTFx_InvalidArgument;
454     }
455 
456     /* preparing passing parameter to erase all execute-only segments
457      * 1st element for the FCCOB register */
458     kFCCOBx[0] = BYTE2WORD_1_3(FTFx_ERASE_ALL_EXECUTE_ONLY_SEGMENT, 0xFFFFFFU);
459 
460     /* Validate the user key */
461     returnCode = ftfx_check_user_key(key);
462     if (returnCode != kStatus_FTFx_Success)
463     {
464         return returnCode;
465     }
466 
467     /* calling flash command sequence function to execute the command */
468     returnCode = ftfx_command_sequence(config);
469 
470     return returnCode;
471 }
472 
473 /*!
474  * @brief Programs flash with data at locations passed in through parameters.
475  */
FTFx_CMD_Program(ftfx_config_t * config,uint32_t start,const uint8_t * src,uint32_t lengthInBytes)476 status_t FTFx_CMD_Program(ftfx_config_t *config, uint32_t start, const uint8_t *src, uint32_t lengthInBytes)
477 {
478     status_t returnCode;
479     uint8_t blockWriteUnitSize = config->opsConfig.addrAligment.blockWriteUnitSize;
480     uint32_t programStart;
481     uint32_t remainingLength;
482     if (src == NULL)
483     {
484         return kStatus_FTFx_InvalidArgument;
485     }
486 
487     /* Check the supplied address range. */
488     returnCode = ftfx_check_mem_range(config, start, lengthInBytes, blockWriteUnitSize);
489     if (returnCode != kStatus_FTFx_Success)
490     {
491         return returnCode;
492     }
493 
494     programStart    = config->opsConfig.convertedAddress;
495     remainingLength = lengthInBytes;
496 
497     while (remainingLength > 0U)
498     {
499         /* preparing passing parameter to program the flash block */
500         kFCCOBx[1] = ftfx_read_word_from_byte_address((const uint8_t *)src);
501         src        = &src[4];
502 
503         if (4U == blockWriteUnitSize)
504         {
505             kFCCOBx[0] = BYTE2WORD_1_3(FTFx_PROGRAM_LONGWORD, programStart);
506         }
507         else if (8U == blockWriteUnitSize)
508         {
509             kFCCOBx[2] = ftfx_read_word_from_byte_address((const uint8_t *)src);
510             src        = &src[4];
511             kFCCOBx[0] = BYTE2WORD_1_3(FTFx_PROGRAM_PHRASE, programStart);
512         }
513         else
514         {
515             return kStatus_FTFx_InvalidArgument;
516         }
517 
518         /* calling flash command sequence function to execute the command */
519         returnCode = ftfx_command_sequence(config);
520 
521         /* checking for the success of command execution */
522         if (kStatus_FTFx_Success != returnCode)
523         {
524             break;
525         }
526         else
527         {
528             /* update programStart address for next iteration */
529             programStart += blockWriteUnitSize;
530 
531             /* update remainingLength for next iteration */
532             remainingLength -= blockWriteUnitSize;
533         }
534     }
535 
536     return returnCode;
537 }
538 
539 /*!
540  * @brief Programs Program Once Field through parameters.
541  */
FTFx_CMD_ProgramOnce(ftfx_config_t * config,uint32_t index,const uint8_t * src,uint32_t lengthInBytes)542 status_t FTFx_CMD_ProgramOnce(ftfx_config_t *config, uint32_t index, const uint8_t *src, uint32_t lengthInBytes)
543 {
544     status_t returnCode;
545 
546     if ((config == NULL) || (src == NULL))
547     {
548         return kStatus_FTFx_InvalidArgument;
549     }
550 
551     /* pass parameters to FTFx */
552     kFCCOBx[0] = BYTE2WORD_1_1_2(FTFx_PROGRAM_ONCE, index, 0xFFFFU);
553 
554     kFCCOBx[1] = ftfx_read_word_from_byte_address((const uint8_t *)src);
555 
556     /* Note: Have to separate the first index from the rest if it equals 0
557      * to avoid a pointless comparison of unsigned int to 0 compiler warning */
558     if (config->ifrDesc.feature.has8ByteIdxSupport != 0U)
559     {
560         if (config->ifrDesc.feature.has4ByteIdxSupport != 0U)
561         {
562             if (((index == config->ifrDesc.idxInfo.mix8byteIdxStart) ||
563                  ((index >= ((uint32_t)config->ifrDesc.idxInfo.mix8byteIdxStart + 1U)) &&
564                   (index <= config->ifrDesc.idxInfo.mix8byteIdxEnd))) &&
565                 (lengthInBytes == 8U))
566             {
567                 kFCCOBx[2] = ftfx_read_word_from_byte_address(&src[4]);
568             }
569         }
570         else
571         {
572             kFCCOBx[2] = ftfx_read_word_from_byte_address(&src[4]);
573         }
574     }
575 
576     /* calling flash command sequence function to execute the command */
577     returnCode = ftfx_command_sequence(config);
578 
579     return returnCode;
580 }
581 
582 #if defined(FSL_FEATURE_FLASH_HAS_PROGRAM_SECTION_CMD) && FSL_FEATURE_FLASH_HAS_PROGRAM_SECTION_CMD
583 /*!
584  * @brief Programs flash with data at locations passed in through parameters via the Program Section command.
585  */
FTFx_CMD_ProgramSection(ftfx_config_t * config,uint32_t start,const uint8_t * src,uint32_t lengthInBytes)586 status_t FTFx_CMD_ProgramSection(ftfx_config_t *config, uint32_t start, const uint8_t *src, uint32_t lengthInBytes)
587 {
588     status_t returnCode;
589     uint32_t sectorSize;
590     uint32_t programaddress;
591     uint8_t aligmentInBytes   = config->opsConfig.addrAligment.sectionCmd;
592     const uint8_t *srcaddress = src;
593 #if defined(FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD) && FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD
594     bool needSwitchFlexRamMode = false;
595 #endif /* FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD */
596 
597     if (srcaddress == NULL)
598     {
599         return kStatus_FTFx_InvalidArgument;
600     }
601 
602     /* Check the supplied address range. */
603     returnCode = ftfx_check_mem_range(config, start, lengthInBytes, aligmentInBytes);
604     if (returnCode != kStatus_FTFx_Success)
605     {
606         return returnCode;
607     }
608 
609     programaddress = config->opsConfig.convertedAddress;
610     sectorSize     = config->flashDesc.sectorSize;
611 
612 #if defined(FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD) && FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD
613     /* Switch function of FlexRAM if needed */
614     if ((FTFx->FCNFG & FTFx_FCNFG_RAMRDY_MASK) == 0U)
615     {
616         needSwitchFlexRamMode = true;
617 
618         returnCode = FTFx_CMD_SetFlexramFunction(config, kFTFx_FlexramFuncOptAvailableAsRam);
619         if (returnCode != kStatus_FTFx_Success)
620         {
621             return returnCode;
622         }
623     }
624 #endif /* FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD */
625 
626     while (lengthInBytes > 0U)
627     {
628         /* Make sure the write operation doesn't span two sectors */
629         uint32_t endAddressOfCurrentSector = ALIGN_UP(programaddress, sectorSize);
630         uint32_t lengthTobeProgrammedOfCurrentSector;
631         uint32_t currentOffset = 0U;
632 
633         if (endAddressOfCurrentSector == programaddress)
634         {
635             endAddressOfCurrentSector += sectorSize;
636         }
637 
638         if ((lengthInBytes + programaddress) > endAddressOfCurrentSector)
639         {
640             lengthTobeProgrammedOfCurrentSector = endAddressOfCurrentSector - programaddress;
641         }
642         else
643         {
644             lengthTobeProgrammedOfCurrentSector = lengthInBytes;
645         }
646 
647         /* Program Current Sector */
648         while (lengthTobeProgrammedOfCurrentSector > 0U)
649         {
650             /* Make sure the program size doesn't exceeds Acceleration RAM size */
651             uint32_t programSizeOfCurrentPass;
652             uint32_t numberOfPhases;
653 
654             if (lengthTobeProgrammedOfCurrentSector > (uint32_t)kFLASH_AccelerationRamSize)
655             {
656                 programSizeOfCurrentPass = (uint32_t)kFLASH_AccelerationRamSize;
657             }
658             else
659             {
660                 programSizeOfCurrentPass = lengthTobeProgrammedOfCurrentSector;
661             }
662 
663             /* Copy data to FlexRAM */
664             (void)memcpy((uint8_t *)config->flexramBlockBase, &srcaddress[currentOffset], programSizeOfCurrentPass);
665             /* Set programaddress address of the data to be programmed */
666             kFCCOBx[0] = BYTE2WORD_1_3(FTFx_PROGRAM_SECTION, programaddress + currentOffset);
667             /* Set program size in terms of FEATURE_FLASH_SECTION_CMD_ADDRESS_ALIGMENT */
668             numberOfPhases = programSizeOfCurrentPass / aligmentInBytes;
669 
670             kFCCOBx[1] = BYTE2WORD_2_2(numberOfPhases, 0xFFFFU);
671 
672             /* Peform command sequence */
673             returnCode = ftfx_command_sequence(config);
674 
675             if (returnCode != kStatus_FTFx_Success)
676             {
677                 return returnCode;
678             }
679 
680             lengthTobeProgrammedOfCurrentSector -= programSizeOfCurrentPass;
681             currentOffset += programSizeOfCurrentPass;
682         }
683 
684         srcaddress = &srcaddress[currentOffset];
685         programaddress += currentOffset;
686         lengthInBytes -= currentOffset;
687     }
688 
689 #if defined(FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD) && FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD
690     /* Restore function of FlexRAM if needed. */
691     if (needSwitchFlexRamMode)
692     {
693         returnCode = FTFx_CMD_SetFlexramFunction(config, kFTFx_FlexramFuncOptAvailableForEeprom);
694         if (returnCode != kStatus_FTFx_Success)
695         {
696             return returnCode;
697         }
698     }
699 #endif /* FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD */
700 
701     return returnCode;
702 }
703 #endif /* FSL_FEATURE_FLASH_HAS_PROGRAM_SECTION_CMD */
704 
705 #if defined(FSL_FEATURE_FLASH_HAS_PROGRAM_PARTITION_CMD) && FSL_FEATURE_FLASH_HAS_PROGRAM_PARTITION_CMD
706 /*!
707  * @brief Prepares the FlexNVM block for use as data flash, EEPROM backup, or a combination of both and initializes the
708  * FlexRAM.
709  */
FTFx_CMD_ProgramPartition(ftfx_config_t * config,ftfx_partition_flexram_load_opt_t option,uint32_t eepromDataSizeCode,uint32_t flexnvmPartitionCode)710 status_t FTFx_CMD_ProgramPartition(ftfx_config_t *config,
711                                    ftfx_partition_flexram_load_opt_t option,
712                                    uint32_t eepromDataSizeCode,
713                                    uint32_t flexnvmPartitionCode)
714 {
715     status_t returnCode;
716 
717     if (config == NULL)
718     {
719         return kStatus_FTFx_InvalidArgument;
720     }
721 
722     /* eepromDataSizeCode[7:6], flexnvmPartitionCode[7:4] should be all 1'b0
723      *  or it will cause access error. */
724     /* eepromDataSizeCode bit with 0x3FU;  */
725     /* flexnvmPartitionCode bit with 0x0FU; */
726 
727     /* preparing passing parameter to program the flash block */
728     kFCCOBx[0] = BYTE2WORD_1_2_1(FTFx_PROGRAM_PARTITION, 0xFFFFU, option);
729     kFCCOBx[1] = BYTE2WORD_1_1_2(eepromDataSizeCode, flexnvmPartitionCode, 0xFFFFU);
730 
731     /* calling flash command sequence function to execute the command */
732     returnCode = ftfx_command_sequence(config);
733 
734 #if defined(FSL_FEATURE_FLASH_HAS_FLEX_NVM) && FSL_FEATURE_FLASH_HAS_FLEX_NVM
735     /* Data flash IFR will be updated by program partition command during reset sequence,
736      * so we just set reserved values for partitioned FlexNVM size here */
737     config->eepromTotalSize     = 0xFFFFU;
738     config->flashDesc.totalSize = 0xFFFFFFFFU;
739 #endif /* FSL_FEATURE_FLASH_HAS_FLEX_NVM */
740 
741     return (returnCode);
742 }
743 #endif /* FSL_FEATURE_FLASH_HAS_PROGRAM_PARTITION_CMD */
744 
745 /*!
746  * @brief Reads the Program Once Field through parameters.
747  */
FTFx_CMD_ReadOnce(ftfx_config_t * config,uint32_t index,uint8_t * dst,uint32_t lengthInBytes)748 status_t FTFx_CMD_ReadOnce(ftfx_config_t *config, uint32_t index, uint8_t *dst, uint32_t lengthInBytes)
749 {
750     status_t returnCode;
751 
752     if ((config == NULL) || (dst == NULL))
753     {
754         return kStatus_FTFx_InvalidArgument;
755     }
756 
757     /* pass parameters to FTFx */
758     kFCCOBx[0] = BYTE2WORD_1_1_2(FTFx_READ_ONCE, index, 0xFFFFU);
759 
760     /* calling flash command sequence function to execute the command */
761     returnCode = ftfx_command_sequence(config);
762 
763     if (returnCode == kStatus_FTFx_Success)
764     {
765         ftfx_write_word_to_byte_address(dst, kFCCOBx[1]);
766         /* Note: Have to separate the first index from the rest if it equals 0
767          *       to avoid a pointless comparison of unsigned int to 0 compiler warning */
768         if (config->ifrDesc.feature.has8ByteIdxSupport != 0U)
769         {
770             if (config->ifrDesc.feature.has4ByteIdxSupport != 0U)
771             {
772                 if (((index == config->ifrDesc.idxInfo.mix8byteIdxStart) ||
773                      ((index >= ((uint32_t)config->ifrDesc.idxInfo.mix8byteIdxStart + 1U)) &&
774                       (index <= config->ifrDesc.idxInfo.mix8byteIdxEnd))) &&
775                     (lengthInBytes == 8U))
776                 {
777                     ftfx_write_word_to_byte_address(&dst[4], kFCCOBx[2]);
778                 }
779             }
780             else
781             {
782                 ftfx_write_word_to_byte_address(&dst[4], kFCCOBx[2]);
783             }
784         }
785     }
786 
787     return returnCode;
788 }
789 
790 #if defined(FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD) && FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD
791 /*!
792  * @brief Reads the resource with data at locations passed in through parameters.
793  *
794  * this function can read  date from  program flash IFR, data flash IFR space,
795  * and the Version ID field.
796  */
FTFx_CMD_ReadResource(ftfx_config_t * config,uint32_t start,uint8_t * dst,uint32_t lengthInBytes,ftfx_read_resource_opt_t option)797 status_t FTFx_CMD_ReadResource(
798     ftfx_config_t *config, uint32_t start, uint8_t *dst, uint32_t lengthInBytes, ftfx_read_resource_opt_t option)
799 {
800     status_t returnCode;
801     uint32_t readstart;
802     uint8_t *destaddress;
803     uint32_t readlengthBytes;
804     readstart       = start;
805     destaddress     = dst;
806     readlengthBytes = lengthInBytes;
807     if ((config == NULL) || (dst == NULL))
808     {
809         return kStatus_FTFx_InvalidArgument;
810     }
811 
812     uint8_t aligmentInBytes = config->opsConfig.addrAligment.resourceCmd;
813 
814     /* Check the supplied address range. */
815     returnCode = ftfx_check_resource_range(config, readstart, readlengthBytes, aligmentInBytes, option);
816     if (returnCode != kStatus_FTFx_Success)
817     {
818         return returnCode;
819     }
820 
821     while (readlengthBytes > 0U)
822     {
823         /* preparing passing parameter */
824         kFCCOBx[0] = BYTE2WORD_1_3(FTFx_READ_RESOURCE, readstart);
825         if (aligmentInBytes == 4U)
826         {
827             kFCCOBx[2] = BYTE2WORD_1_3(option, 0xFFFFFFU);
828         }
829         else if (aligmentInBytes == 8U)
830         {
831             kFCCOBx[1] = BYTE2WORD_1_3(option, 0xFFFFFFU);
832         }
833         else
834         {
835             return kStatus_FTFx_InvalidArgument;
836         }
837 
838         /* calling flash command sequence function to execute the command */
839         returnCode = ftfx_command_sequence(config);
840 
841         if (kStatus_FTFx_Success != returnCode)
842         {
843             break;
844         }
845 
846         /* fetch data */
847         ftfx_write_word_to_byte_address(destaddress, kFCCOBx[1]);
848         destaddress = &destaddress[4];
849         if (aligmentInBytes == 8U)
850         {
851             ftfx_write_word_to_byte_address(destaddress, kFCCOBx[2]);
852             destaddress = &destaddress[4];
853         }
854         /* update readstart address for next iteration */
855         readstart += aligmentInBytes;
856         /* update readlengthBytes for next iteration */
857         readlengthBytes -= aligmentInBytes;
858     }
859 
860     return (returnCode);
861 }
862 #endif /* FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD */
863 
864 /*!
865  * @brief Verifies an erasure of the desired flash area at a specified margin level.
866  *
867  * This function checks the appropriate number of flash sectors based on
868  * the desired start address and length to check whether the flash is erased
869  * to the specified read margin level.
870  */
FTFx_CMD_VerifyErase(ftfx_config_t * config,uint32_t start,uint32_t lengthInBytes,ftfx_margin_value_t margin)871 status_t FTFx_CMD_VerifyErase(ftfx_config_t *config, uint32_t start, uint32_t lengthInBytes, ftfx_margin_value_t margin)
872 {
873     /* Check arguments. */
874     uint32_t blockSize;
875     uint32_t nextBlockStartAddress;
876     uint32_t remainingBytes;
877     uint8_t aligmentInBytes = config->opsConfig.addrAligment.sectionCmd;
878     status_t returnCode;
879     uint32_t erasestart;
880 
881     /* Validates the range and alignment of the given address range.*/
882     returnCode = ftfx_check_mem_range(config, start, lengthInBytes, aligmentInBytes);
883     if (kStatus_FTFx_Success != returnCode)
884     {
885         return returnCode;
886     }
887 
888     erasestart = config->opsConfig.convertedAddress;
889     blockSize  = config->flashDesc.totalSize / config->flashDesc.blockCount;
890 
891     /* Calculate the next block start address */
892     nextBlockStartAddress = ALIGN_UP(erasestart, blockSize);
893 
894     if (nextBlockStartAddress == erasestart)
895     {
896         nextBlockStartAddress += blockSize;
897     }
898 
899     remainingBytes = lengthInBytes;
900 
901     while (0U != remainingBytes)
902     {
903         uint32_t numberOfPhrases;
904 
905         uint32_t verifyLength = nextBlockStartAddress - erasestart;
906         /* Calculate the size to be verified, this flash does not support erase and program across block. */
907         if (verifyLength > remainingBytes)
908         {
909             verifyLength = remainingBytes;
910         }
911 
912         /* Calculate the number of phrases to be verified */
913         numberOfPhrases = verifyLength / aligmentInBytes;
914 
915         /* Fill in verify section command parameters. */
916         kFCCOBx[0] = BYTE2WORD_1_3(FTFx_VERIFY_SECTION, erasestart);
917         kFCCOBx[1] = BYTE2WORD_2_1_1(numberOfPhrases, margin, 0xFFU);
918 
919         /* calling flash command sequence function to execute the command */
920         returnCode = ftfx_command_sequence(config);
921         if (kStatus_FTFx_Success != returnCode)
922         {
923             return returnCode;
924         }
925 
926         remainingBytes -= verifyLength;
927         erasestart += verifyLength;
928         nextBlockStartAddress += blockSize;
929     }
930 
931     return kStatus_FTFx_Success;
932 }
933 
934 /*!
935  * @brief Verifies erasure of the entire flash at a specified margin level.
936  */
FTFx_CMD_VerifyEraseAll(ftfx_config_t * config,ftfx_margin_value_t margin)937 status_t FTFx_CMD_VerifyEraseAll(ftfx_config_t *config, ftfx_margin_value_t margin)
938 {
939     if (config == NULL)
940     {
941         return kStatus_FTFx_InvalidArgument;
942     }
943 
944     /* preparing passing parameter to verify all block command */
945     kFCCOBx[0] = BYTE2WORD_1_1_2(FTFx_VERIFY_ALL_BLOCK, margin, 0xFFFFU);
946 
947     /* calling flash command sequence function to execute the command */
948     return ftfx_command_sequence(config);
949 }
950 
951 /*!
952  * @brief Verifies whether the program flash execute-only segments have been erased to
953  *  the specified read margin level.
954  */
FTFx_CMD_VerifyEraseAllExecuteOnlySegments(ftfx_config_t * config,ftfx_margin_value_t margin)955 status_t FTFx_CMD_VerifyEraseAllExecuteOnlySegments(ftfx_config_t *config, ftfx_margin_value_t margin)
956 {
957     if (config == NULL)
958     {
959         return kStatus_FTFx_InvalidArgument;
960     }
961 
962     /* preparing passing parameter to verify erase all execute-only segments command */
963     kFCCOBx[0] = BYTE2WORD_1_1_2(FTFx_VERIFY_ALL_EXECUTE_ONLY_SEGMENT, margin, 0xFFFFU);
964 
965     /* calling flash command sequence function to execute the command */
966     return ftfx_command_sequence(config);
967 }
968 
969 /*!
970  * @brief Verifies programming of the desired flash area at a specified margin level.
971  *
972  * This function verifies the data programed in the flash memory using the
973  * Flash Program Check Command and compares it to the expected data for a given
974  * flash area as determined by the start address and length.
975  */
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)976 status_t FTFx_CMD_VerifyProgram(ftfx_config_t *config,
977                                 uint32_t start,
978                                 uint32_t lengthInBytes,
979                                 const uint8_t *expectedData,
980                                 ftfx_margin_value_t margin,
981                                 uint32_t *failedAddress,
982                                 uint32_t *failedData)
983 {
984     status_t returnCode;
985     uint8_t aligmentInBytes = config->opsConfig.addrAligment.checkCmd;
986     uint32_t programstart;
987     uint32_t programlength;
988     programlength = lengthInBytes;
989     if (expectedData == NULL)
990     {
991         return kStatus_FTFx_InvalidArgument;
992     }
993 
994     /* Validates the range and alignment of the given address range */
995     returnCode = ftfx_check_mem_range(config, start, lengthInBytes, aligmentInBytes);
996     if (kStatus_FTFx_Success != returnCode)
997     {
998         return returnCode;
999     }
1000 
1001     programstart = config->opsConfig.convertedAddress;
1002 
1003     while (0U != programlength)
1004     {
1005         /* preparing passing parameter to program check the flash block */
1006         kFCCOBx[0] = BYTE2WORD_1_3(FTFx_PROGRAM_CHECK, programstart);
1007         kFCCOBx[1] = BYTE2WORD_1_3(margin, 0xFFFFFFU);
1008         kFCCOBx[2] = ftfx_read_word_from_byte_address((const uint8_t *)expectedData);
1009 
1010         /* calling flash command sequence function to execute the command */
1011         returnCode = ftfx_command_sequence(config);
1012 
1013         /* checking for the success of command execution */
1014         if (kStatus_FTFx_Success != returnCode)
1015         {
1016             if (failedAddress != NULL)
1017             {
1018                 *failedAddress = programstart;
1019             }
1020             if (failedData != NULL)
1021             {
1022                 *failedData = 0U;
1023             }
1024             break;
1025         }
1026 
1027         programlength -= aligmentInBytes;
1028         expectedData = &expectedData[aligmentInBytes];
1029         programstart += aligmentInBytes;
1030     }
1031 
1032     return (returnCode);
1033 }
1034 
1035 /*!
1036  * @brief Allows users to bypass security with a backdoor key.
1037  */
FTFx_CMD_SecurityBypass(ftfx_config_t * config,const uint8_t * backdoorKey)1038 status_t FTFx_CMD_SecurityBypass(ftfx_config_t *config, const uint8_t *backdoorKey)
1039 {
1040     uint8_t registerValue; /* registerValue */
1041     status_t returnCode;   /* return code variable */
1042 
1043     if ((config == NULL) || (backdoorKey == NULL))
1044     {
1045         return kStatus_FTFx_InvalidArgument;
1046     }
1047 
1048     /* set the default return code as kStatus_Success */
1049     returnCode = kStatus_FTFx_Success;
1050 
1051     /* Get flash security register value */
1052     registerValue = FTFx->FSEC;
1053 
1054     /* Check to see if flash is in secure state (any state other than 0x2)
1055      * If not, then skip this since flash is not secure */
1056     if (0x02U != (registerValue & 0x03U))
1057     {
1058         /* preparing passing parameter to erase a flash block */
1059         kFCCOBx[0] = BYTE2WORD_1_3(FTFx_SECURITY_BY_PASS, 0xFFFFFFU);
1060         kFCCOBx[1] = BYTE2WORD_1_1_1_1(backdoorKey[0], backdoorKey[1], backdoorKey[2], backdoorKey[3]);
1061         kFCCOBx[2] = BYTE2WORD_1_1_1_1(backdoorKey[4], backdoorKey[5], backdoorKey[6], backdoorKey[7]);
1062 
1063         /* calling flash command sequence function to execute the command */
1064         returnCode = ftfx_command_sequence(config);
1065     }
1066 
1067     return (returnCode);
1068 }
1069 
1070 /*!
1071  * @brief Returns the security state via the pointer passed into the function.
1072  */
FTFx_REG_GetSecurityState(ftfx_config_t * config,ftfx_security_state_t * state)1073 status_t FTFx_REG_GetSecurityState(ftfx_config_t *config, ftfx_security_state_t *state)
1074 {
1075     /* store data read from flash register */
1076     uint8_t registerValue;
1077     if ((config == NULL) || (state == NULL))
1078     {
1079         return kStatus_FTFx_InvalidArgument;
1080     }
1081 
1082     /* Get flash security register value */
1083     registerValue = FTFx->FSEC;
1084 
1085     /* check the status of the flash security bits in the security register */
1086     if ((uint8_t)kFTFx_FsecRegCode_SEC_Unsecured == (registerValue & FTFx_FSEC_SEC_MASK))
1087     {
1088         /* Flash in unsecured state */
1089         *state = kFTFx_SecurityStateNotSecure;
1090     }
1091     else
1092     {
1093         /* Flash in secured state
1094          * check for backdoor key security enable bit */
1095         if ((uint8_t)kFTFx_FsecRegCode_KEYEN_Enabled == (registerValue & FTFx_FSEC_KEYEN_MASK))
1096         {
1097             /* Backdoor key security enabled */
1098             *state = kFTFx_SecurityStateBackdoorEnabled;
1099         }
1100         else
1101         {
1102             /* Backdoor key security disabled */
1103             *state = kFTFx_SecurityStateBackdoorDisabled;
1104         }
1105     }
1106 
1107     return kStatus_FTFx_Success;
1108 }
1109 
1110 #if defined(FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD) && FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD
1111 /*!
1112  * @brief Sets the FlexRAM function command.
1113  */
FTFx_CMD_SetFlexramFunction(ftfx_config_t * config,ftfx_flexram_func_opt_t option)1114 status_t FTFx_CMD_SetFlexramFunction(ftfx_config_t *config, ftfx_flexram_func_opt_t option)
1115 {
1116     status_t status;
1117     if (config == NULL)
1118     {
1119         return kStatus_FTFx_InvalidArgument;
1120     }
1121 
1122     status = ftfx_check_flexram_function_option(option);
1123     if (kStatus_FTFx_Success != status)
1124     {
1125         return status;
1126     }
1127 
1128     /* preparing passing parameter to verify all block command */
1129     kFCCOBx[0] = BYTE2WORD_1_1_2(FTFx_SET_FLEXRAM_FUNCTION, option, 0xFFFFU);
1130 
1131     /* calling flash command sequence function to execute the command */
1132     return ftfx_command_sequence(config);
1133 }
1134 #endif /* FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD */
1135 
1136 #if defined(FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD) && FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD
1137 /*!
1138  * @brief Configures the Swap function or checks the swap state of the Flash module.
1139  */
FTFx_CMD_SwapControl(ftfx_config_t * config,uint32_t address,ftfx_swap_control_opt_t option,ftfx_swap_state_config_t * returnInfo)1140 status_t FTFx_CMD_SwapControl(ftfx_config_t *config,
1141                               uint32_t address,
1142                               ftfx_swap_control_opt_t option,
1143                               ftfx_swap_state_config_t *returnInfo)
1144 {
1145     status_t returnCode;
1146 
1147     if ((config == NULL) || (returnInfo == NULL))
1148     {
1149         return kStatus_FTFx_InvalidArgument;
1150     }
1151 
1152     if ((address & ((uint32_t)FSL_FEATURE_FLASH_PFLASH_SWAP_CONTROL_CMD_ADDRESS_ALIGMENT - 1u)) != 0U)
1153     {
1154         return kStatus_FTFx_AlignmentError;
1155     }
1156 
1157     /* Make sure address provided is in the lower half of Program flash but not in the Flash Configuration Field */
1158     if ((address >= (config->flashDesc.totalSize / 2u)) ||
1159         ((address >= (uint32_t)kFTFx_PflashConfigAreaStart) && (address <= (uint32_t)kFTFx_PflashConfigAreaEnd)))
1160     {
1161         return kStatus_FTFx_SwapIndicatorAddressError;
1162     }
1163 
1164     /* Checking the option. */
1165     returnCode = ftfx_check_swap_control_option(option);
1166     if (returnCode != kStatus_FTFx_Success)
1167     {
1168         return returnCode;
1169     }
1170 
1171     kFCCOBx[0] = BYTE2WORD_1_3(FTFx_SWAP_CONTROL, address);
1172     kFCCOBx[1] = BYTE2WORD_1_3(option, 0xFFFFFFU);
1173 
1174     returnCode = ftfx_command_sequence(config);
1175 
1176     returnInfo->flashSwapState         = (ftfx_swap_state_t)FTFx_FCCOB5_REG;
1177     returnInfo->currentSwapBlockStatus = (ftfx_swap_block_status_t)FTFx_FCCOB6_REG;
1178     returnInfo->nextSwapBlockStatus    = (ftfx_swap_block_status_t)FTFx_FCCOB7_REG;
1179 
1180     return returnCode;
1181 }
1182 #endif /* FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD */
1183 
ftfx_init_ifr(ftfx_config_t * config)1184 static void ftfx_init_ifr(ftfx_config_t *config)
1185 {
1186 #if FSL_FEATURE_FLASH_IS_FTFA
1187     /* FTFA parts(eg. K80, KL80, L5K) support both 4-bytes and 8-bytes unit size */
1188     config->ifrDesc.feature.has4ByteIdxSupport = 1U;
1189     config->ifrDesc.feature.has8ByteIdxSupport = 1U;
1190     config->ifrDesc.idxInfo.mix8byteIdxStart   = 0x10U;
1191     config->ifrDesc.idxInfo.mix8byteIdxEnd     = 0x13U;
1192 #elif FSL_FEATURE_FLASH_IS_FTFE
1193     /* FTFE parts(eg. K65, KE18) only support 8-bytes unit size */
1194     config->ifrDesc.feature.has4ByteIdxSupport = 0U;
1195     config->ifrDesc.feature.has8ByteIdxSupport = 1U;
1196 #elif FSL_FEATURE_FLASH_IS_FTFL
1197     /* FTFL parts(eg. K20) only support 4-bytes unit size */
1198     config->ifrDesc.feature.has4ByteIdxSupport = 1U;
1199     config->ifrDesc.feature.has8ByteIdxSupport = 0U;
1200 #endif
1201 
1202     config->ifrDesc.resRange.pflashIfrStart = 0x0000U;
1203     config->ifrDesc.resRange.versionIdSize  = 0x08U;
1204 #if FSL_FEATURE_FLASH_IS_FTFE
1205     config->ifrDesc.resRange.versionIdStart = 0x08U;
1206     config->ifrDesc.resRange.ifrMemSize     = 0x0400U;
1207 #else /* FSL_FEATURE_FLASH_IS_FTFL == 1 or FSL_FEATURE_FLASH_IS_FTFA = =1 */
1208     config->ifrDesc.resRange.versionIdStart    = 0x00U;
1209     config->ifrDesc.resRange.ifrMemSize        = 0x0100U;
1210 #endif
1211 
1212 #if FSL_FEATURE_FLASH_HAS_FLEX_NVM
1213     config->ifrDesc.resRange.dflashIfrStart = 0x800000U;
1214 #endif
1215 
1216 #if FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD
1217 #if FSL_FEATURE_FLASH_IS_FTFE
1218     config->ifrDesc.resRange.pflashSwapIfrStart = 0x40000U;
1219 #else /* FSL_FEATURE_FLASH_IS_FTFL == 1 or FSL_FEATURE_FLASH_IS_FTFA == 1 */
1220     config->ifrDesc.resRange.pflashSwapIfrStart = config->flashDesc.totalSize / 4;
1221 #endif
1222 #endif /* FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD */
1223 }
1224 
1225 #if FTFx_DRIVER_IS_FLASH_RESIDENT
1226 /*!
1227  * @brief Copy PIC of flash_run_command() to RAM
1228  */
ftfx_copy_run_command_to_ram(uint32_t * ftfxRunCommand)1229 static void ftfx_copy_run_command_to_ram(uint32_t *ftfxRunCommand)
1230 {
1231     assert(sizeof(s_ftfxRunCommandFunctionCode) <= ((uint32_t)kFTFx_RamFuncMaxSizeInWords * 4U));
1232 
1233     /* Since the value of ARM function pointer is always odd, but the real start address
1234      * of function memory should be even, that's why +1 operation exist. */
1235     (void)memcpy(ftfxRunCommand, s_ftfxRunCommandFunctionCode, sizeof(s_ftfxRunCommandFunctionCode));
1236 }
1237 #endif /* FTFx_DRIVER_IS_FLASH_RESIDENT */
1238 
1239 /*!
1240  * @brief FTFx Command Sequence
1241  *
1242  * This function is used to perform the command write sequence to the flash.
1243  *
1244  * @param driver Pointer to storage for the driver runtime state.
1245  * @return An error code or kStatus_FTFx_Success
1246  */
ftfx_command_sequence(ftfx_config_t * config)1247 static status_t ftfx_command_sequence(ftfx_config_t *config)
1248 {
1249     uint8_t registerValue;
1250 
1251 #if FTFx_DRIVER_IS_FLASH_RESIDENT
1252     /* clear RDCOLERR & ACCERR & FPVIOL flag in flash status register */
1253     FTFx->FSTAT = FTFx_FSTAT_RDCOLERR_MASK | FTFx_FSTAT_ACCERR_MASK | FTFx_FSTAT_FPVIOL_MASK;
1254 
1255     /* Since the value of ARM function pointer is always odd, but the real start address
1256      * of function memory should be even, that's why +1 operation exist. */
1257     config->runCmdFuncAddr.commadAddr += 1UL;
1258     callFtfxRunCommand_t callFtfxRunCommand = config->runCmdFuncAddr.callFlashCommand;
1259 
1260     /* We pass the ftfx_fstat address as a parameter to flash_run_comamnd() instead of using
1261      * pre-processed MICRO sentences or operating global variable in flash_run_comamnd()
1262      * to make sure that flash_run_command() will be compiled into position-independent code (PIC). */
1263     callFtfxRunCommand((FTFx_REG8_ACCESS_TYPE)(&FTFx->FSTAT));
1264     config->runCmdFuncAddr.commadAddr -= 1UL;
1265 #else
1266     /* clear RDCOLERR & ACCERR & FPVIOL flag in flash status register */
1267     FTFx->FSTAT = FTFx_FSTAT_RDCOLERR_MASK | FTFx_FSTAT_ACCERR_MASK | FTFx_FSTAT_FPVIOL_MASK;
1268 
1269     /* clear CCIF bit */
1270     FTFx->FSTAT = FTFx_FSTAT_CCIF_MASK;
1271 
1272     /* Check CCIF bit of the flash status register, wait till it is set.
1273      * IP team indicates that this loop will always complete. */
1274     while (!(FTFx->FSTAT & FTFx_FSTAT_CCIF_MASK))
1275     {
1276     }
1277 #endif /* FTFx_DRIVER_IS_FLASH_RESIDENT */
1278 
1279     /* Check error bits */
1280     /* Get flash status register value */
1281     registerValue = FTFx->FSTAT;
1282 
1283     /* checking access error */
1284     if (0U != (registerValue & FTFx_FSTAT_ACCERR_MASK))
1285     {
1286         return kStatus_FTFx_AccessError;
1287     }
1288     /* checking protection error */
1289     else if (0U != (registerValue & FTFx_FSTAT_FPVIOL_MASK))
1290     {
1291         return kStatus_FTFx_ProtectionViolation;
1292     }
1293     /* checking MGSTAT0 non-correctable error */
1294     else if (0U != (registerValue & FTFx_FSTAT_MGSTAT0_MASK))
1295     {
1296         return kStatus_FTFx_CommandFailure;
1297     }
1298     else
1299     {
1300         return kStatus_FTFx_Success;
1301     }
1302 }
1303 
ftfx_command_sequence_non_blocking(ftfx_config_t * config)1304 static void ftfx_command_sequence_non_blocking(ftfx_config_t *config)
1305 {
1306 #if FTFx_DRIVER_IS_FLASH_RESIDENT
1307     /* clear RDCOLERR & ACCERR & FPVIOL flag in flash status register */
1308     FTFx->FSTAT = FTFx_FSTAT_RDCOLERR_MASK | FTFx_FSTAT_ACCERR_MASK | FTFx_FSTAT_FPVIOL_MASK;
1309 
1310     /* Since the value of ARM function pointer is always odd, but the real start address
1311      * of function memory should be even, that's why +1 operation exist. */
1312     config->runCmdFuncAddr.commadAddr += 1UL;
1313     callFtfxRunCommand_t callFtfxRunCommand = config->runCmdFuncAddr.callFlashCommand;
1314 
1315     /* We pass the ftfx_fstat address as a parameter to flash_run_comamnd() instead of using
1316      * pre-processed MICRO sentences or operating global variable in flash_run_comamnd()
1317      * to make sure that flash_run_command() will be compiled into position-independent code (PIC). */
1318     callFtfxRunCommand((FTFx_REG8_ACCESS_TYPE)(&FTFx->FSTAT));
1319     config->runCmdFuncAddr.commadAddr -= 1UL;
1320 #else
1321     /* clear RDCOLERR & ACCERR & FPVIOL flag in flash status register */
1322     FTFx->FSTAT = FTFx_FSTAT_RDCOLERR_MASK | FTFx_FSTAT_ACCERR_MASK | FTFx_FSTAT_FPVIOL_MASK;
1323 
1324     /* clear CCIF bit */
1325     FTFx->FSTAT = FTFx_FSTAT_CCIF_MASK;
1326 #endif
1327 }
1328 
1329 /*! @brief Validates the range and alignment of the given address range.*/
ftfx_check_mem_range(ftfx_config_t * config,uint32_t startAddress,uint32_t lengthInBytes,uint8_t alignmentBaseline)1330 static status_t ftfx_check_mem_range(ftfx_config_t *config,
1331                                      uint32_t startAddress,
1332                                      uint32_t lengthInBytes,
1333                                      uint8_t alignmentBaseline)
1334 {
1335     status_t status = kStatus_FTFx_AddressError;
1336 
1337     /* Verify the start and length are alignmentBaseline aligned. */
1338     if ((0U != (startAddress & (uint8_t)(alignmentBaseline - 1U))) ||
1339         (0U != (lengthInBytes & (uint8_t)(alignmentBaseline - 1U))))
1340     {
1341         return kStatus_FTFx_AlignmentError;
1342     }
1343 
1344     /* check for valid range of the target addresses */
1345     if ((startAddress >= config->flashDesc.blockBase) &&
1346         ((startAddress + lengthInBytes) <= (config->flashDesc.blockBase + config->flashDesc.totalSize)))
1347     {
1348         status = kStatus_FTFx_Success;
1349     }
1350 #if defined(FSL_FEATURE_FLASH_HAS_FLEX_NVM_ALIAS) && FSL_FEATURE_FLASH_HAS_FLEX_NVM_ALIAS
1351     else if ((startAddress >= config->flashDesc.aliasBlockBase) &&
1352              ((startAddress + lengthInBytes) <= (config->flashDesc.aliasBlockBase + config->flashDesc.totalSize)))
1353     {
1354         status = kStatus_FTFx_Success;
1355     }
1356     else
1357     {
1358         status = kStatus_FTFx_AddressError;
1359     }
1360 #endif
1361 
1362     return status;
1363 }
1364 
1365 /*! @brief Validates the given user key for flash erase APIs.*/
ftfx_check_user_key(uint32_t key)1366 static status_t ftfx_check_user_key(uint32_t key)
1367 {
1368     /* Validate the user key */
1369     if (key != (uint32_t)kFTFx_ApiEraseKey)
1370     {
1371         return kStatus_FTFx_EraseKeyError;
1372     }
1373 
1374     return kStatus_FTFx_Success;
1375 }
1376 
1377 /*! @brief Reads word from byte address.*/
ftfx_read_word_from_byte_address(const uint8_t * src)1378 static uint32_t ftfx_read_word_from_byte_address(const uint8_t *src)
1379 {
1380     uint32_t word          = 0U;
1381     const uint8_t *readsrc = src;
1382     /* If the source address is aligned with 4 bytes */
1383     if (0U == ((uint32_t)readsrc % 4U))
1384     {
1385         word = *(const uint32_t *)(uint32_t)readsrc;
1386     }
1387     /* Read 4 bytes from a non-4-byte aligned address, 1 byte one time */
1388     else
1389     {
1390         for (uint32_t i = 0U; i < 4U; i++)
1391         {
1392             word |= (uint32_t)(*readsrc) << (i * 8U);
1393             readsrc++;
1394         }
1395     }
1396 
1397     return word;
1398 }
1399 
1400 /*! @brief Writes word to byte address.*/
ftfx_write_word_to_byte_address(uint8_t * dst,uint32_t word)1401 static void ftfx_write_word_to_byte_address(uint8_t *dst, uint32_t word)
1402 {
1403     uint8_t *writedst = dst;
1404     /* If the source address is aligned with 4 bytes */
1405     if (0U == ((uint32_t)writedst % 4U))
1406     {
1407         *(uint32_t *)(uint32_t)writedst = word;
1408     }
1409     else
1410     {
1411         /* Write 4 bytes into a non-4-byte aligned address memory, 1 byte one time */
1412         for (uint32_t i = 0U; i < 4U; i++)
1413         {
1414             *writedst = (uint8_t)((word >> (i * 8U)) & 0xFFU);
1415             writedst++;
1416         }
1417     }
1418 }
1419 
1420 #if defined(FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD) && FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD
1421 /*! @brief Validates the range of the given resource address.*/
ftfx_check_resource_range(ftfx_config_t * config,uint32_t start,uint32_t lengthInBytes,uint32_t alignmentBaseline,ftfx_read_resource_opt_t option)1422 static status_t ftfx_check_resource_range(ftfx_config_t *config,
1423                                           uint32_t start,
1424                                           uint32_t lengthInBytes,
1425                                           uint32_t alignmentBaseline,
1426                                           ftfx_read_resource_opt_t option)
1427 {
1428     status_t status;
1429     uint32_t maxReadbleAddress;
1430 
1431     if ((0U != (start & (alignmentBaseline - 1u))) || (0U != (lengthInBytes & (alignmentBaseline - 1u))))
1432     {
1433         return kStatus_FTFx_AlignmentError;
1434     }
1435 
1436     status = kStatus_FTFx_Success;
1437 
1438     maxReadbleAddress = start + lengthInBytes - 1u;
1439     /* read resource code from the version ID field */
1440     if (option == kFTFx_ResourceOptionVersionId)
1441     {
1442         if ((start != config->ifrDesc.resRange.versionIdStart) ||
1443             (lengthInBytes != config->ifrDesc.resRange.versionIdSize))
1444         {
1445             status = kStatus_FTFx_InvalidArgument;
1446         }
1447     }
1448     else if (option == kFTFx_ResourceOptionFlashIfr)
1449     {
1450         /* read resource code from the  program flash IFR space */
1451         if ((start >= config->ifrDesc.resRange.pflashIfrStart) &&
1452             (maxReadbleAddress < (config->ifrDesc.resRange.pflashIfrStart + config->ifrDesc.resRange.ifrMemSize)))
1453         {
1454         }
1455 #if defined(FSL_FEATURE_FLASH_HAS_FLEX_NVM) && FSL_FEATURE_FLASH_HAS_FLEX_NVM
1456         /* read resource code from the  date flash IFR space */
1457         else if ((start >= config->ifrDesc.resRange.dflashIfrStart) &&
1458                  (maxReadbleAddress < (config->ifrDesc.resRange.dflashIfrStart + config->ifrDesc.resRange.ifrMemSize)))
1459         {
1460         }
1461 #endif /* FSL_FEATURE_FLASH_HAS_FLEX_NVM */
1462 #if defined(FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD) && FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD
1463         /* read resource code from the  Program Flash Swap IFR space */
1464         else if ((start >= config->ifrDesc.resRange.pflashSwapIfrStart) &&
1465                  (maxReadbleAddress <
1466                   (config->ifrDesc.resRange.pflashSwapIfrStart + config->ifrDesc.resRange.ifrMemSize)))
1467         {
1468         }
1469 #endif /* FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD */
1470         else
1471         {
1472             status = kStatus_FTFx_InvalidArgument;
1473         }
1474     }
1475     else
1476     {
1477         status = kStatus_FTFx_InvalidArgument;
1478     }
1479 
1480     return status;
1481 }
1482 #endif /* FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD */
1483 
1484 #if defined(FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD) && FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD
1485 /*! @brief Validates the given flexram function option.*/
ftfx_check_flexram_function_option(ftfx_flexram_func_opt_t option)1486 static inline status_t ftfx_check_flexram_function_option(ftfx_flexram_func_opt_t option)
1487 {
1488     if ((option != kFTFx_FlexramFuncOptAvailableAsRam) && (option != kFTFx_FlexramFuncOptAvailableForEeprom))
1489     {
1490         return kStatus_FTFx_InvalidArgument;
1491     }
1492 
1493     return kStatus_FTFx_Success;
1494 }
1495 #endif /* FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD */
1496 
1497 #if defined(FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD) && FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD
1498 /*! @brief Validates the given swap control option.*/
ftfx_check_swap_control_option(ftfx_swap_control_opt_t option)1499 static status_t ftfx_check_swap_control_option(ftfx_swap_control_opt_t option)
1500 {
1501     if ((option == kFTFx_SwapControlOptionIntializeSystem) || (option == kFTFx_SwapControlOptionSetInUpdateState) ||
1502         (option == kFTFx_SwapControlOptionSetInCompleteState) || (option == kFTFx_SwapControlOptionReportStatus) ||
1503         (option == kFTFx_SwapControlOptionDisableSystem))
1504     {
1505         return kStatus_FTFx_Success;
1506     }
1507 
1508     return kStatus_FTFx_InvalidArgument;
1509 }
1510 #endif /* FSL_FEATURE_FLASH_HAS_SWAP_CONTROL_CMD */
1511