/*!
* @file     Fls_Fmc.c
*
* @version  1.0.0
*
* @brief    Code file of AUTOSAR Flash driver based on FMC IP
*
* @attention
*
* Project Name      : AUTOSAR MCAL
*
* Platform          : Arm
*
* Autosar Standard  : Classic Platform 4.4.0
*
* Compiled Version  : G32A10xx_MCAL_1_0_0_01-Otc-25
*
* Copyright (C) 2026 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (Geehy Semiconductor Software License Agreement).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the Geehy Semiconductor Software License Agreement for the governing permissions
* and limitations under the License.
*/

/*
* MISRA-C:2012 compliance checks
*
*      Fls_Flash_c_MISRA_REF1
*          Breaks the required M3CM Rule-13.5 of MISRA 2012 guidelines,
*          The right hand operand of a logical && or || operator shall not contain persistent side effects.
*
*      Fls_Flash_c_MISRA_REF2
*          Breaks the required M3CM Rule-11.1 of MISRA 2012 guidelines,
*          Conversions shall not be performed between a pointer to a function and any other type.
*/

#ifdef __cplusplus
extern "C"{
#endif

#include "Fls_Fmc.h"

#if(( STD_ON == FLS_DETECT_DEV_ERROR_EN ) || ( STD_ON == FLS_DETECT_RUNTIME_ERROR_EN ) || \
    ( STD_ON == FLS_DETECT_TRANSIENT_FAULT_EN ))
    #include "Det.h"
#endif

#include "SchM_Fls.h"
#include "StdRegMacros.h"

/** @addtogroup G32A10xx_StdPeriphDriver
  @{
*/

/** @defgroup FLS_Driver
  * @brief FLS driver modules
  @{
*/

/** @defgroup FLS_Macros
  @{
*/
/**************************************************************************
                  VENDOR ID & AUTOSAR VERSION INFO
**************************************************************************/
/** Vendor ID (vendorId) of the dedicated implementation of this module according to the AUTOSAR vendor list. */
#define FLS_FLASH_VENDOR_ID                        0x00C1U
/** Major version number of AUTOSAR release on which the appropriate implementation is based on. */
#define FLS_FLASH_AR_RELEASE_MAJOR_VERSION         0x04U
/** Minor version number of AUTOSAR release on which the appropriate implementation is based on. */
#define FLS_FLASH_AR_RELEASE_MINOR_VERSION         0x04U
/** Revision version number of AUTOSAR release on which the appropriate implementation is based on. */
#define FLS_FLASH_AR_RELEASE_REVISION_VERSION      0x00U
/** Major version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define FLS_FLASH_SW_MAJOR_VERSION                 0x01U
/** Minor version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define FLS_FLASH_SW_MINOR_VERSION                 0x00U
/** Patch level version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define FLS_FLASH_SW_PATCH_VERSION                 0x00U

/**@} end of group FLS_Macros */

/**************************************************************************
                    VERSION INFOMATION VERIFICATION
**************************************************************************/
/* Make sure the vendor id is the same between Fls_Fmc.c and Fls_Fmc.h */
#if (FLS_FLASH_VENDOR_ID != FLS_FLASH_H_VENDOR_ID)
    #error "Vendor id mismatch between Fls_Fmc.c and Fls_Fmc.h"
#endif
/* Make sure the AUTOSAR major version number is the same between Fls_Fmc.c and Fls_Fmc.h */
#if (FLS_FLASH_AR_RELEASE_MAJOR_VERSION != FLS_FLASH_H_AR_RELEASE_MAJOR_VERSION)
    #error "AUTOSAR Major Version Number mismatch between Fls_Fmc.c and Fls_Fmc.h"
#endif
/* Make sure the AUTOSAR minor version number is the same between Fls_Fmc.c and Fls_Fmc.h */
#if (FLS_FLASH_AR_RELEASE_MINOR_VERSION != FLS_FLASH_H_AR_RELEASE_MINOR_VERSION)
    #error "AUTOSAR Minor Version Number mismatch between Fls_Fmc.c and Fls_Fmc.h"
#endif
/* Make sure the AUTOSAR revision version number is the same between Fls_Fmc.c and Fls_Fmc.h */
#if (FLS_FLASH_AR_RELEASE_REVISION_VERSION != FLS_FLASH_H_AR_RELEASE_REVISION_VERSION)
    #error "AUTOSAR Revision Version Number mismatch between Fls_Fmc.c and Fls_Fmc.h"
#endif
/* Make sure the software major version number is the same between Fls_Fmc.c and Fls_Fmc.h */
#if (FLS_FLASH_SW_MAJOR_VERSION != FLS_FLASH_H_SW_MAJOR_VERSION)
    #error "Software Major Version Number mismatch between Fls_Fmc.c and Fls_Fmc.h"
#endif
/* Make sure the software minor version number is the same between Fls_Fmc.c and Fls_Fmc.h */
#if (FLS_FLASH_SW_MINOR_VERSION != FLS_FLASH_H_SW_MINOR_VERSION)
    #error "Software Minor Version Number mismatch between Fls_Fmc.c and Fls_Fmc.h"
#endif
/* Make sure the software patch version number is the same between Fls_Fmc.c and Fls_Fmc.h */
#if (FLS_FLASH_SW_PATCH_VERSION != FLS_FLASH_H_SW_PATCH_VERSION)
    #error "Software Patch Version Number mismatch between Fls_Fmc.c and Fls_Fmc.h"
#endif

#if(( STD_ON == FLS_DETECT_DEV_ERROR_EN ) || ( STD_ON == FLS_DETECT_RUNTIME_ERROR_EN ) || \
    ( STD_ON == FLS_DETECT_TRANSIENT_FAULT_EN ))
#ifdef ENABLE_INTERMODULE_MCAL_CHECK
    #if (STD_ON == PWM_DEV_ERROR_DETECT)
        /* Make sure the AUTOSAR major version number is the same between Fls_Fmc.c and Det.h */
        #if (FLS_FLASH_AR_RELEASE_MAJOR_VERSION != DET_H_AR_RELEASE_MAJOR_VERSION)
            #error "AUTOSAR Major Version Number mismatch between Fls_Fmc.c and Det.h "
        #endif
        /* Make sure the AUTOSAR minor version number is the same between Fls_Fmc.c and Det.h */
        #if (FLS_FLASH_AR_RELEASE_MINOR_VERSION != DET_H_AR_RELEASE_MINOR_VERSION)
            #error "AUTOSAR Minor Version Number mismatch between Fls_Fmc.c and Det.h "
        #endif
    #endif
#endif
#endif

#ifdef ENABLE_INTERMODULE_MCAL_CHECK
    /* Make sure the AUTOSAR major version number is the same between Fls_Fmc.c and SchM_Fls.h */
    #if (FLS_FLASH_AR_RELEASE_MAJOR_VERSION != SCHM_FLS_H_AR_RELEASE_MAJOR_VERSION)
        #error "AUTOSAR Major Version Number mismatch between Fls_Fmc.c and SchM_Fls.h "
    #endif
    /* Make sure the AUTOSAR minor version number is the same between Fls_Fmc.c and SchM_Fls.h */
    #if (FLS_FLASH_AR_RELEASE_MINOR_VERSION != SCHM_FLS_H_AR_RELEASE_MINOR_VERSION)
        #error "AUTOSAR Minor Version Number mismatch between Fls_Fmc.c and SchM_Fls.h "
    #endif
    /* Make sure the AUTOSAR major version number is the same between Fls_Fmc.c and StdRegMacros.h */
    #if (FLS_FLASH_AR_RELEASE_MAJOR_VERSION != STD_REG_MACROS_H_AR_RELEASE_MAJOR_VERSION)
        #error "AUTOSAR Major Version Number mismatch between Fls_Fmc.c and StdRegMacros.h "
    #endif
    /* Make sure the AUTOSAR minor version number is the same between Fls_Fmc.c and StdRegMacros.h */
    #if (FLS_FLASH_AR_RELEASE_MINOR_VERSION != STD_REG_MACROS_H_AR_RELEASE_MINOR_VERSION)
        #error "AUTOSAR Minor Version Number mismatch between Fls_Fmc.c and StdRegMacros.h "
    #endif
#endif

/**************************************************************************
                    LOCAL FUNCTION DECLARATION
**************************************************************************/
#if (STD_ON == FLASH_PREFETCH_BUFFERS_INVALID)

    #define FLS_START_SEC_RAMCODE
    #include "Fls_MemMap.h"

    /** @defgroup FLS_Fuctions
      @{
    */

    #ifdef G32A_C_LINARO
        static FUNC( void, FLS_CODE ) Fls_FMC_InvalidPrefetchBuff( void ) __attribute__ ((section (".ramcode")));
    #else
        static FUNC( void, FLS_CODE ) Fls_FMC_InvalidPrefetchBuff( void );
    #endif

    /**@} end of group FLS_Fuctions */

    #define FLS_STOP_SEC_RAMCODE
    #include "Fls_MemMap.h"

#endif

