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 > config->flexramTotalSize)
655 {
656 programSizeOfCurrentPass = config->flexramTotalSize;
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