1 /*
2  * Copyright 2022 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 #include "fsl_eeprom_emulation.h"
8 #include "fsl_debug_console.h"
9 
10 /*******************************************************************************
11  * Definitions
12  ******************************************************************************/
13 
14 /* Component ID definition, used by tools. */
15 #ifndef FSL_COMPONENT_ID
16 #define FSL_COMPONENT_ID "platform.drivers.eeprom_emulation"
17 #endif
18 
19 /*******************************************************************************
20  * Prototypes
21  ******************************************************************************/
22 static uint32_t EE_PreInitCheck(eeprom_emulation_handle_t *handle);
23 static uint32_t EE_InitAltSector(eeprom_emulation_handle_t *handle, uint8_t *number);
24 static uint32_t EE_InitActiveSector(eeprom_emulation_handle_t *handle, uint8_t number);
25 
26 /*******************************************************************************
27  * Variables
28  ******************************************************************************/
29 
30 /* Start address of the current active sector */
31 static uint32_t g_currentActiveSector;
32 
33 /* The blank address of the current active sector
34    where the next data record is written */
35 static uint32_t g_freeSpaceAddress;
36 static uint32_t g_eeEndAddress;
37 #if (defined(FLASH_PGM_SIZE) && (FLASH_PGM_SIZE == 16))
38 static uint32_t g_eraseCycles[4];
39 #else
40 static uint32_t g_eraseCycles[2];
41 #endif
42 static eeprom_emulation_data_record_t g_dataRecord;
43 
44 #if (EE_USE_ASYNCHRONOUS_MODEL == true)
45 static uint32_t g_addressToMain;
46 static uint32_t g_endAddressToMain;
47 static uint8_t g_numErase = 0x00u;
48 #endif
49 
50 /* Flag to keep track of Erase State*/
51 static volatile eeprom_emulation_state_type_t g_eraseStatusFlag;
52 
53 #if EE_CALLBACK_ENABLE
54 /* A function pointer to the CallBack function */
55 PEE_FUNCPOINTER g_EECallBack;
56 #endif /* EE_CALLBACK_ENABLE */
57 
58 /*******************************************************************************
59  * Code
60  ******************************************************************************/
EE_GetDefaultConfig(eeprom_emulation_config_t * config)61 void EE_GetDefaultConfig(eeprom_emulation_config_t *config)
62 {
63     config->eeRetryMax           = 0x02U;
64     config->ftfxPGMCheckSize     = 0x04U;
65     config->flashReadMargin      = 0x01U;
66     config->flashStartAddress    = 0x00U;
67     config->eeSectorActIndOffset = 0x00U;
68 }
69 
EE_SetEepromEmulationInfo(eeprom_emulation_handle_t * handle,eeprom_emulation_config_t * config)70 void EE_SetEepromEmulationInfo(eeprom_emulation_handle_t *handle, eeprom_emulation_config_t *config)
71 {
72     /* Number of actual alternative sectors alloted for emulation Eeprom is enough or not */
73     assert(config->eeActualReadySectors >= config->eeMinActualReadySectors);
74 
75     /* Flash sector size */
76     handle->flashSectorSize = config->flashSectorSize;
77     /* Start address for emulated eeprom */
78     handle->eeStartAddress = config->eeStartAddress;
79     /* Program size for ftfx module */
80     handle->ftfxProgramSize = config->ftfxProgramSize;
81     /* Data value size in one record */
82     handle->eeDataValueSize = config->eeDataValueSize;
83     /* Sector size for emulated eeprom */
84     handle->eeSectorSize = config->eeSectorSize;
85     /* The total raw data user wants to emulate in byte */
86     handle->eeMemorySize = config->eeMemorySize;
87     /* Active ready sector numbers */
88     handle->eeActualReadySectors = config->eeActualReadySectors;
89     /* Extra ready sector numbers */
90     handle->eeExtraReadySectors = config->eeExtraReadySectors;
91     /* Extra active sector numbers */
92     handle->eeExtraActiveSectors = config->eeExtraActiveSectors;
93     /* Number of retry if failed to program sector indicator or erase sector */
94     handle->eeRetryMax = config->eeRetryMax;
95     /* Program size for program check function */
96     handle->ftfxPGMCheckSize = config->ftfxPGMCheckSize;
97     /* Read one sector size for ftfx module */
98     handle->ftfxRD1SECSize = config->ftfxRD1SECSize;
99     /* Read margin */
100     handle->flashReadMargin = config->flashReadMargin;
101 
102     /* Calculate complement size */
103     if (config->eccSize == 0x02U)
104     {
105         handle->complementSize = handle->ftfxProgramSize;
106     }
107     else
108     {
109         handle->complementSize = 0;
110     }
111 
112     /* Calculate eeprom emulation sector header size */
113     handle->eeSectorHeaderSize = (0x03U * handle->ftfxProgramSize) + handle->complementSize;
114 
115     /* number of bit to make programable size */
116     if (FTFx_LONGWORD_SIZE == handle->ftfxProgramSize)
117     {
118         handle->ftfxBitNumber      = 0x02U;
119         handle->ftfxProgramCommand = 0x06U;
120     }
121     else if (FTFx_PHRASE_SIZE == handle->ftfxProgramSize)
122     {
123         handle->ftfxBitNumber      = 0x03U;
124         handle->ftfxProgramCommand = 0x07U;
125     }
126     else
127     {
128         /* Should not be here */
129     }
130 
131     /* Calculate eeprom emulation sector record length */
132     if (0x00U != GET_MOD(handle->eeDataValueSize, handle->ftfxProgramSize))
133     {
134         handle->eeSectorRecordLength =
135             (((handle->eeDataValueSize >> handle->ftfxBitNumber) + 0x01U) << handle->ftfxBitNumber) +
136             (2U * handle->ftfxProgramSize) + handle->complementSize;
137     }
138     else
139     {
140         handle->eeSectorRecordLength =
141             handle->eeDataValueSize + (2U * handle->ftfxProgramSize) + handle->complementSize;
142     }
143 
144     /* Calculate active indecator, dead indicator and erase cycle offset */
145     handle->eeSectorActIndOffset     = config->eeSectorActIndOffset;
146     handle->eeSectorDeadIndOffset    = handle->ftfxProgramSize;
147     handle->eeSectorEraseCycleOffset = handle->ftfxProgramSize << 0x01U;
148 
149     /* Calculate record ID and record status offset */
150     handle->eeRecordIDOffset = handle->eeSectorRecordLength - EE_RECORD_ID_SIZE - handle->complementSize;
151     if (FTFx_PHRASE_SIZE == handle->ftfxProgramSize)
152     {
153         handle->eeGapSize = 0x04U;
154         handle->eeRecordStatusOffset =
155             handle->eeSectorRecordLength - FTFx_LONGWORD_SIZE - EE_RECORD_STATUS_SIZE - handle->complementSize;
156     }
157     else if (FTFx_DPHRASE_SIZE == handle->ftfxProgramSize)
158     {
159         handle->eeGapSize = handle->ftfxProgramSize; /* The gap between ID with STATUS. */
160         handle->eeRecordStatusOffset =
161             handle->eeSectorRecordLength - handle->ftfxProgramSize - EE_RECORD_STATUS_SIZE - handle->complementSize;
162     }
163     else
164     {
165         handle->eeGapSize            = 0x02U;
166         handle->eeRecordStatusOffset = handle->eeSectorRecordLength - handle->ftfxProgramSize - handle->complementSize;
167     }
168 
169     /* Calculate eeprom emulation sector waste size */
170     handle->eeSectorWaste = (handle->eeSectorSize - handle->eeSectorHeaderSize) % handle->eeSectorRecordLength;
171 
172     /* Calculate ready sectors number*/
173     handle->eeReadySectors = handle->eeActualReadySectors + handle->eeExtraReadySectors;
174 
175     /* Number of Data Records is calculated if we know the total Data Size */
176     if (0x00U != GET_MOD(handle->eeMemorySize, handle->eeDataValueSize))
177     {
178         handle->eeMaxRecordNumber = (uint16_t)(GET_INT(handle->eeMemorySize, handle->eeDataValueSize) + 0x01u);
179     }
180     else
181     {
182         handle->eeMaxRecordNumber = (uint16_t)(GET_INT(handle->eeMemorySize, handle->eeDataValueSize));
183     }
184 
185     /* Calculate capacity */
186     handle->eeSectorCapacity = GET_INT(handle->eeSectorSize - handle->eeSectorHeaderSize, handle->eeSectorRecordLength);
187 
188     /* Calculate required active sector */
189     if (0x00U != GET_MOD(((uint32_t)handle->eeMaxRecordNumber + 0x01u), handle->eeSectorCapacity))
190     {
191         handle->eeActiveSectorRequired =
192             (GET_INT(((uint32_t)handle->eeMaxRecordNumber + 0x01u), handle->eeSectorCapacity) + 0x01u);
193     }
194     else
195     {
196         handle->eeActiveSectorRequired =
197             GET_INT(((uint32_t)handle->eeMaxRecordNumber + 0x01u), handle->eeSectorCapacity);
198     }
199 
200     /* Total number of active sectors alloted */
201     handle->eeActiveSectors = handle->eeExtraActiveSectors + handle->eeActiveSectorRequired;
202 
203     /* Total number of sectors alloted will also include some 'alternative sectors' */
204     handle->eeAllotedSectors = handle->eeActiveSectors + handle->eeReadySectors;
205 
206     /* End address of eeprom emulation from Flash */
207     handle->eeEndAddress = handle->eeStartAddress + handle->eeAllotedSectors * handle->eeSectorSize;
208 }
209 
210 /*******************************************************************************
211  *
212  *  Function Name    : CheckErrorCode
213  *  Description      : Check error bit of each flash command.
214  *  Purpose          : to optimize code size since this function is called multiple times.
215  *  Arguments        : N/A
216  *  Return Value     :
217  *                     - EE_OK if successful
218  *                     - EE_NOT_OK if failed
219  *
220  *******************************************************************************/
EE_FlashCheckErrorCode(void)221 uint32_t EE_FlashCheckErrorCode(void)
222 {
223     uint32_t returnCode;
224     returnCode = EE_OK;
225     /* checking all errors */
226     if (0u != FMU_CHECK_ERR)
227     {
228         returnCode = EE_NOT_OK;
229     }
230     return (returnCode);
231 }
232 
233 /*******************************************************************************
234  *
235  *  Function Name    : EE_FlashEraseAll
236  *  Description      : Erase one EE sector in Flash with synchronous model and verify as well
237  *  Arguments        :
238  *                     - destination: the offset address to flash base
239  *  Return Value     :
240  *                     - EE_OK if successful
241  *                     - EE_NOT_OK if failed
242  *
243  *******************************************************************************/
AT_QUICKACCESS_SECTION_CODE(uint32_t EE_FlashEraseAll (eeprom_emulation_handle_t * handle))244 AT_QUICKACCESS_SECTION_CODE(uint32_t EE_FlashEraseAll(eeprom_emulation_handle_t *handle))
245 {
246     uint32_t result = EE_OK;
247 
248     /* load FCCOB registers */
249     FMU0->FCCOB[0] = ERSALL;
250 
251     /* Check if previous command complete, wait for CCIF set */
252     while (0x00U == (FMU0->FSTAT & FLASH_FSTAT_CCIF_MASK))
253     {
254     }
255 
256     /* clear CMDABT & ACCERR & PVIOL flag in flash status register */
257     FMU0->FSTAT = (FLASH_FSTAT_CMDABT_MASK | FLASH_FSTAT_ACCERR_MASK | FLASH_FSTAT_PVIOL_MASK);
258 
259     FMU0->FSTAT = FLASH_FSTAT_CCIF_MASK;
260     while (0x00U != (FMU0->FSTAT & FLASH_FSTAT_CCIF_MASK))
261     {
262     }
263 
264     while (0x00U == (FMU0->FSTAT & FLASH_FSTAT_CCIF_MASK))
265     {
266     }
267 
268     /* Check for errors */
269     if (0x00U != (FMU0->FSTAT & FMU_FSTAT_FAIL_MASK))
270     {
271         result = EE_NOT_OK;
272     }
273 
274     return result;
275 }
276 
277 /*******************************************************************************
278  *
279  *  Function Name    : EE_SyncFlashErase
280  *  Description      : Erase one EE sector in Flash with synchronous model and verify as well
281  *  Arguments        :
282  *                     - destination: the offset address to flash base
283  *  Return Value     :
284  *                     - EE_OK if successful
285  *                     - EE_NOT_OK if failed
286  *
287  *******************************************************************************/
AT_QUICKACCESS_SECTION_CODE(uint32_t EE_SyncFlashErase (eeprom_emulation_handle_t * handle,uint32_t destination))288 AT_QUICKACCESS_SECTION_CODE(uint32_t EE_SyncFlashErase(eeprom_emulation_handle_t *handle, uint32_t destination))
289 {
290     uint32_t dest   = destination;
291     uint32_t result = EE_OK;
292     uint32_t i;
293 
294     destination -= handle->flashStartAddress;
295 
296     while (dest < (destination + handle->eeSectorSize))
297     {
298         /*Clear status*/
299         FMU0->FSTAT = FMU_FSTAT_ACCERR_MASK | FMU_FSTAT_PVIOL_MASK | FMU_FSTAT_CMDABT_MASK;
300 
301         /* load FCCOB registers */
302         FMU0->FCCOB[0] = ERSSCR;
303         FMU0->FCCOB[1] = 0x00U;
304 
305         /*Clear CCIF to launch the command*/
306         FMU0->FSTAT = FMU_FSTAT_CCIF_MASK;
307 
308         /*wait for writes to get enabled*/
309         while (0x00U == (FMU0->FSTAT & FMU_FSTAT_PEWEN_MASK))
310         {
311         }
312 
313         /* writing 4 consecutive words to flash. */
314         for (i = 0; i < 4U; i++)
315         {
316             *((uint32_t *)(dest + i * 4U)) = 0x00U;
317         }
318 
319         while (0x00U == (FMU0->FSTAT & FMU_FSTAT_PERDY_MASK))
320         {
321         }
322 
323         /* Clear PERDY status */
324         FMU0->FSTAT = FMU_FSTAT_PERDY_MASK;
325 
326         /* wait until command complete */
327         while (0x00U == (FMU0->FSTAT & FMU_FSTAT_CCIF_MASK))
328         {
329         }
330 
331         /*check for errors*/
332         if (0x00U != (FMU0->FSTAT & FMU_FSTAT_FAIL_MASK))
333         {
334             result = EE_NOT_OK;
335             break;
336         }
337 
338         dest += handle->flashSectorSize;
339     }
340 
341     /* need to verify section here */
342     if (result != EE_NOT_OK)
343     {
344         result = EE_FlashEraseVerifySection(handle, destination + handle->flashStartAddress,
345                                             (uint16_t)(handle->eeSectorSize / handle->ftfxRD1SECSize),
346                                             handle->flashReadMargin);
347     }
348 
349     return result;
350 }
351 
352 /*******************************************************************************
353  *
354  *  Function Name    : EE_AsyncFlashErase
355  *  Description      : Erase one EE sector in Flash with synchronous model and verify as well
356  *  Arguments        :
357  *                     - destination: the offset address to flash base
358  *  Return Value     : N/A
359  *
360  *******************************************************************************/
361 #if (EE_USE_ASYNCHRONOUS_MODEL == true)
EE_AsyncFlashErase(eeprom_emulation_handle_t * handle,uint32_t destination)362 void EE_AsyncFlashErase(eeprom_emulation_handle_t *handle, uint32_t destination)
363 {
364     destination -= handle->flashStartAddress;
365     /* load FCCOB registers */
366     REG_WRITE(FTFx_FCCOB0, FTFx_ERASE_SECTOR);
367     REG_WRITE(FTFx_FCCOB1, (uint8_t)(destination >> 16u));
368     REG_WRITE(FTFx_FCCOB2, (uint8_t)((destination >> 8u) & 0xFFu));
369     REG_WRITE(FTFx_FCCOB3, (uint8_t)(destination & 0xFFu));
370 
371     /* Update erase status */
372     g_eraseStatusFlag = BUSY;
373     /* clear RDCOLERR & ACCERR & FPVIOL flag in flash status register */
374     /* it is impossible to launch command if any error bit set */
375     REG_WRITE(FTFx_FSTAT, FTFx_FSTAT_CLEAR_ERR);
376     /* clear CCIF bit to start command */
377     REG_WRITE(FTFx_FSTAT, FTFx_FSTAT_CCIF);
378     /* Enable command complete interrupt */
379     REG_BIT_SET(FTFx_FCNFG, FTFx_FCNFG_CCIE);
380 }
381 #endif /* of EE_USE_ASYNCHRONOUS_MODEL*/
382 
383 /*******************************************************************************
384  *
385  *  Function Name    : EE_FlashEraseVerifySection
386  *  Description      : Erase verify Number*FTFx_RD1SEC_SIZE bytes in Flash
387  *  Arguments        :
388  *                     - destination: offset address to pflash base
389  *                     - number: number of verify section aligned unit
390  *                     - marginLevel: margin level used to verify
391  *  Return Value     :
392  *                     - EE_OK if successful
393  *                     - EE_NOT_OK if failed
394  *
395  *******************************************************************************/
AT_QUICKACCESS_SECTION_CODE(uint32_t EE_FlashEraseVerifySection (eeprom_emulation_handle_t * handle,uint32_t destination,uint16_t Number,uint8_t marginLevel))396 AT_QUICKACCESS_SECTION_CODE(uint32_t EE_FlashEraseVerifySection(
397     eeprom_emulation_handle_t *handle, uint32_t destination, uint16_t Number, uint8_t marginLevel))
398 {
399     uint32_t result = EE_OK;
400     uint32_t dest   = destination;
401     uint32_t margin = marginLevel;
402 
403     /* load FCCOB registers */
404     FMU0->FCCOB[0] = RD1SCR;
405     FMU0->FCCOB[1] = margin;
406     FMU0->FCCOB[2] = dest;
407 
408     /*Check if previous command complete, wait for CCIF set */
409     while (0U == (FMU0->FSTAT & FLASH_FSTAT_CCIF_MASK))
410     {
411     }
412 
413     /*Clear status*/
414     FMU0->FSTAT = FMU_FSTAT_ACCERR_MASK | FMU_FSTAT_PVIOL_MASK | FMU_FSTAT_CMDABT_MASK;
415 
416     /*Clear CCIF to launch the command*/
417     FMU0->FSTAT = FMU_FSTAT_CCIF_MASK;
418     while (0U != (FMU0->FSTAT & FLASH_FSTAT_CCIF_MASK))
419     {
420     }
421 
422     /* wait until command complete */
423     while (0U == (FMU0->FSTAT & FMU_FSTAT_CCIF_MASK))
424     {
425     }
426 
427     /*check for errors*/
428     if (0U != (FMU0->FSTAT & FMU_FSTAT_FAIL_MASK))
429     {
430         result = EE_NOT_OK;
431     }
432 
433     return result;
434 }
435 
436 /*******************************************************************************
437  *
438  *  Function Name    : EE_SingleProgram
439  *  Description      : Program 1 programmable size to Flash
440  *  Arguments        :
441  *                     - destination: offset address to flash block base
442  *                     - pData: pointer to point to data to be programmed.
443  *  Return Value     :
444  *                     - EE_OK if successful
445  *                     - EE_NOT_OK if failed
446  *
447  *******************************************************************************/
AT_QUICKACCESS_SECTION_CODE(uint32_t EE_SingleProgram (eeprom_emulation_handle_t * handle,uint32_t destination,uint8_t * pData))448 AT_QUICKACCESS_SECTION_CODE(uint32_t EE_SingleProgram(eeprom_emulation_handle_t *handle,
449                                                       uint32_t destination,
450                                                       uint8_t *pData))
451 {
452     assert(handle != NULL);
453 
454     uint32_t i;
455     uint32_t const *src = (uint32_t const *)(void const *)pData;
456     uint32_t result     = EE_OK;
457 
458     destination -= handle->flashStartAddress;
459 
460     /*Load Program PHR command*/
461     FMU0->FCCOB[0] = PGMPHR;
462 
463     /* Check if previous command complete, wait for CCIF set*/
464     while (0x00U == (FMU0->FSTAT & FLASH_FSTAT_CCIF_MASK))
465     {
466     }
467 
468     /* clear CMDABT & ACCERR & PVIOL flag in flash status register */
469     FMU0->FSTAT = (FLASH_FSTAT_CMDABT_MASK | FLASH_FSTAT_ACCERR_MASK | FLASH_FSTAT_PVIOL_MASK);
470 
471     /* clear ccif */
472     FMU0->FSTAT = FLASH_FSTAT_CCIF_MASK;
473     while (0x00U != (FMU0->FSTAT & FLASH_FSTAT_CCIF_MASK))
474     {
475     }
476 
477     /* program */
478     while (0x00U == (FMU0->FSTAT & FLASH_FSTAT_PEWEN_MASK))
479     {
480     }
481 
482     /* Must be write 4 consecutive words */
483     for (i = 0; i < 4U; i++)
484     {
485         *((uint32_t *)(destination + i * 4U)) = src[i];
486     }
487 
488     while (0x00U == (FMU0->FSTAT & FLASH_FSTAT_PERDY_MASK))
489     {
490     }
491 
492     FMU0->FSTAT = FLASH_FSTAT_PERDY_MASK;
493     while (0x00U != (FMU0->FSTAT & FLASH_FSTAT_PERDY_MASK))
494     {
495     }
496 
497     /* wait for command complete */
498     while (0x00U == (FMU0->FSTAT & FLASH_FSTAT_CCIF_MASK))
499     {
500     }
501 
502     /*check for errors*/
503     if (0x00U != (FMU0->FSTAT & FMU_FSTAT_FAIL_MASK))
504     {
505         result = EE_NOT_OK;
506     }
507 
508     return result;
509 }
510 
511 /*******************************************************************************
512  *
513  *  Function Name    : EE_SingleProgramCheck
514  *  Description      : Program check for 1 program check size in PFlash
515  *  Arguments        :
516  *                     - destination: offset address to pflash block base
517  *                     - pExpectedData: expected data to be verified
518  *                     - margin level: margin level to be verified.
519  *  Return Value     :
520  *                     - EE_OK if successful
521  *                     - EE_NOT_OK if failed
522  *
523  *******************************************************************************/
EE_SingleProgramCheck(eeprom_emulation_handle_t * handle,uint32_t destination,uint8_t * pExpectedData,uint8_t marginLevel)524 uint32_t EE_SingleProgramCheck(eeprom_emulation_handle_t *handle,
525                                uint32_t destination,
526                                uint8_t *pExpectedData,
527                                uint8_t marginLevel)
528 {
529     assert(handle != NULL);
530     assert(pExpectedData != NULL);
531 
532     uint32_t result = EE_OK;
533     uint32_t tmp;
534 
535     destination -= handle->flashStartAddress;
536 
537     tmp = *((uint32_t *)(void *)pExpectedData);
538 
539     if (READ32(destination) != tmp)
540     {
541         result = EE_NOT_OK;
542     }
543 
544     return result;
545 }
546 
547 /*  Disable cache within flash controller */
FLASH_CACHE_Disable(void)548 void FLASH_CACHE_Disable(void)
549 {
550     SMSCM->OCMDR0 = (SMSCM->OCMDR0 & (~SMSCM_CACHE_CLEAR_MASK)) | SMSCM_CACHE_CLEAR(0x1);
551     SMSCM->OCMDR0 = (SMSCM->OCMDR0 & (~SMSCM_CACHE_CLEAR_MASK)) | SMSCM_CACHE_CLEAR(0x8);
552     SMSCM->OCMDR0 = (SMSCM->OCMDR0 & (~SMSCM_SPECULATION_DISABLE_MASK)) | SMSCM_SPECULATION_DISABLE_MASK;
553     __ISB();
554     __DSB();
555 }
556 
557 /*middle*/
558 /*******************************************************************************
559  *
560  *  Function Name    : EE_NextSector
561  *  Description      : This function is used to get address of the next sector in
562  *                     the round-robin sequence
563  *  Arguments        :
564  *                     - addr: address of the current sector
565  *  Return Value     :
566  *                     - address of the next sector
567  *
568  *******************************************************************************/
EE_NextSector(eeprom_emulation_handle_t * handle,uint32_t addr)569 uint32_t EE_NextSector(eeprom_emulation_handle_t *handle, uint32_t addr)
570 {
571     uint32_t nextSectorAddr;
572 
573     if (addr == (g_eeEndAddress - (uint32_t)handle->eeSectorSize))
574     {
575         nextSectorAddr = handle->eeStartAddress;
576     }
577     else
578     {
579         nextSectorAddr = addr + (uint32_t)handle->eeSectorSize;
580     }
581 
582     return nextSectorAddr;
583 }
584 
585 /*******************************************************************************
586  *
587  *  Function Name    : EE_PrevSector
588  *  Description      : This function is used to get address of the previous
589  *                     sector in the round-robin sequence
590  *  Arguments        :
591  *                     - addr: address of the current sector
592  *  Return Value     :
593  *                     - address of the next sector
594  *
595  *******************************************************************************/
EE_PrevSector(eeprom_emulation_handle_t * handle,uint32_t addr)596 uint32_t EE_PrevSector(eeprom_emulation_handle_t *handle, uint32_t addr)
597 {
598     uint32_t prevSectorAddr;
599 
600     if (addr == handle->eeStartAddress)
601     {
602         prevSectorAddr = g_eeEndAddress - handle->eeSectorSize;
603     }
604     else
605     {
606         prevSectorAddr = addr - handle->eeSectorSize;
607     }
608 
609     return prevSectorAddr;
610 }
611 
612 /*******************************************************************************
613  *
614  *  Function Name    : EE_VerifyRecordStatus
615  *  Description      : This function is to verify the record status.
616  *  Arguments        :
617  *                     - dest: destination point to record status.
618  *                     - expData: the expected data at record status location.
619  *  Return Value     :
620  *                     - EE_OK if successful
621  *                     - EE_NOT_OK if failed
622  *
623  *******************************************************************************/
EE_VerifyRecordStatus(eeprom_emulation_handle_t * handle,uint32_t dest,uint32_t expData)624 uint32_t EE_VerifyRecordStatus(eeprom_emulation_handle_t *handle, uint32_t dest, uint32_t expData)
625 {
626     uint32_t programCheckSize = handle->ftfxPGMCheckSize;
627 
628     if (handle->ftfxProgramSize != FTFx_LONGWORD_SIZE)
629     {
630         dest = (dest / programCheckSize) * programCheckSize;
631         return (EE_SingleProgramCheck(handle, dest, (uint8_t *)&expData, handle->flashReadMargin));
632     }
633     else
634     {
635         uint32_t returnCode = EE_OK;
636         if ((uint16_t)(expData >> 16u) != READ16(dest))
637         {
638             returnCode = EE_NOT_OK;
639         }
640         return (returnCode);
641     }
642 }
643 
644 /*******************************************************************************
645  *
646  *  Function Name    : EE_VerifySectorHeader
647  *  Description      : This function is to verify the data in sector header.
648  *  Arguments        :
649  *                     - dest: destination need to verify.
650  *                     - expData: the expected data at destination.
651  *  Return Value     :
652  *                     - EE_OK if successful
653  *                     - EE_NOT_OK if failed
654  *
655  *******************************************************************************/
EE_VerifySectorHeader(eeprom_emulation_handle_t * handle,uint32_t dest,uint32_t expData)656 uint32_t EE_VerifySectorHeader(eeprom_emulation_handle_t *handle, uint32_t dest, uint32_t expData)
657 {
658     return (EE_SingleProgramCheck(handle, dest, (uint8_t *)&expData, handle->flashReadMargin));
659 }
660 
661 /*******************************************************************************
662  *
663  *  Function Name    : EE_MultiProgram
664  *  Description      : This function will program a range of contiguous Flash
665  *                     locations (multiple programmable size) and verify them.
666  *  Arguments        :
667  *                     - dest: destination to program
668  *                     - size: size to be programmed
669  *                     - pData: source data
670  *  Return Value     :
671  *                     - EE_OK if successful
672  *                     - EE_NOT_OK if failed
673  *
674  *******************************************************************************/
EE_MultiProgram(eeprom_emulation_handle_t * handle,uint32_t dest,uint32_t size,uint8_t * pData)675 uint32_t EE_MultiProgram(eeprom_emulation_handle_t *handle, uint32_t dest, uint32_t size, uint8_t *pData)
676 {
677     /* Declaration of the local variables */
678     uint32_t returnCode  = EE_OK;
679     uint32_t programSize = handle->ftfxProgramSize;
680     uint8_t *pPtr;
681     pPtr = pData;
682 
683     while ((size > 0x00u) && (returnCode == EE_OK))
684     {
685         /* PFlashProgram function called */
686         returnCode = EE_SingleProgram(handle, dest, pPtr);
687 
688         dest += programSize;
689         size -= programSize;
690         pPtr += programSize;
691     }
692     return (returnCode);
693 }
694 
695 /*******************************************************************************
696  *
697  *  Function Name    : EE_CopyRecord
698  *  Description      : writes user data into Flash in a record format to
699  *                     g_freeSpaceAddress.
700  *  Arguments        :
701  *                     - dataRecord: store record addr and record ID need to be
702  *                       copied.
703  *                     - remainData: the buffer to store remaining data in case
704  *                       of writing new record. In case swapping, this input
705  *                       must be 0xFFFFFFFF.
706  *  Return Value     :
707  *                     - EE_OK if successful
708  *                     - EE_NOT_OK if failed
709  *
710  *******************************************************************************/
EE_CopyRecord(eeprom_emulation_handle_t * handle,eeprom_emulation_data_record_t dataRecord,uint8_t remainData[])711 uint32_t EE_CopyRecord(eeprom_emulation_handle_t *handle,
712                        eeprom_emulation_data_record_t dataRecord,
713                        uint8_t remainData[])
714 {
715     uint32_t returnCode = EE_OK;
716     uint32_t alginedSize;
717     uint32_t remainingSize;
718     uint32_t address = dataRecord.dataAddr;
719 
720     /*Calculate data value aligned part and remaining part */
721     alginedSize   = handle->eeDataValueSize - (handle->eeDataValueSize % handle->ftfxProgramSize);
722     remainingSize = handle->eeSectorRecordLength - alginedSize - handle->ftfxProgramSize - handle->complementSize;
723 
724     /* when writing new data, source data is in ram, so it is word address */
725     if (remainData == (uint8_t *)0xFFFFFFFFu) /* copy data */
726     {
727         alginedSize = handle->eeSectorRecordLength;
728         /* when copy data, source address is in flash, so it is byte address */
729         address = dataRecord.dataAddr;
730     }
731     /* for swapping, entire record is written within EE_MultiProgram*/
732     /* for writing new data, need to write aligned part first, and then write remaining data, and then write status*/
733     returnCode = EE_MultiProgram(handle, g_freeSpaceAddress, alginedSize, (uint8_t *)address);
734     if (remainData != (uint8_t *)0xFFFFFFFFu) /* write new data, need to program ID and over-program status*/
735     {
736         /* remaining data including ID*/
737         if (returnCode == EE_OK)
738         {
739             returnCode = EE_MultiProgram(handle, g_freeSpaceAddress + alginedSize + handle->ftfxProgramSize,
740                                          handle->ftfxProgramSize, remainData);
741         }
742 
743         /* 0xFF setting. */
744         remainData[(uint8_t)remainingSize - 0x01U] = 0xFF;
745         remainData[(uint8_t)remainingSize - 0x02U] = 0xFF;
746 
747         /*and then program status*/
748         if (returnCode == EE_OK)
749         {
750             remainData[(uint8_t)remainingSize - 0x02u] = (uint8_t)((uint16_t)EE_RECORD_STATUS_VALID & 0x00FFu);
751             remainData[(uint8_t)remainingSize - 0x01u] = (uint8_t)((uint16_t)EE_RECORD_STATUS_VALID >> 0x08u);
752             returnCode = EE_MultiProgram(handle, g_freeSpaceAddress + alginedSize, handle->ftfxProgramSize, remainData);
753         }
754     }
755 #if EE_CACHETABLE_ENABLE
756     if (returnCode == EE_OK)
757     {
758         /* this record is written successful, so update cache table */
759         /* Check if the ID is a cache table entry */
760         if (EE_CACHETABLE_MAX_ENTRY >= dataRecord.dataID)
761         {
762             /* Update the cache table item with new value */
763             WRITE32(EE_CACHETABLE_ITEM_ADDR(dataRecord.dataID), g_freeSpaceAddress);
764         }
765     }
766 #endif
767     g_freeSpaceAddress += handle->eeSectorRecordLength;
768     return (returnCode);
769 }
770 
771 /*******************************************************************************
772 *
773 *  Function Name    : EE_SwapSector
774 *  Description      : Swaps the contents of the oldest active sector to
775                       the new sector
776 *  Arguments        : N/A
777 *  Return Value     :
778 *                     - EE_OK if successful
779 *                     - EE_NOT_OK if failed in erase oldest active sector
780 *                     - EE_ERR_UPDATE fail when copy records swapping
781 *
782 *******************************************************************************/
EE_SwapSector(eeprom_emulation_handle_t * handle)783 uint32_t EE_SwapSector(eeprom_emulation_handle_t *handle)
784 {
785     eeprom_emulation_data_record_t dataRecord;
786     uint32_t oldSectorAddress;
787     uint32_t newActSectorAddr;
788     uint32_t bk_currentActiveSector;
789     uint32_t recordAddress;
790     uint32_t recFoundAddress;
791     const uint32_t dataSource = 0xFFFFFFFFu; /* Used to indicate swapping while copying data */
792     uint32_t returnCode       = EE_OK;
793     uint32_t blankCheck;
794     uint32_t aliveCheck;
795     uint16_t dataID;
796 
797     /* backup current active sector for later usage*/
798     bk_currentActiveSector = g_currentActiveSector;
799     newActSectorAddr       = g_currentActiveSector;
800 
801     /* The first Alternative or ready sector after the current active sector is the sector
802     used for update. At this time, next sector can be Dead, ready or alternative only.
803     So, need to check if next sector is not DEAD, it means this sector is ready or alternative*/
804     do
805     {
806         newActSectorAddr = EE_NextSector(handle, newActSectorAddr);
807         blankCheck       = EE_VerifySectorHeader(handle, newActSectorAddr + handle->eeSectorDeadIndOffset,
808                                            (uint32_t)EE_DATA_STATUS_BLANK);
809         aliveCheck       = EE_VerifySectorHeader(handle, newActSectorAddr + handle->eeSectorDeadIndOffset,
810                                            (uint32_t)EE_DATA_STATUS_ALIVE);
811     } while ((EE_OK != blankCheck) && (EE_OK != aliveCheck));
812 
813     g_freeSpaceAddress = newActSectorAddr + (uint32_t)handle->eeSectorHeaderSize;
814     /* At this time, sure new sector is active one, so need to update g_currentActiveSector to this sector */
815     g_currentActiveSector = newActSectorAddr;
816 
817     /* find the oldest active sector */
818     oldSectorAddress = EE_FindActSector(handle, handle->eeStartAddress, false, false);
819     /* point to last record in oldest active sector */
820     recordAddress = oldSectorAddress + handle->eeSectorSize - handle->eeSectorWaste - handle->eeSectorRecordLength;
821 
822     /* Decrement copy */
823     while (recordAddress >= (oldSectorAddress + handle->eeSectorHeaderSize))
824     {
825         /* only read record ID if record status is VALID*/
826         if (EE_OK == EE_VerifyRecordStatus(handle, recordAddress + handle->eeRecordStatusOffset,
827                                            (((uint32_t)(EE_RECORD_STATUS_VALID) << 16u) | 0x0000FFFFu)))
828         {
829             dataID = READ16(recordAddress + handle->eeRecordIDOffset);
830 
831             /* search this ID in all active sectors from bottom up and from newest to oldest one */
832             recFoundAddress = EE_SearchLoop(handle, dataID);
833             /* Means this is latest ID, which is only one in all sectors, and no rewrite it
834                again with new data at this same daia-id , and need to copy it */
835             if (recFoundAddress == recordAddress)
836             {
837                 /* copy this ID to new sector */
838                 dataRecord.dataID   = dataID;
839                 dataRecord.dataAddr = recFoundAddress;
840                 /* Means This unique data-ID is the same as the data-ID to be written, ignore rewrite */
841                 if (dataRecord.dataID == g_dataRecord.dataID)
842                 {
843                     recordAddress -= handle->eeSectorRecordLength;
844                     continue;
845                 }
846 
847                 returnCode = EE_CopyRecord(handle, dataRecord, (uint8_t *)dataSource);
848                 if (returnCode != EE_OK)
849                 {
850                     returnCode = EE_ERR_UPDATE;
851                     break;
852                 }
853             }
854         }
855         /* point to next record */
856         recordAddress -= handle->eeSectorRecordLength;
857     }
858 
859     /* finish copying */
860     /* make new sector as active */
861     if (returnCode == EE_OK)
862     {
863         returnCode = EE_ValidateActIndicator(handle, newActSectorAddr);
864         if (returnCode != EE_OK)
865         {
866             returnCode = EE_ERR_UPDATE;
867         }
868     }
869     else
870     {
871         g_currentActiveSector = bk_currentActiveSector;
872         g_freeSpaceAddress    = g_currentActiveSector + handle->eeSectorSize - handle->eeSectorWaste;
873 /* update cache table to restore the address of all ID like before copying */
874 #if (EE_CACHETABLE_ENABLE == true)
875         EE_UpdateCacheTable(handle);
876 #endif
877     }
878 
879     if (returnCode == EE_OK)
880     {
881         /* At this time, new sector is already be active successfully*/
882         /* backup erase cycle of old active sector */
883         g_eraseCycles[0] = READ32(oldSectorAddress + handle->eeSectorEraseCycleOffset);
884         if (g_eraseCycles[0] != (uint32_t)EE_MAX_ERASING_CYCLE_VALUE)
885         {
886             /* increase erase cycle if it is not maximum value */
887             g_eraseCycles[0]++;
888         }
889 /* synchronous model */
890 #if (EE_USE_ASYNCHRONOUS_MODEL != true)
891         /* erase the old active sector. */
892         returnCode = EE_ReEraseEeprom(handle, oldSectorAddress);
893         if (returnCode == EE_OK)
894         {
895             /* only program erase cycle if validate sector successfully and this is not dead sector */
896             returnCode = EE_ValidateEraseCycle(handle, oldSectorAddress, (uint8_t *)&g_eraseCycles);
897             if (returnCode != EE_OK)
898             {
899                 returnCode = EE_CheckAvailabilityStatus(handle);
900             }
901         }
902         if (returnCode == EE_MAKEDEAD_OK)
903         {
904             returnCode = EE_CheckAvailabilityStatus(handle);
905         }
906 
907 #else /* asynchronous model */
908         g_addressToMain    = oldSectorAddress; /* initialize g_addressToMain variable */
909         g_endAddressToMain = oldSectorAddress + handle->eeSectorSize;
910         EE_AsyncFlashErase(handle, g_addressToMain);
911 #endif
912     }
913     return (returnCode);
914 }
915 
916 /*******************************************************************************
917  *
918  *  Function Name    : EE_SearchInSector
919  *  Description      : Searches the latest record in given sector.
920  *  Arguments        :
921  *                     - dataID: expected ID to search
922  *                     - sectorAddress: start address of sector to be searched
923  *  Return Value     :
924  *                     - address of found record
925  *                     - 0xFFFFFFFF If not found
926  *
927  *******************************************************************************/
EE_SearchInSector(eeprom_emulation_handle_t * handle,uint16_t expID,uint32_t sectorAddress)928 uint32_t EE_SearchInSector(eeprom_emulation_handle_t *handle, uint16_t expID, uint32_t sectorAddress)
929 {
930     uint32_t returnCode = 0xFFFFFFFFu;
931     uint32_t recordAddress;
932 #if EE_CALLBACK_ENABLE
933     uint32_t counter = 0x00u;
934 #endif
935 
936     if (sectorAddress == g_currentActiveSector)
937     {
938         /* point to last record of current active sector */
939         recordAddress = g_freeSpaceAddress;
940     }
941     else
942     {
943         /* point to end of sector if this is not current active sector because it is full of data */
944         recordAddress = sectorAddress + handle->eeSectorSize - handle->eeSectorWaste;
945     }
946     /* point to beginning of the first record */
947     sectorAddress += handle->eeSectorHeaderSize;
948     /* Search all the records of the sector */
949     do
950     {
951         /* Decrement recordAddress by EE_RECORD_LENGTH to point to next record*/
952         recordAddress -= handle->eeSectorRecordLength;
953         /* verify if record status is valid */
954         if (EE_OK == EE_VerifyRecordStatus(handle, recordAddress + handle->eeRecordStatusOffset,
955                                            (((uint32_t)(EE_RECORD_STATUS_VALID) << 16u) | 0x0000FFFFu)))
956         {
957             /* read record ID */
958             if (expID == READ16(recordAddress + handle->eeRecordIDOffset))
959             {
960                 returnCode = recordAddress;
961                 break;
962             }
963         }
964         /* If CallBack is enabled, then serve callback function if counter reaches limitation */
965 #if EE_CALLBACK_ENABLE
966         /* Check if need to serve callback function */
967         counter++;
968         if (counter >= (uint32_t)EE_CALLBACK_COUNTER)
969         {
970             g_EECallBack();
971             /* Reset counter */
972             counter = 0x00u;
973         }
974 #endif
975     } while (recordAddress > sectorAddress);
976     return (returnCode);
977 }
978 
979 /*******************************************************************************
980  *
981  *  Function Name    : EE_SearchBlankSpace
982  *  Description      : To find blank space for each sector
983  *  Arguments        :
984  *                     - sectorAddress: start address of sector to find blank space.
985  *  Return Value     :
986  *                     - blank space of this sector
987  *
988  *******************************************************************************/
EE_SearchBlankSpace(eeprom_emulation_handle_t * handle,uint32_t sectorAddress)989 uint32_t EE_SearchBlankSpace(eeprom_emulation_handle_t *handle, uint32_t sectorAddress)
990 {
991     uint32_t searchAddress;
992 #if EE_CALLBACK_ENABLE
993     uint32_t counter = 0x00u;
994 #endif
995     /* flag to indicate this record is blank or not */
996     bool blankFlag;
997     /* backup blank flag. Initilize it as true to handle with the first search is non blanked record */
998     bool bkBlankFlag = true;
999 
1000     /* point to the beginning of each record. Start with the last record within each sector */
1001     searchAddress = sectorAddress + handle->eeSectorSize - handle->eeSectorWaste;
1002     /* point to beginning of the first record */
1003     sectorAddress += (uint32_t)handle->eeSectorHeaderSize;
1004     /* Search all the records of the sector */
1005     do
1006     {
1007         /* Decrement searchAddress by EE_RECORD_LENGTH */
1008         searchAddress -= handle->eeSectorRecordLength;
1009         /* Do blank check for every record length from bottom up*/
1010         if (EE_OK == EE_BlankCheck(handle, searchAddress, handle->eeSectorRecordLength))
1011         {
1012             blankFlag = true; /* this record is blanked */
1013         }
1014         else /* this record is not blank */
1015         {
1016             if (bkBlankFlag == true) /* and the next record is blank */
1017             {
1018                 /* point to blank space */
1019                 searchAddress = searchAddress + handle->eeSectorRecordLength;
1020                 break;
1021             }
1022         }
1023 
1024         /* backup dataID for the next search */
1025         bkBlankFlag = blankFlag;
1026 
1027         /* If CallBack is enabled, then serve callback function if counter reaches limitation */
1028 #if EE_CALLBACK_ENABLE
1029         /* Check if need to serve callback function */
1030         counter++;
1031 
1032         if (counter >= (uint32_t)EE_CALLBACK_COUNTER)
1033         {
1034             g_EECallBack();
1035             /* Reset counter */
1036             counter = 0x00u;
1037         }
1038 #endif
1039     } while (searchAddress > sectorAddress);
1040 
1041     return (searchAddress);
1042 }
1043 
1044 /*******************************************************************************
1045  *
1046  *  Function Name    : EE_SearchInCache
1047  *  Description      : Searches record with a specific record ID in cache table
1048  *  Arguments        :
1049  *                     - dataID: the ID required to search
1050  *  Return Value     :
1051  *                     - address of found record
1052  *                     - 0xFFFFFFFF If not found
1053  *
1054  *******************************************************************************/
1055 #if EE_CACHETABLE_ENABLE
EE_SearchInCache(uint16_t dataID)1056 uint32_t EE_SearchInCache(uint16_t dataID)
1057 {
1058     uint32_t returnCode = 0xFFFFFFFFu;
1059     /* Check if the DataID is in the cache table */
1060     if (EE_CACHETABLE_MAX_ENTRY >= dataID)
1061     {
1062         returnCode = READ32(EE_CACHETABLE_ITEM_ADDR(dataID));
1063     }
1064     return (returnCode); /* not found return 0xFFFFFFFFu */
1065 }
1066 #endif
1067 
1068 /*******************************************************************************
1069  *
1070  *  Function Name    : EE_SearchInAllActive
1071  *  Description      : Searches record with a specific record ID in all
1072  *                     active sector from bottom up and from newest to oldest
1073  *                     active sector. Don't search in cache table.
1074  *  Arguments        :
1075  *                     - dataID is the expected ID to be searched.
1076  *  Return Value     :
1077  *                     - address of found record
1078  *                     - 0xFFFFFFFF If not found
1079  *
1080  *******************************************************************************/
EE_SearchInAllActives(eeprom_emulation_handle_t * handle,uint16_t dataID)1081 uint32_t EE_SearchInAllActives(eeprom_emulation_handle_t *handle, uint16_t dataID)
1082 {
1083     uint32_t sectorAddress = g_currentActiveSector;
1084     uint32_t recordAddress;
1085     uint32_t returnCode = 0xFFFFFFFFu;
1086     uint8_t actNum;
1087     actNum = (uint8_t)handle->eeActiveSectors;
1088     /* Search in the ACTIVE sectors only. Start with current active sector */
1089     do
1090     {
1091         /* only search in the active sector, ignore alt, ready and dead sectors */
1092         if (EE_SECTOR_ACTIVE == EE_GetSectorStatus(handle, sectorAddress))
1093         {
1094             actNum--;
1095             recordAddress = EE_SearchInSector(handle, dataID, sectorAddress);
1096             if (recordAddress != 0xFFFFFFFFu)
1097             {
1098                 /* break if found the expected ID */
1099                 returnCode = recordAddress;
1100                 break;
1101             }
1102         }
1103         /* search the previous sector */
1104         sectorAddress = EE_PrevSector(handle, sectorAddress);
1105     } while (actNum > 0x00u);
1106     return (returnCode); /* not found return 0xFFFFFFFFu */
1107 }
1108 
1109 /*******************************************************************************
1110  *
1111  *  Function Name    : EE_SearchLoop
1112  *  Description      : Searches record with a specific record ID in cache table
1113  *                     first. If not found in cache, continue to search in all
1114  *                     active sectors from newest to oldest and from bottom to
1115  *                     top.
1116  *  Arguments        :
1117  *                     - dataID: required ID to be searched.
1118  *  Return Value     :
1119  *                     - address of found record
1120  *                     - 0xFFFFFFFF If not found
1121  *
1122  *******************************************************************************/
EE_SearchLoop(eeprom_emulation_handle_t * handle,uint16_t dataID)1123 uint32_t EE_SearchLoop(eeprom_emulation_handle_t *handle, uint16_t dataID)
1124 {
1125     uint32_t recordAddress = 0xFFFFFFFFu;
1126     /* Check if cache table is enabled and data is in valid range of cache, search in cache first */
1127 #if EE_CACHETABLE_ENABLE
1128     if (dataID <= (uint16_t)EE_CACHETABLE_MAX_ENTRY)
1129     {
1130         recordAddress = EE_SearchInCache(dataID);
1131         return recordAddress;
1132     }
1133 #endif
1134 
1135 #if EE_CACHETABLE_ENABLE
1136     if (dataID > (uint16_t)EE_CACHETABLE_MAX_ENTRY)
1137     {
1138 #endif
1139         /* ID is not in the cache table, need to search in all active sectors */
1140         recordAddress = EE_SearchInAllActives(handle, dataID);
1141 #if EE_CACHETABLE_ENABLE
1142     }
1143 #endif
1144 
1145     return recordAddress;
1146 }
1147 
1148 /*******************************************************************************
1149  *
1150  *  Function Name    : EE_BlankCheck
1151  *  Description      : Do blank check for a specific flash range.
1152  *  Arguments        :
1153  *                     - address: address needs to do blank check.
1154  *                     - size: size to do blank check.
1155  *  Return Value     :
1156  *                     - EE_OK if successful
1157  *                     - EE_NOT_OK if failed
1158  *
1159  *******************************************************************************/
EE_BlankCheck(eeprom_emulation_handle_t * handle,uint32_t address,uint32_t size)1160 uint32_t EE_BlankCheck(eeprom_emulation_handle_t *handle, uint32_t address, uint32_t size)
1161 {
1162     uint32_t returnCode      = EE_OK;
1163     uint32_t read1SectorSize = handle->ftfxRD1SECSize;
1164 
1165     while ((size > 0x00u) && (returnCode == EE_OK))
1166     {
1167         if ((GET_MOD(address, read1SectorSize) != 0x00u) || (size < read1SectorSize))
1168         {
1169             /* blank check by READ32 if address is not aligned or size < FTFx_RD1SEC_SIZE*/
1170             returnCode = EE_VerifySectorHeader(handle, address, 0xFFFFFFFFu);
1171             if (returnCode == EE_OK)
1172             {
1173                 address += FTFx_LONGWORD_SIZE;
1174                 size -= FTFx_LONGWORD_SIZE;
1175             }
1176             else
1177             {
1178                 returnCode = EE_NOT_OK;
1179             }
1180         }
1181         else
1182         {
1183             /* blank check by verify section if address is aligned
1184             and size is larger than 1 RD1PHR aligned size*/
1185             returnCode = EE_FlashEraseVerifySection(handle, address, (uint16_t)(size / read1SectorSize),
1186                                                     handle->flashReadMargin);
1187             if (returnCode == EE_OK)
1188             {
1189                 /* if erase verify section returns OK, mean entire sector is blank*/
1190                 address += (size / read1SectorSize) * read1SectorSize;
1191                 size -= (size / read1SectorSize) * read1SectorSize;
1192             }
1193             else
1194             {
1195                 returnCode = EE_NOT_OK;
1196             }
1197         }
1198     }
1199     return (returnCode);
1200 }
1201 
1202 /*******************************************************************************
1203  *
1204  *  Function Name    : EE_GetSectorStatus
1205  *  Description      : This function returns the status of the sector by ignoring
1206  *                     the validation of erase cycle value.
1207  *  Arguments        :
1208  *                     - sectorAddress: start address of sector
1209  *  Return Value     :
1210  *                     - status of sector
1211  *
1212  *******************************************************************************/
EE_GetSectorStatus(eeprom_emulation_handle_t * handle,uint32_t sectorAddress)1213 uint8_t EE_GetSectorStatus(eeprom_emulation_handle_t *handle, uint32_t sectorAddress)
1214 {
1215     uint8_t returnCode    = 0x00u;
1216     uint32_t deadIndValue = 0x00u; /* data in dead indicator */
1217     uint32_t actIndValue  = 0x00u; /* data in active indicator */
1218 
1219     if (EE_VerifySectorHeader(handle, sectorAddress + handle->eeSectorDeadIndOffset, EE_DATA_STATUS_BLANK) == EE_OK)
1220     {
1221         deadIndValue = (uint32_t)EE_DATA_STATUS_BLANK;
1222     }
1223     if (EE_VerifySectorHeader(handle, sectorAddress + handle->eeSectorActIndOffset, EE_DATA_STATUS_BLANK) == EE_OK)
1224     {
1225         actIndValue = (uint32_t)EE_DATA_STATUS_BLANK;
1226     }
1227 
1228     if (deadIndValue != (uint32_t)EE_DATA_STATUS_BLANK)
1229     {
1230         /* if dead indicator is not blank or alive, this is dead sector */
1231         returnCode = EE_SECTOR_DEAD;
1232     }
1233     if (returnCode != EE_SECTOR_DEAD)
1234     {
1235         if (actIndValue != EE_DATA_STATUS_BLANK)
1236         {
1237             if (EE_VerifySectorHeader(handle, sectorAddress + handle->eeSectorEraseCycleOffset, 0xFFFFFFFFu) != EE_OK)
1238             {
1239                 returnCode = EE_SECTOR_ACTIVE;
1240             }
1241             else
1242             {
1243                 returnCode = EE_SECTOR_INVALID;
1244             }
1245         }
1246         else
1247         {
1248             /* From now on, active indicator is blank,
1249             dead indicator is blank or alive,
1250             sector area exclusive sector header is blank.*/
1251             if (EE_VerifySectorHeader(handle, sectorAddress + handle->eeSectorEraseCycleOffset, 0xFFFFFFFFu) != EE_OK)
1252             {
1253                 if (EE_BlankCheck(handle, sectorAddress + (uint32_t)handle->eeSectorHeaderSize,
1254                                   handle->eeSectorSize - handle->eeSectorHeaderSize) == EE_OK)
1255                 {
1256                     /* at this time, have data in erase cycle location, active indicator is blank
1257                     dead indicator is blank or alive*/
1258                     /* if dead indicator is blank, this sector is alternative */
1259                     returnCode = EE_SECTOR_ALTERNATIVE;
1260                 }
1261                 else
1262                 {
1263                     returnCode = EE_SECTOR_INVALID;
1264                 }
1265             }
1266             /*At this time, active indicator is blank,
1267             dead indicator is blank or alive,
1268             no data in erase cycle,
1269             sector area exclusive sector header is blank*/
1270             else
1271             {
1272                 if (EE_BlankCheck(handle, sectorAddress + (uint32_t)handle->eeSectorHeaderSize,
1273                                   handle->eeSectorSize - handle->eeSectorHeaderSize) == EE_OK)
1274                 {
1275                     /* at this time, have data in erase cycle location, active indicator is blank
1276                     dead indicator is blank or alive*/
1277                     /* if dead indicator is blank, this sector is alternative */
1278                     returnCode = EE_SECTOR_BLANK;
1279                 }
1280                 else
1281                 {
1282                     returnCode = EE_SECTOR_INVALID;
1283                 }
1284             }
1285         }
1286     }
1287 
1288     return (returnCode);
1289 }
1290 
1291 /*******************************************************************************
1292  *
1293  *  Function Name    : EE_FindActSector
1294  *  Description      : This function will find the oldest/newest or active
1295  *                     sectors according to closestFlag flag.
1296  *  Arguments        : - sectorAddress: current sector address.
1297  *                     - closestFlag: flag to find the closest (true) active
1298  *                       sector or most far (false) sector.
1299  *                     - nextFlag: flag to find the active sector in the
1300  *                       right (true) or in the left (false).
1301  *  Return Value     :
1302  *                     - address of found record
1303  *                     - 0xFFFFFFFF If not found
1304  *
1305  *******************************************************************************/
EE_FindActSector(eeprom_emulation_handle_t * handle,uint32_t sectorAddress,bool closestFlag,bool nextFlag)1306 uint32_t EE_FindActSector(eeprom_emulation_handle_t *handle, uint32_t sectorAddress, bool closestFlag, bool nextFlag)
1307 {
1308     uint32_t returnCode = 0xFFFFFFFFu;
1309     uint32_t i;
1310     uint8_t sectorStatus;
1311 
1312     for (i = 0x00u; i < handle->eeAllotedSectors; i++)
1313     {
1314         if (nextFlag == true)
1315         {
1316             sectorAddress = EE_NextSector(handle, sectorAddress);
1317         }
1318         else
1319         {
1320             sectorAddress = EE_PrevSector(handle, sectorAddress);
1321         }
1322         sectorStatus = EE_GetSectorStatus(handle, sectorAddress);
1323         if ((EE_SECTOR_ACTIVE == sectorStatus) ||
1324             ((EE_SECTOR_ALTERNATIVE == sectorStatus) && (returnCode != 0xFFFFFFFFu)))
1325         {
1326             if (closestFlag == true)
1327             {
1328                 returnCode = sectorAddress;
1329             }
1330             else
1331             {
1332                 if (EE_SECTOR_ACTIVE == sectorStatus)
1333                 {
1334                     returnCode = sectorAddress;
1335                 }
1336                 else
1337                 {
1338                     i = handle->eeAllotedSectors;
1339                 }
1340             }
1341         }
1342     }
1343     return (returnCode);
1344 }
1345 
1346 /*******************************************************************************
1347  *
1348  *  Function Name    : EE_GetSectorNumber
1349  *  Description      : This function will calculate sector number based on its
1350  *                     state.
1351  *  Arguments        :
1352  *                     - expStatus: expected status to accumulate sector number
1353  *  Return Value     :
1354  *                     - total number of sector for expected status
1355  *
1356  *******************************************************************************/
EE_GetSectorNumber(eeprom_emulation_handle_t * handle,uint8_t expStatus)1357 uint8_t EE_GetSectorNumber(eeprom_emulation_handle_t *handle, uint8_t expStatus)
1358 {
1359     uint32_t sectorAddress;
1360     uint8_t sectorStatus;
1361     uint8_t cnt = 0x00u;
1362     uint8_t i;
1363     /* initialize value for pNum*/
1364     sectorAddress = handle->eeStartAddress;
1365     for (i = 0x00u; i < handle->eeAllotedSectors; i++)
1366     {
1367         sectorStatus = EE_GetSectorStatus(handle, sectorAddress);
1368         if (sectorStatus == expStatus)
1369         {
1370             cnt++;
1371         }
1372         /* sectorAddress += handle->eeSectorSize */
1373         sectorAddress = EE_NextSector(handle, sectorAddress);
1374     }
1375     return (cnt);
1376 }
1377 
1378 /*******************************************************************************
1379  *
1380  *  Function Name    : EE_ValidateDeadIndicator
1381  *  Description      : This function is to make a sector as DEAD
1382  *  Arguments        :
1383  *                     - sectorAddress: address of sector
1384  *  Return Value     :
1385  *                     - EE_OK if successful
1386  *                     - EE_NOT_OK if failed
1387  *
1388  *******************************************************************************/
EE_ValidateDeadIndicator(eeprom_emulation_handle_t * handle,uint32_t sectorAddress)1389 uint32_t EE_ValidateDeadIndicator(eeprom_emulation_handle_t *handle, uint32_t sectorAddress)
1390 {
1391     uint32_t returnCode = EE_OK;
1392     uint32_t data[2];
1393     uint8_t num = 0x00u;
1394     data[0]     = (uint32_t)EE_DATA_STATUS_DEAD;
1395     if (handle->ftfxProgramSize > FTFx_LONGWORD_SIZE)
1396     {
1397         data[1] = 0xFFFFFFFFu;
1398     }
1399     sectorAddress += (uint32_t)handle->eeSectorDeadIndOffset;
1400     do
1401     {
1402         returnCode = EE_MultiProgram(handle, sectorAddress, handle->ftfxProgramSize, (uint8_t *)&data);
1403         /* verify again */
1404         /* point to dead indicator address */
1405         if (EE_OK == EE_VerifySectorHeader(handle, sectorAddress, (uint32_t)EE_DATA_STATUS_BLANK))
1406         {
1407             num++;
1408             /* if after making this as DEAD but the data is still BLANK or ALIVE
1409             it means validate fails*/
1410             if (num > handle->eeRetryMax)
1411             {
1412                 returnCode = EE_NOT_OK;
1413             }
1414         }
1415         else
1416         {
1417             returnCode = EE_OK;
1418         }
1419     } while ((returnCode != EE_OK) && (num <= handle->eeRetryMax));
1420     return (returnCode);
1421 }
1422 /*******************************************************************************
1423  *
1424  *  Function Name    : EE_ValidateEraseCycle
1425  *  Description      : This function will program erase cycle.
1426  *                     If possible, it will make this sector as DEAD if fails in
1427  *                     programming.
1428  *  Arguments        :
1429  *                     - sectorAddress: address of invalid sector
1430  *                     - pData: pointer for expected erase cycle value
1431  *  Return Value     :
1432  *                     - EE_OK if successful
1433  *                     - EE_NOT_OK if failed
1434  *
1435  *******************************************************************************/
EE_ValidateEraseCycle(eeprom_emulation_handle_t * handle,uint32_t sectorAddress,uint8_t * pData)1436 uint32_t EE_ValidateEraseCycle(eeprom_emulation_handle_t *handle, uint32_t sectorAddress, uint8_t *pData)
1437 {
1438     uint32_t returnCode = EE_OK;
1439     uint32_t ret        = EE_OK;
1440     uint8_t num         = 0x00u;
1441 
1442     do
1443     {
1444         returnCode =
1445             EE_MultiProgram(handle, sectorAddress + handle->eeSectorEraseCycleOffset, handle->ftfxProgramSize, pData);
1446         if (returnCode != EE_OK)
1447         {
1448             ret = EE_ReEraseEeprom(handle, sectorAddress);
1449             if (ret != EE_OK)
1450             {
1451                 returnCode = ret;
1452                 break;
1453             }
1454             else
1455             {
1456                 num++;
1457                 if (num > handle->eeRetryMax)
1458                 {
1459                     returnCode = EE_ValidateDeadIndicator(handle, sectorAddress);
1460                     if (returnCode == EE_OK)
1461                     {
1462                         returnCode = EE_MAKEDEAD_OK;
1463                     }
1464                 }
1465             }
1466         }
1467     } while ((returnCode != EE_OK) && (num <= handle->eeRetryMax));
1468     return (returnCode);
1469 }
1470 /*******************************************************************************
1471  *
1472  *  Function Name    : EE_ValidateActIndicator
1473  *  Description      : This function will program data to active indicator.
1474  *                     If possible, it will make this sector as DEAD if fails in
1475  *                     programming.
1476  *  Arguments        :
1477  *                     - sectorAddress: address sector
1478  *                     - deadNum: current number of dead sector
1479  *  Return Value     :
1480  *                     - EE_OK if successful
1481  *                     - EE_NOT_OK if failed
1482  *
1483  *******************************************************************************/
EE_ValidateActIndicator(eeprom_emulation_handle_t * handle,uint32_t sectorAddress)1484 uint32_t EE_ValidateActIndicator(eeprom_emulation_handle_t *handle, uint32_t sectorAddress)
1485 {
1486     uint32_t returnCode = EE_OK;
1487     uint32_t ret        = EE_OK;
1488 #if (defined(FLASH_PGM_SIZE) && (FLASH_PGM_SIZE == 16))
1489     uint32_t data[4];
1490 #else
1491     uint32_t data[2];
1492 #endif
1493     uint8_t num = 0x00u;
1494 
1495     data[0] = (uint32_t)EE_DATA_STATUS_ACTIVE;
1496     if (handle->ftfxProgramSize > FTFx_LONGWORD_SIZE)
1497     {
1498 #if (defined(FLASH_PGM_SIZE) && (FLASH_PGM_SIZE == 16))
1499         data[1] = 0xFFFFFFFFu;
1500         data[2] = 0xFFFFFFFFu;
1501         data[3] = 0xFFFFFFFFu;
1502 #else
1503         data[1] = 0xFFFFFFFFu;
1504 #endif
1505     }
1506     do
1507     {
1508         ret = EE_MultiProgram(handle, sectorAddress + (uint32_t)handle->eeSectorActIndOffset, handle->ftfxProgramSize,
1509                               (uint8_t *)&data);
1510         ret = EE_VerifySectorHeader(handle, sectorAddress + handle->eeSectorActIndOffset, EE_DATA_STATUS_BLANK);
1511         if (ret != EE_OK)
1512         {
1513             break;
1514         }
1515         else
1516         {
1517             num++;
1518             if (num > handle->eeRetryMax)
1519             {
1520                 returnCode = EE_ValidateDeadIndicator(handle, sectorAddress);
1521                 if (returnCode == EE_OK)
1522                 {
1523                     returnCode = EE_MAKEDEAD_OK;
1524                 }
1525             }
1526         }
1527     } while (num <= handle->eeRetryMax);
1528 
1529     return (returnCode);
1530 }
1531 
1532 /*******************************************************************************
1533  *
1534  *  Function Name    : EE_ReEraseEeprom
1535  *  Description      : This function will re-erase 1 sector with several times
1536  *  Arguments        :
1537  *                     - sectorAddress: the address of sector need to re-erase
1538  *  Return Value     :
1539  *                     - EE_OK if successful
1540  *                     - EE_NOT_OK if re-erase fail and make DEAD fail
1541  *                     - EE_MAKEDEAD_OK if re-erase fail and make DEAD successful
1542  *
1543  *******************************************************************************/
EE_ReEraseEeprom(eeprom_emulation_handle_t * handle,uint32_t sectorAddress)1544 uint32_t EE_ReEraseEeprom(eeprom_emulation_handle_t *handle, uint32_t sectorAddress)
1545 {
1546     uint32_t returnCode = EE_OK;
1547     uint8_t num         = 0x00u;
1548 
1549     do
1550     {
1551         /* if re-erase sector fail, re-erase several times before make it to DEAD sector */
1552         returnCode = EE_SyncFlashErase(handle, sectorAddress);
1553         if (returnCode != EE_OK)
1554         {
1555             num++;
1556             if (num > handle->eeRetryMax)
1557             {
1558                 returnCode = EE_ValidateDeadIndicator(handle, sectorAddress);
1559                 if (returnCode == EE_OK)
1560                 {
1561                     returnCode = EE_MAKEDEAD_OK;
1562                 }
1563             }
1564         }
1565     } while ((returnCode != EE_OK) && (num <= handle->eeRetryMax));
1566     return (returnCode);
1567 }
1568 
1569 /*******************************************************************************
1570  *
1571  *  Function Name    : EE_ReEraseEeprom
1572  *  Description      : This function will re-erase 1 sector with several times
1573  *  Arguments        : N/A
1574  *  Return Value     :
1575  *                     - EE_OK if enough sector for working sequence
1576  *                     - EE_NOT_OK if not enough sector for working sequence
1577  *
1578  *******************************************************************************/
EE_CheckAvailabilityStatus(eeprom_emulation_handle_t * handle)1579 uint32_t EE_CheckAvailabilityStatus(eeprom_emulation_handle_t *handle)
1580 {
1581     uint32_t returnCode = EE_OK;
1582     uint32_t sectorAddress;
1583     uint32_t sectorStatus;
1584     uint8_t totalAliveSector = 0x00u;
1585     uint8_t i;
1586     sectorAddress = handle->eeStartAddress;
1587     for (i = 0x00u; i < handle->eeAllotedSectors; i++)
1588     {
1589         sectorStatus = EE_GetSectorStatus(handle, sectorAddress);
1590         if ((sectorStatus == EE_SECTOR_BLANK) || (sectorStatus == EE_SECTOR_ALTERNATIVE))
1591         {
1592             totalAliveSector++;
1593         }
1594         /* sectorAddress += handle->eeSectorSize */
1595         sectorAddress = EE_NextSector(handle, sectorAddress);
1596     }
1597     if (totalAliveSector < handle->eeActualReadySectors)
1598     {
1599         returnCode = EE_NOT_OK;
1600     }
1601     return (returnCode);
1602 }
1603 /*******************************************************************************
1604  *
1605  *  Function Name    : EE_UpdateCacheTable
1606  *  Description      : This function will update the cache table
1607  *  Arguments        : N/A
1608  *  Return Value     : N/A
1609  *
1610  *******************************************************************************/
1611 /* Initialize the cache table with all the values, if it is enabled */
1612 #if EE_CACHETABLE_ENABLE
EE_UpdateCacheTable(eeprom_emulation_handle_t * handle)1613 void EE_UpdateCacheTable(eeprom_emulation_handle_t *handle)
1614 {
1615     uint32_t tableAddress;
1616     uint32_t recordAddress;
1617     uint16_t dataID;
1618 
1619     /* Hold the start address of cache table */
1620     tableAddress = EE_CACHETABLE_START_ADDRESS;
1621     /* Loop through the data ID that should be written to the Cache Table */
1622     for (dataID = 1u; dataID <= EE_CACHETABLE_MAX_ENTRY; dataID++)
1623     {
1624         /* Search all the ACTIVE sectors */
1625         recordAddress = EE_SearchInAllActives(handle, dataID);
1626         WRITE32(tableAddress, recordAddress);
1627 
1628         tableAddress += (uint32_t)EE_CACHETABLE_ITEM_SIZE;
1629     }
1630 }
1631 #endif
1632 
1633 /*******************************************************************************
1634  *
1635  *  Function Name    : EE_ISRHandler
1636  *  Description      : Interrupt service routine for Command Complete.
1637  *  Arguments        : N/A
1638  *  Return Value     : N/A
1639  *
1640  *******************************************************************************/
1641 #if (EE_USE_ASYNCHRONOUS_MODEL == true)
1642 #ifdef DSC_CORE
1643 #pragma interrupt
1644 #endif
EE_ISRHandler(void)1645 void INTERRUPT EE_ISRHandler(void) /* Flash interrupt service function */
1646 {
1647     /* Disable command complete interrupt */
1648     REG_BIT_CLEAR(FTFx_FCNFG, FTFx_FCNFG_CCIE);
1649 
1650     /* checking error */
1651     if (0x00u != (REG_READ(FTFx_FSTAT) & FTFx_FSTAT_CHECK_ERR))
1652     {
1653         g_eraseStatusFlag = FAIL;
1654     }
1655     else
1656     {
1657         g_eraseStatusFlag = DONE;
1658     }
1659 }
1660 #endif
1661 
1662 /* High level functions */
1663 
EE_PreInitCheck(eeprom_emulation_handle_t * handle)1664 static uint32_t EE_PreInitCheck(eeprom_emulation_handle_t *handle)
1665 {
1666     uint32_t returnCode = EE_OK; /* variable return EE_InitEeprom() function state.*/
1667 #if (defined(FLASH_PGM_SIZE) && (FLASH_PGM_SIZE == 16))
1668     uint32_t expErsCycValue[4]; /* buffer to store erase cycle, which is written to erase cycle address.*/
1669 #else
1670     uint32_t expErsCycValue[2]; /* buffer to store erase cycle, which is written to erase cycle address.*/
1671 #endif
1672     uint32_t sectorAddress; /* variable help we know the address is activated at that time.*/
1673     uint32_t currentActsectorAddress = 0x00u;
1674     uint8_t i;
1675 
1676     /***********
1677     STEP 1: Check for the first time initialization
1678        This step will find and erase oldest active sector if it has more than number expected active sector .
1679        If erasing oldest active sector is fail, it will re-erase this sector several times before make this
1680        to dead sector. If make dead sector fail return EE_NOT_OK error.It will check total dead sector and
1681        return EE_NOT_OK error if break sequence because of not enough alive sector.
1682     ***********/
1683 
1684     if (EE_GetSectorNumber(handle, EE_SECTOR_ACTIVE) >
1685         (uint8_t)handle->eeActiveSectors) /* check if more than expected active sectors */
1686     {
1687         /* find oldest active sector and erase it */
1688         sectorAddress = EE_FindActSector(handle, handle->eeStartAddress, false, false);
1689         returnCode    = EE_ReEraseEeprom(handle, sectorAddress);
1690         if (returnCode != EE_NOT_OK)
1691         {
1692             returnCode = EE_CheckAvailabilityStatus(handle);
1693         }
1694     }
1695     /***********
1696     STEP 2: Check for other cases - isn't the first time initialization
1697         This step will find and erase all invalid sector. If erasing all invalid sectors is fail, it will re-erase
1698     all these sector several times before make them to dead sectors. If make dead sector fail return EE_NOT_OK
1699     error. It will check total dead sector and return EE_NOT_OK error if break sequence because of not enough alive
1700     sector
1701     ***********/
1702     else
1703     {
1704         /* find all invalid sector and erase it */
1705         sectorAddress = (uint32_t)handle->eeStartAddress;
1706         for (i = 0x00u; i < handle->eeAllotedSectors; i++)
1707         {
1708             if (EE_GetSectorStatus(handle, sectorAddress) == EE_SECTOR_INVALID)
1709             {
1710                 returnCode = EE_ReEraseEeprom(handle, sectorAddress);
1711                 if (returnCode != EE_NOT_OK)
1712                 {
1713                     returnCode = EE_CheckAvailabilityStatus(handle);
1714                 }
1715             }
1716             if (returnCode == EE_NOT_OK)
1717             {
1718                 break;
1719             }
1720             sectorAddress += (uint32_t)handle->eeSectorSize;
1721         }
1722     }
1723 
1724     if (returnCode == EE_OK)
1725     {
1726         sectorAddress = EE_FindActSector(handle, handle->eeStartAddress, false, false);
1727         /* it isn't the first time initialization because it has active sector*/
1728         if (sectorAddress != 0xFFFFFFFFu)
1729         {
1730             expErsCycValue[0]       = READ32(sectorAddress + handle->eeSectorEraseCycleOffset);
1731             currentActsectorAddress = sectorAddress;
1732             /* find the ALT sector before ACT sector that have invalid erase cycle and erase it */
1733             do
1734             {
1735                 sectorAddress = EE_PrevSector(handle, sectorAddress);
1736                 /* erase all alternate sector have invalid sector before oldest active sector */
1737                 if ((EE_GetSectorStatus(handle, sectorAddress) == EE_SECTOR_ALTERNATIVE) &&
1738                     ((sectorAddress >= handle->eeStartAddress) && (sectorAddress < currentActsectorAddress)))
1739                 {
1740                     if (EE_OK != EE_VerifySectorHeader(handle, sectorAddress + handle->eeSectorEraseCycleOffset,
1741                                                        expErsCycValue[0] + 0x01u))
1742                     {
1743                         returnCode = EE_ReEraseEeprom(handle, sectorAddress);
1744                         if (returnCode != EE_NOT_OK)
1745                         {
1746                             returnCode = EE_CheckAvailabilityStatus(handle);
1747                         }
1748                     }
1749                 }
1750                 /* erase all alternate sector have invalid sector behind oldest active sector */
1751                 if ((EE_GetSectorStatus(handle, sectorAddress) == EE_SECTOR_ALTERNATIVE) &&
1752                     (sectorAddress > currentActsectorAddress) &&
1753                     (sectorAddress <= (g_eeEndAddress - handle->eeSectorSize)))
1754                 {
1755                     if (EE_OK != EE_VerifySectorHeader(handle, sectorAddress + handle->eeSectorEraseCycleOffset,
1756                                                        expErsCycValue[0]))
1757                     {
1758                         returnCode = EE_ReEraseEeprom(handle, sectorAddress);
1759                         if (returnCode != EE_NOT_OK)
1760                         {
1761                             returnCode = EE_CheckAvailabilityStatus(handle);
1762                         }
1763                     }
1764                 }
1765                 if (returnCode == EE_NOT_OK)
1766                 {
1767                     break;
1768                 }
1769             } while (sectorAddress != currentActsectorAddress);
1770         }
1771         /* it is the first time initialization because it does not has active sector*/
1772         else
1773         {
1774             sectorAddress = (uint32_t)handle->eeStartAddress;
1775             /* find and erase all the ALT sectors have erase cycle different 1 if there is no ACT sector */
1776             for (i = 0x00u; i < handle->eeAllotedSectors; i++)
1777             {
1778                 uint32_t tempVal =
1779                     EE_VerifySectorHeader(handle, sectorAddress + handle->eeSectorEraseCycleOffset, 0x01u);
1780                 uint32_t tempValBackup =
1781                     EE_VerifySectorHeader(handle, sectorAddress + handle->eeSectorEraseCycleOffset, 0xFFFFFFFFu);
1782 
1783                 if ((EE_OK != tempVal) && (EE_OK != tempValBackup))
1784                 {
1785                     returnCode = EE_ReEraseEeprom(handle, sectorAddress);
1786                     if (returnCode != EE_NOT_OK)
1787                     {
1788                         returnCode = EE_CheckAvailabilityStatus(handle);
1789                     }
1790                 }
1791                 if (returnCode == EE_NOT_OK)
1792                 {
1793                     break;
1794                 }
1795                 sectorAddress += (uint32_t)handle->eeSectorSize;
1796             }
1797         }
1798     }
1799 
1800     return returnCode;
1801 }
1802 
EE_InitAltSector(eeprom_emulation_handle_t * handle,uint8_t * number)1803 static uint32_t EE_InitAltSector(eeprom_emulation_handle_t *handle, uint8_t *number)
1804 {
1805     uint32_t returnCode = EE_OK; /* variable return EE_InitEeprom() function state.*/
1806 #if (defined(FLASH_PGM_SIZE) && (FLASH_PGM_SIZE == 16))
1807     uint32_t expErsCycValue[4]; /* buffer to store erase cycle, which is written to erase cycle address.*/
1808 #else
1809     uint32_t expErsCycValue[2]; /* buffer to store erase cycle, which is written to erase cycle address.*/
1810 #endif
1811     uint32_t sectorAddress; /* variable help we know the address is activated at that time.*/
1812     uint32_t currentActsectorAddress = 0x00u;
1813     uint8_t tempTotalActiveSector    = 0x00u; /* variable help we know how many active sector at that time.*/
1814     uint8_t sectorStatus;                     /* variable help we know the state of sector when we call.*/
1815     uint8_t i;
1816 
1817     if (handle->ftfxProgramSize > FTFx_LONGWORD_SIZE)
1818     {
1819 #if (defined(FLASH_PGM_SIZE) && (FLASH_PGM_SIZE == 16))
1820         expErsCycValue[1] = 0xFFFFFFFFu;
1821         expErsCycValue[2] = 0xFFFFFFFFu;
1822         expErsCycValue[3] = 0xFFFFFFFFu;
1823         g_eraseCycles[1]  = 0xFFFFFFFFu;
1824         g_eraseCycles[2]  = 0xFFFFFFFFu;
1825         g_eraseCycles[3]  = 0xFFFFFFFFu;
1826 #else
1827         expErsCycValue[1] = 0xFFFFFFFFu;
1828         g_eraseCycles[1]  = 0xFFFFFFFFu;
1829 #endif
1830     }
1831 
1832     /***********
1833     STEP 3:
1834        This step will check if STEP 1 & STEP 2is done and successful, it will make all alive sectors to ALT sectors
1835     ***********/
1836 
1837     /* This segment will make all blank sector to alter sector by write erase cycle to its address.
1838        When make a blank sector to alter sector, if making fail. It will re-erase this sector and
1839        re-make to alter sector several time before make dead sector. If make dead sector fail too
1840        return EE_NOT_OK error. It will check total dead sector and return EE_NOT_OK error if break
1841        sequence because of not enough alter sector */
1842     tempTotalActiveSector = EE_GetSectorNumber(handle, EE_SECTOR_ACTIVE);
1843     /* If this is the first time initializing, erase cycle must is 1 */
1844     if (tempTotalActiveSector == 0x00u)
1845     {
1846         expErsCycValue[0u]   = 0x01u;
1847         g_eraseCycles[0x00u] = expErsCycValue[0u];
1848         sectorAddress        = (uint32_t)handle->eeStartAddress;
1849         for (i = 0x00u; i < handle->eeAllotedSectors; i++)
1850         {
1851             sectorStatus = EE_GetSectorStatus(handle, sectorAddress);
1852             if (sectorStatus == EE_SECTOR_BLANK)
1853             {
1854                 returnCode = EE_ValidateEraseCycle(handle, sectorAddress, (uint8_t *)expErsCycValue);
1855             }
1856             if (returnCode == EE_MAKEDEAD_OK)
1857             {
1858                 returnCode = EE_CheckAvailabilityStatus(handle);
1859             }
1860             if (returnCode == EE_NOT_OK)
1861             {
1862                 break;
1863             }
1864             sectorAddress += (uint32_t)handle->eeSectorSize;
1865         }
1866     }
1867     /* Write valid erase cycle for all BLANKS sectors */
1868     else
1869     {
1870         expErsCycValue[0u]      = READ32(currentActsectorAddress + handle->eeSectorEraseCycleOffset);
1871         g_eraseCycles[0u]       = expErsCycValue[0u];
1872         sectorAddress           = EE_FindActSector(handle, handle->eeStartAddress, false, false);
1873         currentActsectorAddress = sectorAddress;
1874         /* Make all blank sector before active sector to alternate sector */
1875         do
1876         {
1877             sectorAddress = EE_PrevSector(handle, sectorAddress);
1878             /* calculate erase cycle of all blank sectors before oldest active sector */
1879             if ((EE_GetSectorStatus(handle, sectorAddress) == EE_SECTOR_BLANK) &&
1880                 (sectorAddress >= handle->eeStartAddress))
1881             {
1882                 expErsCycValue[0u] = g_eraseCycles[0] + 0x01u;
1883             }
1884             /* calculate erase cycle of all blank sectors behind oldest active sector */
1885             if ((EE_GetSectorStatus(handle, sectorAddress) == EE_SECTOR_BLANK) &&
1886                 (sectorAddress > currentActsectorAddress) && (sectorAddress <= (g_eeEndAddress - handle->eeSectorSize)))
1887             {
1888                 expErsCycValue[0u] = g_eraseCycles[0u];
1889             }
1890             /* write erase cycle for blank sector */
1891             if (EE_GetSectorStatus(handle, sectorAddress) == EE_SECTOR_BLANK)
1892             {
1893                 returnCode = EE_ValidateEraseCycle(handle, sectorAddress, (uint8_t *)expErsCycValue);
1894                 if (returnCode == EE_MAKEDEAD_OK)
1895                 {
1896                     returnCode = EE_CheckAvailabilityStatus(handle);
1897                 }
1898                 if (returnCode == EE_NOT_OK)
1899                 {
1900                     break;
1901                 }
1902             }
1903         } while (sectorAddress != currentActsectorAddress);
1904     }
1905 
1906     *number = tempTotalActiveSector;
1907 
1908     return returnCode;
1909 }
1910 
EE_InitActiveSector(eeprom_emulation_handle_t * handle,uint8_t number)1911 static uint32_t EE_InitActiveSector(eeprom_emulation_handle_t *handle, uint8_t number)
1912 {
1913     uint32_t returnCode           = EE_OK;  /* variable return EE_InitEeprom() function state.*/
1914     uint32_t sectorAddress        = 0x00U;  /* variable help we know the address is activated at that time.*/
1915     uint8_t tempTotalActiveSector = number; /* variable help we know how many active sector at that time.*/
1916     uint8_t sectorStatus;                   /* variable help we know the state of sector when we call.*/
1917 
1918     /***********
1919     STEP 4:
1920        This step will check if STEP 1, STEP 2,  and STEP 3 is done and successful, it will make all ALT sectors to
1921     ACT sectors
1922     ***********/
1923 
1924     /* This segment will make all alter sector to active sector by write erase cycle to its address.
1925        When make a alter sector to active sector, if making fail. It will re-erase this sector and
1926        re-make to active sector several time before make dead sector. If make dead sector fail return
1927        EE_NOT_OK error. It will check total dead sector and return EE_NOT_OK error if break sequence
1928        because of not enough alter sector */
1929     /* check enough sector for sequence */
1930     if (tempTotalActiveSector == 0x00u)
1931     {
1932         sectorAddress = handle->eeStartAddress;
1933     }
1934     else
1935     {
1936         sectorAddress = EE_FindActSector(handle, sectorAddress, true, true);
1937     }
1938 
1939     /* make enough active sector for EEE */
1940     if (tempTotalActiveSector < (uint32_t)handle->eeActiveSectors)
1941     {
1942         do
1943         {
1944             sectorStatus = EE_GetSectorStatus(handle, sectorAddress);
1945             if (sectorStatus == EE_SECTOR_ALTERNATIVE)
1946             {
1947                 returnCode = EE_ValidateActIndicator(handle, sectorAddress);
1948                 if (returnCode == EE_OK)
1949                 {
1950                     tempTotalActiveSector++;
1951                 }
1952                 if (returnCode == EE_MAKEDEAD_OK)
1953                 {
1954                     returnCode = EE_CheckAvailabilityStatus(handle);
1955                 }
1956                 if (returnCode == EE_NOT_OK)
1957                 {
1958                     break;
1959                 }
1960             }
1961             sectorAddress = EE_NextSector(handle, sectorAddress);
1962         } while (tempTotalActiveSector < handle->eeActiveSectors);
1963     }
1964 
1965     /* re-check enough sector for sequence */
1966     if (returnCode == EE_OK)
1967     {
1968         returnCode = EE_CheckAvailabilityStatus(handle);
1969         if (returnCode == EE_OK)
1970         {
1971             tempTotalActiveSector = 0x01u;
1972             g_currentActiveSector = EE_FindActSector(handle, handle->eeStartAddress, false, false);
1973             g_freeSpaceAddress    = EE_SearchBlankSpace(handle, g_currentActiveSector);
1974             while (
1975                 (tempTotalActiveSector < handle->eeActiveSectors) &&
1976                 ((g_freeSpaceAddress + handle->eeSectorRecordLength) > (g_currentActiveSector + handle->eeSectorSize)))
1977             {
1978                 /* update g_freeSpaceAddress */
1979                 g_currentActiveSector = EE_NextSector(handle, g_currentActiveSector);
1980                 if (EE_GetSectorStatus(handle, g_currentActiveSector) == EE_SECTOR_ACTIVE)
1981                 {
1982                     tempTotalActiveSector++;
1983                     g_freeSpaceAddress = EE_SearchBlankSpace(handle, g_currentActiveSector);
1984                 }
1985             }
1986         }
1987     }
1988 
1989     return returnCode;
1990 }
1991 
1992 /*******************************************************************************
1993 *
1994 *  Function Name    : EE_Init
1995 *  Description      : This function will determine active,
1996                       alternative and brown out affected sectors and
1997                       erase/update the sectors. Initializing variables
1998                       that hold active sector related information like
1999                       the start addresses of the active sector
2000                       and the blank space available is also done in this
2001                       function. The dead sectors are re-erased again for
2002                       next usage and cache table is also initialized in this
2003                       function. If no sectors are initialized then,
2004                       this function shall initialize all the sectors in
2005                       a round robin queue
2006 *  Arguments        : N/A
2007 *  Return Value     :
2008 *                     - EE_OK if successful
2009 *                     - EE_NOT_OK if failed
2010 *
2011 *******************************************************************************/
2012 
EE_Init(eeprom_emulation_handle_t * handle)2013 uint32_t EE_Init(eeprom_emulation_handle_t *handle)
2014 {
2015     uint32_t returnCode       = EE_OK; /* variable return EE_InitEeprom() function state.*/
2016     uint8_t totalActiveSector = 0x00u; /* variable help we know how many active sector at that time.*/
2017     /* Initialize all global variables */
2018 #if (EE_USE_ASYNCHRONOUS_MODEL == true)
2019     g_addressToMain    = 0xFFFFFFFFu;
2020     g_endAddressToMain = 0xFFFFFFFFu;
2021 #endif
2022     g_eraseStatusFlag = IDLE;
2023     g_eeEndAddress    = handle->eeEndAddress;
2024 
2025     {
2026 /* clear cache */
2027 #if EE_CACHETABLE_ENABLE
2028         sectorAddress = (uint32_t)EE_CACHETABLE_START_ADDRESS;
2029         for (i = 0x01u; i <= EE_CACHETABLE_MAX_ENTRY; i++)
2030         {
2031             WRITE32(sectorAddress, 0xFFFFFFFFu);
2032             sectorAddress += (uint32_t)EE_CACHETABLE_ITEM_SIZE;
2033         }
2034 #endif
2035 
2036         /* Check initliazation or not. */
2037         returnCode = EE_PreInitCheck(handle);
2038         if (EE_OK == returnCode)
2039         {
2040             /* Init altnative sectors. */
2041             returnCode = EE_InitAltSector(handle, &totalActiveSector);
2042         }
2043 
2044         if (EE_OK == returnCode)
2045         {
2046             /* Init active sectors. */
2047             returnCode = EE_InitActiveSector(handle, totalActiveSector);
2048         }
2049     }
2050 
2051 /* update cache table if enabled */
2052 #if EE_CACHETABLE_ENABLE == true
2053     if (returnCode == EE_OK)
2054     {
2055         EE_UpdateCacheTable(handle);
2056     }
2057 #endif
2058     return (returnCode);
2059 }
2060 
2061 /*******************************************************************************
2062 *
2063 *  Function Name    : EE_ReadEeprom
2064 *  Description      : This function is used to read the specific data record.
2065                       The starting address of the record data will be returned.
2066 *  Arguments        :
2067 *                     - dataID: the record ID to be read.
2068 *                     - recordAddr: address of found record.
2069 *  Return Value     :
2070 *                     - EE_OK if found record.
2071 *                     - 0xFFFFFFFFu if not found record.
2072 *                     - EE_ERR_IDRANGE if ID invalid value.
2073 *
2074 *******************************************************************************/
EE_ReadData(eeprom_emulation_handle_t * handle,uint16_t dataID,uint32_t * recordAddr)2075 uint32_t EE_ReadData(eeprom_emulation_handle_t *handle, uint16_t dataID, uint32_t *recordAddr)
2076 {
2077     uint32_t returnCode = EE_OK;
2078     /* This segment will for validate ID, sure that it is in the range of ID */
2079     if (((uint16_t)(handle->eeMaxRecordNumber) < dataID) || (0x00u == dataID))
2080     {
2081         returnCode = EE_ERR_IDRANGE;
2082     }
2083     /* Search for data for the record in all active sectors. It will return address
2084        of data record if found ID. Or it return 0xFFFFFFFFu value*/
2085     if (returnCode != EE_ERR_IDRANGE)
2086     {
2087         *recordAddr = EE_SearchLoop(handle, dataID);
2088         if (*recordAddr == 0xFFFFFFFFu)
2089         {
2090             returnCode = 0xFFFFFFFFu;
2091         }
2092     }
2093     return (returnCode);
2094 }
2095 
2096 /*******************************************************************************
2097  *
2098  *  Function Name    : EE_WriteData
2099  *  Description      : This function will be used to write new data record to
2100  *                     EEPROM emulation.
2101  *  Arguments        :
2102  *                     - dataID: record ID to be written.
2103  *                     - source: source data to be written.
2104  *  Return Value     :
2105  *                     - EE_OK if successful
2106  *                     - EE_NOT_OK if failed
2107  *                     - EE_ERR_IDRANGE if ID out of range
2108  *                     - EE_ERR_UPDATE if swapping occurred but fail
2109  *
2110  *******************************************************************************/
EE_WriteData(eeprom_emulation_handle_t * handle,uint16_t dataID,uint32_t source)2111 uint32_t EE_WriteData(eeprom_emulation_handle_t *handle, uint16_t dataID, uint32_t source)
2112 {
2113     uint32_t returnCode = EE_OK;
2114     uint32_t sectorAddress;
2115     uint32_t alginedSize;
2116     uint32_t remainingSize;
2117 #if (EE_USE_ASYNCHRONOUS_MODEL != true) /* synchronous model */
2118     uint32_t i;
2119 #endif
2120 
2121     uint8_t sectorStatus = 0x00u;
2122     /* Defined in preprocessor */
2123     uint8_t remainData[EE_DATA_VALUE_REMAINING_PART];
2124     bool swapFlag = false;
2125 
2126     /*Calculate data value aligned part and remaining part */
2127     alginedSize   = handle->eeDataValueSize - (handle->eeDataValueSize % handle->ftfxProgramSize);
2128     remainingSize = handle->eeSectorRecordLength - alginedSize - handle->ftfxProgramSize - handle->complementSize;
2129 
2130     /* Check if the ID is within the range or equal to zero */
2131     if ((dataID > (uint16_t)handle->eeMaxRecordNumber) || (dataID == 0x00u))
2132     {
2133         returnCode = EE_ERR_IDRANGE;
2134     }
2135     else
2136     {
2137         /* Copying the data ID and the data Values into the structure */
2138         g_dataRecord.dataID = dataID;
2139         /* Copying the dataAddr into the structure */
2140         g_dataRecord.dataAddr = source;
2141 /* Calculate free space available in the current active sector */
2142 /* Check if the space is enough to write a record */
2143 #if (EE_USE_ASYNCHRONOUS_MODEL != true) /* synchronous model */
2144         /* scan for 2 times in synchronous model to write internal data */
2145         for (i = 0x00u; i < handle->eeActiveSectors; i++)
2146         {
2147 #endif
2148             /* for synchronous model,need to back WriteEeprom function to write
2149                internal data here (when i is 0x1) */
2150 
2151             if (((g_currentActiveSector + handle->eeSectorSize) - g_freeSpaceAddress) < handle->eeSectorRecordLength)
2152             {
2153                 /* if there is no free space on current active sector*/
2154                 sectorAddress = g_currentActiveSector;
2155                 returnCode    = EE_CheckAvailabilityStatus(handle);
2156 
2157                 if (returnCode == EE_NOT_OK)
2158                 {
2159                     /* Return EE_NOT_OK error if break sequence because of not enough alter sector */
2160                     break;
2161                 }
2162 
2163                 if (returnCode == EE_OK)
2164                 {
2165                     do
2166                     {
2167                         sectorAddress = EE_NextSector(handle, sectorAddress);
2168                         sectorStatus  = EE_GetSectorStatus(handle, sectorAddress);
2169                     } while ((sectorStatus == EE_SECTOR_DEAD) || (sectorStatus == EE_SECTOR_READY));
2170                 }
2171 
2172                 if ((sectorStatus == EE_SECTOR_ALTERNATIVE) && (returnCode == EE_OK))
2173                 {
2174 /* if there is no active sector in the next ones. Swapping must occur*/
2175 #if (EE_USE_ASYNCHRONOUS_MODEL != true) /* synchronous model */
2176                     returnCode = EE_SwapSector(handle);
2177                     if (returnCode == EE_OK)
2178                     {
2179                         /* if swapping successful, continue to write internal data*/
2180                         continue;
2181                     }
2182                     else
2183                     {
2184                         /* if swapping fail, return EE_ERR_UPDATE*/
2185                         returnCode = EE_ERR_UPDATE;
2186                         break;
2187                     }
2188 #else
2189                 returnCode = EE_SwapSector(handle);
2190                 swapFlag   = true;
2191 #endif
2192                 }
2193                 /* if find active one in the next sector, no swapping is needed.*/
2194                 /* Make new sector as active one to write record to this new sector */
2195                 if (sectorStatus == EE_SECTOR_ACTIVE)
2196                 {
2197                     g_currentActiveSector = sectorAddress;
2198                     g_freeSpaceAddress    = g_currentActiveSector + (uint32_t)handle->eeSectorHeaderSize;
2199 #if (EE_USE_ASYNCHRONOUS_MODEL != true) /* synchronous model */
2200                     /* "i = handle->eeActiveSectors;" is same method to break this for() loop, but it violates MISRA
2201                      * rule 14.2(required). */
2202                     break;
2203 #endif
2204                 }
2205             }
2206 
2207 #if (EE_USE_ASYNCHRONOUS_MODEL != true) /* synchronous model */
2208         }
2209 #endif
2210     }
2211 
2212     /* no swapping occurs. Write new record to current free space address*/
2213     /* prepare remaining data */
2214     /* initialize remainData, reuse sectorStatus variable to save stack */
2215     if (((returnCode == (uint32_t)EE_OK) && (swapFlag == false) &&
2216          (((g_currentActiveSector + handle->eeSectorSize) - g_freeSpaceAddress) >=
2217           (uint32_t)handle->eeSectorRecordLength)))
2218     {
2219         for (sectorStatus = 0x00u; sectorStatus < remainingSize; sectorStatus++)
2220         {
2221             if (sectorStatus < ((uint8_t)handle->eeDataValueSize - (uint8_t)alginedSize))
2222             {
2223                 remainData[sectorStatus] = (uint8_t)READ8(g_dataRecord.dataAddr + (uint8_t)alginedSize + sectorStatus);
2224             }
2225             else
2226             {
2227                 remainData[sectorStatus] = 0xFFu;
2228             }
2229         }
2230         remainData[remainingSize - ID_LOWBYTE_OFFSET]  = (uint8_t)(g_dataRecord.dataID);
2231         remainData[remainingSize - ID_HIGHBYTE_OFFSET] = (uint8_t)(g_dataRecord.dataID >> 8);
2232         returnCode                                     = EE_CopyRecord(handle, g_dataRecord, remainData);
2233         if (returnCode == EE_OK)
2234         {
2235             g_eraseStatusFlag = IDLE;
2236         }
2237     }
2238 
2239     return (returnCode);
2240 }
2241 
2242 /*******************************************************************************
2243  *
2244  *  Function Name    : EE_ReportStatus
2245  *  Description      : This function reports the erase cycle of current active sector.
2246  *  Arguments        : N/A
2247  *  Return Value     :
2248  *                     - erase cycle of current active sector.
2249  *
2250  *******************************************************************************/
EE_ReportStatus(eeprom_emulation_handle_t * handle)2251 uint32_t EE_ReportStatus(eeprom_emulation_handle_t *handle)
2252 {
2253     /* get erase cycle for current active sector */
2254     return (READ32(g_currentActiveSector + handle->eeSectorEraseCycleOffset));
2255 }
2256 
2257 /*******************************************************************************
2258 *
2259 *  Function Name    : EE_Deinit
2260 *  Description      : This function is to release all the Flash used to
2261                       EEPROM emulation. After de-initialize, the Flash
2262                       for emulation will be fully erased.
2263 *  Arguments        : N/A
2264 *  Return Value     :
2265 *                     - EE_OK if successful
2266 *                     - EE_NOT_OK if failed
2267 *
2268 *******************************************************************************/
EE_Deinit(eeprom_emulation_handle_t * handle)2269 uint32_t EE_Deinit(eeprom_emulation_handle_t *handle)
2270 {
2271     uint32_t sectorAddress = handle->eeStartAddress;
2272     uint32_t returnCode    = EE_OK;
2273     uint8_t numDead        = 0x00u;
2274     uint8_t i;
2275     /* Re-erase all sectors, one by one from first sector to end sector */
2276     for (i = 0x00u; i < handle->eeAllotedSectors; i++)
2277     {
2278         returnCode = EE_ReEraseEeprom(handle, sectorAddress);
2279         if (returnCode == EE_NOT_OK)
2280         {
2281             break;
2282         }
2283         if (returnCode == EE_MAKEDEAD_OK)
2284         {
2285             numDead++;
2286         }
2287         sectorAddress += (uint32_t)handle->eeSectorSize;
2288     }
2289     if (numDead > handle->eeExtraReadySectors)
2290     {
2291         returnCode = EE_NOT_OK;
2292     }
2293     if ((returnCode != EE_NOT_OK) && (numDead <= handle->eeActualReadySectors))
2294     {
2295         returnCode = EE_OK;
2296     }
2297 
2298     return (returnCode);
2299 }
2300 
2301 /*******************************************************************************
2302 *
2303 *  Function Name    : EE_Main()
2304 *  Description      : Completes the initialization of sectors and other
2305                       operations to make it ready for EEPROM emulation.
2306 *  Arguments        : N/A
2307 *  Return Value     :
2308 *                     - EE_OK if successful
2309 *                     - EE_NOT_OK if failed
2310 *                     - EE_ERR_UPDATE if swapping occurred but fail
2311 *
2312 *******************************************************************************/
2313 #if (EE_USE_ASYNCHRONOUS_MODEL == true)
EE_Main(eeprom_emulation_handle_t * handle)2314 uint32_t EE_Main(eeprom_emulation_handle_t *handle)
2315 {
2316     uint32_t returnCode = EE_OK;
2317     uint32_t erasedSectorAddr;
2318 
2319     if (DONE == g_eraseStatusFlag)
2320     {
2321         /* Check for there is still flash sector in the EEE sector need erased */
2322         g_addressToMain += handle->flashSectorSize;
2323         if (g_addressToMain < g_endAddressToMain)
2324         {
2325             /* Erase the next flash sector in the EEE sector */
2326             EE_AsyncFlashErase(handle, g_addressToMain);
2327         }
2328         else
2329         {
2330             /* Get address of the erased sector */
2331             erasedSectorAddr = g_endAddressToMain - handle->eeSectorSize;
2332 
2333             /* complete erase for entire EE sector. So, verify section to make sure the sector
2334                was erased successfully */
2335             /* verify if sector erase done and successful. If sector is dead ignore this section */
2336             returnCode = EE_FlashEraseVerifySection(handle, erasedSectorAddr,
2337                                                     (uint16_t)(handle->eeSectorSize / handle->ftfxRD1SECSize),
2338                                                     handle->flashReadMargin);
2339             if (returnCode == EE_OK)
2340             {
2341                 /* pass verify section, change g_eraseStatusFlag to IDLE */
2342                 /* program erase cycle to the sector which has been erased */
2343                 /* write internal data which causes swapping */
2344                 returnCode = EE_MultiProgram(handle, erasedSectorAddr + handle->eeSectorEraseCycleOffset,
2345                                              (uint32_t)handle->ftfxProgramSize, (uint8_t *)&g_eraseCycles);
2346             }
2347 
2348             if (returnCode != EE_OK)
2349             {
2350                 /* fail in verify section, make the global flag to FAIL */
2351                 g_eraseStatusFlag = FAIL;
2352 
2353                 g_numErase++;
2354                 if (g_numErase <= handle->eeRetryMax)
2355                 {
2356                     /* Reset address point to start-address of the erased sector... */
2357                     g_addressToMain = erasedSectorAddr;
2358 
2359                     /* ...then re-erase the EEE sector  */
2360                     EE_AsyncFlashErase(handle, g_addressToMain);
2361 
2362                     /* Update return code */
2363                     returnCode = EE_OK;
2364                 }
2365                 else
2366                 {
2367                     /* Make this sector as DEAD */
2368                     returnCode = EE_ValidateDeadIndicator(handle, erasedSectorAddr);
2369 
2370                     if (returnCode == EE_OK)
2371                     {
2372                         /* validate successfully */
2373                         /* update global flag to IDLE and then write internal data which causes swapping */
2374                         returnCode = EE_CheckAvailabilityStatus(handle);
2375                         if (returnCode == EE_OK)
2376                         {
2377                             /* Reset erase flag */
2378                             g_eraseStatusFlag = IDLE;
2379                         }
2380                     }
2381 
2382                     if (returnCode != EE_OK)
2383                     {
2384                         /* Return UPDATE error if can't make the sector to DEAD or
2385                          * there isn't enough sectors for the sequence */
2386                         returnCode = EE_ERR_UPDATE;
2387                     }
2388 
2389                     /* Reset re-erase number */
2390                     g_numErase = 0u;
2391                 }
2392             }
2393             else
2394             {
2395                 /* Reset erase flag */
2396                 g_eraseStatusFlag = IDLE;
2397                 g_numErase        = 0u;
2398             }
2399 
2400             /* Only write internal data if finish the erasing, updating erase cycle */
2401             if ((IDLE == g_eraseStatusFlag) && (returnCode == EE_OK))
2402             {
2403                 returnCode = EE_WriteData(handle, g_dataRecord.dataID, g_dataRecord.dataAddr);
2404             }
2405         }
2406     }
2407 
2408     return (returnCode);
2409 }
2410 #endif /* EE_USE_ASYNCHRONOUS_MODEL */
2411