#define FLS_START_SEC_CODE
#include "Fls_MemMap.h"

/** @defgroup FLS_Fuctions
  @{
*/

static FUNC( Fls_LLDResultType, FLS_CODE ) Fls_FMC_GetProtReg
           ( VAR( Fls_AddressType, AUTOMATIC) SectStartAddr,
           P2VAR( Fls_AddressType, AUTOMATIC, FLS_APPL_DATA ) RegAddrPtr,
           P2VAR( uint8, AUTOMATIC, FLS_APPL_DATA ) ProtNoPtr );

static FUNC( Fls_LLDResultType, FLS_CODE ) Fls_FMC_CheckPageProtect (void);

#if( STD_ON == FLS_WRITE_VERIFICATION_EN )
static FUNC( Fls_LLDResultType, FLS_CODE ) Fls_FMC_VerifyWriteOpn
           ( P2CONST( volatile Fls_DataWidthType, AUTOMATIC, FLS_APPL_CONST ) WstartAddrPtr,
             P2CONST( uint8, AUTOMATIC, FLS_APPL_CONST ) WriteBufferPtr,
               CONST( Fls_LengthType, AUTOMATIC) VerifyLength );
#endif

static FUNC(Fls_LLDResultType, FLS_CODE) Fls_FMC_CheckStatusIdle(void);

#if(( STD_ON == FLS_ERASE_VERIFICATION_EN ) || ( STD_ON == FLS_WRITEBLANK_VERFY_EN ))
static FUNC( Fls_LLDResultType, FLS_CODE ) Fls_FMC_VerifyEraseOpn
           ( P2CONST(volatile Fls_DataWidthType, AUTOMATIC, FLS_APPL_CONST ) EstartAddrPtr,
               CONST( Fls_LengthType, AUTOMATIC ) VerifyLength );
#endif

/**@} end of group FLS_Fuctions */

#define FLS_STOP_SEC_CODE
#include "Fls_MemMap.h"

/**************************************************************************
                    LOCAL VARIABLE
**************************************************************************/
#define FLS_START_SEC_VAR_INIT_UNSPECIFIED
#include "Fls_MemMap.h"

/** @defgroup FLS_Variable
  @{
*/

#if( STD_ON == FLS_DSIHANDLER_API_EN )
/** Record current status of the sector read operation */
static VAR( volatile Fls_LLDResultType, FLS_VAR ) s_flsReadStatus = FLS_E_OK;
/** Record current status of the sector compare operation */
static VAR( volatile Fls_LLDResultType, FLS_VAR ) s_flsCompareStatus = FLS_E_OK;
#endif

/**@} end of group FLS_Variable */

#define FLS_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Fls_MemMap.h"

#define FLS_START_SEC_VAR_INIT_8
#include "Fls_MemMap.h"

/** @defgroup FLS_Variable
  @{
*/

/** Pointer to current physical address to read uint8, uint32 from flash */
static P2CONST(volatile uint8, FLS_VAR, FLS_APPL_CONST) volatile s_flsReadAddrPtr = NULL_PTR;
/** Pointer to current physical address to compare uint8, uint32 from user buffer */
static P2CONST(volatile uint8, FLS_VAR, FLS_APPL_CONST) volatile s_flsCompareAddrPtr = NULL_PTR;
/** Current sector bit position in Protect register */
static VAR(uint8, FLS_VAR) s_proRegBitPos = 0U;

/**@} end of group FLS_Variable */

#define FLS_STOP_SEC_VAR_INIT_8
#include "Fls_MemMap.h"

#define FLS_START_SEC_VAR_INIT_32
#include "Fls_MemMap.h"

/** @defgroup FLS_Variable
  @{
*/

#if (STD_ON == FLS_TIMEOUT_SUPERVISION_EN)
/** For counting during flash operations */
static VAR(uint32, FLS_VAR) g_timeoutCounter = 0UL;
#endif

/** current sector protect register address */
static VAR(Fls_AddressType, FLS_VAR) s_flsProtAddr = 0UL;
/** Pointer to current target address */
static P2CONST(volatile uint32, FLS_VAR, FLS_APPL_DATA) s_flsTargetAddrPtr = NULL_PTR;

/**@} end of group FLS_Variable */

#define FLS_STOP_SEC_VAR_INIT_32
#include "Fls_MemMap.h"

/**************************************************************************
                    LOCAL FUNCTION
**************************************************************************/
#if (STD_ON == FLASH_PREFETCH_BUFFERS_INVALID)
#define FLS_START_SEC_RAMCODE
#include "Fls_MemMap.h"

/** @defgroup FLS_Fuctions
  @{
*/

/*!
* @brief            Invalidate flash prefetch buffers in ram
*
* @param[in]        None
* @param[out]       None
* @param[in,out]    None
*
* @retval  None
*/
static FUNC(void, FLS_CODE) Fls_FMC_InvalidPrefetchBuff(void)
{
    /* Disable Prefetch Buffer */
    REG_BIT_CLEAR32(FMC_CTRL1_REG_ADDR, FMC_CTRL1_PBEN_MASK);
}

/**@} end of group FLS_Fuctions */

#define FLS_STOP_SEC_RAMCODE
#include "Fls_MemMap.h"
#endif


#define FLS_START_SEC_CODE
#include "Fls_MemMap.h"

/** @defgroup FLS_Fuctions
  @{
*/

/*!
* @brief            Set the ECC error flag
* @details          This function is called by the ECC interrupt service routine. 
*                   When an ECC error occurs, the corresponding global variable is set 
*                   to prevent further reading of the flash memory.
* @param[in]        None
* @param[out]       None
* @param[in,out]    None
*
* @retval  FLS_HANDLEDSTS_UN, FLS_HANDLEDSTS_SKIP
*/
#if( STD_ON == FLS_DSIHANDLER_API_EN )
FUNC( Fls_HandlerRetType, FLS_CODE ) Fls_DsiHandler( void )
{
    VAR( Fls_HandlerRetType, AUTOMATIC ) retResult = FLS_HANDLEDSTS_UN;

    switch (s_flsReadStatus)
    {
        case FLS_E_PENDING:
            s_flsReadStatus = FLS_E_FAILED;
            retResult = FLS_HANDLEDSTS_SKIP;
            break;

        default:
            switch (s_flsCompareStatus)
            {
                case FLS_E_PENDING:
                    s_flsCompareStatus = FLS_E_FAILED;
                    retResult = FLS_HANDLEDSTS_SKIP;
                    break;

                default:
                    /* nothing */
                    break;
            }
            break;
    }
    return retResult;
}
#endif

/*!
* @brief           Get sector's associated protection register address and bit position.
*
* @param[in]       SectStartAddr    Sector start address
* @param[in]       RegAddrPtr       The register corresponding to the sector
* @param[in]       ProtNoPtr        The register bit corresponding to the sector
* @param[out]      None
* @param[in,out]   None
*
* @retval          FLS_E_OK, FLS_E_FAILED
*/
static FUNC(Fls_LLDResultType, FLS_CODE) Fls_FMC_GetProtReg( VAR( Fls_AddressType, AUTOMATIC ) SectStartAddr,
                                                           P2VAR( Fls_AddressType, AUTOMATIC, FLS_APPL_DATA ) RegAddrPtr,
                                                           P2VAR( uint8, AUTOMATIC, FLS_APPL_DATA ) ProtNoPtr )
{
    VAR( Fls_LLDResultType, AUTOMATIC) retResult = FLS_E_OK;
    /* The capacity protected by each bit of the FMC_WRTPROT0 register */
    VAR( uint32, AUTOMATIC) pFlsBitSize = PFLASH_SIZE / 32U;
    /* The capacity protected by each bit of the FMC_WRTPROT1 register */
    VAR( uint32, AUTOMATIC) dFlsBitSize = DFLASH_SIZE / 32U;

    if( (SectStartAddr >= PFLASH_BASEADDR) && (SectStartAddr < (PFLASH_BASEADDR + PFLASH_SIZE)) ) /* Pflash */
    {
        *RegAddrPtr = FMC_WRTPROT0_REG_ADDR;
        *ProtNoPtr = (uint8)( (SectStartAddr - PFLASH_BASEADDR) / pFlsBitSize );
    }
    else if( (SectStartAddr >= DFLASH_BASEADDR) && (SectStartAddr < (DFLASH_BASEADDR + DFLASH_SIZE)) ) /* Dflash */
    {
        *RegAddrPtr = FMC_WRTPROT1_REG_ADDR;
        *ProtNoPtr = (uint8)( (SectStartAddr - DFLASH_BASEADDR) / dFlsBitSize );
    }
    else /* Not flash */
    {
        retResult = FLS_E_FAILED;
    }

    return retResult;
}

