/**
* @file    Fls_Lld_Qspi.c
*==================================================================================================
*   Project              : YTMicro AUTOSAR 4.4.0 MCAL
*   Platform             : ARM
*   Peripheral           : Fls_Lld_Qspi
*   Dependencies         : none
*
*   Autosar Version      : V4.4.0
*   Autosar Revision     : ASR_REL_4_4_REV_0000
*   SW Version           : V2.3.0
*
*   (c) Copyright 2020-2025 Yuntu Microelectronics co.,ltd.
*   All Rights Reserved.
==================================================================================================*/

#ifdef __cplusplus
extern "C"
{
#endif

/*
 * @page misra_violations MISRA-C:2012 violations list
 * PRQA S 2985 Rule 2.2: There shall be no dead code.
 *
 * PRQA S 0306 Rule 11.4: Rule-11.4 A conversion should not be performed between a pointer to
 *                          object and an integer type.
 *
 * PRQA S 0310 Rule 11.3: A cast shall not be performed between a pointer to object type and a
 *                          pointer to a different object type
 *
 * PRQA S 3305 Rule 11.3: A cast shall not be performed between a pointer to object type and a
 *                          pointer to a different object type
 */
/*==================================================================================================
                                              INCLUDE FILES
==================================================================================================*/
#include "Fls_Cfg.h"
#if (FLS_QSPI_SECTORS_CONFIGURED==STD_ON)
#include "Fls_Qspi_Types.h"
#include "Fls_Lld_Qspi.h"
#include "Fls_Qspi_Reg.h"
#include "Fls_Qspi_Cfg.h"
#include "OsIf.h"
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
#include "DevAssert.h"
#endif
/*==================================================================================================
                                      SOURCE FILE VERSION INFORMATION
==================================================================================================*/
#define FLS_LLD_QSPI_VENDOR_ID_C                    (180)
#define FLS_LLD_QSPI_AR_REL_MAJOR_VER_C              (4)
#define FLS_LLD_QSPI_AR_REL_MINOR_VER_C              (4)
#define FLS_LLD_QSPI_AR_REL_REVISION_VER_C           (0)
#define FLS_LLD_QSPI_SW_MAJOR_VER_C                  (2)
#define FLS_LLD_QSPI_SW_MINOR_VER_C                  (3)
#define FLS_LLD_QSPI_SW_PATCH_VER_C                  (0)
/*==================================================================================================
                                            FILE VERSION CHECKS
==================================================================================================*/
/* Check if source file and FLS_LLD_QSPI header file are of the same vendor */
#if (FLS_LLD_QSPI_VENDOR_ID_C != FLS_LLD_QSPI_VENDOR_ID)
#error "Fls_Lld_Qspi.c and Fls_Lld_Qspi.h have different vendor ids"
#endif

/* Check if source file and FLS_LLD_QSPI header file are of the same Autosar version */
#if (( FLS_LLD_QSPI_AR_REL_MAJOR_VER_C != FLS_LLD_QSPI_AR_REL_MAJOR_VER) || \
      ( FLS_LLD_QSPI_AR_REL_MINOR_VER_C != FLS_LLD_QSPI_AR_REL_MINOR_VER) || \
      ( FLS_LLD_QSPI_AR_REL_REVISION_VER_C != FLS_LLD_QSPI_AR_REL_REVISION_VER))
#error "AutoSar Version Numbers of Fls_Lld_Qspi.c and Fls_Lld_Qspi.h are different"
#endif

/* Check if source file and FLS_LLD_QSPI header file are of the same Software version */
#if (( FLS_LLD_QSPI_SW_MAJOR_VER_C != FLS_LLD_QSPI_SW_MAJOR_VER) || \
      ( FLS_LLD_QSPI_SW_MINOR_VER_C != FLS_LLD_QSPI_SW_MINOR_VER) || \
      ( FLS_LLD_QSPI_SW_PATCH_VER_C != FLS_LLD_QSPI_SW_PATCH_VER))
#error "Software Version Numbers of Fls_Lld_Qspi.c and Fls_Lld_Qspi.h are different"
#endif

/*Check if source file and Fls_Qspi_Cfg.h header file are of the same vendor */
#if (FLS_LLD_QSPI_VENDOR_ID_C != FLS_QSPI_VENDOR_ID_CFG)
#error "Fls_Lld_Qspi.c and Fls_Qspi_Cfg.h have different vendor ids"
#endif

/*Check if source file and Fls_Qspi_Cfg.h header file are of the same vendor */
#if (( FLS_LLD_QSPI_AR_REL_MAJOR_VER_C != FLS_QSPI_AR_REL_MAJOR_VER_CFG) || \
      ( FLS_LLD_QSPI_AR_REL_MINOR_VER_C != FLS_QSPI_AR_REL_MINOR_VER_CFG) || \
      ( FLS_LLD_QSPI_AR_REL_REVISION_VER_C != FLS_QSPI_AR_REL_REVISION_VER_CFG))
#error "AutoSar Version Numbers of Fls_Lld_Qspi.c and Fls_Qspi_Cfg.h are different"
#endif

/*Check if source file and Fls_Qspi_Cfg.h header file are of the same vendor */
#if (( FLS_LLD_QSPI_SW_MAJOR_VER_C != FLS_QSPI_SW_MAJOR_VER_CFG) || \
      ( FLS_LLD_QSPI_SW_MINOR_VER_C != FLS_QSPI_SW_MINOR_VER_CFG) || \
      ( FLS_LLD_QSPI_SW_PATCH_VER_C != FLS_QSPI_SW_PATCH_VER_CFG))
#error "Software Version Numbers of Fls_Lld_Qspi.c and Fls_Qspi_Cfg.h are different"
#endif

/*==================================================================================================
                                                GLOBAL VARIABLES
==================================================================================================*/
/*==================================================================================================
                                                LOCAL VARIABLES
==================================================================================================*/
#define FLS_START_SEC_VAR_INIT_32
#include "Fls_MemMap.h"
/* Table of base addresses for QuadSPI instances. */
FLS_VAR volatile static QSPI_Type *const Qspi_RegBase[QSPI_INSTANCE_COUNT] = QSPI_BASE_PTRS;

#define FLS_STOP_SEC_VAR_INIT_32
#include "Fls_MemMap.h"

#define FLS_START_SEC_CONST_32
#include "Fls_MemMap.h"
/* Table of AHB addresses for QuadSPI instances. */
FLS_CONST static const uint32 Qspi_AhbAddress[QSPI_INSTANCE_COUNT] = QSPI_AHB_PTRS;
#define FLS_STOP_SEC_CONST_32
#include "Fls_MemMap.h"

#define FLS_START_SEC_VAR_CLEARED_8
#include "Fls_MemMap.h"
/* The Padding bytes information to handle unaligned read/write Operation for QuadSPI instances:
   - For read:
        [7:0] the number of Padding bytes to handle read from unaligned Address
   - For write:
        [7:4] the number of pre-Padding bytes to handle write from unaligned start Address
        [3:0] the number of post-Padding bytes to handle write from unaligned end Address
 */
FLS_VAR static uint8 Qspi_MemoryPadding[QSPI_INSTANCE_COUNT];
#define FLS_STOP_SEC_VAR_CLEARED_8
#include "Fls_MemMap.h"

#define FLS_START_SEC_VAR_CLEARED_32
#include "Fls_MemMap.h"
/* Pointer to runtime State structures */
FLS_VAR static Qspi_StateType Qspi_MemoryStateStructure[QSPI_MEM_INSTANCE_COUNT];
#define FLS_STOP_SEC_VAR_CLEARED_32
#include "Fls_MemMap.h"

/*==================================================================================================
                                                LOCAL CONSTANTS
==================================================================================================*/
/*==================================================================================================
                                                LOCAL MACROS
==================================================================================================*/
#define QSPI_ERR_FLAGS_MASK    (QSPI_IF_TXUF_MASK | \
                                QSPI_IF_IIE_MASK | \
                                QSPI_IF_RXOF_MASK | \
                                QSPI_IF_APBTE_MASK | \
                                QSPI_IF_APBAE_MASK)

#define QSPI_WORD_SIZE              4U
#define QSPI_HALFWORD_SIZE          2U
#define QSPI_BYTE_SIZE              1U
#define QSPI_TOWBIT_MASK         0x03U


/* Bit-fields of chip-specific MCFG[SCLKCFG] field */
#define QSPI_MCFG_SCLKCFG_INPUT_EN      0x80U    /* Enable input buffer of QSPI pads */
#define QSPI_MCFG_SCLKCFG_CLK_MOD       0x40U    /* Quadspi Clocking mode selection  */
#define QSPI_MCFG_SCLKCFG_EXT_DQS       0x20U    /* Use external DQS (HyperRAM mode) */
#define QSPI_MCFG_SCLKCFG_CLK_SRC       0x10U    /* QSPI source clock selection   */
#define QSPI_MCFG_SCLKCFG_DQS_INV_B     0x08U    /* B-side DQS invert                */
#define QSPI_MCFG_SCLKCFG_DQS_SEL_B     0x04U    /* B-side DQS select                */
#define QSPI_MCFG_SCLKCFG_DQS_INV_A     0x02U    /* A-side DQS invert                */
#define QSPI_MCFG_SCLKCFG_DQS_SEL_A     0x01U    /* A-side DQS select                */
/* Bit-fields of chip-specific SOCCR[SOCCFG] field */
/* Programmable Divider Selection */
#define QSPI_SOCCR_PD_MASK                 0xE0000000u
#define QSPI_SOCCR_PD_SHIFT                29u
#define QSPI_SOCCR_PD(x)                   (((uint32)(((uint32)(x))<<QSPI_SOCCR_PD_SHIFT))&QSPI_SOCCR_PD_MASK)
/* Programmable Divider Disable */
#define QSPI_SOCCR_PDD_MASK                0x10000000u
#define QSPI_SOCCR_PDD_SHIFT               28u
#define QSPI_SOCCR_PDD(x)                  (((uint32)(((uint32)(x))<<QSPI_SOCCR_PDD_SHIFT))&QSPI_SOCCR_PDD_MASK)

#define QSPI_SOCCR_DSQ_DEL_B               8u
#define QSPI_SOCCR_DSQ_DEL_A               0u


#define QSPI_RX_READOUT_IP   1U        /* RX Buffer content is read using the AHB Bus registers QSPI_ARDBn */
#define QSPI_RX_READOUT_AHB  0U        /* RX Buffer content is read using the IP Bus registers QSPI_RXDATn  */

/* Last command sent to the flash device */
#define QSPI_LAST_COMMAND_NONE     0U
#define QSPI_LAST_COMMAND_WRITE    1U
#define QSPI_LAST_COMMAND_ERASE    2U
/*==================================================================================================
                                                LOCAL FUNCTIONS
==================================================================================================*/

static Qspi_StatusType Qspi_Lld_WaitTransactionComplete(volatile const QSPI_Type *BaseAddr);

static inline uint32 Qspi_Lld_GetWordSize(uint32 SizeRemaining);


#define FLS_START_SEC_CODE
#include "Fls_MemMap.h"
/*
 * Triggers an APB transaction
 */
FLS_FUNC static inline void Qspi_Lld_IpTrigger(volatile QSPI_Type *BaseAddr,
        uint8 SeqID,
        uint16 DataSize)
{
    /*MR12 RULE 2.2 VIOLATION: For the sake of stylistic uniformity of register manipulation functions,
    *                         there is a shift as '<<0'.
    */
    BaseAddr->APBCFG =  QSPI_APBCFG_SEQID(SeqID) | QSPI_APBCFG_DATSZ(DataSize); /*PRQA S 2985*/
}


/*
 * Triggers an AHB transaction
 */
#if defined (UNIT_TEST)
FLS_FUNC static inline void Qspi_Lld_AhbTrigger(volatile QSPI_Type *BaseAddr,
        uint8 SeqID,
        uint16 ResTimeOut)
{
    BaseAddr->AHBCFG =  QSPI_AHBCFG_SEQID(SeqID) | \
                        QSPI_AHBCFG_RESPTO(ResTimeOut);
}
#endif

/*
 * Clear Rx buffer
 */
FLS_FUNC static inline void Qspi_Lld_ClearRxBuf(volatile QSPI_Type *BaseAddr)
{
    BaseAddr->MCFG |= QSPI_MCFG_RXFCLR_MASK;
}


/*
 * Clear Tx buffer
 */
FLS_FUNC static inline void Qspi_Lld_ClearTxBuf(volatile QSPI_Type *BaseAddr)
{
    BaseAddr->MCFG |= QSPI_MCFG_TXFCLR_MASK;
}


/*
 * Enable QSPI device
 */
FLS_FUNC static inline void Qspi_Lld_Enable(volatile QSPI_Type *BaseAddr)
{
    BaseAddr->MEN |= QSPI_MEN_EN_MASK;
}


/*
 * Disable QSPI device
 */
FLS_FUNC static inline void Qspi_Lld_Disable(volatile QSPI_Type *BaseAddr)
{
    BaseAddr->MEN &= ~QSPI_MEN_EN_MASK;
}


/*
 * Enable DDR mode
 */
FLS_FUNC static inline void Qspi_Lld_DdrEnable(volatile QSPI_Type *BaseAddr)
{
    BaseAddr->MCFG |= QSPI_MCFG_DDREN_MASK;
}


/*
 * Disable DDR mode
 */
FLS_FUNC static inline void Qspi_Lld_DdrDisable(volatile QSPI_Type *BaseAddr)
{
    BaseAddr->MCFG &= ~QSPI_MCFG_DDREN_MASK;
}

#if defined (UNIT_TEST)
/*
 * Enable DQS
 */
FLS_FUNC static inline void Qspi_Lld_DqsEnable(volatile QSPI_Type *BaseAddr)
{
    BaseAddr->MCFG |= QSPI_MCFG_DQSEN_MASK;
}


/*
 * Disable DQS
 */
FLS_FUNC static inline void Qspi_Lld_DqsDisable(volatile QSPI_Type *BaseAddr)
{
    BaseAddr->MCFG &= ~QSPI_MCFG_DQSEN_MASK;
}


/*
 * Enable or disable DQS Output
 */
FLS_FUNC static inline void Qspi_Lld_DqsOutputEnable(volatile QSPI_Type *BaseAddr, boolean Enable)
{
    uint32 RegValue = BaseAddr->MCFG;
    RegValue &= (~QSPI_MCFG_DQSOUTEN_MASK);
    RegValue |= QSPI_MCFG_DQSOUTEN(Enable);
    BaseAddr->MCFG = RegValue;
}
#endif

/*
 * Enable or disable DQS Latency
 */
FLS_FUNC static inline void Qspi_Lld_DqsLatEnable(volatile QSPI_Type *BaseAddr, boolean Enable)
{
    uint32 RegValue = BaseAddr->MCFG;
    RegValue &= (~QSPI_MCFG_DQSLATEN_MASK);
    RegValue |= QSPI_MCFG_DQSLATEN(Enable);
    BaseAddr->MCFG = RegValue;
}

#if defined (UNIT_TEST)
/*
 * Enable or disable Variable Latency (Only used in HyperRAM device)
 */
