1 /*
2  * Copyright 2020 NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 /*!*********************************************************************************
9 *************************************************************************************
10 * Include
11 *************************************************************************************
12 ********************************************************************************** */
13 #include "fsl_flash.h"
14 #include "fsl_k4_flash.h"
15 #include "fsl_adapter_flash.h"
16 /*****************************************************************************
17  *****************************************************************************
18  * Private macros
19  *****************************************************************************
20  *****************************************************************************/
21 #define PGM_SIZE_BYTE FSL_FEATURE_FLASH_PFLASH_PHRASE_SIZE
22 
23 #if defined(__IAR_SYSTEMS_ICC__)
24 #define __RAMFUNC __ramfunc
25 #elif defined(__GNUC__)
26 #define __RAMFUNC __attribute__((section(".ramfunc"))) __attribute__((__noinline__))
27 #endif
28 
29 /* ECC_SIM_OM option is to be used only when simulating ECC faults for test purposes.
30  * The controller raises an ECC fault at the first read access to the flash whatever the master.
31  * Any intruction fetch from flash would cause the simulated ECC fault to raise, so need to place
32  * such code in RAM. Likewise the flash cache must be disabled.
33  * These reasons justify the __ECC_FCT_PLACEMENT attribute used for the ECC related functions.
34  */
35 #ifdef ECC_SIM_ON
36 #define __ECC_FCT_PLACEMENT __RAMFUNC
37 __ECC_FCT_PLACEMENT static void flash_cache_disable1(void);
38 #define FLASH_CACHE_DISABLE() flash_cache_disable1()
39 #else
40 #define __ECC_FCT_PLACEMENT
41 #define FLASH_CACHE_DISABLE() flash_cache_disable()
42 #endif
43 
44 #define OCMDR0_CF0_DNCBEI_SHIFT (2u + SMSCM_OCMDR0_OCMCF0_SHIFT)
45 #define OCMDR0_CF0_DNCBED_SHIFT (3u + SMSCM_OCMDR0_OCMCF0_SHIFT)
46 #define OCMDR0_CF0_DNCBEI_MASK  (1u << OCMDR0_CF0_DNCBEI_SHIFT)
47 #define OCMDR0_CF0_DNCBED_MASK  (1u << OCMDR0_CF0_DNCBED_SHIFT)
48 
49 /*!*********************************************************************************
50 *************************************************************************************
51 * Private type definitions
52 *************************************************************************************
53 ********************************************************************************** */
54 static flash_config_t s_flashConfig;
55 /*!*********************************************************************************
56 *************************************************************************************
57 * Private prototypes
58 *************************************************************************************
59 ********************************************************************************** */
60 static hal_flash_status_t HAL_FlashProgramAdaptation(uint32_t dest, uint32_t size, uint8_t *pData);
61 /*!*********************************************************************************
62 *************************************************************************************
63 * Public memory declarations
64 *************************************************************************************
65 ********************************************************************************** */
66 
67 /*****************************************************************************
68  *****************************************************************************
69  * Private functions
70  *****************************************************************************
71  *****************************************************************************/
HAL_FlashGetStatus(status_t status)72 static hal_flash_status_t HAL_FlashGetStatus(status_t status)
73 {
74 #if (defined(HAL_FLASH_TRANSFER_MODE) && (HAL_FLASH_TRANSFER_MODE > 0U))
75     hal_flash_status_t flashStatus = kStatus_HAL_Flash_Error;
76     switch (status)
77     {
78         case (status_t)kStatus_Success:
79             flashStatus = kStatus_HAL_Flash_Success;
80             break;
81         case (status_t)kStatus_FLASH_InvalidArgument:
82             flashStatus = kStatus_HAL_Flash_InvalidArgument;
83             break;
84         case (status_t)kStatus_FLASH_AlignmentError:
85             flashStatus = kStatus_HAL_Flash_AlignmentError;
86             break;
87         default:
88             /*MISRA rule 16.4*/
89             break;
90     }
91     return flashStatus;
92 #else
93     return (hal_flash_status_t)status;
94 #endif
95 }
96 
HAL_FlashGetPropertyTag(hal_flash_property_tag_t tag)97 static flash_property_tag_t HAL_FlashGetPropertyTag(hal_flash_property_tag_t tag)
98 {
99     flash_property_tag_t ret;
100     switch (tag)
101     {
102         case kHAL_Flash_PropertyPflashSectorSize:
103             ret = kFLASH_PropertyPflash0SectorSize;
104             break;
105         case kHAL_Flash_PropertyPflashTotalSize:
106             ret = kFLASH_PropertyPflash0TotalSize;
107             break;
108         case kHAL_Flash_PropertyPflashBlockCount:
109             ret = kFLASH_PropertyPflash0BlockCount;
110             break;
111         case kHAL_Flash_PropertyPflashBlockBaseAddr:
112             ret = kFLASH_PropertyPflash0BlockBaseAddr;
113             break;
114         case kHAL_Flash_PropertyPflashBlockSize:
115             ret = kFLASH_PropertyPflash0BlockSize;
116             break;
117         default:
118             /*MISRA rule 16.4*/
119             ret = (flash_property_tag_t)-1;
120             break;
121     }
122     return ret;
123 }
124 
HAL_FlashProgramAdaptation(uint32_t dest,uint32_t size,uint8_t * pData)125 static hal_flash_status_t HAL_FlashProgramAdaptation(uint32_t dest, uint32_t size, uint8_t *pData)
126 {
127     int32_t status;
128 
129     uint32_t regPrimask = DisableGlobalIRQ();
130 
131     status = FLASH_Program(&s_flashConfig, FLASH, dest, (uint8_t *)pData, size);
132 
133     EnableGlobalIRQ(regPrimask);
134 
135     return HAL_FlashGetStatus(status);
136 }
137 
138 /*!*********************************************************************************
139 *************************************************************************************
140 * Public functions
141 *************************************************************************************
142 ********************************************************************************** */
143 
144 /*!
145  * @brief Initializes the global flash properties structure members.
146  *
147  * This function initializes the Flash module for the other Flash APIs.
148  *
149  *
150  * @retval #kStatus_HAL_Flash_Success API was executed successfully.
151  * @retval #kStatus_HAL_Flash_InvalidArgument An invalid argument is provided.
152  * @retval #kStatus_HAL_Flash_ExecuteInRamFunctionNotReady Execute-in-RAM function is not available.
153  * @retval #kStatus_HAL_Flash_PartitionStatusUpdateFailure Failed to update the partition status.
154  */
HAL_FlashInit()155 hal_flash_status_t HAL_FlashInit()
156 {
157     static uint32_t flashInit = 0;
158     status_t status           = (status_t)kStatus_HAL_Flash_Success;
159 
160     uint32_t regPrimask = DisableGlobalIRQ();
161     /*  Disable cache/Prefetch */
162     flash_cache_disable();
163     EnableGlobalIRQ(regPrimask);
164     if (0U == flashInit)
165     {
166         /* Init Flash */
167         status    = FLASH_Init(&s_flashConfig);
168         flashInit = 1U;
169     }
170     return HAL_FlashGetStatus(status);
171 }
172 
173 /*!
174  * \brief  Verify erase data in Flash
175  *
176  * @param start           The address of the Flash location
177  * @param lengthInBytes   The number of bytes to be checked
178  * @param margin          Flash margin value
179  * @retval #kStatus_HAL_Flash_Success API was executed successfully.
180  */
HAL_FlashVerifyErase(uint32_t start,uint32_t lengthInBytes,hal_flash_margin_value_t margin)181 hal_flash_status_t HAL_FlashVerifyErase(uint32_t start, uint32_t lengthInBytes, hal_flash_margin_value_t margin)
182 {
183     int32_t status;
184     uint32_t regPrimask = DisableGlobalIRQ();
185 
186     (void)margin;
187     if (start >= s_flashConfig.msf1Config[0].ifrDesc.pflashIfr0Start)
188     {
189         status = FLASH_VerifyEraseIFRPhrase(&s_flashConfig, FLASH, start, lengthInBytes);
190     }
191     else
192     {
193         status = FLASH_VerifyErasePhrase(&s_flashConfig, FLASH, start, lengthInBytes);
194     }
195     EnableGlobalIRQ(regPrimask);
196     return HAL_FlashGetStatus(status);
197 }
198 
199 /*!
200  * \brief  Write aligned data to FLASH
201  *
202  * @param halFlashHandle  Hal flash adapter handle
203  * @param dest            The address of the Flash location
204  * @param size            The number of bytes to be programed
205  * @param pData           Pointer to the data to be programmed to Flash
206  *
207  * @retval #kStatus_HAL_Flash_Success API was executed successfully.
208  *
209  */
HAL_FlashProgram(uint32_t dest,uint32_t size,uint8_t * pData)210 hal_flash_status_t HAL_FlashProgram(uint32_t dest, uint32_t size, uint8_t *pData)
211 {
212     return HAL_FlashProgramAdaptation(dest, size, pData);
213 }
214 
215 /*!
216  * \brief  Write data to FLASH
217  *
218  * @param dest        The address of the Flash location
219  * @param size        The number of bytes to be programed
220  * @param pData       Pointer to the data to be programmed to Flash
221  *
222  * @retval #kStatus_HAL_Flash_Success API was executed successfully.
223  *
224  */
HAL_FlashProgramUnaligned(uint32_t dest,uint32_t size,uint8_t * pData)225 hal_flash_status_t HAL_FlashProgramUnaligned(uint32_t dest, uint32_t size, uint8_t *pData)
226 {
227     uint8_t buffer[PGM_SIZE_BYTE];
228     uint32_t bytes            = dest & ((uint32_t)PGM_SIZE_BYTE - 1U);
229     hal_flash_status_t status = kStatus_HAL_Flash_Success;
230 
231     if (bytes != 0U)
232     {
233         uint32_t unalignedBytes = (uint32_t)PGM_SIZE_BYTE - bytes;
234 
235         if (unalignedBytes > size)
236         {
237             unalignedBytes = size;
238         }
239 
240         memcpy(buffer, (uint8_t *)(dest - bytes), PGM_SIZE_BYTE);
241         memcpy(&buffer[bytes], pData, unalignedBytes);
242 
243         status = HAL_FlashProgramAdaptation(dest - bytes, PGM_SIZE_BYTE, buffer);
244         if (kStatus_HAL_Flash_Success == status)
245         {
246             dest += (uint32_t)PGM_SIZE_BYTE - bytes;
247             pData += unalignedBytes;
248             size -= unalignedBytes;
249         }
250     }
251 
252     if (kStatus_HAL_Flash_Success == status)
253     {
254         bytes = size & ~((uint32_t)PGM_SIZE_BYTE - 1U);
255 
256         if (bytes != 0U)
257         {
258             status = HAL_FlashProgramAdaptation(dest, bytes, pData);
259             if (kStatus_HAL_Flash_Success == status)
260             {
261                 dest += bytes;
262                 pData += bytes;
263                 size -= bytes;
264             }
265         }
266 
267         if (kStatus_HAL_Flash_Success == status)
268         {
269             if (size != 0U)
270             {
271                 memcpy(buffer, (uint8_t *)dest, PGM_SIZE_BYTE);
272                 memcpy(buffer, pData, size);
273                 status = HAL_FlashProgramAdaptation(dest, PGM_SIZE_BYTE, buffer);
274             }
275         }
276     }
277     return status;
278 }
279 
280 /*!
281  * \brief  Erase to 0xFF one or more FLASH sectors.
282  *
283  * @param dest            The start address of the first sector to be erased
284  * @param size            The amount of flash to be erased (multiple of sector size)
285  *
286  * @retval #kStatus_HAL_Flash_Success API was executed successfully.
287  *
288  */
HAL_FlashEraseSector(uint32_t dest,uint32_t size)289 hal_flash_status_t HAL_FlashEraseSector(uint32_t dest, uint32_t size)
290 {
291     int32_t status;
292 
293     uint32_t regPrimask = DisableGlobalIRQ();
294 
295     status = FLASH_Erase(&s_flashConfig, FLASH, dest, size, (uint32_t)kFLASH_ApiEraseKey);
296 
297     EnableGlobalIRQ(regPrimask);
298 
299     return HAL_FlashGetStatus(status);
300 }
301 
302 /*!
303  * \brief  Read data from FLASH
304  *
305 
306  * @param scr             The address of the Flash location to be read
307  * @param size            The number of bytes to be read
308  * @param pData           Pointer to the data to be read from Flash
309  *
310  * @retval #kStatus_HAL_Flash_Success API was executed successfully.
311  *
312  */
HAL_FlashRead(uint32_t src,uint32_t size,uint8_t * pData)313 hal_flash_status_t HAL_FlashRead(uint32_t src, uint32_t size, uint8_t *pData)
314 {
315     (void)memcpy(pData, (uint8_t *)src, size);
316     return kStatus_HAL_Flash_Success;
317 }
318 
319 #ifdef ECC_SIM_ON
flash_cache_disable1(void)320 __ECC_FCT_PLACEMENT static void flash_cache_disable1(void)
321 {
322     SMSCM->OCMDR0 = (SMSCM->OCMDR0 & (~SMSCM_FLASH_CACHE_CTRL_MASK)) | SMSCM_FLASH_CACHE_CTRL(0x1);
323     SMSCM->OCMDR0 = (SMSCM->OCMDR0 & (~SMSCM_FLASH_CACHE_CTRL_MASK)) | SMSCM_FLASH_CACHE_CTRL(0x8);
324     SMSCM->OCMDR0 = (SMSCM->OCMDR0 & (~SMSCM_FLASH_SPECULATION_CTRL_MASK)) | SMSCM_FLASH_SPECULATION_CTRL(0x3);
325     __ISB();
326     __DSB();
327 }
328 #endif
flash_bus_fault_ecc_non_correctable_err_on_data_fetch(bool enableNdisable)329 __ECC_FCT_PLACEMENT static int flash_bus_fault_ecc_non_correctable_err_on_data_fetch(bool enableNdisable)
330 {
331     int st = -1;
332     uint32_t reg_val;
333     reg_val = SMSCM->OCMDR0;
334     if ((reg_val & SMSCM_OCMDR0_RO_MASK) != SMSCM_OCMDR0_RO_MASK)
335     {
336         FLASH_CACHE_DISABLE();
337         // flash_cache_speculation_control(true, FLASH);
338         reg_val &= ~SMSCM_OCMDR0_OCMCF0_MASK;
339         if (!enableNdisable)
340         {
341             /* disable bus fault on data read in case of ECC non recoverable error */
342             reg_val |= OCMDR0_CF0_DNCBED_MASK;
343         }
344         SMSCM->OCMDR0 = reg_val;
345         st            = 0;
346     }
347     return st;
348 }
349 
350 /*!
351  * \brief  Activate or deactivate ECC fault detection without bus faulting
352  *
353  * Note a RAM version of this function is required when ECC fault simulation is used.
354  *
355  * @param sav_cfg      pointer of 32 bit location to remember flash cache and
356  *                     ECC configuration to be restored
357  *
358  * @retval 0 if OK might be -1 if configuration is readonly.
359  *
360  */
FLASH_ActivateEccFaultDetection(FMU_Type * base,uint32_t * sav_cfg)361 __ECC_FCT_PLACEMENT int FLASH_ActivateEccFaultDetection(FMU_Type *base, uint32_t *sav_cfg)
362 {
363     int st;
364     uint32_t fcncf_val;
365     *sav_cfg = SMSCM->OCMDR0;
366     st       = flash_bus_fault_ecc_non_correctable_err_on_data_fetch(false);
367     if (0 == st)
368     {
369         fcncf_val = base->FCNFG;
370         fcncf_val |= FMU_FCNFG_DFDIE_MASK;
371         /* Command Complete CCIE must remain unset */
372         // fcncf_val &= ~FMU_FCNFG_CCIE_MASK;
373         base->FCNFG = fcncf_val;
374         __ISB();
375         __DSB();
376     }
377     return st;
378 }
379 
FLASH_DeactivateEccFaultDetection(FMU_Type * base,uint32_t restore_cfg)380 __ECC_FCT_PLACEMENT int FLASH_DeactivateEccFaultDetection(FMU_Type *base, uint32_t restore_cfg)
381 {
382     int st;
383     uint32_t fcncf_val;
384     st = flash_bus_fault_ecc_non_correctable_err_on_data_fetch(true);
385 
386     /* Reenable flash cache and reenable bus fault on  ECC non correctable fault detection */
387     SMSCM->OCMDR0 = restore_cfg;
388     fcncf_val     = base->FCNFG;
389     base->FCNFG   = fcncf_val;
390     __ISB();
391     __DSB();
392     return st;
393 }
394 
HAL_FlashEccStatusRaised(void)395 bool HAL_FlashEccStatusRaised(void)
396 {
397     return (FMU0->FSTAT & FLASH_FSTAT_DFDIF_MASK) ? true : false;
398 }
399 
400 /*!
401  * \brief  Read data from FLASH checking for ECC errors
402  *
403  * Note a RAM version of this function is required when ECC fault simulation is used.
404  *
405  * @param scr             The address of the Flash location to be read
406  * @param size            The number of bytes to be read
407  * @param pData           Pointer to the data to be read from Flash
408  *
409  * @retval #kStatus_HAL_Flash_Success API was executed successfully.
410  *         #kStatus_HAL_Flash_EccError if ECC Fault error got raised.
411  *
412  */
HAL_FlashReadCheckEccFaults(uint32_t src,uint32_t size,uint8_t * pData)413 hal_flash_status_t HAL_FlashReadCheckEccFaults(uint32_t src, uint32_t size, uint8_t *pData)
414 {
415     hal_flash_status_t st = kStatus_HAL_Flash_Success;
416 
417     uint32_t sav_cfg;
418     uint8_t *addr       = (uint8_t *)src;
419     uint8_t *end_addr   = addr + size;
420     uint32_t regPrimask = DisableGlobalIRQ();
421     FMU0->FSTAT         = FLASH_FSTAT_DFDIF_MASK;
422     if (FLASH_ActivateEccFaultDetection(FMU0, &sav_cfg) == 0)
423     {
424         while (addr < end_addr)
425         {
426             *pData = *addr;
427             if ((FMU0->FSTAT & FLASH_FSTAT_DFDIF_MASK) == FLASH_FSTAT_DFDIF_MASK)
428             {
429                 /* Acknowledge Double ECC Fault event */
430                 FMU0->FSTAT = FLASH_FSTAT_DFDIF_MASK;
431                 st          = kStatus_HAL_Flash_EccError;
432                 break;
433             }
434             addr++;
435             pData++;
436         }
437         (void)FLASH_DeactivateEccFaultDetection(FMU0, sav_cfg);
438     }
439     EnableGlobalIRQ(regPrimask);
440     return st;
441 }
442 
443 /*!
444  * @brief Returns the desired hal flash property.
445  *
446  * @param Property        The desired property from the list of properties in
447  *                        enum hal_flash_property_tag_t
448  * @param value           A pointer to the value returned for the desired flash property.
449  *
450  * @retval #kStatus_HAL_Flash_Success API was executed successfully.
451  * @retval #kStatus_HAL_Flash_InvalidArgument An invalid argument is provided.
452  * @retval #kStatus_HAL_Flash_NotSupport Flash currently not support.
453  */
HAL_FlashGetProperty(hal_flash_property_tag_t property,uint32_t * value)454 hal_flash_status_t HAL_FlashGetProperty(hal_flash_property_tag_t property, uint32_t *value)
455 {
456     flash_property_tag_t ret;
457     if (value == NULL)
458     {
459         return kStatus_HAL_Flash_InvalidArgument;
460     }
461     ret = HAL_FlashGetPropertyTag(property);
462     if (((flash_property_tag_t)-1) == ret)
463     {
464         return kStatus_HAL_Flash_NotSupport;
465     }
466     else
467     {
468         return HAL_FlashGetStatus(FLASH_GetProperty(&s_flashConfig, ret, value));
469     }
470 }
471 
472 /*!
473  * @brief Set the desired hal flash property.
474  *
475  * @param Property        The desired property from the list of properties in
476  *                        enum hal_flash_property_tag_t
477  * @param value           The value would be set to the desired flash property.
478  *
479  * @retval #kStatus_HAL_Flash_Success API was executed successfully.
480  * @retval #kStatus_HAL_Flash_InvalidArgument An invalid argument is provided.
481  * @retval #kStatus_HAL_Flash_NotSupport Flash currently not support.
482  */
HAL_FlashSetProperty(hal_flash_property_tag_t property,uint32_t value)483 hal_flash_status_t HAL_FlashSetProperty(hal_flash_property_tag_t property, uint32_t value)
484 {
485     return kStatus_HAL_Flash_NotSupport;
486 }
487 
488 /*!
489  * @brief Returns the security state via the pointer passed into the function.
490  *
491  * This function retrieves the current flash security status, including the
492  * security enabling state and the backdoor key enabling state.
493  *
494  * @param state           A pointer to the value returned for the current security status
495  *
496  * @retval #kStatus_HAL_Flash_Success API was executed successfully.
497  * @retval #kStatus_HAL_Flash_InvalidArgument An invalid argument is provided.
498  * @retval #kStatus_HAL_Flash_NotSupport Flash currently not support.
499  */
HAL_FlashGetSecurityState(hal_flash_security_state_t * state)500 hal_flash_status_t HAL_FlashGetSecurityState(hal_flash_security_state_t *state)
501 {
502 #if 0
503     return HAL_FlashGetStatus(FLASH_GetSecurityState(s_flashConfig, (ftfx_security_state_t *)state));
504 #else
505     return kStatus_HAL_Flash_NotSupport;
506 #endif
507 }