/*!
* @brief           Check if the page is write-protected.
*
* @param[in]       None
* @param[out]      None
* @param[in,out]   None
*
* @retval          FLS_E_OK, FLS_E_FAILED
*/
static FUNC(Fls_LLDResultType, FLS_CODE) Fls_FMC_CheckPageProtect(void)
{
    VAR(Fls_LLDResultType, AUTOMATIC) retResult = FLS_E_OK;

    if(Fls_FMC_GetProtReg((uint32)s_flsTargetAddrPtr, &s_flsProtAddr, &s_proRegBitPos) == FLS_E_OK)
    {
        if((uint32)0U == REG_BIT_GET32(s_flsProtAddr, ((uint32)1U << s_proRegBitPos)))
        {
            retResult = FLS_E_FAILED; /* sector has been protected */
        }
        else
        {
            /* Target sector address valid and not in protected state */
        }
    }
    else
    {
        retResult = FLS_E_FAILED; /* Target sector address invalid */
    }

    return retResult;
}

#if( STD_ON == FLS_WRITE_VERIFICATION_EN )
/*!
* @brief           Verify the result status after write operation.
*
* @param[in]       WstartAddrPtr     Flash address
* @param[in]       WriteBufferPtr    source address
* @param[in]       VerifyLength      length to compare
* @param[out]      None
* @param[in,out]   None
*
* @retval          FLS_E_OK, FLS_E_FAILED
*/
static FUNC( Fls_LLDResultType, FLS_CODE ) Fls_FMC_VerifyWriteOpn
     ( P2CONST( volatile Fls_DataWidthType, AUTOMATIC, FLS_APPL_CONST ) WstartAddrPtr,
       P2CONST( uint8, AUTOMATIC, FLS_APPL_CONST ) WriteBufferPtr,
       CONST(Fls_LengthType, AUTOMATIC) VerifyLength )
{
    VAR(Fls_LLDResultType, AUTOMATIC) retResult = FLS_E_OK;

    VAR(uint8, AUTOMATIC) i = 0U;

    VAR(uint8, AUTOMATIC) readData = 0U;
    VAR(uint8, AUTOMATIC) dataCompare = 0U;

    /* avoid More than one read access to volatile objects between sequence points warning */
    volatile const uint8 * basePtr = NULL_PTR;
    VAR(uint8, AUTOMATIC) data = 0U;

#if( STD_ON == FLS_DSIHANDLER_API_EN )
    VAR(Std_ReturnType, AUTOMATIC) flsCompareResult = (Std_ReturnType)E_OK;
    s_flsCompareStatus = FLS_E_PENDING;
#endif

    s_flsCompareAddrPtr = (const uint8 *)WriteBufferPtr;

#if (STD_ON == FLASH_PREFETCH_BUFFERS_INVALID)
    Fls_FMC_InvalidPrefetchBuff();
#endif

    /* Enter special read mode 0 */
    REG_RMW32(FMC_CTRL1_REG_ADDR, FMC_CTRL1_WS_MASK, FMC_CTRL1_WS_MASK);
    REG_BIT_SET32(FMC_CTRL1_REG_ADDR, FMC_CTRL1_VREAD0_EN_MASK);
    while(1U == REG_BIT_GET32(FMC_STS_REG_ADDR, FMC_STS_BUSYF_MASK))
    {
        /* do nothing */
    }
    REG_BIT_SET32(FMC_STS_REG_ADDR, FMC_STS_OCF_MASK);
    while(0U == REG_BIT_GET32(FMC_CTRL1_REG_ADDR, FMC_CTRL1_VREAD0_STS_MASK))
    {
        /* do nothing */
    }

    /* Cycle the all check area */
    for(i = 0U; i < VerifyLength; i++)
    {
#if( STD_ON == FLS_DSIHANDLER_API_EN )
        /* Check start flash access notification */
        if( NULL_PTR != g_flsConfigPtr->startFlsAcNotifyPtr )
        {
            g_flsConfigPtr->startFlsAcNotifyPtr();
        }
        else
        {
            /* do nothing */
        }

        REG_BIT_SET32(FMC_STS_REG_ADDR, FMC_STS_DBFIFLG_MASK);  /* clear DBFIFLG bit */

        basePtr = (volatile const uint8 *)WstartAddrPtr;
        data = basePtr[i];
        readData = data;               /* read flash data */

        /* Check finish Flash Access Notification */
        if( NULL_PTR != g_flsConfigPtr->endFlsAcNotifyPtr )
        {
            g_flsConfigPtr->endFlsAcNotifyPtr();
        }
        else
        {
            /* do nothing */
        }

        /* The exception handler have updated the value of s_flsCompareStatus or ECC handler has been triggered*/
        if (FLS_E_FAILED == s_flsCompareStatus)
        {
            flsCompareResult =  (Std_ReturnType)E_NOT_OK;
        }
        else if (FLS_E_PENDING != s_flsCompareStatus)
        {
            flsCompareResult =  (Std_ReturnType)E_NOT_OK;
        }
        else /* s_flsCompareStatus unchange */
        {
            /* do nothing */
        }
#else
        basePtr = (volatile const uint8 *)WstartAddrPtr;
        data = basePtr[i];
        readData = data;               /* read flash data */
#endif

        basePtr = (volatile const uint8 *)s_flsCompareAddrPtr;
        data = basePtr[i];
        dataCompare = data;               /* read source data */

        if(
#if( STD_ON == FLS_DSIHANDLER_API_EN )
            (E_NOT_OK ==  flsCompareResult) ||
#endif
            (readData != dataCompare) )
        {
            break; /* Read data differs from user buffer or ECC handler has been triggered */
        }
        else /* compare data match */
        {
            /* do nothing */
        }
    }

    /* Exit special read mode 0 */
    REG_BIT_CLEAR32(FMC_CTRL1_REG_ADDR, FMC_CTRL1_VREAD0_EN_MASK);
    while(1U == REG_BIT_GET32(FMC_STS_REG_ADDR, FMC_STS_BUSYF_MASK))
    {
        /* do nothing */
    }
    REG_BIT_SET32(FMC_STS_REG_ADDR, FMC_STS_OCF_MASK);
    while(1U == REG_BIT_GET32(FMC_CTRL1_REG_ADDR, FMC_CTRL1_VREAD0_STS_MASK))
    {
        /* do nothing */
    }
    REG_RMW32(FMC_CTRL1_REG_ADDR, FMC_CTRL1_WS_MASK, 2U);

    if(i == VerifyLength)
    {
        retResult = FLS_E_OK;
#if( STD_ON == FLS_DSIHANDLER_API_EN )
        s_flsCompareStatus = FLS_E_OK;
#endif
    }
    else  /* Not compare all expected address */
    {
#if( STD_ON == FLS_DETECT_RUNTIME_ERROR_EN )
        (void)Det_ReportRuntimeError( (uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID,
                                              FLS_MAINFUNCTION_SVC_ID, FLS_E_VERIFY_WRITE_FAILED );
#endif
        retResult = FLS_E_FAILED;
#if( STD_ON == FLS_DSIHANDLER_API_EN )
        s_flsCompareStatus = FLS_E_FAILED;
#endif
    }

    return retResult;
}
#endif

/*!
* @brief           Check if the flash in idle status.
*
* @param[in]       None
* @param[out]      None
* @param[in,out]   None
*
* @retval          FLS_E_OK, FLS_E_FAILED
*/
static FUNC(Fls_LLDResultType, FLS_CODE) Fls_FMC_CheckStatusIdle(void)
{
    VAR(Fls_LLDResultType, AUTOMATIC) retResult = FLS_E_FAILED;

    retResult = ((uint8)0 == REG_BIT_GET32(FMC_STS_REG_ADDR, FMC_STS_BUSYF_MASK)) ? FLS_E_OK : FLS_E_FAILED ;

    return retResult;
}

#if( (STD_ON == FLS_ERASE_VERIFICATION_EN) || (STD_ON == FLS_WRITEBLANK_VERFY_EN) )
/*!
* @brief           Verify the result status after erase operation.
*
* @param[in]       EstartAddrPtr    start address to be checked
* @param[in]       VerifyLength     length to be checked
* @param[out]      None
* @param[in,out]   None
*
* @retval          FLS_E_OK, FLS_E_FAILED
*/
static FUNC(Fls_LLDResultType, FLS_CODE) Fls_FMC_VerifyEraseOpn
     ( P2CONST(volatile Fls_DataWidthType, AUTOMATIC, FLS_APPL_CONST ) EstartAddrPtr,
         CONST(Fls_LengthType, AUTOMATIC) VerifyLength )
{
    VAR(Fls_LLDResultType, AUTOMATIC) retResult = FLS_E_OK;

    VAR(uint32, AUTOMATIC) numElements = ((uint32)VerifyLength / sizeof(Fls_DataWidthType));
    VAR(uint32, AUTOMATIC) i = 0U;

    /* Get the flash data */
    VAR(Fls_DataWidthType, AUTOMATIC) readData = 0U;

#if( STD_ON == FLS_DSIHANDLER_API_EN )
    /* Indicate read operation verify result, initialized with E_OK */
    VAR(Std_ReturnType, AUTOMATIC) flsReadResult = (Std_ReturnType)E_OK;
    /* Set fls read status as FLS_E_PENDING */
    s_flsReadStatus = FLS_E_PENDING;
#endif

#if (STD_ON == FLASH_PREFETCH_BUFFERS_INVALID)
    Fls_FMC_InvalidPrefetchBuff();
#endif

    /* Enter special read mode 1 */
    REG_RMW32(FMC_CTRL1_REG_ADDR, FMC_CTRL1_WS_MASK, FMC_CTRL1_WS_MASK);
    REG_BIT_SET32(FMC_CTRL1_REG_ADDR, FMC_CTRL1_VREAD1_EN_MASK);
    while(1U == REG_BIT_GET32(FMC_STS_REG_ADDR, FMC_STS_BUSYF_MASK))
    {
        /* do nothing */
    }
    REG_BIT_SET32(FMC_STS_REG_ADDR, FMC_STS_OCF_MASK);
    while(0U == REG_BIT_GET32(FMC_CTRL1_REG_ADDR, FMC_CTRL1_VREAD1_STS_MASK))
    {
        /* do nothing */
    }

    /* Cycle the all check area */
    for(i = 0U; i < numElements; i++)
    {
#if( STD_ON == FLS_DSIHANDLER_API_EN )
        /* Check start flash access notification */
        if( NULL_PTR != g_flsConfigPtr->startFlsAcNotifyPtr )
        {
            g_flsConfigPtr->startFlsAcNotifyPtr();
        }
        else
        {
            /* do nothing */
        }

        REG_BIT_SET32(FMC_STS_REG_ADDR, FMC_STS_DBFIFLG_MASK);  /* clear DBFIFLG bit */

        readData = EstartAddrPtr[i];  /* read flash data */

        /* Check finish Flash Access Notification */
        if( NULL_PTR != g_flsConfigPtr->endFlsAcNotifyPtr )
        {
            g_flsConfigPtr->endFlsAcNotifyPtr();
        }
        else
        {
            /* do nothing */
        }

        /* The exception handler have updated the value of s_flsReadStatus */
        if (FLS_E_FAILED == s_flsReadStatus)
        {
            flsReadResult = (Std_ReturnType)E_NOT_OK;
        }
        else if(FLS_E_PENDING != s_flsReadStatus)
        {
            flsReadResult = (Std_ReturnType)E_NOT_OK;
        }
        else
        {
            /* do nothing */
        }
#else
        readData = EstartAddrPtr[i];  /* read flash data */
#endif

        if(
#if( STD_ON == FLS_DSIHANDLER_API_EN )
            (E_NOT_OK ==  flsReadResult) ||
#endif
            (FLS_ERASED_VALUE != readData))
        {
            break; /* Read data differs from erased value or ECC handler has been triggered */
        }
        else /* Read data match */
        {
            /* do nothing */
        }
    }

    /* Exit special read mode 1 */
    REG_BIT_CLEAR32(FMC_CTRL1_REG_ADDR, FMC_CTRL1_VREAD1_EN_MASK);
    while(1U == REG_BIT_GET32(FMC_STS_REG_ADDR, FMC_STS_BUSYF_MASK))
    {
        /* do nothing */
    }
    REG_BIT_SET32(FMC_STS_REG_ADDR, FMC_STS_OCF_MASK);
    while(1U == REG_BIT_GET32(FMC_CTRL1_REG_ADDR, FMC_CTRL1_VREAD1_STS_MASK))
    {
        /* do nothing */
    }
    REG_RMW32(FMC_CTRL1_REG_ADDR, FMC_CTRL1_WS_MASK, 2U);

    /* Check the result of flash read address */
    if(i == numElements)
    {
        retResult = FLS_E_OK;
#if( STD_ON == FLS_DSIHANDLER_API_EN )
        s_flsReadStatus = FLS_E_OK;
#endif
    }
    else /* Not read all expected address */
    {
#if( STD_ON == FLS_DETECT_RUNTIME_ERROR_EN )
        (void)Det_ReportRuntimeError( (uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID,
                                              FLS_MAINFUNCTION_SVC_ID, FLS_E_VERIFY_ERASE_FAILED );
#endif
        retResult = FLS_E_FAILED;
#if( STD_ON == FLS_DSIHANDLER_API_EN )
        s_flsReadStatus = retResult;
#endif
    }

    return retResult;
}
#endif

/**************************************************************************
                    GLOBAL FUNCTION
**************************************************************************/
#if( STD_ON == FLS_CANCEL_API_EN )
/*!
* @brief           Service for cancel ongoing job
*
* @param[in]       None
* @param[out]      None
* @param[in,out]   None
*
* @retval          None
*/
FUNC(void, FLS_CODE) Fls_FMC_Cancel(void)
{
    VAR(Fls_LLDResultType, AUTOMATIC) retResult = FLS_E_FAILED;

#if( STD_ON == FLS_TIMEOUT_SUPERVISION_EN )
    VAR(uint32, AUTOMATIC) timerCntrAbort = FLS_ABORT_TIMEOUT_CFG;  /* Set the timeout value */
#endif

    /* wait until Command Complete done or timeout */
    while( (1U == (REG_BIT_GET32(FMC_STS_REG_ADDR, FMC_STS_BUSYF_MASK)))
           #if( STD_ON == FLS_TIMEOUT_SUPERVISION_EN )
           && (0U < timerCntrAbort)
           #endif
         )
    {
#if( STD_ON == FLS_TIMEOUT_SUPERVISION_EN )
        --timerCntrAbort;
#endif
    }

    MCAL_FAULT_INJECTION_POINT(FLS_FIP_1_WAIT_FOR_OPERATION_FINISH); /* FIP_1 INJECTION */

    retResult = (0U == REG_BIT_GET32(FMC_STS_REG_ADDR, FMC_STS_BUSYF_MASK)) ? FLS_E_OK : FLS_E_FAILED;

    MCAL_FAULT_INJECTION_POINT(FLS_FIP_10_FLS_FLASH_FINISH_HV_OPERATION); /* FIP_10 INJECTION */

    if(FLS_E_OK == retResult)
    {
        g_jobResult = MEMIF_JOB_CANCELED;
    }
    else
    {
        /* current pending operation not finished, the cancel config fail */
    }
}
#endif

/*!
* @brief           Read flash sector data
*
* @param[in]       readByteOffset    The offset of the starting address relative to the beginning of the page
* @param[in]       DataLen           length to be read
* @param[in]       DataPtr           Used to store the content read from Flash
* @param[out]      None
* @param[in,out]   None
*
* @retval          FLS_E_OK, FLS_E_FAILED
*/
FUNC(Fls_LLDResultType, FLS_CODE) Fls_FMC_Read( CONST(Fls_AddressType, AUTOMATIC) readByteOffset,
                                                  VAR(Fls_LengthType,  AUTOMATIC) DataLen,
                                                P2VAR(uint8, AUTOMATIC, FLS_APPL_DATA) DataPtr )
{
    /* avoid DataLen change warning */
    VAR(Fls_LengthType,  AUTOMATIC) leng = DataLen;
    /* avoid DataPtr change warning */
    P2VAR(uint8, AUTOMATIC, FLS_APPL_DATA) bakeupPtr = DataPtr;
    /* avoid More than one read access to volatile objects between sequence points warning */
    volatile const uint8 * basePtr = NULL_PTR;
    VAR(uint8, AUTOMATIC) data = 0U;

    VAR(Fls_LLDResultType, AUTOMATIC) retResult = FLS_E_FAILED;
    VAR(uint32, AUTOMATIC) currentOffset = readByteOffset;
    /* Get the read begin address */
    P2CONST(volatile uint32, FLS_VAR, FLS_APPL_CONST) volatile sectorArray = (*((*(g_flsConfigPtr->sectorlistPtr))[g_ReadCurSectorId])).sectorStartAddrPtr;
    s_flsReadAddrPtr = &((volatile const uint8*)sectorArray)[readByteOffset];

#if (STD_ON == FLASH_PREFETCH_BUFFERS_INVALID)
    Fls_FMC_InvalidPrefetchBuff();
#endif

#if( STD_ON == FLS_DSIHANDLER_API_EN )
    s_flsReadStatus = FLS_E_PENDING;
#endif

    if( FLS_E_OK != Fls_FMC_CheckStatusIdle() ) /* Make sure Flash controller is idle */
    {
        /* do nothing */
    }
    else
    {
        /* Read one byte at a time; there is no need to consider four-byte alignment issues */
        for( ;(
#if( STD_ON == FLS_DSIHANDLER_API_EN )
               (FLS_E_PENDING == s_flsReadStatus) && 
#endif
              (leng > 0U))
             ; leng--)
        {
#if( STD_ON == FLS_DSIHANDLER_API_EN )
            /* Check start flash access notification */
            if( NULL_PTR != g_flsConfigPtr->startFlsAcNotifyPtr )
            {
                g_flsConfigPtr->startFlsAcNotifyPtr();
            }
            else
            {
                /* do nothing */
            }

            REG_BIT_SET32(FMC_STS_REG_ADDR, FMC_STS_DBFIFLG_MASK);  /* clear DBFIFLG bit */

            basePtr = (volatile const uint8 *)sectorArray;
            data = basePtr[currentOffset];
            *bakeupPtr = data;               /* read flash data */

            /* Check finish Flash Access Notification */
            if( NULL_PTR != g_flsConfigPtr->endFlsAcNotifyPtr )
            {
                g_flsConfigPtr->endFlsAcNotifyPtr();
            }
            else
            {
                /* do nothing */
            }
#else
            basePtr = (volatile const uint8 *)sectorArray;
            data = basePtr[currentOffset];
            *bakeupPtr = data;               /* read flash data */
#endif

            bakeupPtr++;
            currentOffset++;
        }
    }

#if( STD_ON == FLS_DSIHANDLER_API_EN )
    s_flsReadStatus = (FLS_E_PENDING == s_flsReadStatus) ? FLS_E_OK : s_flsReadStatus;
    retResult = s_flsReadStatus;
#else
    retResult = FLS_E_OK;
#endif

    return retResult;
}

/*!
* @brief           Initialize flash hardware unit.
*
* @param[in]       None
* @param[out]      None
* @param[in,out]   None
*
* @retval          None
*/
FUNC(void, FLS_CODE) Fls_FMC_Init(void)
{
    VAR(uint16, AUTOMATIC) cfgIter = 0U;
    VAR(Fls_AddressType, AUTOMATIC) secStartAddr = 0UL;

    g_jobResult = MEMIF_JOB_OK;

    /* Cycle all configured sectors */
    for( cfgIter = 0U; cfgIter < g_flsConfigPtr->sectorCnt; cfgIter++ )
    {
        /* Get the start absolute address of sector */
        secStartAddr = (uint32)(*((*(g_flsConfigPtr->sectorlistPtr))[cfgIter])).sectorStartAddrPtr;

        /* Get the sector protection register address and bit position according to secor start address */
        if( FLS_E_OK == Fls_FMC_GetProtReg(secStartAddr, &s_flsProtAddr, &s_proRegBitPos) )
        {
            /* Check if the sector is protected */
            if( 0U == REG_BIT_GET32(s_flsProtAddr, ((uint32)1U << s_proRegBitPos)) )
            {
                #if( STD_ON == FLS_DETECT_DEV_ERROR_EN )
                    (void)Det_ReportError((uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID, FLS_INIT_SVC_ID, FLS_E_PROTECTED_SECTOR);
                #endif
                    g_jobResult = MEMIF_JOB_FAILED;
            }
            else
            {
                /* This area is unprotected and can be read and written normally. */
            }
        }
        else /* Detected an address that is neither pflash nor dflash */
        {
            g_jobResult = MEMIF_JOB_FAILED;
        }

        if(MEMIF_JOB_FAILED == g_jobResult)
        {
            break;
        }
        else
        {
            /* do nothing */
        }
    }

    if( g_jobResult == MEMIF_JOB_OK )
    {
        /* Ensure that the flash module is in an idle state */
        while(1U == (REG_BIT_GET32(FMC_STS_REG_ADDR, FMC_STS_BUSYF_MASK)))
        {
            /* do nothing */
        }

        /* Unlock Flash to set registers */
        REG_WRITE32(FMC_KEY_REG_ADDR, FMC_KEY_1);
        REG_WRITE32(FMC_KEY_REG_ADDR, FMC_KEY_2);

        /* Enable/Disable Prefetch Buffer function */
    #if( STD_ON == FLASH_PREFETCH_BUFFERS_INVALID )
        REG_BIT_CLEAR32(FMC_CTRL1_REG_ADDR, FMC_CTRL1_PBEN_MASK);
    #else
        REG_BIT_SET32(FMC_CTRL1_REG_ADDR, FMC_CTRL1_PBEN_MASK);
    #endif

        /* Enable/Disable ECC function */
    #if( STD_ON == FLS_DSIHANDLER_API_EN )
        REG_BIT_SET32(FMC_CTRL1_REG_ADDR, FMC_CTRL1_ECCEN_MASK);
        REG_BIT_SET32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_DBFIEN_MASK);
    #else
        REG_BIT_CLEAR32(FMC_CTRL1_REG_ADDR, FMC_CTRL1_ECCEN_MASK);
        REG_BIT_CLEAR32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_DBFIEN_MASK);
    #endif

        /* Clear Flag Bit */
        REG_BIT_SET32(FMC_STS_REG_ADDR, FMC_STS_PEF_MASK | FMC_STS_PAEF_MASK |
                                        FMC_STS_WPEF_MASK | FMC_STS_OCF_MASK | FMC_STS_DBFIFLG_MASK);

    #if (8U == FLS_PROGRAMMING_LENGTH)
        REG_BIT_SET32(FMC_CTRL2_REG_ADDR, 0U);
    #elif (16U == FLS_PROGRAMMING_LENGTH)
        REG_BIT_SET32(FMC_CTRL2_REG_ADDR, 0x00100000U);
    #elif (32U == FLS_PROGRAMMING_LENGTH)
        REG_BIT_SET32(FMC_CTRL2_REG_ADDR, 0x00200000U);
    #elif (64U == FLS_PROGRAMMING_LENGTH)
        REG_BIT_SET32(FMC_CTRL2_REG_ADDR, 0x00300000U);
    #endif

        /* Lock flash registers */
        REG_BIT_SET32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_LOCK_MASK);
    }
    else
    {
        /* do nothing */
    }
}