FLS_FUNC static inline void Qspi_Lld_VariableLatEnable(volatile QSPI_Type *BaseAddr, boolean Enable)
{
    uint32 RegValue = BaseAddr->MCFG;
    RegValue &= (~QSPI_MCFG_VARLATEN_MASK);
    RegValue |= QSPI_MCFG_VARLATEN(Enable);
    BaseAddr->MCFG = RegValue;
}
#endif

/*
 * Assert QSPI sw reset bits
 */
FLS_FUNC static inline void Qspi_Lld_SwResetOn(volatile QSPI_Type *BaseAddr)
{
    BaseAddr->MCFG |= QSPI_MCFG_SWRSTBD_MASK | QSPI_MCFG_SWRSTSD_MASK;
}


/*
 * Deassert QSPI sw reset bits
 */
FLS_FUNC static inline void Qspi_Lld_SwResetOff(volatile QSPI_Type *BaseAddr)
{
    BaseAddr->MCFG &= ~(QSPI_MCFG_SWRSTBD_MASK | QSPI_MCFG_SWRSTSD_MASK);
}


/*
 * Configure idle values for Data lines 2:3
 */
FLS_FUNC static inline void Qspi_Lld_SetIdleLineValues(volatile QSPI_Type *BaseAddr,
        uint8 Iofa2IdleValue,
        uint8 Iofa3IdleValue,
        uint8 Iofb2IdleValue,
        uint8 Iofb3IdleValue)
{
    uint32 RegValue = BaseAddr->MCFG;
    RegValue &= (uint32)(~(QSPI_MCFG_FADDO2_MASK | QSPI_MCFG_FADDO3_MASK | QSPI_MCFG_FBDDO2_MASK | QSPI_MCFG_FBDDO3_MASK));
    RegValue |= (QSPI_MCFG_FADDO2(Iofa2IdleValue) |
                 QSPI_MCFG_FADDO3(Iofa3IdleValue) |
                 QSPI_MCFG_FBDDO2(Iofb2IdleValue) |
                 QSPI_MCFG_FBDDO3(Iofb3IdleValue)
                );
    BaseAddr->MCFG = RegValue;
}

/*
 * Configure serial flash endianess
 */
FLS_FUNC static inline void Qspi_Lld_SetEndianess(volatile QSPI_Type *BaseAddr, Qspi_EndianessType Endianess)
{
    uint32 RegValue = BaseAddr->MCFG;
    RegValue &= (uint32)(~QSPI_MCFG_ENDIAN_MASK);
    RegValue |= QSPI_MCFG_ENDIAN(Endianess);
    BaseAddr->MCFG = RegValue;
}


/*
 * Enalbe or disable clock output stop when RxFIFO full.
 */
FLS_FUNC static inline void Qspi_Lld_SetClockStopEnable(volatile QSPI_Type *BaseAddr, boolean Enable)
{
    uint32 RegValue = BaseAddr->MCFG;
    RegValue &= (~QSPI_MCFG_CLKSPEN_MASK);
    RegValue |= QSPI_MCFG_CLKSPEN(Enable);
    BaseAddr->MCFG = RegValue;
}


/*
 * Configure external flash memory map
 */
FLS_FUNC static inline void Qspi_Lld_SetMemMap(volatile QSPI_Type *BaseAddr, uint32 SizeA, uint32 SizeB)
{
    BaseAddr->SFATA = FEATURE_QSPI_AMBA_BASE + SizeA;
    BaseAddr->SFBTA = FEATURE_QSPI_AMBA_BASE + SizeA + SizeB;
}


/*
 * Set CS hold time in serial clock cycles
 */
FLS_FUNC static inline void Qspi_Lld_SetCsHoldTime(volatile QSPI_Type *BaseAddr, uint8 Cycles)
{
    uint32 RegValue = BaseAddr->FACFG;
    RegValue &= (~QSPI_FACFG_CSHT_MASK);
    RegValue |= QSPI_FACFG_CSHT(Cycles);
    BaseAddr->FACFG = RegValue;
}


/*
 * Set CS setup time
 */
FLS_FUNC static inline void Qspi_Lld_SetCsSetupTime(volatile QSPI_Type *BaseAddr, uint8 Cycles)
{
    uint32 RegValue = BaseAddr->FACFG;
    RegValue &= (~QSPI_FACFG_CSST_MASK);
    /*MR12 RULE 2.2 VIOLATION: For the sake of stylistic uniformity of register manipulation functions,
    *                         there is a shift as '<<0'.
    */
    RegValue |= QSPI_FACFG_CSST(Cycles);/*PRQA S 2985*/
    BaseAddr->FACFG = RegValue;
}


/*
 * Set Data in hold time
 */
FLS_FUNC static inline void Qspi_Lld_SetDataInHoldTime(volatile QSPI_Type *BaseAddr, Qspi_FlashDataAlignType DataAlign)
{
    uint32 RegValue = BaseAddr->FACFG;
    RegValue &= (~QSPI_FACFG_DODLY_MASK);
    RegValue |= QSPI_FACFG_DODLY(DataAlign);
    BaseAddr->FACFG = RegValue;
}


/*
 * Sets AHB buffer 0 Configuration
 */
FLS_FUNC static inline void Qspi_Lld_SetAhbBuf0(volatile QSPI_Type *BaseAddr,
        uint16 Size,
        uint8 Master,
        boolean HighPriority)
{
    /*MR12 RULE 2.2 VIOLATION: For the sake of stylistic uniformity of register manipulation functions,
    *                         there is a shift as '<<0'.
    */
    BaseAddr->BUF0CFG =  QSPI_BUF0CFG_DATSZ((uint32)Size >> QSPI_HALFWORD_SIZE)
                         | QSPI_BUF0CFG_HPEN(HighPriority) | QSPI_BUF0CFG_MSTRID(Master);/*PRQA S 2985*/
}


/*
 * Sets AHB buffer 1 Configuration
 */
FLS_FUNC static inline void Qspi_Lld_SetAhbBuf1(volatile QSPI_Type *BaseAddr,
        uint16 Size,
        uint8 Master)
{
    /*MR12 RULE 2.2 VIOLATION: For the sake of stylistic uniformity of register manipulation functions,
    *                         there is a shift as '<<0'.
    */
    BaseAddr->BUF1CFG =  QSPI_BUF1CFG_DATSZ((uint32)Size >> QSPI_HALFWORD_SIZE)
                         | QSPI_BUF1CFG_MSTRID(Master);/*PRQA S 2985*/
}


/*
 * Sets AHB buffer 2 Configuration
 */
FLS_FUNC static inline void Qspi_Lld_SetAhbBuf2(volatile QSPI_Type *BaseAddr,
        uint16 Size,
        uint8 Master)
{
    /*MR12 RULE 2.2 VIOLATION: For the sake of stylistic uniformity of register manipulation functions,
    *                         there is a shift as '<<0'.
    */
    BaseAddr->BUF2CFG =  QSPI_BUF2CFG_DATSZ((uint32)Size >> QSPI_HALFWORD_SIZE)
                         | QSPI_BUF2CFG_MSTRID(Master);/*PRQA S 2985*/
}


/*
 * Sets AHB buffer 3 Configuration
 */
FLS_FUNC static inline void Qspi_Lld_SetAhbBuf3(volatile QSPI_Type *BaseAddr,
        uint16 Size,
        uint8 Master,
        boolean AllMasters)
{
    /*MR12 RULE 2.2 VIOLATION: For the sake of stylistic uniformity of register manipulation functions,
    *                         there is a shift as '<<0'.
    */
    BaseAddr->BUF3CFG =  QSPI_BUF3CFG_DATSZ((uint32)Size >> QSPI_HALFWORD_SIZE)
                         | QSPI_BUF3CFG_MSTRID(Master) | QSPI_BUF3CFG_ALLACC(AllMasters);/*PRQA S 2985*/
}


/*
 * Sets AHB buffer 0 index. Parameter represents desired end index of the buffer.
 */
FLS_FUNC static inline void Qspi_Lld_SetAhbBuf0Ind(volatile QSPI_Type *BaseAddr,
        uint32 Index)
{
    BaseAddr->BUF0IND =  Index;
}


/*
 * Sets AHB buffer 1 index. Parameter represents desired end index of the buffer.
 */
FLS_FUNC static inline void Qspi_Lld_SetAhbBuf1Ind(volatile QSPI_Type *BaseAddr,
        uint32 Index)
{
    BaseAddr->BUF1IND =  Index;
}


/*
 * Sets AHB buffer 2 index. Parameter represents desired end index of the buffer.
 */
FLS_FUNC static inline void Qspi_Lld_SetAhbBuf2Ind(volatile QSPI_Type *BaseAddr,
        uint32 Index)
{
    BaseAddr->BUF2IND =  Index;
}


/*
 * Sets Address for IP transactions
 */
FLS_FUNC static inline void Qspi_Lld_SetIpAddr(volatile QSPI_Type *BaseAddr,
        uint32 Addr)
{
    BaseAddr->SFA = Addr;
}


/*
 * Sets flash Address options
 */
FLS_FUNC static inline void Qspi_Lld_SetAddrOptions(volatile QSPI_Type *BaseAddr,
        uint32 ColumnAddr,
        boolean WordAdressable)
{
    /*MR12 RULE 2.2 VIOLATION: For the sake of stylistic uniformity of register manipulation functions,
    *                         there is a shift as '<<0'.
    */
    BaseAddr->SFACFG =  QSPI_SFACFG_WA(WordAdressable)
                        | QSPI_SFACFG_CAS(ColumnAddr);/*PRQA S 2985*/
}

#if defined (UNIT_TEST)
/*
 * Enable or disable Loopback sample
 */
FLS_FUNC static inline void Qspi_Lld_LoopbackEnable(volatile QSPI_Type *BaseAddr, boolean Enable)
{
    uint32 RegValue = BaseAddr->SMP;
    RegValue &= (~QSPI_SMP_LPBKEN_MASK);
    RegValue |= QSPI_SMP_LPBKEN(Enable);
    BaseAddr->SMP = RegValue;
}

/*
 * Sampling with half cycle Offset in DDR mode, only work with Data Test disable
 */
FLS_FUNC static inline void Qspi_Lld_DDRHalf(volatile QSPI_Type *BaseAddr, boolean Enable)
{
    uint32 RegValue = BaseAddr->SMP;
    RegValue &= (~QSPI_SMP_DDRHF_MASK);
    RegValue |= QSPI_SMP_DDRHF(Enable);
    BaseAddr->SMP = RegValue;
}
#endif

/*
 * Enable or disable Data Test
 */
FLS_FUNC static inline void Qspi_Lld_DataTestEnable(volatile QSPI_Type *BaseAddr, boolean Enable)
{
    uint32 RegValue = BaseAddr->SMP;
    RegValue &= (~QSPI_SMP_DTEN_MASK);
    RegValue |= QSPI_SMP_DTEN(Enable);
    BaseAddr->SMP = RegValue;
}


/*
 * Set coarse clock delay length, only works in loopback mode or DQS mode
 */
FLS_FUNC static inline void Qspi_Lld_ClockDelayLen(volatile QSPI_Type *BaseAddr, uint8 Delay)
{
    uint32 RegValue = BaseAddr->SMP;
    RegValue &= (~QSPI_SMP_CLKDLL_MASK);
    RegValue |= QSPI_SMP_CLKDLL(Delay);
    BaseAddr->SMP = RegValue;
}


/*
 * Configures parameters related to sampling Rx Data, only work with Data Test disable
 */
FLS_FUNC static inline void Qspi_Lld_SetRxCfg(volatile QSPI_Type *BaseAddr,
        uint8 Delay,
        Qspi_SampleEdgeType ClockPhase)
{

    uint32 RegValue = BaseAddr->SMP;
    RegValue &= (~QSPI_SMP_SMPEDG_MASK) & (~QSPI_SMP_SMPDLY_MASK);
    /*MR12 RULE 2.2 VIOLATION: For the sake of stylistic uniformity of register manipulation functions,
    *                         there is a shift as '<<0'.
    */
    RegValue |= QSPI_SMP_SMPEDG(ClockPhase) | QSPI_SMP_SMPDLY(Delay);/*PRQA S 2985*/
    BaseAddr->SMP = RegValue;
}


/*
 * Checks if module is busy with a transaction
 */
FLS_FUNC static inline boolean Qspi_Lld_GetBusyStatus(volatile const QSPI_Type *BaseAddr)
{
    uint32 RegValue = BaseAddr->ST;
    /*MR12 RULE 2.2 VIOLATION: For the sake of stylistic uniformity of register manipulation functions,
    *                         there is a shift as '<<0'.
    */
    RegValue = (RegValue & QSPI_ST_BUSY_MASK) >> QSPI_ST_BUSY_SHIFT;/*PRQA S 2985*/
    return (boolean)RegValue;
}

#if defined (UNIT_TEST)
/*
 * Returns the current fill level of the Rx buffer
 */
FLS_FUNC static inline uint32 Qspi_Lld_GetRxBufFill(volatile const QSPI_Type *BaseAddr)
{
    uint32 RegValue = BaseAddr->RBCS;
    RegValue = (RegValue & QSPI_RBCS_RXFL_MASK) >> QSPI_RBCS_RXFL_SHIFT;
    return RegValue;
}


/*
 * Checks if enough Rx Data is available, according to the watermark setting
 */
FLS_FUNC static inline boolean Qspi_Lld_GetRxDataEvent(volatile const QSPI_Type *BaseAddr)
{
    uint32 RegValue = BaseAddr->IF;
    RegValue = (RegValue & QSPI_IF_RXWE_MASK) >> QSPI_IF_RXWE_SHIFT;
    return (boolean)RegValue;
}
#endif

/*
 * Returns Tx buffer fill level expressed in 4-byte entries
 */
FLS_FUNC static inline uint32 Qspi_Lld_GetTxBufFill(volatile const QSPI_Type *BaseAddr)
{
    uint32 RegValue = BaseAddr->TBCS;
    RegValue = (RegValue & QSPI_TBCS_TXFL_MASK) >> QSPI_TBCS_TXFL_SHIFT;
    return RegValue;
}

#if defined (UNIT_TEST)
/*
 * Checks the Tx buffer watermark.
 * Returns true if number of buffer entries specified by the watermark is available.
 */
FLS_FUNC static inline boolean Qspi_Lld_GetTxWatermarkAvailable(volatile const QSPI_Type *BaseAddr)
{
    uint32 RegValue = BaseAddr->ST;
    RegValue = (RegValue & QSPI_ST_TXWA_MASK) >> QSPI_ST_TXWA_SHIFT;
    return (boolean)RegValue;
}
#endif

/*
 * Writes Data in the Tx buffer
 */
FLS_FUNC static inline void Qspi_Lld_WriteTxData(volatile QSPI_Type *BaseAddr, uint32 Data)
{
    BaseAddr->TXDAT = Data;
}

#if defined (UNIT_TEST)
/*
 * Returns the Address of the Tx Data register
 */
FLS_FUNC static inline uint32 Qspi_Lld_GetTxDataAddr(const QSPI_Type *BaseAddr)
{
    return (uint32) & (BaseAddr->TXDAT);
}


/*
 * Returns the Address of the first Rx Data register
 */
FLS_FUNC static inline uint32 Qspi_Lld_GetRxDataAddr(volatile const QSPI_Type *BaseAddr)
{
    return (uint32) & (BaseAddr->RXDAT[0U]);
}


