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_flexnvm.h"
11
12 #if FSL_FEATURE_FLASH_HAS_FLEX_NVM
13
14 /*******************************************************************************
15 * Definitions
16 ******************************************************************************/
17
18 /* Component ID definition, used by tools. */
19 #ifndef FSL_COMPONENT_ID
20 #define FSL_COMPONENT_ID "platform.drivers.flash"
21 #endif
22
23 /*******************************************************************************
24 * Prototypes
25 ******************************************************************************/
26
27 /*! @brief Convert address for Flexnvm dflash.*/
28 static status_t flexnvm_convert_start_address(flexnvm_config_t *config, uint32_t start);
29
30 /*******************************************************************************
31 * Variables
32 ******************************************************************************/
33
34 /*******************************************************************************
35 * Code
36 ******************************************************************************/
37
FLEXNVM_Init(flexnvm_config_t * config)38 status_t FLEXNVM_Init(flexnvm_config_t *config)
39 {
40 status_t returnCode;
41
42 if (config == NULL)
43 {
44 return kStatus_FTFx_InvalidArgument;
45 }
46
47 config->ftfxConfig.flashDesc.type = (uint8_t)kFTFx_MemTypeFlexnvm;
48 config->ftfxConfig.flashDesc.index = 0U;
49
50 /* Set Flexnvm memory operation parameters */
51 config->ftfxConfig.opsConfig.addrAligment.blockWriteUnitSize = FSL_FEATURE_FLASH_FLEX_NVM_BLOCK_WRITE_UNIT_SIZE;
52 config->ftfxConfig.opsConfig.addrAligment.sectorCmd = FSL_FEATURE_FLASH_FLEX_NVM_SECTOR_CMD_ADDRESS_ALIGMENT;
53 config->ftfxConfig.opsConfig.addrAligment.sectionCmd = FSL_FEATURE_FLASH_FLEX_NVM_SECTION_CMD_ADDRESS_ALIGMENT;
54 config->ftfxConfig.opsConfig.addrAligment.resourceCmd = FSL_FEATURE_FLASH_FLEX_NVM_RESOURCE_CMD_ADDRESS_ALIGMENT;
55 config->ftfxConfig.opsConfig.addrAligment.checkCmd = FSL_FEATURE_FLASH_FLEX_NVM_CHECK_CMD_ADDRESS_ALIGMENT;
56
57 /* Set Flexnvm memory properties */
58 config->ftfxConfig.flashDesc.blockBase = FSL_FEATURE_FLASH_FLEX_NVM_START_ADDRESS;
59 #if defined(FSL_FEATURE_FLASH_HAS_FLEX_NVM_ALIAS) && FSL_FEATURE_FLASH_HAS_FLEX_NVM_ALIAS
60 config->ftfxConfig.flashDesc.aliasBlockBase = FSL_FEATURE_FLASH_FLEX_NVM_ALIAS_START_ADDRESS;
61 #endif
62 config->ftfxConfig.flashDesc.sectorSize = FSL_FEATURE_FLASH_FLEX_NVM_BLOCK_SECTOR_SIZE;
63 config->ftfxConfig.flashDesc.blockCount = FSL_FEATURE_FLASH_FLEX_NVM_BLOCK_COUNT;
64
65 /* Init FTFx Kernel */
66 FTFx_API_Init(&config->ftfxConfig);
67
68 returnCode = FTFx_API_UpdateFlexnvmPartitionStatus(&config->ftfxConfig);
69 if (returnCode != kStatus_FTFx_Success)
70 {
71 return returnCode;
72 }
73
74 return kStatus_FTFx_Success;
75 }
76
77 /*!
78 * @brief Erases the Dflash sectors encompassed by parameters passed into function.
79 */
FLEXNVM_DflashErase(flexnvm_config_t * config,uint32_t start,uint32_t lengthInBytes,uint32_t key)80 status_t FLEXNVM_DflashErase(flexnvm_config_t *config, uint32_t start, uint32_t lengthInBytes, uint32_t key)
81 {
82 status_t returnCode;
83 returnCode = flexnvm_convert_start_address(config, start);
84 if (returnCode != kStatus_FTFx_Success)
85 {
86 return returnCode;
87 }
88
89 return FTFx_CMD_Erase(&config->ftfxConfig, start, lengthInBytes, key);
90 }
91
92 /*!
93 * @brief Erases entire flexnvm
94 */
FLEXNVM_EraseAll(flexnvm_config_t * config,uint32_t key)95 status_t FLEXNVM_EraseAll(flexnvm_config_t *config, uint32_t key)
96 {
97 return FTFx_CMD_EraseAll(&config->ftfxConfig, key);
98 }
99
100 #if defined(FSL_FEATURE_FLASH_HAS_ERASE_ALL_BLOCKS_UNSECURE_CMD) && FSL_FEATURE_FLASH_HAS_ERASE_ALL_BLOCKS_UNSECURE_CMD
101 /*!
102 * @brief Erases the entire flexnvm, including protected sectors.
103 */
FLEXNVM_EraseAllUnsecure(flexnvm_config_t * config,uint32_t key)104 status_t FLEXNVM_EraseAllUnsecure(flexnvm_config_t *config, uint32_t key)
105 {
106 return FTFx_CMD_EraseAllUnsecure(&config->ftfxConfig, key);
107 }
108 #endif /* FSL_FEATURE_FLASH_HAS_ERASE_ALL_BLOCKS_UNSECURE_CMD */
109
110 /*!
111 * @brief Programs flash with data at locations passed in through parameters.
112 */
FLEXNVM_DflashProgram(flexnvm_config_t * config,uint32_t start,uint8_t * src,uint32_t lengthInBytes)113 status_t FLEXNVM_DflashProgram(flexnvm_config_t *config, uint32_t start, uint8_t *src, uint32_t lengthInBytes)
114 {
115 status_t returnCode;
116 returnCode = flexnvm_convert_start_address(config, start);
117 if (returnCode != kStatus_FTFx_Success)
118 {
119 return returnCode;
120 }
121
122 return FTFx_CMD_Program(&config->ftfxConfig, start, src, lengthInBytes);
123 }
124
125 #if defined(FSL_FEATURE_FLASH_HAS_PROGRAM_SECTION_CMD) && FSL_FEATURE_FLASH_HAS_PROGRAM_SECTION_CMD
126 /*!
127 * @brief Programs flash with data at locations passed in through parameters via the Program Section command.
128 */
FLEXNVM_DflashProgramSection(flexnvm_config_t * config,uint32_t start,uint8_t * src,uint32_t lengthInBytes)129 status_t FLEXNVM_DflashProgramSection(flexnvm_config_t *config, uint32_t start, uint8_t *src, uint32_t lengthInBytes)
130 {
131 status_t returnCode;
132 /* Convert address for Flexnvm dflash */
133 returnCode = flexnvm_convert_start_address(config, start);
134 if (returnCode != kStatus_FTFx_Success)
135 {
136 return returnCode;
137 }
138
139 return FTFx_CMD_ProgramSection(&config->ftfxConfig, start, src, lengthInBytes);
140 }
141 #endif /* FSL_FEATURE_FLASH_HAS_PROGRAM_SECTION_CMD */
142
143 /*!
144 * @brief Prepares the FlexNVM block for use as data flash, EEPROM backup, or a combination
145 * of both and initializes the FlexRAM.
146 */
FLEXNVM_ProgramPartition(flexnvm_config_t * config,ftfx_partition_flexram_load_opt_t option,uint32_t eepromDataSizeCode,uint32_t flexnvmPartitionCode)147 status_t FLEXNVM_ProgramPartition(flexnvm_config_t *config,
148 ftfx_partition_flexram_load_opt_t option,
149 uint32_t eepromDataSizeCode,
150 uint32_t flexnvmPartitionCode)
151 {
152 return FTFx_CMD_ProgramPartition(&config->ftfxConfig, option, eepromDataSizeCode, flexnvmPartitionCode);
153 }
154
155 #if defined(FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD) && FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD
156 /*!
157 * @brief Reads the resource with data at locations passed in through parameters.
158 */
FLEXNVM_ReadResource(flexnvm_config_t * config,uint32_t start,uint8_t * dst,uint32_t lengthInBytes,ftfx_read_resource_opt_t option)159 status_t FLEXNVM_ReadResource(
160 flexnvm_config_t *config, uint32_t start, uint8_t *dst, uint32_t lengthInBytes, ftfx_read_resource_opt_t option)
161 {
162 return FTFx_CMD_ReadResource(&config->ftfxConfig, start, dst, lengthInBytes, option);
163 }
164 #endif /* FSL_FEATURE_FLASH_HAS_READ_RESOURCE_CMD */
165
166 /*!
167 * @brief Verifies an erasure of the desired flash area at a specified margin level.
168 */
FLEXNVM_DflashVerifyErase(flexnvm_config_t * config,uint32_t start,uint32_t lengthInBytes,ftfx_margin_value_t margin)169 status_t FLEXNVM_DflashVerifyErase(flexnvm_config_t *config,
170 uint32_t start,
171 uint32_t lengthInBytes,
172 ftfx_margin_value_t margin)
173 {
174 status_t returnCode;
175 returnCode = flexnvm_convert_start_address(config, start);
176 if (returnCode != kStatus_FTFx_Success)
177 {
178 return returnCode;
179 }
180
181 return FTFx_CMD_VerifyErase(&config->ftfxConfig, start, lengthInBytes, margin);
182 }
183
184 /*!
185 * @brief Verifies erasure of the entire flash at a specified margin level.
186 */
FLEXNVM_VerifyEraseAll(flexnvm_config_t * config,ftfx_margin_value_t margin)187 status_t FLEXNVM_VerifyEraseAll(flexnvm_config_t *config, ftfx_margin_value_t margin)
188 {
189 return FTFx_CMD_VerifyEraseAll(&config->ftfxConfig, margin);
190 }
191
192 /*!
193 * @brief Verifies programming of the desired flash area at a specified margin level.
194 */
FLEXNVM_DflashVerifyProgram(flexnvm_config_t * config,uint32_t start,uint32_t lengthInBytes,const uint8_t * expectedData,ftfx_margin_value_t margin,uint32_t * failedAddress,uint32_t * failedData)195 status_t FLEXNVM_DflashVerifyProgram(flexnvm_config_t *config,
196 uint32_t start,
197 uint32_t lengthInBytes,
198 const uint8_t *expectedData,
199 ftfx_margin_value_t margin,
200 uint32_t *failedAddress,
201 uint32_t *failedData)
202 {
203 status_t returnCode;
204 returnCode = flexnvm_convert_start_address(config, start);
205 if (returnCode != kStatus_FTFx_Success)
206 {
207 return returnCode;
208 }
209
210 return FTFx_CMD_VerifyProgram(&config->ftfxConfig, start, lengthInBytes, expectedData, margin, failedAddress,
211 failedData);
212 }
213
214 /*!
215 * @brief Returns the security state via the pointer passed into the function.
216 */
FLEXNVM_GetSecurityState(flexnvm_config_t * config,ftfx_security_state_t * state)217 status_t FLEXNVM_GetSecurityState(flexnvm_config_t *config, ftfx_security_state_t *state)
218 {
219 return FTFx_REG_GetSecurityState(&config->ftfxConfig, state);
220 }
221
222 /*!
223 * @brief Allows users to bypass security with a backdoor key.
224 */
FLEXNVM_SecurityBypass(flexnvm_config_t * config,const uint8_t * backdoorKey)225 status_t FLEXNVM_SecurityBypass(flexnvm_config_t *config, const uint8_t *backdoorKey)
226 {
227 return FTFx_CMD_SecurityBypass(&config->ftfxConfig, backdoorKey);
228 }
229
230 #if defined(FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD) && FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD
231 /*!
232 * @brief Sets the FlexRAM function command.
233 */
FLEXNVM_SetFlexramFunction(flexnvm_config_t * config,ftfx_flexram_func_opt_t option)234 status_t FLEXNVM_SetFlexramFunction(flexnvm_config_t *config, ftfx_flexram_func_opt_t option)
235 {
236 return FTFx_CMD_SetFlexramFunction(&config->ftfxConfig, option);
237 }
238 #endif /* FSL_FEATURE_FLASH_HAS_SET_FLEXRAM_FUNCTION_CMD */
239
240 /*!
241 * @brief Programs the EEPROM with data at locations passed in through parameters.
242 */
FLEXNVM_EepromWrite(flexnvm_config_t * config,uint32_t start,uint8_t * src,uint32_t lengthInBytes)243 status_t FLEXNVM_EepromWrite(flexnvm_config_t *config, uint32_t start, uint8_t *src, uint32_t lengthInBytes)
244 {
245 status_t returnCode;
246 bool needSwitchFlexRamMode = false;
247
248 if (config == NULL)
249 {
250 return kStatus_FTFx_InvalidArgument;
251 }
252
253 /* Validates the range of the given address */
254 if ((start < config->ftfxConfig.flexramBlockBase) ||
255 ((start + lengthInBytes) > (config->ftfxConfig.flexramBlockBase + config->ftfxConfig.eepromTotalSize)))
256 {
257 return kStatus_FTFx_AddressError;
258 }
259
260 returnCode = kStatus_FTFx_Success;
261
262 /* Switch function of FlexRAM if needed */
263 if (0U == (FTFx->FCNFG & FTFx_FCNFG_EEERDY_MASK))
264 {
265 needSwitchFlexRamMode = true;
266
267 returnCode = FTFx_CMD_SetFlexramFunction(&config->ftfxConfig, kFTFx_FlexramFuncOptAvailableForEeprom);
268 if (returnCode != kStatus_FTFx_Success)
269 {
270 return kStatus_FTFx_SetFlexramAsEepromError;
271 }
272 }
273
274 /* Write data to FlexRAM when it is used as EEPROM emulator */
275 while (lengthInBytes > 0U)
276 {
277 if ((0U == (start & 0x3U)) && (0U == ((uint32_t)src & 0x3U)) && (lengthInBytes >= 4U))
278 {
279 *(uint32_t *)start = *(uint32_t *)(uint32_t)src;
280 start += 4U;
281 src = &src[4];
282 lengthInBytes -= 4U;
283 }
284 else if ((0U == (start & 0x1U)) && (0U == ((uint32_t)src & 0x1U)) && (lengthInBytes >= 2U))
285 {
286 *(uint16_t *)start = *(uint16_t *)(uint32_t)src;
287 start += 2U;
288 src = &src[2];
289 lengthInBytes -= 2U;
290 }
291 else
292 {
293 *(uint8_t *)start = *src;
294 start += 1U;
295 src = &src[1];
296 lengthInBytes -= 1U;
297 }
298 /* Wait till EEERDY bit is set */
299 while (0U == (FTFx->FCNFG & FTFx_FCNFG_EEERDY_MASK))
300 {
301 }
302
303 /* Check for protection violation error */
304 if (0U != (FTFx->FSTAT & FTFx_FSTAT_FPVIOL_MASK))
305 {
306 return kStatus_FTFx_ProtectionViolation;
307 }
308 }
309
310 /* Switch function of FlexRAM if needed */
311 if (needSwitchFlexRamMode)
312 {
313 returnCode = FTFx_CMD_SetFlexramFunction(&config->ftfxConfig, kFTFx_FlexramFuncOptAvailableAsRam);
314 if (returnCode != kStatus_FTFx_Success)
315 {
316 return kStatus_FTFx_RecoverFlexramAsRamError;
317 }
318 }
319
320 return returnCode;
321 }
322
323 /*!
324 * @brief Sets the DFlash protection to the intended protection status.
325 */
FLEXNVM_DflashSetProtection(flexnvm_config_t * config,uint8_t protectStatus)326 status_t FLEXNVM_DflashSetProtection(flexnvm_config_t *config, uint8_t protectStatus)
327 {
328 if (config == NULL)
329 {
330 return kStatus_FTFx_InvalidArgument;
331 }
332
333 if ((config->ftfxConfig.flashDesc.totalSize == 0U) || (config->ftfxConfig.flashDesc.totalSize == 0xFFFFFFFFU))
334 {
335 return kStatus_FTFx_CommandNotSupported;
336 }
337
338 /* Individual data flash regions will be protected from program and erase operations by setting the
339 * associated DPROT bit to the protected state. Each FDPROT bit only be changed from 1s to 0s,
340 * meaning the protection can only be increased */
341 FTFx->FDPROT = protectStatus;
342
343 if (FTFx->FDPROT != protectStatus)
344 {
345 return kStatus_FTFx_CommandFailure;
346 }
347
348 return kStatus_FTFx_Success;
349 }
350
351 /*!
352 * @brief Gets the DFlash protection status.
353 */
FLEXNVM_DflashGetProtection(flexnvm_config_t * config,uint8_t * protectStatus)354 status_t FLEXNVM_DflashGetProtection(flexnvm_config_t *config, uint8_t *protectStatus)
355 {
356 if ((config == NULL) || (protectStatus == NULL))
357 {
358 return kStatus_FTFx_InvalidArgument;
359 }
360
361 if ((config->ftfxConfig.flashDesc.totalSize == 0U) || (config->ftfxConfig.flashDesc.totalSize == 0xFFFFFFFFU))
362 {
363 return kStatus_FTFx_CommandNotSupported;
364 }
365
366 /* return the flexnvm DFlash protection status */
367 *protectStatus = FTFx->FDPROT;
368
369 return kStatus_FTFx_Success;
370 }
371
372 /*!
373 * @brief Sets the EEPROM protection to the intended protection status.
374 */
FLEXNVM_EepromSetProtection(flexnvm_config_t * config,uint8_t protectStatus)375 status_t FLEXNVM_EepromSetProtection(flexnvm_config_t *config, uint8_t protectStatus)
376 {
377 if (config == NULL)
378 {
379 return kStatus_FTFx_InvalidArgument;
380 }
381
382 if ((config->ftfxConfig.eepromTotalSize == 0U) || (config->ftfxConfig.eepromTotalSize == 0xFFFFU))
383 {
384 return kStatus_FTFx_CommandNotSupported;
385 }
386 /* Individual data flash regions will be protected from program and erase operations by setting the
387 * associated FEPROT bit to the protected state; Each FEPROT bit only be changed from 1s to 0s,
388 * meaning the protection can only be increased. */
389 FTFx->FEPROT = protectStatus;
390
391 if (FTFx->FEPROT != protectStatus)
392 {
393 return kStatus_FTFx_CommandFailure;
394 }
395
396 return kStatus_FTFx_Success;
397 }
398
399 /*!
400 * @brief Gets the EEPROM protection status.
401 */
FLEXNVM_EepromGetProtection(flexnvm_config_t * config,uint8_t * protectStatus)402 status_t FLEXNVM_EepromGetProtection(flexnvm_config_t *config, uint8_t *protectStatus)
403 {
404 if ((config == NULL) || (protectStatus == NULL))
405 {
406 return kStatus_FTFx_InvalidArgument;
407 }
408
409 if ((config->ftfxConfig.eepromTotalSize == 0U) || (config->ftfxConfig.eepromTotalSize == 0xFFFFU))
410 {
411 return kStatus_FTFx_CommandNotSupported;
412 }
413
414 /* return EEPROM protection status */
415 *protectStatus = FTFx->FEPROT;
416
417 return kStatus_FTFx_Success;
418 }
419
420 /*!
421 * @brief Returns the desired flexnvm property.
422 */
FLEXNVM_GetProperty(flexnvm_config_t * config,flexnvm_property_tag_t whichProperty,uint32_t * value)423 status_t FLEXNVM_GetProperty(flexnvm_config_t *config, flexnvm_property_tag_t whichProperty, uint32_t *value)
424 {
425 if ((config == NULL) || (value == NULL))
426 {
427 return kStatus_FTFx_InvalidArgument;
428 }
429
430 status_t status = kStatus_FTFx_Success;
431
432 switch (whichProperty)
433 {
434 /* get flexnvm date flash sector size */
435 case kFLEXNVM_PropertyDflashSectorSize:
436 *value = config->ftfxConfig.flashDesc.sectorSize;
437 break;
438 /* get flexnvm date flash total size */
439 case kFLEXNVM_PropertyDflashTotalSize:
440 *value = config->ftfxConfig.flashDesc.totalSize;
441 break;
442 /* get flexnvm date flash block size */
443 case kFLEXNVM_PropertyDflashBlockSize:
444 *value = config->ftfxConfig.flashDesc.totalSize / config->ftfxConfig.flashDesc.blockCount;
445 break;
446 /* get flexnvm date flash block cont */
447 case kFLEXNVM_PropertyDflashBlockCount:
448 *value = config->ftfxConfig.flashDesc.blockCount;
449 break;
450 /* get flexnvm date flash block base address */
451 case kFLEXNVM_PropertyDflashBlockBaseAddr:
452 *value = config->ftfxConfig.flashDesc.blockBase;
453 break;
454 #if defined(FSL_FEATURE_FLASH_HAS_FLEX_NVM_ALIAS) && FSL_FEATURE_FLASH_HAS_FLEX_NVM_ALIAS
455 case kFLEXNVM_PropertyAliasDflashBlockBaseAddr:
456 *value = config->ftfxConfig.flashDesc.aliasBlockBase;
457 break;
458 #endif /* FSL_FEATURE_FLASH_HAS_FLEX_NVM_ALIAS */
459 case kFLEXNVM_PropertyFlexRamBlockBaseAddr:
460 *value = config->ftfxConfig.flexramBlockBase;
461 break;
462 /* get flexram total size */
463 case kFLEXNVM_PropertyFlexRamTotalSize:
464 *value = config->ftfxConfig.flexramTotalSize;
465 break;
466 /* get flexnvm eeprom total size */
467 case kFLEXNVM_PropertyEepromTotalSize:
468 *value = config->ftfxConfig.eepromTotalSize;
469 break;
470 /* catch inputs that are not recognized */
471 default:
472 status = kStatus_FTFx_UnknownProperty;
473 break;
474 }
475 return status;
476 }
477
478 /*! @brief Convert address for Flexnvm dflash.*/
flexnvm_convert_start_address(flexnvm_config_t * config,uint32_t start)479 static status_t flexnvm_convert_start_address(flexnvm_config_t *config, uint32_t start)
480 {
481 status_t status = kStatus_FTFx_AddressError;
482
483 if (config == NULL)
484 {
485 return kStatus_FTFx_InvalidArgument;
486 }
487
488 /* From Spec: When required by the command, address bit 23 selects between program flash memory
489 * (=0) and data flash memory (=1).*/
490 if (start >= config->ftfxConfig.flashDesc.blockBase)
491 {
492 config->ftfxConfig.opsConfig.convertedAddress = start - config->ftfxConfig.flashDesc.blockBase + 0x800000U;
493 status = kStatus_FTFx_Success;
494 }
495 #if defined(FSL_FEATURE_FLASH_HAS_FLEX_NVM_ALIAS) && FSL_FEATURE_FLASH_HAS_FLEX_NVM_ALIAS
496 /* for MKW39/38/37 which have alias blockBase */
497 else if (start >= config->ftfxConfig.flashDesc.aliasBlockBase)
498 {
499 config->ftfxConfig.opsConfig.convertedAddress = start - config->ftfxConfig.flashDesc.aliasBlockBase + 0x800000U;
500 status = kStatus_FTFx_Success;
501 }
502 else
503 {
504 status = kStatus_FTFx_Success;
505 }
506 #endif /* FSL_FEATURE_FLASH_HAS_FLEX_NVM_ALIAS */
507
508 return status;
509 }
510
511 #endif /* FSL_FEATURE_FLASH_HAS_FLEX_NVM */
512