#if( STD_ON == FLS_COMPARE_API_EN )
/*!
* @brief           Compare flash sector data other data block.
*
* @param[in]       compareByteOffset    The offset of the starting address relative to the beginning of the page
* @param[in]       DataLen              length to be compare
* @param[in]       DataPtr              The content to be compared
* @param[out]      None
* @param[in,out]   None
*
* @retval          FLS_E_OK, FLS_E_BLOCK_INCONSISTENT
*/
FUNC(Fls_LLDResultType, FLS_CODE) Fls_FMC_Compare( CONST(Fls_AddressType, AUTOMATIC) compareByteOffset,
                                                     VAR(Fls_LengthType, AUTOMATIC) DataLen,
                                            CONSTP2CONST(uint8, AUTOMATIC, FLS_APPL_CONST) DataPtr )
{
    VAR(Fls_LLDResultType, AUTOMATIC) retResult = FLS_E_OK;
    VAR(uint16, AUTOMATIC) count = 0U;

    VAR(uint8, AUTOMATIC) readData = 0U;
    VAR(uint8, AUTOMATIC) dataCompare = 0U;

    /* avoid More than one read access to volatile objects between sequence points warning */
    volatile const uint8 * basePtr = NULL_PTR;
    VAR(uint8, AUTOMATIC) data = 0U;

    /* Get flash begin address */
    P2CONST(volatile uint32, FLS_VAR, FLS_APPL_CONST) volatile sectorArray = ((*((*(g_flsConfigPtr->sectorlistPtr))[g_CompareCurSectorId])).sectorStartAddrPtr);
    s_flsReadAddrPtr = &((volatile const uint8*)sectorArray)[compareByteOffset];
    /* Get compare address */
    s_flsCompareAddrPtr = DataPtr;

#if (STD_ON == FLASH_PREFETCH_BUFFERS_INVALID)
    Fls_FMC_InvalidPrefetchBuff();
#endif

#if( STD_ON == FLS_DSIHANDLER_API_EN )
    s_flsCompareStatus = FLS_E_PENDING;
#endif

    /* Compare one byte at a time; there is no need to consider four-byte alignment issues */
    for(count = 0U; (
#if( STD_ON == FLS_DSIHANDLER_API_EN )
                    ( FLS_E_PENDING == s_flsCompareStatus ) &&
#endif
                  (count < DataLen))
                  ; count++)
    {
#if( STD_ON == FLS_DSIHANDLER_API_EN )
        /* Check start flash access notification */
        if( NULL_PTR != g_flsConfigPtr->startFlsAcNotifyPtr )
        {
            g_flsConfigPtr->startFlsAcNotifyPtr();
        }
        else
        {
            /* do nothing */
        }

        REG_BIT_SET32(FMC_STS_REG_ADDR, FMC_STS_DBFIFLG_MASK);  /* clear DBFIFLG bit */

        basePtr = (volatile const uint8 *)sectorArray;
        data = basePtr[compareByteOffset + count];
        readData = data;               /* read flash data */

        /* Check finish Flash Access Notification */
        if( NULL_PTR != g_flsConfigPtr->endFlsAcNotifyPtr )
        {
            g_flsConfigPtr->endFlsAcNotifyPtr();
        }
        else
        {
            /* do nothing */
        }
#else
        basePtr = (volatile const uint8 *)sectorArray;
        data = basePtr[compareByteOffset + count];
        readData = data;               /* read flash data */
#endif

        basePtr = (volatile const uint8 *)s_flsCompareAddrPtr;
        data = basePtr[count];
        dataCompare = data;               /* read source data */

        if(readData != dataCompare)
        {
#if( STD_ON == FLS_DSIHANDLER_API_EN )
            s_flsCompareStatus = (FLS_E_PENDING == s_flsCompareStatus) ? FLS_E_BLOCK_INCONSISTENT : s_flsCompareStatus;
#else
            retResult = FLS_E_BLOCK_INCONSISTENT;
            break;
#endif
        }
        else
        {
            /* do nothing */
        }
    }

    switch (retResult)
    {
        case FLS_E_OK:
#if( STD_ON == FLS_DSIHANDLER_API_EN )
                s_flsCompareStatus = (FLS_E_PENDING == s_flsCompareStatus) ? FLS_E_OK : s_flsCompareStatus;
                retResult = s_flsCompareStatus;
#endif
            break;

        default:
            /* do nothing */
            break;
    }

    return retResult;
}
#endif