/*
 * Enables Tx DMA request (when Tx buffer has room for more Data)
 */
FLS_FUNC static inline void Qspi_Lld_EnableTxDmaReq(volatile QSPI_Type *BaseAddr)
{
    BaseAddr->MCFG |= QSPI_MCFG_TDMAEN_MASK;
}


/*
 * Enables Rx DMA request (when Rx buffer has room for more Data)
 */
FLS_FUNC static inline void Qspi_Lld_EnableRxDmaReq(volatile QSPI_Type *BaseAddr)
{
    BaseAddr->MCFG |= QSPI_MCFG_RDMAEN_MASK;
}


/*
 * Disables both Rx and Tx DMA requests
 */
FLS_FUNC static inline void Qspi_Lld_DisableDmaReq(volatile QSPI_Type *BaseAddr)
{
    BaseAddr->MCFG &= ~(QSPI_MCFG_TDMAEN_MASK | QSPI_MCFG_RDMAEN_MASK);
}
#endif

/*
 * Perform a POP Operation on the Rx buffer, removing Rx_watermark entries
 */
FLS_FUNC static inline void Qspi_Lld_RxPop(volatile QSPI_Type *BaseAddr)
{
    BaseAddr->IF |= QSPI_IF_RXWE_MASK;
}


/*
 * Configures the watermark for the Rx buffer, expressed in number of 4-byte entries
 */
FLS_FUNC static inline void Qspi_Lld_SetRxWatermark(volatile QSPI_Type *BaseAddr,
        uint8 WaterMark)
{
    uint32 RegValue = BaseAddr->RBCS;
    RegValue &= (~QSPI_RBCS_WM_MASK);
    /*MR12 RULE 2.2 VIOLATION: For the sake of stylistic uniformity of register manipulation functions,
    *                         there is a shift as '<<0'.
    */
    RegValue |= QSPI_RBCS_WM((uint32)WaterMark - 1U);/*PRQA S 2985*/
    BaseAddr->RBCS = RegValue;
}


/*
 * Configures the watermark for the Tx buffer, expressed in number of 4-byte entries
 */
FLS_FUNC static inline void Qspi_Lld_SetTxWatermark(volatile QSPI_Type *BaseAddr,
        uint8 WaterMark)
{
    uint32 RegValue = BaseAddr->TBCS;
    RegValue &= (~QSPI_TBCS_WM_MASK);
    /*MR12 RULE 2.2 VIOLATION: For the sake of stylistic uniformity of register manipulation functions,
    *                         there is a shift as '<<0'.
    */
    RegValue |= QSPI_TBCS_WM((uint32)WaterMark);/*PRQA S 2985*/
    BaseAddr->TBCS = RegValue;
}

#if defined (UNIT_TEST)
/*
 * Enables interrupts specified by the Mask parameter
 */
FLS_FUNC static inline void Qspi_Lld_EnableInt(QSPI_Type *BaseAddr,
        uint32 Mask)
{
    BaseAddr->IE |= Mask;
}


/*
 * Disables interrupts specified by the Mask parameter
 */
FLS_FUNC static inline void Qspi_Lld_DisableInt(QSPI_Type *BaseAddr,
        uint32 Mask)
{
    BaseAddr->IE &= ~Mask;
}


/*
 * Clears interrupt flags specified by the Mask parameter
 */
FLS_FUNC static inline void Qspi_Lld_ClearIntFlag(volatile QSPI_Type *BaseAddr,
        uint32 Mask)
{
    BaseAddr->IF = Mask;
}
#endif

#ifdef QSPI_MCFG_AHBPTRC_MASK
/*
 * Clear AHB buffer
 */
FLS_FUNC static inline void Qspi_Lld_ClearAhbBuf(volatile QSPI_Type *BaseAddr)
{
    BaseAddr->MCFG |= QSPI_MCFG_AHBPTRC_MASK;
}

/*
 * Checks the Ahb buffer clear flag
 * Returns TRUE if the Ahb buffer content is invalidated.
 */
FLS_FUNC static inline boolean Qspi_Lld_GetClrAhbStatus(volatile const QSPI_Type *BaseAddr)
{
    uint32 RegValue = BaseAddr->MCFG;
    RegValue = (RegValue & QSPI_MCFG_AHBPTRC_MASK) >> QSPI_MCFG_AHBPTRC_SHIFT;
    return (0U == RegValue) ? TRUE : FALSE;
}
#endif


/*FUNCTION**********************************************************************
 *
 * Function Name : QSPI_DRV_ErrorCheck
 * Description   : Checks if there were Errors during IP command execution
 *
 *END**************************************************************************/
FLS_FUNC static inline Qspi_StatusType Qspi_Lld_ErrorCheck(volatile QSPI_Type *BaseAddr)
{
    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;
    if ((BaseAddr->IF & QSPI_ERR_FLAGS_MASK) != 0U)
    {
        /* clear error flags */
        BaseAddr->IF = QSPI_ERR_FLAGS_MASK;
        Status = STATUS_QSPI_ERROR;
    }
    else
    {
        /* Empty clause added to fulfill MISRA. */
    }
    return Status;
}


/*
 * Set all hardware registers to their reset Value
 */