#if( STD_ON == FLS_BLANKCHECK_API_EN )
/*!
* @brief           Check whether the given flash content is blank(0xFF).
*
* @param[in]       blankcheckByteOffset    The offset of the starting address relative to the beginning of the page
* @param[in]       DataLen                 length to be compare
* @param[out]      None
* @param[in,out]   None
*
* @retval          FLS_E_OK, FLS_E_BLOCK_INCONSISTENT
*/
FUNC(Fls_LLDResultType, FLS_CODE) Fls_FMC_BlankCheck( CONST(Fls_AddressType, AUTOMATIC) blankcheckByteOffset,
                                                        VAR(Fls_LengthType,  AUTOMATIC) DataLen)
{
    VAR(Fls_LLDResultType, AUTOMATIC) retResult = FLS_E_OK;
    VAR(uint16, AUTOMATIC) count = 0U;

    VAR(uint8, AUTOMATIC) readData = 0U;

    /* avoid More than one read access to volatile objects between sequence points warning */
    volatile const uint8 * basePtr = NULL_PTR;
    VAR(uint8, AUTOMATIC) data = 0U;

    /* Get flash address */
    P2CONST(volatile uint32, FLS_VAR, FLS_APPL_CONST) volatile sectorArray = ((*((*(g_flsConfigPtr->sectorlistPtr))[g_BlankCheckCurSectorId])).sectorStartAddrPtr);
    s_flsReadAddrPtr = &((volatile const uint8*)sectorArray)[blankcheckByteOffset];

#if (STD_ON == FLASH_PREFETCH_BUFFERS_INVALID)
    Fls_FMC_InvalidPrefetchBuff();
#endif

#if( STD_ON == FLS_DSIHANDLER_API_EN )
    s_flsCompareStatus = FLS_E_PENDING;
#endif

    /* Compare one byte at a time; there is no need to consider four-byte alignment issues */
    for(count = 0U; (
#if( STD_ON == FLS_DSIHANDLER_API_EN )
                    (FLS_E_PENDING == s_flsCompareStatus) &&
#endif
                    (count < DataLen))
                  ; count++)
    {
#if( STD_ON == FLS_DSIHANDLER_API_EN )
        /* Check start flash access notification */
        if( NULL_PTR != g_flsConfigPtr->startFlsAcNotifyPtr )
        {
            g_flsConfigPtr->startFlsAcNotifyPtr();
        }
        else
        {
            /* do nothing */
        }

        REG_BIT_SET32(FMC_STS_REG_ADDR, FMC_STS_DBFIFLG_MASK);  /* clear DBFIFLG bit */

        basePtr = (volatile const uint8 *)sectorArray;
        data = basePtr[blankcheckByteOffset + count];
        readData = data;               /* read flash data */

        /* Check finish Flash Access Notification */
        if( NULL_PTR != g_flsConfigPtr->endFlsAcNotifyPtr )
        {
            g_flsConfigPtr->endFlsAcNotifyPtr();
        }
        else
        {
            /* do nothing */
        }
#else
        basePtr = (volatile const uint8 *)sectorArray;
        data = basePtr[blankcheckByteOffset + count];
        readData = data;               /* read flash data */
#endif

        if(readData != 0xFFU)
        {
#if( STD_ON == FLS_DSIHANDLER_API_EN )
            s_flsCompareStatus = (FLS_E_PENDING == s_flsCompareStatus) ? FLS_E_BLOCK_INCONSISTENT : s_flsCompareStatus;
#else
            retResult = FLS_E_BLOCK_INCONSISTENT;
            break;
#endif
        }
        else
        {
            /* do nothing */
        }
    }

    switch (retResult)
    {
        case FLS_E_OK:
#if( STD_ON == FLS_DSIHANDLER_API_EN )
                s_flsCompareStatus = (FLS_E_PENDING == s_flsCompareStatus) ? FLS_E_OK : s_flsCompareStatus;
                retResult = s_flsCompareStatus;
#endif
            break;

        default:
            /* do nothing */
            break;
    }

    return retResult;
}
#endif

/*!
* @brief           Service for write data to flash
*
* @param[in]       writeByteOffset    The offset of the starting address relative to the beginning of the page
* @param[in]       DataLen            length to be write
* @param[in]       DataPtr            data source
* @param[out]      None
* @param[in,out]   None
*
* @retval          FLS_E_OK, FLS_E_FAILED
*/
FUNC(Fls_LLDResultType, FLS_CODE) Fls_FMC_Write( CONST(Fls_AddressType, AUTOMATIC) writeByteOffset,
                                                   VAR(Fls_LengthType,  AUTOMATIC) DataLen,
                                          CONSTP2CONST(uint8, AUTOMATIC, FLS_APPL_CONST) DataPtr )
{
    VAR(Fls_LLDResultType, AUTOMATIC) retResult = FLS_E_FAILED;
    /* used for count */
    VAR(uint32, AUTOMATIC) i = 0;
    VAR(uint32, AUTOMATIC) j = 0;
    /* avoid DataLen change warning */
    VAR(Fls_LengthType, AUTOMATIC) sizeByte = DataLen;
    /* used for storing the 32-bit data after splicing  */
    VAR(uint32, AUTOMATIC) combinedData = 0U;
    /* creating array indices to replace pointer offsets */
    VAR(uint32, AUTOMATIC) dataIndex = 0U;
    VAR(uint32, AUTOMATIC) addressIndex = 0U;
    /* flash sector start address */
    P2CONST(volatile uint32, FLS_VAR, FLS_APPL_DATA) sectorStartAddr = (*((*(g_flsConfigPtr->sectorlistPtr))[g_WriteCurSectorId])).sectorStartAddrPtr;

    SchM_Enter_Fls_FLS_CRITICAL_SECTION0();

    /* Unlock Flash to write register */
    REG_WRITE32(FMC_KEY_REG_ADDR, FMC_KEY_1);
    REG_WRITE32(FMC_KEY_REG_ADDR, FMC_KEY_2);

    /* using the concept of array indexing to calculate the starting address offset */
    /* This is the address offset calculation. Since sectorStartAddrPtr is of type uint32, 
       incrementing the data by 1 results in a 4-byte address offset. As DataLen is measured in bytes, 
       it needs to be divided by 4. */
    addressIndex = (writeByteOffset / 4U);

    s_flsTargetAddrPtr = &sectorStartAddr[addressIndex];

    if ( FLS_E_OK != Fls_FMC_CheckPageProtect() ) /* Check the legality and writability of the sector */
    {
        retResult = FLS_E_FAILED;
    }
    else
    {
        if( FLS_E_OK != Fls_FMC_CheckStatusIdle() ) /* Make sure Flash controller is idle */
        {
            retResult = FLS_E_FAILED;
        }
        else
        {
            REG_BIT_SET32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_PG_MASK);

            for( ;sizeByte >= FLS_PROGRAMMING_LENGTH; sizeByte -= FLS_PROGRAMMING_LENGTH)
            {
            #if( STD_ON == FLS_WRITEBLANK_VERFY_EN )
                /* Verify the target address already erased */
                if( FLS_E_OK != Fls_FMC_VerifyEraseOpn(&sectorStartAddr[addressIndex], FLS_PROGRAMMING_LENGTH) )
                {
                    retResult = FLS_E_FAILED;
                }
                else
            #endif
                {
                    /* write page address */
                    REG_WRITE32(FMC_ADDR_REG_ADDR, (uint32)&sectorStartAddr[addressIndex]);

                    /* Fill Data Register */
                    for (i = 0; i < (FLS_PROGRAMMING_LENGTH / 4U); i++)
                    {
                        /* using array indexing instead of pointer offsets to concatenate 32-bit data */
                        combinedData = 0U;
                        for (j = 0; j < 4U; j++)
                        {
                            combinedData |= (uint32)(DataPtr[dataIndex + (i * 4U) + j]) << (j * 8U);
                        }
                        REG_WRITE32(FMC_PROG_DATA_REG_ADDR(i), combinedData);
                    }

                    #if( STD_ON == FLS_TIMEOUT_SUPERVISION_EN )
                        g_timeoutCounter = FLS_WRITE_TIMEOUT_SYNC; /* Initialize timeout counters */
                    #endif
                    /* Check start flash access notification */
                    if( NULL_PTR != g_flsConfigPtr->startFlsAcNotifyPtr )
                    {
                        g_flsConfigPtr->startFlsAcNotifyPtr();
                    }
                    else
                    {
                        /* do nothing */
                    }

                    MCAL_FAULT_INJECTION_POINT(FLS_FIP_13_FLS_FLASH_SECTOR_WRITE);

                    /*** @warning Fls_Flash_c_MISRA_REF2 [I] Cast between a pointer to function and an integral type. */
                    FLS_ACCESSCODE_CALL(g_flsConfigPtr->acWritePtr,Fls_AcWritePtrType)( FMC_BASEADDR,
                                                                                        g_flsConfigPtr->acNotificationPtr
                    #if( STD_ON == FLS_TIMEOUT_SUPERVISION_EN )
                                                                                      , &g_timeoutCounter
                    #endif
                                                                                      );

                    MCAL_FAULT_INJECTION_POINT(FLS_FIP_14_FLS_FLASH_SECTOR_ERASE);

                    /* Check finish Flash Access Notification */
                    if( NULL_PTR != g_flsConfigPtr->endFlsAcNotifyPtr )
                    {
                        g_flsConfigPtr->endFlsAcNotifyPtr();
                    }
                    else
                    {
                        /* do nothing */
                    }

                    #if( STD_ON == FLS_DSIHANDLER_API_EN )
                    if((0U == REG_BIT_GET32(FMC_STS_REG_ADDR, FMC_STS_PEF_MASK | FMC_STS_PAEF_MASK | FMC_STS_WPEF_MASK | FMC_STS_DBFIFLG_MASK))
                    #else
                    if((0U == REG_BIT_GET32(FMC_STS_REG_ADDR, FMC_STS_PEF_MASK | FMC_STS_PAEF_MASK | FMC_STS_WPEF_MASK))
                    #endif
                    #if( STD_ON == FLS_TIMEOUT_SUPERVISION_EN )
                    && (0U != g_timeoutCounter)
                    #endif
                      )
                    {
                        #if( STD_ON == FLS_WRITE_VERIFICATION_EN )
                        if (FLS_E_OK != Fls_FMC_VerifyWriteOpn(&sectorStartAddr[addressIndex], (const uint8 *)&DataPtr[dataIndex], FLS_PROGRAMMING_LENGTH ))
                        {
                            retResult = FLS_E_FAILED;
                        }
                        else
                        #endif
                        {
                            retResult = FLS_E_OK;
                        }
                    }
                    else /* errors, program operation fail */
                    {
                        #if( STD_ON == FLS_TIMEOUT_SUPERVISION_EN )
                        if (0U == g_timeoutCounter)
                        {
                            #if( STD_ON == FLS_DETECT_RUNTIME_ERROR_EN )
                            (void)Det_ReportRuntimeError((uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID,
                                                                 FLS_MAINFUNCTION_SVC_ID, FLS_E_TIMEOUT);
                            #endif
                        }
                        else
                        {
                            /* nothing to do */
                        }
                        #endif

                        retResult = FLS_E_FAILED;
                    }
                    dataIndex += FLS_PROGRAMMING_LENGTH;
                    addressIndex += (FLS_PROGRAMMING_LENGTH / 4U);
                }

                if(FLS_E_FAILED == retResult)
                {
                    break;
                }
                else
                {
                    /* do nothing */
                }
            }
        }
    }

    /* clear Program bit */
    REG_BIT_CLEAR32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_PG_MASK);
    /* Lock flash registers */
    REG_BIT_SET32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_LOCK_MASK);

    SchM_Exit_Fls_FLS_CRITICAL_SECTION0();

    return retResult;
}