FLS_FUNC static inline void Qspi_Lld_ResetAllRegisters(volatile QSPI_Type *BaseAddr)
{
    /*Reset MEN register*/
    BaseAddr->MEN = 0x00000000U;
    /*Reset MCFG register*/
    BaseAddr->MCFG = 0x0F000000U;
    /*Reset SMP register*/
    BaseAddr->SMP = 0x00009F00U;
    /*Reset ST register*/
    BaseAddr->ST = 0x00207000U;
    /*Reset IF register*/
    BaseAddr->IF = 0x00800000U;
    /*Reset IE register*/
    BaseAddr->IE = 0x00000000U;
    /*Reset SPNDST register*/
    BaseAddr->SPNDST = 0x00000000U;
    /*Reset RBCS register*/
    BaseAddr->RBCS = 0x00000000U;
    /*Reset TBCS register*/
    BaseAddr->TBCS = 0x00000000U;
    /*Reset APBCFG register*/
    BaseAddr->APBCFG = 0x00000000U;
    /*Reset AHBCFG register*/
    BaseAddr->AHBCFG = 0x00002000U;
    /*Reset BUF0CFG register*/
    BaseAddr->BUF0CFG = 0x00000003U;
    /*Reset BUF1CFG register*/
    BaseAddr->BUF1CFG = 0x00000002U;
    /*Reset BUF2CFG register*/
    BaseAddr->BUF2CFG = 0x00000001U;
    /*Reset BUF3CFG register*/
    BaseAddr->BUF3CFG = 0x80000000U;
    /*Reset BUF0IND register*/
    BaseAddr->BUF0IND = 0x00000000U;
    /*Reset BUF1IND register*/
    BaseAddr->BUF1IND = 0x00000000U;
    /*Reset BUF2IND register*/
    BaseAddr->BUF2IND = 0x00000000U;
    /*Reset FACFG register*/
    BaseAddr->FACFG = 0x00000303U;
    /*Reset SFA register*/
    BaseAddr->SFA = 0x00000000U;
    /*Reset SFACFG register*/
    BaseAddr->SFACFG = 0x00000000U;
    /*Reset SFATA register*/
    BaseAddr->SFATA = 0x6C000000U;
    /*Reset SFBTA register*/
    BaseAddr->SFBTA = 0x70000000U;
    /*Reset DTPR register*/
    BaseAddr->DTPR = 0x5A691E78U;
    /*Reset LUTKEY register*/
    BaseAddr->LUTKEY = QSPI_LUT_LOCK_KEY;
    /*Reset LOCK register*/
    BaseAddr->LOCK = 0x00000002U;
    for (uint8 LoopCnt = 2U; LoopCnt < QSPI_LUT_COUNT; ++LoopCnt)
    {
        BaseAddr->LUT[LoopCnt] = 0x00000000U;
    }
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_GetWordSize
 * Description   : Calculates the word Size for the up coming loop
 *******************************************************************************/
FLS_FUNC static inline uint32 Qspi_Lld_GetWordSize(uint32 SizeRemaining)
{
    return (SizeRemaining > QSPI_WORD_SIZE) ? QSPI_WORD_SIZE : SizeRemaining;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_ProcessDataRead
 * Description   : Processes read Data
 * @implements     Qspi_Lld_ProcessDataRead_Activity
 *******************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_ProcessDataRead(uint8 *DataRead,
        uint32 Size,
        volatile  QSPI_Type *BaseAddr,
        uint32 Padding
                                                        )
{
    uint8 *Data = DataRead;
    uint32 Cnt = 0U;
    uint32 RecvData;
    const uint8 *RecvDataPtr = (uint8 *)(&RecvData);
    uint32 WordSize;
    uint32 ByteCnt;
    uint32 SizeRemaining = Size;
    uint32 PaddingBytes = Padding;

    if (0U != PaddingBytes)
    {
        /* Ignore all Padding words, jump to the fist Data */
        Cnt            = PaddingBytes >> QSPI_HALFWORD_SIZE;
        SizeRemaining -= Cnt << QSPI_HALFWORD_SIZE;
        PaddingBytes  &= 0x3U;

        /* Get first received word */
        RecvData = BaseAddr->RXDAT[Cnt];
        ++Cnt;
        /* Get WordSize for the loop */
        WordSize = Qspi_Lld_GetWordSize(SizeRemaining);

        /* Ignore Padding bytes and copy the rest to buffer */
        for (ByteCnt = PaddingBytes; ByteCnt < WordSize; ++ByteCnt)
        {
#if (defined(CORE_BIG_ENDIAN))
            *Data = RecvDataPtr[QSPI_HALFWORD_SIZE - ByteCnt];
#else
            *Data = RecvDataPtr[ByteCnt];
#endif
            ++Data;
        }
        SizeRemaining -= WordSize;
    }

    /* Check user buffer alignment */
    /*MR12 RULE 11.4 VIOLATION: The Data pointer needs to be checked for alignment due to 4-byte copies,
     so the rule 11.4 can't be observed here*/
    if (((uint32)Data & 0x3U) == 0U)/*PRQA S 0306*/
    {
        /* Process 4 bytes at a time to speed up read */
        while (SizeRemaining >= QSPI_WORD_SIZE)
        {
            /*MR12 RULE 11.3 VIOLATION: The Data has been checked alignment to 4-byte, so Data convert to
                                        uint32 * is no risk*/
            *((uint32 *)Data) = BaseAddr->RXDAT[Cnt];  /*PRQA S 0310,3305*/
            Data = &(Data[QSPI_WORD_SIZE]);
            ++Cnt;
            SizeRemaining -= QSPI_WORD_SIZE;
        }
    }

    /* Process remaining bytes one by one */
    while (SizeRemaining > 0U)
    {
        /* Get next received word */
        RecvData = BaseAddr->RXDAT[Cnt];
        /* get WordSize for the loop */
        WordSize = Qspi_Lld_GetWordSize(SizeRemaining);
        for (ByteCnt = 0U; ByteCnt < WordSize; ++ByteCnt)
        {
#if (defined(CORE_BIG_ENDIAN))
            *Data = (uint8)(RecvData >> 24U);
            RecvData <<= 8U;
#else
            *Data = (uint8)(RecvData & 0xFFU);
            RecvData >>= 8U;
#endif
            ++Data;
            --SizeRemaining;
        }
        ++Cnt;
    }

    Qspi_Lld_RxPop(BaseAddr);

    return STATUS_QSPI_SUCCESS;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_ProcessDataVerify
 * Description   : Processes program verify Data
 * @implements     Qspi_Lld_ProcessDataVerify_Activity
 *******************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_ProcessDataVerify(const uint8 *DataCmp,
        uint32 Size,
        volatile const QSPI_Type *BaseAddr,
        uint32 Padding
                                                          )
{
    const uint8 *RoData = DataCmp;
    uint32 Cnt = 0U;
    uint32 RecvData;
    uint8 RecvByte;
    const uint8 *RecvDataPtr = (uint8 *)(&RecvData);
    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;
    uint32 ByteCnt;
    uint32 WordSize;
    uint32 PaddingBytes = Padding;
    uint32 SizeRemaining = Size;

    if (0U != PaddingBytes)
    {
        /* Ignore all Padding words, jump to the fist Data */
        Cnt            = PaddingBytes >> QSPI_HALFWORD_SIZE;
        SizeRemaining -= Cnt << QSPI_HALFWORD_SIZE;
        PaddingBytes  &= 0x3U;

        /* Get first received word */
        RecvData = BaseAddr->RXDAT[Cnt];
        ++Cnt;
        /* Get WordSize for the loop */
        WordSize = Qspi_Lld_GetWordSize(SizeRemaining);
        SizeRemaining -= WordSize;

        /* Ignore Padding bytes and compare the rest with user buffer */
        for (ByteCnt = PaddingBytes; ByteCnt < WordSize; ++ByteCnt)
        {
#if (defined(CORE_BIG_ENDIAN))
            RecvByte = RecvDataPtr[QSPI_HALFWORD_SIZE - ByteCnt];
#else
            RecvByte = RecvDataPtr[ByteCnt];
#endif

            /* return STATUS_QSPI_ERROR_PROGRAM_VERIFY if the Data is not match */
            if (*RoData != RecvByte)
            {
                Status = STATUS_QSPI_ERROR_PROGRAM_VERIFY;
                SizeRemaining = 0U;
                break;
            }
            ++RoData;
        }
    }

    /* Check user buffer alignment */
    /*MR12 RULE 11.4 VIOLATION: The Data pointer needs to be checked for alignment due to 4-byte copies,
     so the rule 11.4 can't be observed here*/
    if (((uint32)RoData & 0x3U) == 0U)/*PRQA S 0306*/
    {
        while (SizeRemaining >= QSPI_WORD_SIZE)
        {
            /* Process 4 bytes at a time to speed up read */
            /*MR12 RULE 11.3 VIOLATION: The RoData has been checked alignment to 4-byte, so RoData convert to
                                        const uint32 * is no risk*/
            if (*((const uint32 *)RoData) != BaseAddr->RXDAT[Cnt])/*PRQA S 0310,3305*/
            {
                /* return STATUS_QSPI_ERROR_PROGRAM_VERIFY if the Data is not match */
                Status = STATUS_QSPI_ERROR_PROGRAM_VERIFY;
                SizeRemaining = 0U;
                break;
            }
            /* update the RoData */
            RoData = &(RoData[QSPI_WORD_SIZE]);
            ++Cnt;
            SizeRemaining -= QSPI_WORD_SIZE;
        }
    }

    /* Process remaining bytes one by one */
    while (SizeRemaining > 0U)
    {
        /* Get next received word */
        RecvData = BaseAddr->RXDAT[Cnt];
        /* get WordSize for the loop */
        WordSize = Qspi_Lld_GetWordSize(SizeRemaining);
        for (ByteCnt = 0U; ByteCnt < WordSize; ++ByteCnt)
        {
#if (defined(CORE_BIG_ENDIAN))
            RecvByte = (uint8)(RecvData >> 24U);
            RecvData <<= 8U;
#else
            RecvByte = (uint8)(RecvData & 0xFFU);
            RecvData >>= 8U;
#endif
            /* return STATUS_QSPI_ERROR_PROGRAM_VERIFY if the Data is not match */
            if (*RoData != RecvByte)
            {
                Status = STATUS_QSPI_ERROR_PROGRAM_VERIFY;
                SizeRemaining = 0U;
                break;
            }
            else
            {
                /* update the RoData, SizeRemaining */
                ++RoData;
                --SizeRemaining;
            }
        }
        ++Cnt;
    }
    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_ProcessDataBlankCheck
 * Description   : Processes blank check Data
 * @implements     Qspi_Lld_ProcessDataBlankCheck_Activity
 ******************************************************************************/
FLS_FUNC static inline Qspi_StatusType Qspi_Lld_ProcessDataBlankCheck(uint32 Size,
        volatile const QSPI_Type *BaseAddr,
        uint32 Padding
                                                                     )
{
    uint32 Cnt = 0U;
    uint32 RecvData = 0U;
    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;
    uint32 DataSize;
    uint32 SizeRemaining = Size;
    uint32 PaddingBytes = Padding;

    if (0U != PaddingBytes)
    {
        /* Ignore all Padding words, jump to the fist Data */
        Cnt            = PaddingBytes >> QSPI_HALFWORD_SIZE;
        SizeRemaining -= Cnt << QSPI_HALFWORD_SIZE;
        PaddingBytes  &= 0x3U;

        /* Get first received word */
        RecvData = ~(BaseAddr->RXDAT[Cnt]);
        ++Cnt;
        /* Get WordSize for the blank check */
        DataSize = Qspi_Lld_GetWordSize(SizeRemaining);
        SizeRemaining -= DataSize;

        /* Mask Data: ignore Padding at the beginning and unused bytes at the end */
#if (defined(CORE_BIG_ENDIAN))
        RecvData &= 0xFFFFFFFFUL << ((4UL - DataSize) * 8UL);
        RecvData &= 0xFFFFFFFFUL >> (PaddingBytes * 8UL);
#else
        RecvData &= 0xFFFFFFFFUL >> ((4UL - DataSize) * 8UL);
        RecvData &= 0xFFFFFFFFUL << (PaddingBytes * 8UL);
#endif
        if (RecvData != 0U)
        {
            /* The Data is not blank */
            Status = STATUS_QSPI_ERROR;
            SizeRemaining = 0U;
        }
    }

    /* Blank check */
    while (SizeRemaining >= QSPI_WORD_SIZE)
    {
        if (BaseAddr->RXDAT[Cnt] != 0xFFFFFFFFU)
        {
            /* The Data is not blank */
            Status = STATUS_QSPI_ERROR;
            SizeRemaining = 0U;
            break;
        }
        ++Cnt;
        SizeRemaining -= QSPI_WORD_SIZE;
    }

    if (SizeRemaining != 0U)
    {
        /* Process last few bytes */
        RecvData = BaseAddr->RXDAT[Size >> QSPI_HALFWORD_SIZE];
#if (defined(CORE_BIG_ENDIAN))
        if ((~RecvData & ~(((uint32)1U << (((uint32)QSPI_WORD_SIZE - SizeRemaining) * 8U)) - 1U)) != 0U)
#else
        if ((~RecvData & (((uint32)1U << (SizeRemaining * 8U)) - 1U)) != 0U)
#endif
        {
            /* The Data is not blank */
            Status = STATUS_QSPI_ERROR;
        }
    }
    return Status;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_FillTxBuf
 * Description   : Fill Tx buffer with the specified number of 4-byte entries
* @implements      Qspi_Lld_FillTxBuf_Activity
*******************************************************************************/
FLS_FUNC static uint32 Qspi_Lld_FillTxBuf(volatile QSPI_Type *BaseAddr,
        const uint8 *RoData,
        uint32 Size,
        uint32 PaddingInfo
                                         )
{
    uint32 SizeLeft = Size;
    uint32 WordSize;
    uint32 Data = 0xFFFFFFFFUL;
    uint8 *DataPtr = (uint8 *)(&Data);
    uint32 ByteCnt;
    const uint8 *RoDataPtr = RoData;

    uint32 PrePadding   = PaddingInfo >> QSPI_WORD_SIZE;
    uint32 PostPadding  = PaddingInfo & 0x0FU;
    uint32 TotalPadding = PrePadding + PostPadding;

    /* Insert PrePadding words */
    while (PrePadding >= QSPI_WORD_SIZE)
    {
        Qspi_Lld_WriteTxData(BaseAddr, 0xFFFFFFFFUL);
        PrePadding -= QSPI_WORD_SIZE;
    }

    if (PrePadding != 0U)
    {
        WordSize = PrePadding + SizeLeft;

        if (WordSize > QSPI_WORD_SIZE)
        {
            WordSize  = QSPI_WORD_SIZE;
            SizeLeft -= (QSPI_WORD_SIZE - PrePadding);
        }
        else
        {
            /* Note for special case: PrePadding + Data + PostPadding are fit into a word
               Decreaseing PostPadding is not needed because out of user Data, all branches below will be skipped
             */
            SizeLeft = 0U;
        }

        /* Fill user Data between PrePadding and PostPadding */
        for (ByteCnt = PrePadding; ByteCnt < WordSize; ++ByteCnt)
        {
#if (defined(CORE_BIG_ENDIAN))
            DataPtr[QSPI_HALFWORD_SIZE - ByteCnt] = *RoDataPtr;
#else
            DataPtr[ByteCnt] = *RoDataPtr;
#endif

            ++RoDataPtr;
        }
        Qspi_Lld_WriteTxData(BaseAddr, Data);
    }

    /* Check user buffer alignment */
    /*MR12 RULE 11.4 VIOLATION: The Data pointer needs to be checked for alignment due to 4-byte copies,
     so the rule 11.4 can't be observed here*/
    if (((uint32)RoDataPtr & 0x3U) == 0U)/*PRQA S 0306*/
    {
        /* Process 4 bytes at a time to speed things up */
        while (SizeLeft >= QSPI_WORD_SIZE)
        {
            /*MR12 RULE 11.3 VIOLATION: The RoDataPtr has been checked alignment to 4-byte, so RoDataPtr convert to
            const uint32 * is no risk*/
            Data = *((const uint32 *)RoDataPtr);  /*PRQA S 0310,3305*/
            SizeLeft -= QSPI_WORD_SIZE;
            RoDataPtr = &(RoDataPtr[QSPI_WORD_SIZE]);
            Qspi_Lld_WriteTxData(BaseAddr, Data);
        }
    }

    /* Process remaining bytes one by one */
    while (SizeLeft > 0U)
    {
        /* Processes last few Data bytes (less than 4) */
        Data = 0xFFFFFFFFUL;
        WordSize = Qspi_Lld_GetWordSize(SizeLeft);

        for (ByteCnt = 0U; ByteCnt < WordSize; ++ByteCnt)
        {
#if (defined(CORE_BIG_ENDIAN))
            DataPtr[QSPI_HALFWORD_SIZE - ByteCnt] = *RoDataPtr;
#else
            DataPtr[ByteCnt] = *RoDataPtr;
#endif

            ++RoDataPtr;
        }
        Qspi_Lld_WriteTxData(BaseAddr, Data);
        SizeLeft -= WordSize;
    }

    /* Insert PostPadding words */
    while (PostPadding >= QSPI_WORD_SIZE)
    {
        Qspi_Lld_WriteTxData(BaseAddr, 0xFFFFFFFFUL);
        PostPadding -= QSPI_WORD_SIZE;
    }

    return TotalPadding;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_SwResetDelay
 * Description   : Insert waiting loops after changing the Value of the software
                   reset bits
 *******************************************************************************/
FLS_FUNC static inline void Qspi_Lld_SwResetDelay(void)
{
    volatile uint32 CurrentTicks;
    /* Prepare timeout counter */
    CurrentTicks = QSPI_SOFTWARE_RESET_DELAY;
    /* Insert delay after changing the Value of the software reset bits. */
    while (CurrentTicks > 0U)
    {
        CurrentTicks -= 1U;
    }
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_SwReset
 * Description   : Resets the QuadSPI device
* @implements      Qspi_Lld_SwReset_Activity */
FLS_FUNC static void Qspi_Lld_SwReset(volatile QSPI_Type *BaseAddr)
{
    /* Software reset AHB domain and Serial Flash domain at the same time. */
    Qspi_Lld_SwResetOn(BaseAddr);
    /* Insert delay after changing the Value of the reset bits. */
    Qspi_Lld_SwResetDelay();
    /* Disable QuadSPI module before de-asserting the reset bits. */
    Qspi_Lld_Disable(BaseAddr);
    /* De-asset Software reset AHB domain and Serial Flash domain bits. */
    Qspi_Lld_SwResetOff(BaseAddr);
    /* Re-enable QuadSPI module after reset. */
    Qspi_Lld_Enable(BaseAddr);
    /* Insert delay after changing the Value of the reset bits. */
    Qspi_Lld_SwResetDelay();
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_AhbFlush
 * Description   : Reset AHB buffers
 *******************************************************************************/
FLS_FUNC static void Qspi_Lld_AhbFlush(volatile QSPI_Type *BaseAddr)
{
#ifdef QSPI_MCFG_AHBPTRC_MASK
    uint32  ElapsedTicks = 0U;

    /* Use the AHB buffer clear bit to avoid losing the DLL lock */
    Qspi_Lld_ClearAhbBuf(BaseAddr);

    /* Wait for clearing the AHB buffer pointers */
    while ((FALSE == Qspi_Lld_GetClrAhbStatus(BaseAddr)) && (ElapsedTicks < QSPI_CMD_COMPLETE_TIMEOUT))
    {
        ++ElapsedTicks;
    }
#else
    /* Otherwise use the software reset */
    Qspi_Lld_SwReset(BaseAddr);
#endif
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_ConfigureReadOptions
 * Description   : Configures Data read settings
 * @implements      Qspi_Lld_ConfigureReadOptions_Activity
 ******************************************************************************/
FLS_FUNC static void Qspi_Lld_ConfigureReadOptions(volatile QSPI_Type *BaseAddr,
        const Qspi_ControllerConfigType *UserConfigPtr
                                                  )
{
    /* Always enable DQS */
    Qspi_Lld_DqsLatEnable(BaseAddr, UserConfigPtr->DqsLatencyEnable);
    if (QSPI_DATA_RATE_SDR == UserConfigPtr->DataRate)
    {
        Qspi_Lld_DdrDisable(BaseAddr);
        /* Ignore output Data align setting in SDR mode */
        Qspi_Lld_SetDataInHoldTime(BaseAddr, QSPI_FLASH_DATA_ALIGN_REFCLK);
    }
    else  /* QSPI_DATA_RATE_DDR */
    {
        Qspi_Lld_DdrEnable(BaseAddr);
        Qspi_Lld_SetDataInHoldTime(BaseAddr, UserConfigPtr->DataAlign);
    }
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_AhbSetup
 * Description   : Sets up AHB accesses to the serial flash
 * @implements      Qspi_Lld_AhbSetup_Activity
 ******************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_AhbSetup(volatile QSPI_Type *BaseAddr,
        const Qspi_ControllerAhbConfigType *Config
                                                 )
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(0U == (Config->Sizes[0U] & 7U));
    DevAssert(((uint32)Config->Sizes[0U] +
               (uint32)Config->Sizes[1U] +
               (uint32)Config->Sizes[2U] +
               (uint32)Config->Sizes[3U]) <= FEATURE_QSPI_AHB_BUF_SIZE);
#endif
    /* configure AHB transfer sizes to match the buffer sizes */
    /* Set AHB buffer 0 */
    Qspi_Lld_SetAhbBuf0(BaseAddr, Config->Sizes[0U], Config->Masters[0U], Config->HighPriority);
    /* Set AHB buffer 1 */
    Qspi_Lld_SetAhbBuf1(BaseAddr, Config->Sizes[1U], Config->Masters[1U]);
    /* Set AHB buffer 2 */
    Qspi_Lld_SetAhbBuf2(BaseAddr, Config->Sizes[2U], Config->Masters[2U]);
    /* Set AHB buffer 3 */
    Qspi_Lld_SetAhbBuf3(BaseAddr, Config->Sizes[3U], Config->Masters[3U], Config->AllMasters);
    /* Set AHB buffer index 0 */
    Qspi_Lld_SetAhbBuf0Ind(BaseAddr, (uint32)Config->Sizes[0U]);
    /* Set AHB buffer index 1 */
    Qspi_Lld_SetAhbBuf1Ind(BaseAddr, (uint32)Config->Sizes[0U] + (uint32)Config->Sizes[1U]);
    /* Set AHB buffer index 2 */
    Qspi_Lld_SetAhbBuf2Ind(BaseAddr, (uint32)Config->Sizes[0U] + (uint32)Config->Sizes[1U] + (uint32)Config->Sizes[2U]);

    return STATUS_QSPI_SUCCESS;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_SetLut
 * Description   : Configures a pair of LUT commands in the specified LUT register
 *
 *END**************************************************************************/
FLS_FUNC static void Qspi_Lld_SetLut(uint32 Instance,
                                     uint8 Lut,
                                     Qspi_InstrOpType Operation0,
                                     Qspi_InstrOpType Operation1
                                    )
{
    volatile QSPI_Type *BaseAddr;
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_INSTANCE_COUNT);
    DevAssert(Lut < QSPI_LUT_COUNT);
#endif
    BaseAddr = Qspi_RegBase[Instance];
    BaseAddr->LUT[Lut] = (uint32)Operation0 + ((uint32)Operation1 << 16U);
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_SetAhbSeqId
 * Description   : Sets sequence ID for AHB Operations
 *
 *END**************************************************************************/
FLS_FUNC static void Qspi_Lld_SetAhbSeqId(uint32 Instance,
        uint8 SeqID
                                         )
{
    volatile QSPI_Type *BaseAddr;
    uint32 TempRegData;
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_INSTANCE_COUNT);
#endif
    BaseAddr = Qspi_RegBase[Instance];
    TempRegData = BaseAddr->AHBCFG;
    TempRegData &= (uint32)~(QSPI_AHBCFG_SEQID_MASK);
    TempRegData |= QSPI_AHBCFG_SEQID(SeqID);
    BaseAddr->AHBCFG =  TempRegData;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_SetCsTime
 * Description   : Configure the CS holdtime and CS setup time
 *
 *END**************************************************************************/
FLS_FUNC static inline void Qspi_Lld_SetCsTime(volatile QSPI_Type *BaseAddr,
        const Qspi_ControllerConfigType *UserConfigPtr
                                              )
{
    /* Configure the CS holdtime and CS setup time */
    Qspi_Lld_SetCsHoldTime(BaseAddr, UserConfigPtr->CsHoldTime);
    Qspi_Lld_SetCsSetupTime(BaseAddr, UserConfigPtr->CsSetupTime);
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_ConfigureBuffers
 * Description   : Configure the Tx, Rx and AHB buffers
 *
 *END**************************************************************************/
FLS_FUNC static inline void Qspi_Lld_ConfigureBuffers(volatile QSPI_Type *BaseAddr,
        const Qspi_ControllerConfigType *UserConfigPtr
                                                     )
{
    /* Read Rx buffer through RBDR registers */
    /* Set watermarks */
    Qspi_Lld_SetTxWatermark(BaseAddr, 1U);
    Qspi_Lld_SetRxWatermark(BaseAddr, 1U);
    /* Configure AHB buffers settings */
    (void)Qspi_Lld_AhbSetup(BaseAddr, &(UserConfigPtr->AhbConfig));
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_ConfigureController
 * Description   : Configure the controller register following user configurations
 *
 *END**************************************************************************/
FLS_FUNC static inline void Qspi_Lld_ConfigureController(uint32 Instance,
        const Qspi_ControllerConfigType *UserConfigPtr
                                                        )
{
    volatile QSPI_Type *BaseAddr = Qspi_RegBase[Instance];

    /* Configure external flash memory map Size A */
    Qspi_Lld_SetMemMap(BaseAddr, UserConfigPtr->MemSizeA, UserConfigPtr->MemSizeB);

    /* Configure the Serial Flash Memory Address */
    Qspi_Lld_SetAddrOptions(BaseAddr, UserConfigPtr->ColumnAddr, UserConfigPtr->WordAddresable);

    Qspi_Lld_SetClockStopEnable(BaseAddr, TRUE);

    Qspi_Lld_ClockDelayLen(BaseAddr, 0);

    Qspi_Lld_SetRxCfg(BaseAddr, UserConfigPtr->SampleDelay, UserConfigPtr->SampleEdge);

    /* Configure the CS holdtime and CS setup time */
    Qspi_Lld_SetCsTime(BaseAddr, UserConfigPtr);

    /* Unused side lines are "no matter" so just repeat idle settings on both sides */
    Qspi_Lld_SetIdleLineValues(BaseAddr, UserConfigPtr->Io2IdleValueA, UserConfigPtr->Io3IdleValueA
                               , UserConfigPtr->Io2IdleValueB, UserConfigPtr->Io3IdleValueB
                              );
    /* Configure buffers */
    Qspi_Lld_ConfigureBuffers(BaseAddr, UserConfigPtr);



    /* Configure read options */
    Qspi_Lld_ConfigureReadOptions(BaseAddr, UserConfigPtr);
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_ControllerInit
 * Description   : Initializes the qspi controller
 * @implements     Qspi_Lld_ControllerInit_Activity
 *END**************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_ControllerInit(uint32 Instance,
        const Qspi_ControllerConfigType *UserConfigPtr
                                                )
{
    volatile QSPI_Type *BaseAddr;
    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_INSTANCE_COUNT);
    DevAssert(UserConfigPtr != NULL_PTR);
#endif
    /* Initialize driver Status structure */

    BaseAddr = Qspi_RegBase[Instance];

    /* Ensure module is disabled */
    Qspi_Lld_Disable(BaseAddr);

    /* Ensure all registers contain their reset Value */
    Qspi_Lld_ResetAllRegisters(BaseAddr);

    /* Disable test mode*/
    Qspi_Lld_DataTestEnable(BaseAddr, FALSE);

    /* Set Endian data*/

    Qspi_Lld_SetEndianess(BaseAddr, UserConfigPtr->Endianess);

    /* Configure the controller following the user configurations */
    Qspi_Lld_ConfigureController(Instance, UserConfigPtr);

    /* Enable QuadSPI module */
    Qspi_Lld_Enable(BaseAddr);

    /* Reset serial flash and AHB domains */
    Qspi_Lld_SwReset(BaseAddr);


    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_ControllerDeinit
 * Description   : De-initialize the qspi driver
 * @implements     Qspi_Lld_ControllerDeinit_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_ControllerDeinit(uint32 Instance)
{
    volatile QSPI_Type *BaseAddr;
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_INSTANCE_COUNT);
#endif
    BaseAddr = Qspi_RegBase[Instance];

    /* Disable QuadSPI module */
    Qspi_Lld_Disable(BaseAddr);

    return STATUS_QSPI_SUCCESS;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_GetBaseAdress
 * Description   : Returns the physical base Address of a flash device on the AHB bus.
 *                 The controller must be initialized prior to calling this function.
 * @implements     Qspi_Lld_GetBaseAdress_Activity
 *END**************************************************************************/
FLS_FUNC static uint32 Qspi_Lld_GetBaseAdress(uint32 Instance,
        Qspi_ConnectionType ConnectionType
                                             )
{
    volatile const QSPI_Type *BaseAddr;
    uint32 Address = 0U;

#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_INSTANCE_COUNT);
#endif
    /* get the base Address base on the Instance */
    BaseAddr = Qspi_RegBase[Instance];

    switch (ConnectionType)
    {
        case QSPI_SIDE_A:
            /* get base Address of side A */
            Address = Qspi_AhbAddress[Instance];
            break;
        case QSPI_SIDE_B:
            /* get base Address of side B */
            Address = BaseAddr->SFBTA;
            break;
        default:
            /* Not possible */
            break;
    }

    return Address;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_IpCommand
 * Description   : Launches a simple IP command
 * @implements     Qspi_Lld_IpCommand_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_IpCommand(uint32 Instance,
        uint8 Lut,
        uint32 Address
                                                  )
{
    volatile QSPI_Type *BaseAddr;
    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;
    uint32  ElapsedTicks = 0UL;
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_INSTANCE_COUNT);
    DevAssert(Lut < QSPI_LUT_COUNT);
#endif
    BaseAddr = Qspi_RegBase[Instance];

    /* Reset AHB buffers to force re-read from memory after erase Operation */
    Qspi_Lld_AhbFlush(BaseAddr);

    /* Set Address */
    Qspi_Lld_SetIpAddr(BaseAddr, Address);
    /* Trigger APB command with specified sequence and dummy Size */
    Qspi_Lld_IpTrigger(BaseAddr, Lut, 1U);

    do
    {
        ++ElapsedTicks;
        Status = Qspi_Lld_ControllerGetStatus(Instance);
    } while ((ElapsedTicks < QSPI_CMD_COMPLETE_TIMEOUT) && (STATUS_QSPI_BUSY == Status));
    if (STATUS_QSPI_BUSY == Status)
    {
        Status = STATUS_QSPI_TIMEOUT;
    }
    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_WaitTransactionComplete
 * Description   : Wait until Qspi controller is not busy or timeout
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_WaitTransactionComplete(volatile const QSPI_Type *BaseAddr)
{
    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;
    uint32  ElapsedTicks = 0UL;

    /* Wait for command to be completed */
    while (TRUE == Qspi_Lld_GetBusyStatus(BaseAddr))
    {
        if (ElapsedTicks >= QSPI_CMD_COMPLETE_TIMEOUT)
        {
            Status = STATUS_QSPI_TIMEOUT;
            break;
        }
        ++ElapsedTicks;
    }
    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_IpRead
 * Description   : Launches an IP read command
 * @implements     Qspi_Lld_IpRead_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_IpRead(uint32 Instance,
        uint8 Lut,
        uint32 Address,
        uint8 *DataRead,
        const uint8 *DataCmp,
        uint32 Size
                                               )
{
    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;
    volatile QSPI_Type *BaseAddr;
    uint32 Padding;
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_INSTANCE_COUNT);
    DevAssert(Lut < QSPI_LUT_COUNT);
    DevAssert(Size <= FEATURE_QSPI_RX_BUF_SIZE);
#endif

    BaseAddr = Qspi_RegBase[Instance];
    Padding  = (uint32)(Qspi_MemoryPadding[Instance]);

    /* Make sure there is no garbage in Rx fifo */
    Qspi_Lld_ClearRxBuf(BaseAddr);
    /* Set read Address */
    Qspi_Lld_SetIpAddr(BaseAddr, Address);
    /* Trigger IP command with specified sequence and Size */
    /* If Size is odd, round up to even Size; this is needed in octal DDR mode */
    Qspi_Lld_IpTrigger(BaseAddr, Lut, (uint16)(Size));

    /* Wait until the command is sent */
    Status = Qspi_Lld_WaitTransactionComplete(BaseAddr);

    if (STATUS_QSPI_SUCCESS == Status)
    {
        /* Check for Errors reported by the QuadSPI */
        Status = Qspi_Lld_ErrorCheck(BaseAddr);
    }
    if (STATUS_QSPI_SUCCESS == Status)
    {
        /* Process received Data */
        if (DataRead != NULL_PTR)
        {
            /* Normal read */
            Status = Qspi_Lld_ProcessDataRead(DataRead, Size, BaseAddr, Padding);
        }
        else if (DataCmp != NULL_PTR)
        {
            /* Verify */
            Status = Qspi_Lld_ProcessDataVerify(DataCmp, Size, BaseAddr, Padding);
        }
        else
        {
            /* Blank check */
            Status = Qspi_Lld_ProcessDataBlankCheck(Size, BaseAddr, Padding);
        }
    }   /* (Status = STATUS_QSPI_SUCCESS) */

    /* Reset Rx fifo */
    Qspi_Lld_ClearRxBuf(BaseAddr);
    /* Clear Padding, only needed for the first read */
    Qspi_MemoryPadding[Instance] = 0U;

    return Status;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_InvalidateTxBuf
 * Description   : Invalidates the TX buffer content and wait until it is completed or timed out
 * @implements     Qspi_Lld_InvalidateTxBuf_Activity
 *END**************************************************************************/
FLS_FUNC static inline void Qspi_Lld_InvalidateTxBuf(uint32 Instance)
{
    volatile QSPI_Type *BaseAddr;
    volatile uint32  CurrentTicks = QSPI_TX_BUFFER_RESET_DELAY;

    BaseAddr = Qspi_RegBase[Instance];

    Qspi_Lld_ClearTxBuf(BaseAddr);

    /* Prepare timeout counter */
    CurrentTicks = QSPI_TX_BUFFER_RESET_DELAY;
    /* Insert delay to ensure TX FIFO reset is complete */
    while (CurrentTicks > 0U)
    {
        CurrentTicks -= 1U;
    }
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_PadTxBuf
 * Description   : Pad Tx buffer up to a minimum number of entries required
 *                 by the device for transmission to start
 *
 *END**************************************************************************/
#if (FEATURE_QSPI_TX_MIN_BUF_FILL > 1)
FLS_FUNC static void Qspi_Lld_PadTxBuf(volatile QSPI_Type *BaseAddr)
{
    uint32 BufFill = Qspi_Lld_GetTxBufFill(BaseAddr);
    /* Pad buffer will blank Data */
    while ((BufFill < FEATURE_QSPI_TX_MIN_BUF_FILL) || ((BufFill & 3U) != 0U))
    {
        Qspi_Lld_WriteTxData(BaseAddr, 0xFFFFFFFFU);
        ++BufFill;
    }
}
#else
FLS_FUNC static void Qspi_Lld_PadTxBuf(const QSPI_Type *BaseAddr)
{
    /* Remove unused variable */
    (void)BaseAddr;
}
#endif


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_IpWrite
 * Description   : Launches an IP write command
 * @implements     Qspi_Lld_IpWrite_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_IpWrite(uint32 Instance,
        uint8 Lut,
        uint32 Address,
        const uint8 *Data,
        uint32 Size
                                                )
{
    volatile QSPI_Type *BaseAddr;
    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;
    Qspi_StatusType Errors = STATUS_QSPI_SUCCESS;
    uint32 Padding;


#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_INSTANCE_COUNT);
    DevAssert(Size <= (uint16)FEATURE_QSPI_TX_BUF_SIZE);
    DevAssert(Lut < QSPI_LUT_COUNT);
    DevAssert(Data != NULL_PTR);
#endif
    BaseAddr = Qspi_RegBase[Instance];
    /* Reset AHB buffers to force re-read from memory after write Operation */
    Qspi_Lld_AhbFlush(BaseAddr);

    /* Set write Address */
    Qspi_Lld_SetIpAddr(BaseAddr, Address);

    /* Ensure there is no garbage in Tx FIFO */
    Qspi_Lld_InvalidateTxBuf(Instance);

    /* Fill Tx buffer */
    Padding = Qspi_Lld_FillTxBuf(BaseAddr, Data, Size, (uint32)(Qspi_MemoryPadding[Instance]));
    Qspi_MemoryPadding[Instance] = 0U;  /* Clear Padding */

    /* Pad Tx buffer up to the minimum number of entries required by the device */
    Qspi_Lld_PadTxBuf(BaseAddr);

    /* Trigger IP command with specified sequence and Size */
    Qspi_Lld_IpTrigger(BaseAddr, Lut, (uint16)(Size + Padding));

    /* Wait until the command is sent */
    Status = Qspi_Lld_WaitTransactionComplete(BaseAddr);

    /* Check for Errors reported by the QuadSPI */
    Errors = Qspi_Lld_ErrorCheck(BaseAddr);
    if (STATUS_QSPI_SUCCESS == Status)
    {
        Status = Errors;
    }

    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_ControllerGetStatus
 * Description   : Checks the Status of the currently running IP command
 * @implements     Qspi_Lld_ControllerGetStatus_Activity
 *END**************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_ControllerGetStatus(uint32 Instance)
{
    volatile QSPI_Type *BaseAddr;
    Qspi_StatusType Status;
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert((Instance < QSPI_INSTANCE_COUNT));
#endif
    BaseAddr = Qspi_RegBase[Instance];

    /* Check device for busy Status */
    if (TRUE == Qspi_Lld_GetBusyStatus(BaseAddr))
    {
        Status = STATUS_QSPI_BUSY;
    }
    else
    {
        /* Check for Errors reported by the QuadSPI */
        Status = Qspi_Lld_ErrorCheck(BaseAddr);
    }
    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_InitLutSeq
 * Description   : Initializes one sequence in the LUT table from a virtual table sequence.
                   Returns start index of next sequence.
* @implements      Qspi_Lld_InitLutSeq_Activity
*END**************************************************************************/
FLS_FUNC static uint16 Qspi_Lld_InitLutSeq(uint32 Instance,
        uint16 VirtualLutIdx,
        uint8 LutIndex
                                          )
{
    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);
    const Qspi_InstrOpType *VirtualLutTable = State->Configuration->LutSequences.LutOps;
    Qspi_InstrOpType Operation1, Operation2;
    uint16 VLutIdx = VirtualLutIdx;         /* Index in virtual LUT  */
    uint8 LutIdx = 0U;                      /* Index in phisical LUT */

    do
    {
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
        DevAssert(VLutIdx < State->Configuration->LutSequences.OpCount);
#endif
        Operation1 = VirtualLutTable[VLutIdx];
        ++VLutIdx;
        Operation2 = QSPI_LUT_SEQ_END;
        if (Operation1 != QSPI_LUT_SEQ_END)
        {
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
            DevAssert(VLutIdx < State->Configuration->LutSequences.OpCount);
#endif
            Operation2 = VirtualLutTable[VLutIdx];
            ++VLutIdx;
        }
        /* Add two Operations to Lut sequence */
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
        DevAssert(LutIdx < FEATURE_QSPI_LUT_SEQUENCE_SIZE);
#endif
        Qspi_Lld_SetLut(Instance, (FEATURE_QSPI_LUT_SEQUENCE_SIZE * LutIndex) + LutIdx, Operation1, Operation2);
        ++LutIdx;
    } while (Operation2 != QSPI_LUT_SEQ_END);

    return VLutIdx;
}



/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_SetValue
 * Description   : Converts a long value in data to be sent to flash
 * @implements      Qspi_Lld_SetValue_Activity
*END**************************************************************************/
FLS_FUNC static inline void Qspi_Lld_SetValue(uint8 *Data,
        uint8 Size,
        uint32 Value
                                             )
{
    uint8 LoopCnt;
    uint32 TempValue = Value;

    /* Put Value in the data buffer */
    for (LoopCnt = 0U; LoopCnt < Size; LoopCnt++)
    {
        Data[LoopCnt] = (uint8)(TempValue & 0xFFU);
        TempValue >>= 8U;
    }
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_SetBitfield
 * Description   : Sets a new value in a register bitfield
 * @implements      Qspi_Lld_SetBitfield_Activity
*END**************************************************************************/
FLS_FUNC static void Qspi_Lld_SetBitfield(uint8 *Data,
        uint8 Size,
        uint8 Shift,
        uint8 Width,
        uint32 Value
                                         )
{
    uint8 LoopCnt;
    uint32 LongData = 0UL;
    uint32 Mask;

    /* Pack Data in a long value */
    for (LoopCnt = 0U; LoopCnt < Size; LoopCnt++)
    {
        LongData = (LongData << 8U) + Data[LoopCnt];
    }
    /* Apply change */
    Mask = ((1UL << (uint32)Width) - 1UL) << (uint32)Shift;
    LongData &= ~Mask;
    LongData |= (Value << Shift) & Mask;
    /* Put data back in the data buffer */
    for (LoopCnt = 0U; LoopCnt < Size; LoopCnt++)
    {
        Data[LoopCnt] = (uint8)(LongData & 0xFFU);
        LongData >>= 8U;
    }
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_GetBitfield
 * Description   : Extracts the Value of a register bitfield
 * @implements     Qspi_Lld_GetBitfield_Activity
 *END**************************************************************************/
FLS_FUNC static uint32 Qspi_Lld_GetBitfield(const uint8 *Data,
        uint8 Size,
        uint8 Shift,
        uint8 Width
                                           )
{
    uint8 LoopCnt;
    uint32 LongData = 0U;
    uint32 Mask;
    uint32 Value;

    /* Pack Data in a long Value */
    for (LoopCnt = 0U; LoopCnt < Size; ++LoopCnt)
    {
        LongData = (LongData << 8U) + Data[LoopCnt];
    }
    /* Extract field */
    Mask = (1UL << (uint32)Width) - 1UL;
    Value = (LongData >> Shift) & Mask;
    return Value;
}
/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_RunCommand
 * Description   : Launches a simple command for the serial flash
 * @implements      Qspi_Lld_RunCommand_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_RunCommand(uint32 Instance,
        uint16 Lut,
        uint32 Addr
                                                   )
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
#endif

    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;
    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);

#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Lut != QSPI_LUT_INVALID);
    DevAssert(Addr < State->Configuration->MemSize);
#endif

    if (QSPI_LUT_INVALID == Lut)
    {
        Status = STATUS_QSPI_ERROR;
    }
    else
    {
        /* Copy sequence in LUT registers */
        (void)Qspi_Lld_InitLutSeq(Instance, Lut, QSPI_COMMAND_LUT);

        /* Run QSPI command */
        Status = Qspi_Lld_IpCommand(State->Connection->QspiInstance, QSPI_COMMAND_LUT, State->BaseAddress + Addr);
    }

    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_RunReadCommand
 * Description   : Launches a read command for the serial flash
 * @implements      Qspi_Lld_RunReadCommand_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_RunReadCommand(uint32 Instance,
        uint16 Lut,
        uint32 Addr,
        uint8 *DataRead,
        const uint8 *DataCmp,
        uint32 Size
                                                       )
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
    DevAssert(Lut != QSPI_LUT_INVALID);
#endif

    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;
    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);

#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Addr < State->Configuration->MemSize);
    DevAssert((Size > 0UL) && ((Addr + Size) <= State->Configuration->MemSize));
#endif

    if (QSPI_LUT_INVALID == Lut)
    {
        Status = STATUS_QSPI_ERROR;
    }
    else
    {
        /* Copy sequence in LUT registers */
        (void)Qspi_Lld_InitLutSeq(Instance, Lut, QSPI_COMMAND_LUT);

        /* Run QSPI command */
        Status = Qspi_Lld_IpRead(State->Connection->QspiInstance, QSPI_COMMAND_LUT, State->BaseAddress + Addr, DataRead, DataCmp, Size);
    }

    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_RunWriteCommand
 * Description   : Launches a write command for the serial flash
 * @implements     Qspi_Lld_RunWriteCommand_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_RunWriteCommand(uint32 Instance,
        uint16 Lut,
        uint32 Addr,
        const uint8 *Data,
        uint32 Size
                                                        )
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
    DevAssert(Lut != QSPI_LUT_INVALID);
#endif
    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;
    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);

#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Addr < State->Configuration->MemSize);
    DevAssert((Size > 0UL) && ((Addr + Size) <= State->Configuration->MemSize));
    DevAssert(Data != NULL_PTR);
#endif

    if (QSPI_LUT_INVALID == Lut)
    {
        Status = STATUS_QSPI_ERROR;
    }
    else
    {
        /* Copy sequence in LUT registers */
        (void)Qspi_Lld_InitLutSeq(Instance, Lut, QSPI_COMMAND_LUT);

        /* Run QSPI command */
        Status = Qspi_Lld_IpWrite(State->Connection->QspiInstance, QSPI_COMMAND_LUT, State->BaseAddress + Addr, Data, Size);
    }

    return Status;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_UpdateStatusReg
 * Description   : Updates a bitfield in the Status register
 * @implements      Qspi_Lld_UpdateStatusReg_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_UpdateStatusReg(uint32 Instance,
        uint8 Offset,
        uint8 Width,
        uint8 Value
                                                        )
{
    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);
    const Qspi_StatusConfigType *StatusConfig = &(State->Configuration->StatusConfig);
    uint8 Data[4U];
    Qspi_StatusType Status;

    /* Read Status register */
    Status = Qspi_Lld_RunReadCommand(Instance, StatusConfig->StatusRegReadLut, 0U, Data, NULL_PTR, StatusConfig->RegSize);

    if (STATUS_QSPI_SUCCESS == Status)
    {
        /* Check existing Value, write Status register only if needed */
        if (Value != Qspi_Lld_GetBitfield(Data, StatusConfig->RegSize, Offset, Width))
        {
            Qspi_Lld_SetBitfield(Data, StatusConfig->RegSize, Offset, Width, Value);
        }
        /* send WREN command for Status register */
        if (StatusConfig->WriteEnableSRLut != QSPI_LUT_INVALID)
        {
            Status = Qspi_Lld_RunCommand(Instance, StatusConfig->WriteEnableSRLut, 0U);
        }
        if (STATUS_QSPI_SUCCESS == Status)
        {
            /* send write Status register command */
            Status = Qspi_Lld_RunWriteCommand(Instance, StatusConfig->StatusRegWriteLut, 0U, Data, StatusConfig->RegSize);
        }
    }

    return Status;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_CheckStatusReg
 * Description   : Checks a bitfield in the Status register
 * @implements      Qspi_Lld_CheckStatusReg_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_CheckStatusReg(uint32 Instance,
        uint8 Offset,
        uint8 Width,
        uint8 *Value
                                                       )
{
    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);
    const Qspi_StatusConfigType *StatusConfig = &(State->Configuration->StatusConfig);
    uint8 Data[4];
    Qspi_StatusType Status;

    /* Read Status register */
    Status = Qspi_Lld_RunReadCommand(Instance, StatusConfig->StatusRegReadLut, 0U, Data, NULL_PTR, StatusConfig->RegSize);
    if (STATUS_QSPI_SUCCESS == Status)
    {
        /* Extract bit-field */
        *Value = (uint8)Qspi_Lld_GetBitfield(Data, StatusConfig->RegSize, Offset, Width);
    }

    return Status;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_SetProtection
 * Description   : Sets the protection bits of the device
 * @implements     Qspi_Lld_SetProtection_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_SetProtection(uint32 Instance,
        uint8 Value
                                                      )
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
#endif
    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);
    const Qspi_StatusConfigType *StatusConfig = &(State->Configuration->StatusConfig);

    return Qspi_Lld_UpdateStatusReg(Instance, StatusConfig->BlockProtectionOffset, StatusConfig->BlockProtectionWidth, Value);
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_GetProtection
 * Description   : Returns the current protection bits of the device
 * @implements     Qspi_Lld_GetProtection_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_GetProtection(uint32 Instance,
        uint8 *Value
                                                      )
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
    DevAssert(Value != NULL_PTR);
#endif
    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);
    const Qspi_StatusConfigType *StatusConfig = &(State->Configuration->StatusConfig);

    return Qspi_Lld_CheckStatusReg(Instance, StatusConfig->BlockProtectionOffset, StatusConfig->BlockProtectionWidth, Value);
}
/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_WriteEnable
 * Description   : Enables the serial flash memory for a program or erase Operation
 * @implements      Qspi_Lld_WriteEnable_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_WriteEnable(uint32 Instance)
{
    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);
    const Qspi_StatusConfigType *StatusConfig = &(State->Configuration->StatusConfig);

    uint32 Retries = QSPI_MAX_RETRY + 1U;
    Qspi_StatusType Status = STATUS_QSPI_TIMEOUT;
    Qspi_StatusType CmdStatus;
    uint8 WelValue = 0U;

    while (Retries > 0UL)
    {
        /* send WREN command */
        CmdStatus = Qspi_Lld_RunCommand(Instance, StatusConfig->WriteEnableLut, 0U);
        if (CmdStatus != STATUS_QSPI_SUCCESS)
        {
            Status = CmdStatus;
        }
        /* check WEL bit */
        CmdStatus = Qspi_Lld_CheckStatusReg(Instance, StatusConfig->WriteEnableOffset, 1U, &WelValue);
        if (STATUS_QSPI_SUCCESS == CmdStatus)
        {
            /* 1 == check WEL */
            if (1U == WelValue)
            {
                Status = STATUS_QSPI_SUCCESS;
                break;
            }
        }
        else
        {
            /* record error */
            Status = CmdStatus;
        }
        --Retries;
    }

    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_BasicErase
 * Description   : Perform one of the supported erase types in the serial flash.
 * @implements      Qspi_Lld_BasicErase_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_BasicErase(uint32 Instance,
        uint32 Address,
        uint16 EraseLut
                                                   )
{
    Qspi_StatusType Status;

    /* enable write before erasing */
    Status = Qspi_Lld_WriteEnable(Instance);

    if (STATUS_QSPI_SUCCESS == Status)
    {
        /* launch erase command and return */
        Status = Qspi_Lld_RunCommand(Instance, EraseLut, Address);
    }
    else
    {
        /* Empty clause added to fulfill MISRA. */
    }

    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_CheckMemoryStatus
 * Description   : Check that the memory is idle. Used internally by the driver
                   during initialization
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_CheckMemoryStatus(uint32 Instance,
        uint16 Lut
                                                          )
{
    Qspi_StatusType Status;
    uint8 BusyValue;
    uint8 Data[4];
    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);
    const Qspi_StatusConfigType *StatusConfig = &(State->Configuration->StatusConfig);

    /* Check if the QuadSPI controller is idle */
    Status = Qspi_Lld_ControllerGetStatus(State->Connection->QspiInstance);
    if (STATUS_QSPI_SUCCESS == Status)
    {
        /* Check if the Operation has finished in the serial flash */
        /* Read Status register */
        Status = Qspi_Lld_RunReadCommand(Instance, Lut, 0U, Data, NULL_PTR, StatusConfig->RegSize);
        if (STATUS_QSPI_SUCCESS == Status)
        {
            /* Extract bit-field */
            BusyValue = (uint8)Qspi_Lld_GetBitfield(Data, StatusConfig->RegSize, StatusConfig->BusyOffset, 1U);
            if (BusyValue == StatusConfig->BusyValue)
            {
                /* Flash device is busy */
                Status = STATUS_QSPI_BUSY;
            }
        }
    }

    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_CheckCommandComplete
 * Description   : Wait until external memory is not busy
 * @implements      Qspi_Lld_CheckCommandComplete_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_CheckCommandComplete(uint32 Instance,
        uint16 Lut
                                                             )
{
    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;
    uint32  ElapsedTicks = 0U;

    /* Wait for the command to complete */
    do
    {
        /* Get memory Status */
        Status = Qspi_Lld_CheckMemoryStatus(Instance, Lut);
        /* Check timeout */
        if (ElapsedTicks >= QSPI_FLS_INIT_TIMEOUT)
        {
            Status = STATUS_QSPI_TIMEOUT;
            break;
        }
        ++ElapsedTicks;
    } while (STATUS_QSPI_BUSY == Status);
    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_CheckResetComplete
 * Description   : Wait until external memory is available for Operation after a reset
 * @implements      Qspi_Lld_CheckResetComplete_Activity
 *END**************************************************************************/
FLS_FUNC static void Qspi_Lld_CheckResetComplete(void)
{
    uint32  ElapsedTicks = 0U;
    /* Wait for the specified time */
    while (ElapsedTicks < QSPI_RESET_TIMEOUT)
    {
        ++ElapsedTicks;
    }
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_InitWriteReg
 * Description   : Write the configured Value into a register of external flash device
 * @implements      Qspi_Lld_InitWriteReg_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_InitWriteReg(uint32 Instance,
        const Qspi_InitOperationType *Operation
                                                     )
{
    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;
    uint8 Value[4U];

    /* write a Value in a register */
    if (QSPI_LUT_INVALID != Operation->WeLut)
    {
        /* send WREN command */
        Status = Qspi_Lld_RunCommand(Instance, Operation->WeLut, Operation->Addr);
    }
    /*Write register Value*/
    if (STATUS_QSPI_SUCCESS == Status)
    {
        Qspi_Lld_SetValue(Value, Operation->Size, Operation->Value);
        Status = Qspi_Lld_RunWriteCommand(Instance, Operation->Command1Lut, Operation->Addr, Value, Operation->Size);
    }
    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_InitRMWReg
 * Description   : Change a bitfield in a register of external flash device
 * @implements      Qspi_Lld_InitRMWReg_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_InitRMWReg(uint32 Instance,
        const Qspi_InitOperationType *Operation
                                                   )
{
    Qspi_StatusType Status;
    uint32 FieldVal;
    uint8 Value[4U];

    /* Read current register Value */
    Status = Qspi_Lld_RunReadCommand(Instance, Operation->Command1Lut, Operation->Addr, Value, NULL_PTR, Operation->Size);
    if (STATUS_QSPI_SUCCESS == Status)
    {
        /* Retrieve target bitfield */
        FieldVal = Qspi_Lld_GetBitfield(Value, Operation->Size, Operation->Shift, Operation->Width);
        if (FieldVal != Operation->Value)
        {
            /* Modify target bitfield */
            Qspi_Lld_SetBitfield(Value, Operation->Size, Operation->Shift, Operation->Width, Operation->Value);
            if (QSPI_LUT_INVALID != Operation->WeLut)
            {
                /* Send WREN command */
                Status = Qspi_Lld_RunCommand(Instance, Operation->WeLut, Operation->Addr);
            }
            if (STATUS_QSPI_SUCCESS == Status)
            {
                /* Write back register Value; use second LUT command */
                Status = Qspi_Lld_RunWriteCommand(Instance, Operation->Command2Lut, Operation->Addr, (uint8 *)&Value, Operation->Size);
            }
        }
    }

    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_InitReadReg
 * Description   : Read the register's Value of external flash device and loop until matching the configured one
 * @implements      Qspi_Lld_InitReadReg_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_InitReadReg(uint32 Instance,
        const Qspi_InitOperationType *Operation
                                                    )
{
    Qspi_StatusType Status;
    uint32 FieldVal = 0UL;
    uint8 Value[4U];
    uint32 ElapsedTicks = 0UL;

    /* Prepare timeout counter */
    do
    {
        /* read current register Value */
        Status = Qspi_Lld_RunReadCommand(Instance, Operation->Command1Lut, Operation->Addr, Value, NULL_PTR, Operation->Size);
        if (STATUS_QSPI_SUCCESS == Status)
        {
            /* retrieve target bitfield */
            FieldVal = Qspi_Lld_GetBitfield(Value, Operation->Size, Operation->Shift, Operation->Width);
        }
        ++ElapsedTicks;
        if (ElapsedTicks > QSPI_FLS_INIT_TIMEOUT)
        {
            Status = STATUS_QSPI_TIMEOUT;
            break;
        }
    } while (FieldVal != Operation->Value);

    return Status;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_InitOperation
 * Description   : Execute initialization sequence to get the serial flash memory
 *               in the target State for Operation
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_InitOperation(uint32 Instance,
        const Qspi_StateType *State,
        uint8 InitOp
                                                      )
{
    const Qspi_InitOperationType *InitOperations;
    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;

    InitOperations = State->Configuration->InitConfiguration.Operations;

    switch (InitOperations[InitOp].OpType)
    {
        case QSPI_OP_TYPE_CMD:
            /* Execute a simple command */
            Status = Qspi_Lld_RunCommand(Instance, InitOperations[InitOp].Command1Lut, InitOperations[InitOp].Addr);
            break;

        case QSPI_OP_TYPE_WRITE_REG:
            /* Write Value into the register */
            Status = Qspi_Lld_InitWriteReg(Instance, &InitOperations[InitOp]);
            break;

        case QSPI_OP_TYPE_RMW_REG:
            /* Change a bitfield in the register */
            Status = Qspi_Lld_InitRMWReg(Instance, &InitOperations[InitOp]);
            break;

        case QSPI_OP_TYPE_READ_REG:
            /* Check a bitfield in the register */
            Status = Qspi_Lld_InitReadReg(Instance, &InitOperations[InitOp]);
            break;

        case QSPI_OP_TYPE_QSPI_CFG:
            /* Re-initialize QSPI controller with the given Configuration */
            (void)Qspi_Lld_ControllerDeinit(State->Connection->QspiInstance);
#if defined (FLS_USER_MODE_SUPPORTED)
            Status = (Qspi_StatusType)OsIf_Trusted_Call_Return2param(Qspi_Lld_ControllerInit, State->Connection->QspiInstance, InitOperations[InitOp].CtrlCfgPtr);
#else
            Status = Qspi_Lld_ControllerInit(State->Connection->QspiInstance, InitOperations[InitOp].CtrlCfgPtr);
#endif
            break;

        default:
            ; /* unknown Operation */
            break;
    }   /* switch */

    return Status;

}

/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_InitDevice
 * Description   : Execute initialization sequence to get the serial flash memory
 *                 in the target State for Operation
 * @implements      Qspi_Lld_InitDevice_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_InitDevice(uint32 Instance,
        const Qspi_StateType *State
                                                   )
{
    Qspi_StatusType Status;
    uint8 InitConfigOpCount;
    uint8 InitOp;

    Status = STATUS_QSPI_SUCCESS;

    /* Perform Operations in initialization list */
    InitConfigOpCount = State->Configuration->InitConfiguration.OpCount;
    if (InitConfigOpCount > 0U)
    {
        for (InitOp = 0; InitOp < InitConfigOpCount; ++InitOp)
        {
            Status = Qspi_Lld_InitOperation(Instance, State, InitOp);

            if (STATUS_QSPI_SUCCESS != Status)
            {
                break;
            }
        }   /* for */
    }  /* if (InitConfigOpCount > 0U) */

    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_InitProtection
 * Description   : Update the protection Configuration Value if needed
 * @implements      Qspi_Lld_InitProtection_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_InitProtection(uint32 Instance,
        const Qspi_StateType *State
                                                       )
{
    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;
    uint8 ConfigProtection = State->Configuration->StatusConfig.BlockProtectionValue;
    uint8 GetProtection = 0U;

    if (State->Configuration->StatusConfig.BlockProtectionWidth != 0U)
    {
        /* Ensure the previous command is completed */
        Status = Qspi_Lld_CheckCommandComplete(Instance, State->Configuration->StatusConfig.StatusRegReadLut);
        if (STATUS_QSPI_SUCCESS == Status)
        {
            /* Read and check the current setting */
            Status = Qspi_Lld_GetProtection(Instance, &GetProtection);
            if ((STATUS_QSPI_SUCCESS == Status) && (GetProtection != ConfigProtection))
            {
                /* Set new setting */
                Status = Qspi_Lld_SetProtection(Instance, ConfigProtection);
                if (STATUS_QSPI_SUCCESS == Status)
                {
                    /* Ensure the write is completed  */
                    Status = Qspi_Lld_CheckCommandComplete(Instance, State->Configuration->StatusConfig.StatusRegReadLut);
                }
            }
        }
    }

    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_InitReset
 * Description   : Perform the software reset sequence
 * @implements      Qspi_Lld_InitReset_Activity
 *END**************************************************************************/
FLS_FUNC static Qspi_StatusType Qspi_Lld_InitReset(uint32 Instance,
        uint16 ResetCmdLut,
        uint8 ResetCmdCount,
        const Qspi_StateType *State
                                                  )
{
    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;
    uint16 CrtLut = ResetCmdLut;
    uint8 LoopCnt;

    if (QSPI_LUT_INVALID != ResetCmdLut)
    {
        for (LoopCnt = 0U; LoopCnt < ResetCmdCount; ++LoopCnt)
        {
            /* Copy sequence in LUT registers */
            CrtLut = Qspi_Lld_InitLutSeq(Instance, CrtLut, QSPI_COMMAND_LUT);

            /* Run QSPI command */
            Status = Qspi_Lld_IpCommand(State->Connection->QspiInstance, QSPI_COMMAND_LUT, State->BaseAddress);
            if (Status != STATUS_QSPI_SUCCESS)
            {
                break;
            }
        }
        if (STATUS_QSPI_SUCCESS == Status)
        {
            /* Ensure flash is ready after reset */
            Qspi_Lld_CheckResetComplete();
        }
    }

    return Status;
}

/*==================================================================================================
                                                GLOBAL FUNCTIONS
==================================================================================================*/

/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_EraseBlock
 * Description   : Erase a sector in the serial flash.
 *                 The Size must match one of the device's erase types.
 * @implements     Qspi_Lld_EraseBlock_Activity
 *END**************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_EraseBlock(uint32 Instance,
        uint32 Address,
        uint32 Size
                                            )
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
#endif

    Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);
    Qspi_StatusType Status = STATUS_QSPI_ERROR;
    uint8 EraseType;

#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Address < State->Configuration->MemSize);
    DevAssert((Size > 0UL) && ((Address + Size) <= State->Configuration->MemSize));
#endif
    /* Check Address range */
    if (Address < State->Configuration->MemSize)
    {
        /* find the suited erase type */
        for (EraseType = 0U; EraseType < QSPI_ERASE_TYPES; ++EraseType)
        {
            if ((State->Configuration->EraseSettings.EraseTypes[EraseType].EraseLut != QSPI_LUT_INVALID) &&
                    (Size == (uint32)((uint32)1U << (State->Configuration->EraseSettings.EraseTypes[EraseType].Size))))
            {
                break;
            }
            else
            {
                /* Empty clause added to fulfill MISRA. */
            }
        }
        /* if erase type was found, launch the erase */
        if (EraseType < QSPI_ERASE_TYPES)
        {
#ifdef FLS_USER_MODE_SUPPORTED
            Status = (Qspi_StatusType)OsIf_Trusted_Call_Return3param(Qspi_Lld_BasicErase, Instance, Address, State->Configuration->EraseSettings.EraseTypes[EraseType].EraseLut);
#else
            Status = Qspi_Lld_BasicErase(Instance, Address, State->Configuration->EraseSettings.EraseTypes[EraseType].EraseLut);
#endif
            if (STATUS_QSPI_SUCCESS == Status)
            {
                State->LastCommand = QSPI_LAST_COMMAND_ERASE;
            }
        }
        else
        {
            /* Empty clause added to fulfill MISRA. */
        }
    }
    else
    {
        /* Empty clause added to fulfill MISRA. */
    }
    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_EraseChip
 * Description   : Erase the entire serial flash
 * @implements     Qspi_Lld_EraseChip_Activity
 *END**************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_EraseChip(uint32 Instance)
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
#endif

    Qspi_StatusType Status = STATUS_QSPI_ERROR;
    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);

    if (State->Configuration->EraseSettings.ChipEraseLut != QSPI_LUT_INVALID)
    {
        /* enable write before erasing */
        Status = Qspi_Lld_WriteEnable(Instance);
        if (STATUS_QSPI_SUCCESS == Status)
        {
            /* launch erase command */
            Status = Qspi_Lld_RunCommand(Instance, State->Configuration->EraseSettings.ChipEraseLut, 0U);
        }
        else
        {
            /* Empty clause added to fulfill MISRA. */
        }
    }
    else
    {
        /* Empty clause added to fulfill MISRA. */
    }
    return Status;
}

#if 0
/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_ProgramSuspend
 * Description   : Suspends a program Operation
 * @implements     Qspi_Lld_ProgramSuspend_Activity
 *END**************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_ProgramSuspend(uint32 Instance)
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
#endif
    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);

    return Qspi_Lld_RunCommand(Instance, State->Configuration->SuspendSettings.ProgramSuspendLut, 0U);
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_ProgramResume
 * Description   : Resumes a program Operation
 * @implements     Qspi_Lld_ProgramResume_Activity
 *END**************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_ProgramResume(uint32 Instance)
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
#endif
    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);

    return Qspi_Lld_RunCommand(Instance, State->Configuration->SuspendSettings.ProgramResumeLut, 0U);
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_EraseSuspend
 * Description   : Suspends an erase Operation
 * @implements     Qspi_Lld_EraseSuspend_Activity
 *END**************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_EraseSuspend(uint32 Instance)
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
#endif
    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);

    return Qspi_Lld_RunCommand(Instance, State->Configuration->SuspendSettings.EraseSuspendLut, 0U);
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_EraseResume
 * Description   : Resumes an erase Operation
 * @implements     Qspi_Lld_EraseResume_Activity
 *END**************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_EraseResume(uint32 Instance)
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
#endif
    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);

    return Qspi_Lld_RunCommand(Instance, State->Configuration->SuspendSettings.EraseResumeLut, 0U);
}
#endif

/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_Reset
 * Description   : Issues a software reset command
 * @implements     Qspi_Lld_Reset_Activity
 *END**************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_Reset(uint32 Instance)
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
#endif
    uint16 ResetCmdLut;        /*!< First command in reset sequence            */
    uint8 ResetCmdCount;       /*!< Number of commands in reset sequence       */
    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);
    Qspi_StatusType Status = STATUS_QSPI_ERROR;

    ResetCmdLut = State->Configuration->ResetSettings.ResetCmdLut;
    if (QSPI_LUT_INVALID != ResetCmdLut)
    {
        ResetCmdCount = State->Configuration->ResetSettings.ResetCmdCount;
        /* Perform reset */
#if defined (FLS_USER_MODE_SUPPORTED)
        Status = (Qspi_StatusType)OsIf_Trusted_Call_Return4param(Qspi_Lld_InitReset,
                 Instance, ResetCmdLut, ResetCmdCount, State);
#else
        Status = Qspi_Lld_InitReset(Instance, ResetCmdLut, ResetCmdCount, State);
#endif
        /* Bring corresponding controller to initial Configuration if required */
        if ((STATUS_QSPI_SUCCESS == Status) && (State->Configuration->CtrlAutoCfgPtr != NULL_PTR))
        {
#if defined (FLS_USER_MODE_SUPPORTED)
            Status = (Qspi_StatusType)OsIf_Trusted_Call_Return2param(Qspi_Lld_ControllerInit,
                     State->Connection->QspiInstance, State->Configuration->CtrlAutoCfgPtr);
#else
            Status = Qspi_Lld_ControllerInit(State->Connection->QspiInstance, State->Configuration->CtrlAutoCfgPtr);
#endif
        }
        if (STATUS_QSPI_SUCCESS == Status)
        {
            /* Execute initial setup of external device */
#if defined (FLS_USER_MODE_SUPPORTED)
            Status = (Qspi_StatusType)OsIf_Trusted_Call_Return2param(Qspi_Lld_InitDevice,
                     Instance, State);
#else
            Status = Qspi_Lld_InitDevice(Instance, State);
#endif
        }
    }

    /* If enabled, call the reset callout. */
    if (NULL_PTR != State->Configuration->ResetCallout)
    {
        Status = State->Configuration->ResetCallout(Instance);
    }

    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_GetMemoryStatus
 * Description   : Get the Status of the last Operation
 * @implements     Qspi_Llp_GetMemoryStatus_Activity
 *END**************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_GetMemoryStatus(uint32 Instance)
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
#endif
    Qspi_StatusType Status;
    uint8 BusyValue;
    Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);
    const Qspi_StatusConfigType *StatusConfig = &(State->Configuration->StatusConfig);

    /* Check if the QuadSPI command is complete */
    Status = Qspi_Lld_ControllerGetStatus(State->Connection->QspiInstance);
    if (STATUS_QSPI_SUCCESS == Status)
    {
        /* Check if the Operation has finished in the serial flash */
        Status = Qspi_Lld_CheckStatusReg(Instance, StatusConfig->BusyOffset, 1U, &BusyValue);
        if (STATUS_QSPI_SUCCESS == Status)
        {
            /* Check BUSY Value */
            if (BusyValue == StatusConfig->BusyValue)
            {
                /* Write/erase in progress */
                Status = STATUS_QSPI_BUSY;
            }
            else
            {
                /* Call user callout, if available, to check Operation result */
                if ((State->LastCommand != QSPI_LAST_COMMAND_NONE) && (NULL_PTR != State->Configuration->ErrorCheckCallout))
                {
                    Status = State->Configuration->ErrorCheckCallout(Instance);
                }
                State->LastCommand = QSPI_LAST_COMMAND_NONE;
            }
        }
        else
        {
            /* Empty clause added to fulfill MISRA. */
        }
    }
    else
    {
        /* Empty clause added to fulfill MISRA. */
    }

    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_CalcPaddingRead
 * Description   : Calculates the number of padding bytes to handle reading from unaligned addresses
 *END**************************************************************************/
FLS_FUNC static inline uint32 Qspi_Lld_CalcPaddingRead(const Qspi_StateType *State,
        uint32 *Address,
        uint32 *Size
                                                      )
{
    uint32 QspiInstance  = State->Connection->QspiInstance;
    uint32 ReadAlignment = State->Connection->MemAlignment;

    /* Checking for unaligned addresses */
    uint32 Offset = *Address & ((uint32)ReadAlignment - 1U);
    if (Offset != 0U)
    {
        /* The number of padding bytes to handle unaligned Address */
        Qspi_MemoryPadding[QspiInstance] = (uint8)Offset;
        /* Decreasing the Address */
        *Address -= Offset;
        /* Increasing the Size to compensate */
        *Size += Offset;
    }

    return Offset;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_Read
 * Description   : Read Data from serial flash
 * @implements     Qspi_Lld_Read_Activity
 *END**************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_Read(uint32 Instance,
                                       uint32 Address,
                                       uint8 *Data,
                                       uint32 Size
                                      )
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
#endif

    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;
    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);
    uint32 CrtAddress = Address;
    uint8 *CrtData = Data;
    uint32 CrtSize = Size;
    uint32 ChunkSize = QSPI_MAX_READ_SIZE;
    uint32 Offset;
    uint32  ElapsedTicks = 0U;

#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(CrtAddress < State->Configuration->MemSize);
    DevAssert((CrtSize > 0UL) && ((CrtAddress + CrtSize) <= State->Configuration->MemSize));
    DevAssert(Data != NULL_PTR);
#endif

    /* Checks and handles unaligned addresses */
    Offset = Qspi_Lld_CalcPaddingRead(State, &CrtAddress, &CrtSize);

    /* Prepare timeout counter */
    while ((CrtSize > 0UL) && (STATUS_QSPI_SUCCESS == Status))
    {
        if (ChunkSize > CrtSize)
        {
            /* Adjust Size for last chunk */
            ChunkSize = CrtSize;
        }
        /* Check timeout */
        if (ElapsedTicks >= QSPI_READ_TIMEOUT)
        {
            Status = STATUS_QSPI_TIMEOUT;
            break;
        }
        ++ElapsedTicks;
        Status = Qspi_Lld_RunReadCommand(Instance, State->ActiveReadLut, CrtAddress, CrtData, NULL_PTR, ChunkSize);
        /* Move to next chunk */
        CrtSize -= ChunkSize;
        CrtAddress += ChunkSize;
        CrtData = &(CrtData[ChunkSize - Offset]);  /* Handle alignment for the first read */
        Offset = 0U;

        /* Call user callout, if available, to check ecc Status */
        if ((STATUS_QSPI_SUCCESS == Status) && (NULL_PTR != State->Configuration->EccCheckCallout))
        {
            Status = State->Configuration->EccCheckCallout(Instance, CrtAddress, ChunkSize);
        }
    }
    return Status;
}



/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_ReadId
 * Description   : Read manufacturer ID from serial flash
 * @implements     Qspi_Lld_ReadId_Activity
 *END**************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_ReadId(uint32 Instance,
        uint8 *Data
                                        )
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
    DevAssert(Data != NULL_PTR);
#endif

    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);

    return Qspi_Lld_RunReadCommand(Instance,
                                   State->Configuration->ReadIdSettings.ReadIdLut,
                                   0U,
                                   Data,
                                   NULL_PTR,
                                   State->Configuration->ReadIdSettings.ReadIdSize);
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_ProgramVerify
 * Description   : Verifies Data written in serial flash
 * @implements     Qspi_Lld_ProgramVerify_Activity
 *END**************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_ProgramVerify(uint32 Instance,
        uint32 Address,
        const uint8 *Data,
        uint32 Size
                                               )
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Data != NULL_PTR);
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
#endif

    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;
    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);
    uint32 CrtAddress = Address;
    const uint8 *CrtData = Data;
    uint32 CrtSize = Size;
    uint32 ChunkSize = QSPI_MAX_READ_SIZE;
    uint32 Offset;
    uint32  ElapsedTicks = 0U;

#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(CrtAddress < State->Configuration->MemSize);
    DevAssert((CrtSize > 0UL) && ((CrtAddress + CrtSize) <= State->Configuration->MemSize));
#endif

    /* Checks and handles unaligned addresses */
    Offset = Qspi_Lld_CalcPaddingRead(State, &CrtAddress, &CrtSize);

    /* Prepare timeout counter */
    while ((CrtSize > 0U) && (STATUS_QSPI_SUCCESS == Status))
    {
        if (ChunkSize > CrtSize)
        {
            /* Adjust Size for last chunk */
            ChunkSize = CrtSize;
        }
        /* Check timeout */
        if (ElapsedTicks >= QSPI_READ_TIMEOUT)
        {
            Status = STATUS_QSPI_TIMEOUT;
            break;
        }
        ++ElapsedTicks;
        Status = Qspi_Lld_RunReadCommand(Instance, State->ActiveReadLut, CrtAddress, NULL_PTR, CrtData, ChunkSize);
        /* Move to next chunk */
        CrtSize -= ChunkSize;
        CrtAddress += ChunkSize;
        CrtData = &(CrtData[ChunkSize - Offset]);  /* Handle alignment for the first read */
        Offset = 0U;
    }
    return Status;
}



/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_EraseVerify
 * Description   : Verifies that an area in serial flash is in erased State
 * @implements     Qspi_Lld_EraseVerify_Activity
 *END**************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_EraseVerify(uint32 Instance,
        uint32 Address,
        uint32 Size
                                             )
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
#endif
    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;
    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);
    uint32 CrtAddress = Address;
    uint32 CrtSize = Size;
    uint32 ChunkSize = QSPI_MAX_READ_SIZE;
    uint32  ElapsedTicks = 0U;

#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(CrtAddress < State->Configuration->MemSize);
    DevAssert((CrtSize > 0UL) && ((CrtAddress + CrtSize) <= State->Configuration->MemSize));
#endif

    /* Checks and handles unaligned addresses */
    (void)Qspi_Lld_CalcPaddingRead(State, &CrtAddress, &CrtSize);

    /* Prepare timeout counter */
    while ((CrtSize > 0UL) && (STATUS_QSPI_SUCCESS == Status))
    {
        if (ChunkSize > CrtSize)
        {
            /* Adjust Size for last chunk */
            ChunkSize = CrtSize;
        }
        /* Check timeout */
        ++ElapsedTicks;
        if (ElapsedTicks >= QSPI_READ_TIMEOUT)
        {
            Status = STATUS_QSPI_TIMEOUT;
            break;
        }
        ++ElapsedTicks;
        Status = Qspi_Lld_RunReadCommand(Instance, State->ActiveReadLut, CrtAddress, NULL_PTR, NULL_PTR, ChunkSize);
        /* Move to next chunk */
        CrtSize -= ChunkSize;
        CrtAddress += ChunkSize;
    }
    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_CalcPaddingWrite
 * Description   : Calculates the number of padding bytes to handle writing to unaligned addresses
 *END**************************************************************************/
FLS_FUNC static inline uint32 Qspi_Lld_CalcPaddingWrite(const Qspi_StateType *State,
        uint32 Address,
        uint32 Size
                                                       )
{
    uint32 QspiInstance  = State->Connection->QspiInstance;
    uint32 AlignmentMask = (uint32)(State->Connection->MemAlignment) - 1U;

    /* The number of pre-padding bytes */
    uint32 PrePadding    = Address & AlignmentMask;

    /* The number of post-padding bytes */
    uint32 EndAddr       = (Address + Size) - 1U;
    uint32 PostPadding   = AlignmentMask - (EndAddr & AlignmentMask);

    /* Store padding information */
    Qspi_MemoryPadding[QspiInstance] = (uint8)((PrePadding << 4U) | PostPadding);

    /* Decreasing the Address */
    return (Address - PrePadding);
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_Program
 * Description   : Writes Data in serial flash
 * @implements     Qspi_Lld_Program_Activity
 *END**************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_Program(uint32 Instance,
        uint32 Address,
        const uint8 *Data,
        uint32 Size
                                         )
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
    DevAssert(Data != NULL_PTR);
#endif

    Qspi_StatusType Status;
    Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);
    uint32 WriteAddress;

#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Address < State->Configuration->MemSize);
    DevAssert((Size > 0UL) && ((Address + Size) <= State->Configuration->MemSize));
#endif

    /* Check Address range and page Size */
    if ((Address >= State->Configuration->MemSize) || (Size > State->Configuration->PageSize))
    {
        Status = STATUS_QSPI_ERROR;
    }
    else
    {
        /* enable write before programming */
        Status = Qspi_Lld_WriteEnable(Instance);
        if (STATUS_QSPI_SUCCESS == Status)
        {
            /* Perform alignment checking before write Data */
            WriteAddress = Qspi_Lld_CalcPaddingWrite(State, Address, Size);

            Status = Qspi_Lld_RunWriteCommand(Instance, State->Configuration->WriteLut, WriteAddress, Data, Size);
            if (STATUS_QSPI_SUCCESS == Status)
            {
                State->LastCommand = QSPI_LAST_COMMAND_WRITE;
            }
        }
        else
        {
            /* Empty clause added to fulfill MISRA. */
        }
    }
    return Status;
}

#if 0
/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_Enter0XX
 * Description   : Enters 0-X-X mode (no command for read instructions)
 * @implements     Qspi_Lld_Enter0XX_Activity
 *END**************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_Enter0XX(uint32 Instance)
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
#endif

    Qspi_StatusType Status = STATUS_QSPI_ERROR;
    Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);
    uint8 DummyData;

    if (State->Configuration->Read0xxLut != QSPI_LUT_INVALID)
    {
        State->ActiveReadLut = State->Configuration->Read0xxLut;
        /* Perform a dummy read to activate 0-X-X mode */
        Status = Qspi_Lld_RunReadCommand(Instance, State->ActiveReadLut, 0U, &DummyData, NULL_PTR, 1U);
    }

    if (State->Configuration->Read0xxLutAHB != QSPI_LUT_INVALID)
    {
        /* Set 0-x-x mode LUT sequence for AHB */
        (void)Qspi_Lld_InitLutSeq(Instance, State->Configuration->Read0xxLutAHB, QSPI_AHB_LUT);
    }

    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_Exit0XX
 * Description   : Exits 0-X-X mode (no command for read instructions)
 * @implements     Qspi_Lld_Exit0XX_Activity
 *END**************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_Exit0XX(uint32 Instance)
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
#endif

    Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);
    Qspi_StatusType Status = STATUS_QSPI_ERROR;
    uint8 DummyData;

    if (State->Configuration->Read0xxLut != QSPI_LUT_INVALID)
    {
        State->ActiveReadLut = State->Configuration->ReadLut;
        /* Perform a dummy read to disable 0-X-X mode */
        Status = Qspi_Lld_RunReadCommand(Instance, State->ActiveReadLut, 0U, &DummyData, NULL_PTR, 1U);
    }

    if (State->Configuration->Read0xxLutAHB != QSPI_LUT_INVALID)
    {
        /* Set back to normal mode LUT sequence for AHB */
        (void)Qspi_Lld_InitLutSeq(Instance, State->Configuration->ReadLut, QSPI_AHB_LUT);
    }

    return Status;
}
#endif


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_AhbReadEnable
 * Description   : Enables AHB reads for the current flash device
 * @implements     Qspi_Lld_AhbReadEnable_Activity
 *END**************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_AhbReadEnable(uint32 Instance)
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
#endif

    const Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);
    Qspi_StatusType Status = STATUS_QSPI_ERROR;

    if (State->ActiveReadLut != QSPI_LUT_INVALID)
    {
        /* Copy sequence in LUT registers */
        (void)Qspi_Lld_InitLutSeq(Instance, State->ActiveReadLut, QSPI_AHB_LUT);
        /* Set sequence number */
        Qspi_Lld_SetAhbSeqId(Instance, QSPI_AHB_LUT);
        Status = STATUS_QSPI_SUCCESS;
    }
    return Status;
}