/*!
* @brief           Service for flash sector erase.
*
* @param[in]       None
* @param[out]      None
* @param[in,out]   None
*
* @retval          FLS_E_OK, FLS_E_FAILED
*/
FUNC( Fls_LLDResultType, FLS_CODE ) Fls_FMC_Erase(void)
{
    VAR(Fls_LLDResultType, AUTOMATIC) retResult = FLS_E_FAILED;
    VAR(uint32, AUTOMATIC) eraSecCycle = 0U;

    SchM_Enter_Fls_FLS_CRITICAL_SECTION0();

    /* Unlock Flash to write register */
    REG_WRITE32(FMC_KEY_REG_ADDR, FMC_KEY_1);
    REG_WRITE32(FMC_KEY_REG_ADDR, FMC_KEY_2);

    /* Traverse all the sectors that need to be erased */
    for(eraSecCycle = g_EraseSectorStartId; eraSecCycle <= g_EraseSectorEndId; eraSecCycle++)
    {
        s_flsTargetAddrPtr = (*((*(g_flsConfigPtr->sectorlistPtr))[eraSecCycle])).sectorStartAddrPtr;

        /* Check whether the sector to be erased is valid and not write-protected */
        if ( FLS_E_OK == Fls_FMC_CheckPageProtect() )
        {
            /* Make sure the verify Flash controller is idle */
            if( FLS_E_OK == Fls_FMC_CheckStatusIdle() )
            {
                #if( STD_ON == FLS_TIMEOUT_SUPERVISION_EN )
                g_timeoutCounter = FLS_ERASE_TIMEOUT_SYNC;
                #endif
                /* clear error flag */
                REG_BIT_SET32(FMC_STS_REG_ADDR, FMC_STS_PEF_MASK | FMC_STS_PAEF_MASK | FMC_STS_WPEF_MASK | FMC_STS_DBFIFLG_MASK);
                /* enable page erase */
                REG_BIT_SET32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_PAGEERA_MASK);
                /* write page address */
                REG_WRITE32(FMC_ADDR_REG_ADDR, (uint32)s_flsTargetAddrPtr);

                /* Check start flash access notification */
                if( NULL_PTR != g_flsConfigPtr->startFlsAcNotifyPtr )
                {
                    g_flsConfigPtr->startFlsAcNotifyPtr();
                }
                else
                {
                    /* do nothing */
                }

                /* Star to erase operation */
                /*** @warning Fls_Flash_c_MISRA_REF2 [I] Cast between a pointer to function and an integral type. */
                FLS_ACCESSCODE_CALL( g_flsConfigPtr->acErasePtr,
                                     Fls_AcErasePtrType)(FMC_BASEADDR, g_flsConfigPtr->acNotificationPtr
                                     #if( STD_ON == FLS_TIMEOUT_SUPERVISION_EN )
                                     , &g_timeoutCounter
                                     #endif
                                    );

                /* Check finish Flash Access Notification */
                if( NULL_PTR != g_flsConfigPtr->endFlsAcNotifyPtr )
                {
                    g_flsConfigPtr->endFlsAcNotifyPtr();
                }
                else
                {
                    /* do nothing */
                }

                /* Check error of erase operation */

                #if( STD_ON == FLS_DSIHANDLER_API_EN )
                if((0U == REG_BIT_GET32(FMC_STS_REG_ADDR, FMC_STS_PEF_MASK | FMC_STS_PAEF_MASK | FMC_STS_WPEF_MASK| FMC_STS_DBFIFLG_MASK))
                #else
                if((0U == REG_BIT_GET32(FMC_STS_REG_ADDR, FMC_STS_PEF_MASK | FMC_STS_PAEF_MASK | FMC_STS_WPEF_MASK))
                #endif
                #if( STD_ON == FLS_TIMEOUT_SUPERVISION_EN )
                    && (0U != g_timeoutCounter)
                #endif
                  )
                {
                    /* Check the memory area after erase */
                    #if( STD_ON == FLS_ERASE_VERIFICATION_EN )
                        if( FLS_E_OK != Fls_FMC_VerifyEraseOpn(s_flsTargetAddrPtr, PAGE_SIZE) )
                        {
                            retResult = FLS_E_FAILED;
                        }
                        else
                    #endif
                        {
                            retResult = FLS_E_OK;
                        }
                }
                else /* errors, erase operation fail */
                {
                    #if( STD_ON == FLS_TIMEOUT_SUPERVISION_EN )
                    if( 0U == g_timeoutCounter )
                    {
                        #if( STD_ON == FLS_DETECT_RUNTIME_ERROR_EN )
                        (void)Det_ReportRuntimeError((uint16)FLS_H_MODULE_ID, FLS_INSTANCE_MODULE_ID,
                                                             FLS_MAINFUNCTION_SVC_ID, FLS_E_TIMEOUT);
                        #endif
                    }
                    else
                    {
                          /* do nothing */
                    }
                    #endif
                    /* clear error flag */
                    REG_BIT_SET32(FMC_STS_REG_ADDR, FMC_STS_PEF_MASK | FMC_STS_PAEF_MASK | FMC_STS_WPEF_MASK | FMC_STS_DBFIFLG_MASK);

                    retResult = FLS_E_FAILED;
                }
            }
            else
            {
                retResult = FLS_E_FAILED;
            }
        }
        else
        {
            retResult = FLS_E_FAILED;
        }

        if(FLS_E_FAILED == retResult)
        {
            break;
        }
        else
        {
            /* do nothing */
        }
    }

    /* clear PAGEERA bit */
    REG_BIT_CLEAR32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_PAGEERA_MASK);
    /* Lock flash registers */
    REG_BIT_SET32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_LOCK_MASK);

    SchM_Exit_Fls_FLS_CRITICAL_SECTION0();

    return retResult;
}