/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_Init
 * Description   : Initialize the serial flash memory driver
 *
 * @implements     Qspi_Lld_Init_Activity
 *END**************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_Init(uint32 Instance,
                                       const Qspi_MemoryConfigType *ConfigPtr,
                                       const Qspi_MemoryConnectionType *ConnectPtr
                                      )
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_MEM_INSTANCE_COUNT);
    DevAssert(ConfigPtr != NULL_PTR);
    DevAssert(ConnectPtr != NULL_PTR);
#endif
    Qspi_StatusType Status = STATUS_QSPI_SUCCESS;
    Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);

    /* Copy Configuration information to State structure */
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(NULL_PTR == State->Configuration);
#endif
    State->Configuration = ConfigPtr;
    State->Connection = ConnectPtr;
    State->ActiveReadLut = ConfigPtr->ReadLut;    /* 0-X-X mode disabled by default */
    State->LastCommand = QSPI_LAST_COMMAND_NONE;
    State->BaseAddress = Qspi_Lld_GetBaseAdress(ConnectPtr->QspiInstance, ConnectPtr->ConnectionType);

    /* Initialize corresponding controller if required */
    if (ConfigPtr->CtrlAutoCfgPtr != NULL_PTR)
    {
#ifdef FLS_USER_MODE_SUPPORTED
        Status = (Qspi_StatusType)OsIf_Trusted_Call_Return2param(Qspi_Lld_ControllerInit,
                 ConnectPtr->QspiInstance, ConfigPtr->CtrlAutoCfgPtr);
#else
        Status = Qspi_Lld_ControllerInit(ConnectPtr->QspiInstance, ConfigPtr->CtrlAutoCfgPtr);
#endif
    }
    if (STATUS_QSPI_SUCCESS == Status)
    {
        /* Perform initial reset */
        Status = Qspi_Lld_InitReset(Instance, ConfigPtr->InitResetSettings.ResetCmdLut, ConfigPtr->InitResetSettings.ResetCmdCount, State);
    }
    if (STATUS_QSPI_SUCCESS == Status)
    {
        /* Execute initial setup of external device */
        Status = Qspi_Lld_InitDevice(Instance, State);
    }

    /* If enabled, call the init callout, for additional QSPI IP or external memory settings. */
    if ((STATUS_QSPI_SUCCESS == Status) && (NULL_PTR != ConfigPtr->InitCallout))
    {
        Status = ConfigPtr->InitCallout(Instance);
    }

    /* Perform protection Configuration */
    if (STATUS_QSPI_SUCCESS == Status)
    {
        Status = Qspi_Lld_InitProtection(Instance, State);
    }

    return Status;
}

#if 0
/*FUNCTION**********************************************************************
 *
 * Function Name : Qspi_Lld_Deinit
 * Description   : De-initialize the serial flash memory driver
 * @implements     Qspi_Lld_Deinit_Activity
 *END***************************************************************************/
FLS_FUNC Qspi_StatusType Qspi_Lld_Deinit(uint32 Instance)
{
#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(Instance < QSPI_INSTANCE_COUNT);
#endif

    Qspi_StateType *State = &(Qspi_MemoryStateStructure[Instance]);

#if (FLS_DEV_ERROR_DETECT_IN_IPLEVEL==STD_ON)
    DevAssert(State->Configuration != NULL_PTR);
#endif

    State->Configuration = NULL_PTR;
    return STATUS_QSPI_SUCCESS;
}
#endif
#define FLS_STOP_SEC_CODE
#include "Fls_MemMap.h"

#endif
#ifdef __cplusplus
}
#endif

/* End of file Fls_Lld_Qspi.c */