#if(STD_ON == FLS_WRITE_OPTION_BYTE_API_EN)
/*!
* @brief           Program Option Byte Area.
*
* @param[in]       DataPtr  - pointer to target option byte area data 
* @param[out]      None
* @param[in,out]   None
*
* @retval          None
*/
FUNC(void, FLS_CODE) Fls_FMC_WriteOptionByte( CONSTP2CONST(uint32, AUTOMATIC, FLS_APPL_CONST) DataPtr )
{
    /* used for count */
    VAR(uint8, AUTOMATIC) i = 0U;

    /* Unlock Flash to write register */
    REG_WRITE32(FMC_KEY_REG_ADDR, FMC_KEY_1);
    REG_WRITE32(FMC_KEY_REG_ADDR, FMC_KEY_2);

    while(1U == REG_BIT_GET32(FMC_STS_REG_ADDR, FMC_STS_BUSYF_MASK))
    {
        /* do nothing */
    }

    /* Erase option byte area */
    REG_WRITE32(FMC_OBKEY_REG_ADDR, FMC_KEY_1);
    REG_WRITE32(FMC_OBKEY_REG_ADDR, FMC_KEY_2);

    while(0U == REG_BIT_GET32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_OBWEN_MASK))
    {
        /* do nothing */
    }

    REG_BIT_SET32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_OBE_MASK);

    REG_BIT_SET32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_STA_MASK);

    while(1U == REG_BIT_GET32(FMC_STS_REG_ADDR, FMC_STS_BUSYF_MASK))
    {
        /* do nothing */
    }

    REG_BIT_CLEAR32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_OBE_MASK);

    /* Write 16 bytes to option byte area */
    while(0U == REG_BIT_GET32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_OBWEN_MASK))
    {
        /* do nothing */
    }

    REG_BIT_SET32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_OBP_MASK);

    REG_WRITE32(FMC_ADDR_REG_ADDR, 0x1FFFF800U);

    REG_RMW32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_PROGLEN_MASK, (uint32)1U << FMC_CTRL2_PROGLEN_SHIFT);

    for(i = 0U; i < 4U; i++)
    {
        REG_WRITE32(FMC_PROG_DATA_REG_ADDR(i), DataPtr[i]);
    }

    REG_BIT_SET32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_STA_MASK);

    while(1U == REG_BIT_GET32(FMC_STS_REG_ADDR, FMC_STS_BUSYF_MASK))
    {
        /* do nothing */
    }

    REG_BIT_CLEAR32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_OBP_MASK);

    /* Write 8 bytes to option byte area */
    while(0U ==  REG_BIT_GET32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_OBWEN_MASK))
    {
        /* do nothing */
    }

    REG_BIT_SET32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_OBP_MASK);

    REG_WRITE32(FMC_ADDR_REG_ADDR, 0x1FFFF810U);

    REG_BIT_CLEAR32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_PROGLEN_MASK);

    REG_WRITE32(FMC_PROG_DATA_REG_ADDR(0U), DataPtr[4U]);
    REG_WRITE32(FMC_PROG_DATA_REG_ADDR(1U), DataPtr[5U]);

    REG_BIT_SET32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_STA_MASK);

    while(1U == REG_BIT_GET32(FMC_STS_REG_ADDR, FMC_STS_BUSYF_MASK))
    {
        /* do nothing */
    }

    REG_BIT_CLEAR32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_OBP_MASK);

    /* Lock Flash */
    REG_BIT_SET32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_LOCK_MASK);
}
#endif

/*!
* @brief           Read Option Byte Register.
*
* @param[in]       RegId  - Option Byte Register Id
* @param[out]      None
* @param[in,out]   None
*
* @retval          uint8    register value
*/
FUNC(uint8, FLS_CODE) Fls_FMC_ReadOptByteReg(VAR(Fls_OptByteReadRegIdType, AUTOMATIC) RegId)
{
    VAR(uint8, AUTOMATIC) regValue = 0U;

    switch (RegId)
    {
        case OPTBYTE_READPORT_REG:
                regValue = REG_READ8((uint32)OPTBYTE_READPORT_REG);
             break;

        case OPTBYTE_UOB_REG:
                regValue = REG_READ8((uint32)OPTBYTE_UOB_REG);
             break;

        case OPTBYTE_DATA0_REG:
                regValue = REG_READ8((uint32)OPTBYTE_DATA0_REG);
             break;

        case OPTBYTE_DATA1_REG:
                regValue = REG_READ8((uint32)OPTBYTE_DATA1_REG);
             break;

        case OPTBYTE_WRP0_REG:
                regValue = REG_READ8((uint32)OPTBYTE_WRP0_REG);
             break;

        case OPTBYTE_WRP1_REG:
                regValue = REG_READ8((uint32)OPTBYTE_WRP1_REG);
             break;

        case OPTBYTE_WRP2_REG:
                regValue = REG_READ8((uint32)OPTBYTE_WRP2_REG);
             break;

        case OPTBYTE_WRP3_REG:
                regValue = REG_READ8((uint32)OPTBYTE_WRP3_REG);
             break;

        case OPTBYTE_WRP4_REG:
                regValue = REG_READ8((uint32)OPTBYTE_WRP4_REG);
             break;

        case OPTBYTE_WRP5_REG:
                regValue = REG_READ8((uint32)OPTBYTE_WRP5_REG);
             break;

        case OPTBYTE_WRP6_REG:
                regValue = REG_READ8((uint32)OPTBYTE_WRP6_REG);
             break;

        case OPTBYTE_WRP7_REG:
                regValue = REG_READ8((uint32)OPTBYTE_WRP7_REG);
             break;

        default:
            /* do nothing */
            break;
    }

    return (uint8)regValue;
}

#if(STD_ON == FLS_ERASE_PFLASH_DFLASH_API_EN)
/*!
* @brief           Select erase area.
*
* @param[in]       TargetFlash    flash type (ONLY_EARSE_PFLASH, ONLY_EARSE_DFLASH, EARSE_PFLASH_DFLASH)
* @param[out]      None
* @param[in,out]   None
*
* @retval          FLS_E_FAILED, FLS_E_OK
*/
FUNC(Fls_LLDResultType, FLS_CODE) Fls_FMC_ErasePflashDflash(VAR(Fls_EraseFlashType, AUTOMATIC) TargetFlash)
{
    VAR(Fls_LLDResultType, AUTOMATIC) retResult = FLS_E_FAILED;
    VAR(Fls_AddressType, AUTOMATIC) addrStartCheck = 0UL;
    VAR(Fls_LengthType, AUTOMATIC) lengthCheck = 0UL;

    if(ONLY_EARSE_PFLASH == TargetFlash)
    {
        addrStartCheck = PFLASH_BASEADDR;
        lengthCheck = PFLASH_SIZE;
    }
    else if(ONLY_EARSE_DFLASH == TargetFlash)
    {
        addrStartCheck = DFLASH_BASEADDR;
        lengthCheck = DFLASH_SIZE;
    }
    else
    {
        addrStartCheck = PFLASH_BASEADDR;
        lengthCheck = PFLASH_SIZE + DFLASH_SIZE;
    }

    REG_WRITE32(FMC_KEY_REG_ADDR, FMC_KEY_1);
    REG_WRITE32(FMC_KEY_REG_ADDR, FMC_KEY_2);

    while(1U == REG_BIT_GET32(FMC_STS_REG_ADDR, FMC_STS_BUSYF_MASK))
    {
        /* do nothing */
    }

    REG_BIT_SET32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_MASSERA_MASK);

    REG_BIT_SET32(FMC_CTRL2_REG_ADDR, (uint32)TargetFlash << FMC_CTRL2_MER_TYPE_SHIFT);

    REG_BIT_SET32(FMC_CTRL2_REG_ADDR, FMC_CTRL2_STA_MASK);

    while(1U == REG_BIT_GET32(FMC_STS_REG_ADDR, FMC_STS_BUSYF_MASK))
    {
        /* do nothing */
    }

#if( STD_ON == FLS_ERASE_VERIFICATION_EN )
    if( FLS_E_OK != Fls_FMC_VerifyEraseOpn((const volatile Fls_DataWidthType*)addrStartCheck, lengthCheck) )
    {
        retResult = FLS_E_FAILED;
    }
    else
#endif
    {
        retResult = FLS_E_OK;
    }

    return retResult;
}
#endif

/**@} end of group FLS_Fuctions */

#define FLS_STOP_SEC_CODE
#include "Fls_MemMap.h"

#ifdef __cplusplus
}
#endif

/**@} end of group FLS_Driver */
/**@} end of group G32A10xx_StdPeriphDriver */
