Newer
Older
mbed-os / targets / TARGET_Cypress / TARGET_PSOC6 / mtb-pdl-cat1 / drivers / source / cy_smif_memslot.c
@Dustin Crossman Dustin Crossman on 4 Jun 2021 175 KB Fix file modes.
/***************************************************************************//**
* \file cy_smif_memslot.c
* \version 2.20
*
* \brief
*  This file provides the source code for the memory-level APIs of the SMIF driver.
*
* Note:
*
********************************************************************************
* \copyright
* Copyright 2016-2021 Cypress Semiconductor Corporation
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

#include "cy_device.h"

#if defined (CY_IP_MXSMIF)

#include "cy_smif_memslot.h"

#if defined(__cplusplus)
extern "C" {
#endif

/** \cond INTERNAL */
/***************************************
*     Internal Constants
***************************************/

#define READ_ENHANCED_MODE_DISABLED (0xFFU)
#define BITS_IN_BYTE                (8U)
#define BYTES_IN_DWORD              (4U)
#define FOUR_BYTE_ADDRESS           (4U)     /* 4 byte addressing mode */
#define BITS_IN_BYTE_ABOVE_4GB      (3U)     /* Density of memory above 4GBit stored as poser of 2 */
#define PARAM_HEADERS_NUM           (CY_SMIF_SFDP_BFPT_BYTE_06)
#define FIRST_HEADER_OFFSET         (0x08U)  /* The offset of the 1-st Parameter Header */
#define PARAM_ID_MSB_REL_OFFSET     (0x07U)  /* The relative offset of Parameter ID MSB 
                                             * in the SFDP Header table 
                                             */
#define PARAM_MINOR_REV_REL_OFFSET  (0x01U)  /* The relative offset of Parameter Minor Revision 
                                             * in the SFDP Header table 
                                             */
#define PARAM_MAJOR_REV_REL_OFFSET  (0x02U)  /* The relative offset of Parameter Major Revision
                                             * in the SFDP Header table
                                             */
#define PARAM_ID_MSB_OFFSET         (0x08U)  /* The offset of Parameter ID MSB */
#define PARAM_ID_LSB_MASK           (0xFFUL) /* The mask of Parameter ID LSB */
#define PARAM_TABLE_PRT_OFFSET      (0x04UL) /* The relative offset of Parameter Table Pointer Byte 1 */
#define PARAM_TABLE_LENGTH_OFFSET   (0X03U)  /* The offset of Parameter Table Length in the Header Table */
#define PARAM_HEADER_NUM            (6U)     /* The supported number of the parameter headers */
#define HEADER_LENGTH               (0x8U)   /* The length of the SFDP header */
#define HEADERS_LENGTH              (HEADER_LENGTH + \
                                                 (CY_SMIF_SFDP_PARAM_HEADER_LENGTH * PARAM_HEADER_NUM))
#define TYPE_STEP                   (2UL)    /* The Erase Type step in the Basic Flash Parameter Table */
#define INSTRUCTION_NOT_SUPPORTED   (0XFFU)  /* The code for the not supported instruction */
#define BASIC_SPI_ID_LSB            (0X00UL) /* The JEDEC SFDP Basic SPI Flash Parameter ID LSB */
#define BASIC_SPI_ID_MSB            (0XFFUL) /* The JEDEC SFDP Basic SPI Flash Parameter ID MSB */
#define SECTOR_MAP_ID_LSB            (0x81UL) /* The JEDEC SFDP Sector Map ID LSB */
#define SECTOR_MAP_ID_MSB            (0xFFUL) /* The JEDEC SFDP Sector Map ID MSB */
#define SECTOR_MAP_DESCRIPTOR_MASK   (0x2U)  /* The mask for the type bit of the Sector Map descriptor */
#define SECTOR_MAP_COMAND_DESCRIPTOR_TYPE (0U) /* Code for the command descriptor type */
#define SECTOR_MAP_REGION_SIZE_MULTIPLIER (256UL) /* The multiplier for region size units */
#define FOUR_BYTE_ADDR_ID_LSB       (0X84UL) /* The 4-byte Address Instruction Table is assigned the ID LSB of 84h */
#define FOUR_BYTE_ADDR_ID_MSB       (0XFFUL) /* The 4-byte Address Instruction Table is assigned the ID MSB of FFh */
#define FOUR_BYTE_ADDR_ERASE_TYPE_1 (0X4UL)  /* The Erase Type 1 offset in 4-byte Address Instruction Table */
#define FOUR_BYTE_ADDR_ERASE_TYPE_4 (0X7UL)  /* The Erase Type 4 offset in 4-byte Address Instruction Table */
#define ERASE_T_COUNT_Pos           (0UL)    /* Erase Type X Erase, Typical time: count (Bits 4:0) */
#define ERASE_T_COUNT_Msk           (0x1FUL) /* Erase Type X Erase, Typical time: count (Bitfield-Mask) */
#define ERASE_T_UNITS_Pos           (5UL)    /* Erase Type X Erase, Typical time: units (Bits 6:5) */
#define ERASE_T_UNITS_Msk           (0x60UL) /* Erase Type X Erase, Typical time: units (Bitfield-Mask) */
#define ERASE_T_COUNT_OFFSET        (0x04U)  /* The offset of the Erase count 10th DWORD */
#define ERASE_T_LENGTH              (0x07U)  /* The Erase Type Typical time length */
#define COMMAND_IS_NOT_FOUND        (0x0U) 
#define PARAMETER_IS_NOT_FOUND      (0x0U)
#define SMIF_MAX_RX_COUNT           (65536UL)
#define ONE_MILLI_IN_MICRO          (1000UL)
#define SMIF_TRANSFER_TIMEOUT       (1000UL)      /* The timeout (microseconds) to use in polling of 
                                                   * the transfer status of the SMIF block 
                                                   */
#define TIMEOUT_SLICE_DIV           (4U)           /* The division factor to use for slicing the timeout
                                                   * while polling the memory
                                                   */
#define TIMEOUT_SLICE_MAX           (1000000UL)    /* The maximum timeout slice (microseconds)
                                                   * while polling the memory */
#define SUPPORT_ERASE_COMMAND_Pos   (1UL)          /* The position of the Support for Erase Commands 
                                                   * in byte 1 of the JEDEC 4-byte Address Instruction Table 
                                                   */ 
#define SUPPORT_ERASE_COMMAND_Msk   (0x0000001EUL) /* The mask of the Support for Erase Commands
                                                   * in the JEDEC 4-byte Address Instruction Table 
                                                   */                                                   
#define SUPPORT_FAST_READ_1S_1S_1S_CMD_Pos (1UL)          /* The position of the Support for Fast Read Command 1S-1S-1S 
                                                          * in the JEDEC 4-byte Address Instruction Table, DWORD 1 
                                                          */
#define SUPPORT_FAST_READ_1S_1S_1S_CMD_Msk (0x00000002UL) /* The mask of the Support for Fast Read Command 1S-1S-1S
                                                          * in the JEDEC 4-byte Address Instruction Table, DWORD 1
                                                          */
#define SUPPORT_FAST_READ_1S_1S_2S_CMD_Pos (2UL)          /* The position of the Support for Fast Read Command 1S-1S-2S 
                                                          * in the JEDEC 4-byte Address Instruction Table, DWORD 1 
                                                          */
#define SUPPORT_FAST_READ_1S_1S_2S_CMD_Msk (0x00000004UL) /* The mask of the Support for Fast Read Command 1S-1S-2S
                                                          * in the JEDEC 4-byte Address Instruction Table, DWORD 1
                                                          */
#define SUPPORT_FAST_READ_1S_2S_2S_CMD_Pos (3UL)          /* The position of the Support for Fast Read Command 1S-2S-2S 
                                                          * in the JEDEC 4-byte Address Instruction Table, DWORD 1 
                                                          */
#define SUPPORT_FAST_READ_1S_2S_2S_CMD_Msk (0x00000008UL) /* The mask of the Support for Fast Read Command 1S-2S-2S
                                                          * in the JEDEC 4-byte Address Instruction Table, DWORD 1
                                                          */                                                    
#define SUPPORT_FAST_READ_1S_1S_4S_CMD_Pos (4UL)          /* The position of the Support for Fast Read Command 1S-1S-4S 
                                                          * in the JEDEC 4-byte Address Instruction Table, DWORD 1 
                                                          */
#define SUPPORT_FAST_READ_1S_1S_4S_CMD_Msk (0x00000010UL) /* The mask of the Support for Fast Read Command 1S-1S-4S
                                                          * in the JEDEC 4-byte Address Instruction Table, DWORD 1
                                                          */
#define SUPPORT_FAST_READ_1S_4S_4S_CMD_Pos (5UL)          /* The position of the Support for Fast Read Command 1S-4S-4S 
                                                          * in the JEDEC 4-byte Address Instruction Table, DWORD 1 
                                                          */
#define SUPPORT_FAST_READ_1S_4S_4S_CMD_Msk (0x00000020UL) /* The mask of the Support for Fast Read Command 1S-4S-4S
                                                          * in the JEDEC 4-byte Address Instruction Table, DWORD 1
                                                          */                             
#define SUPPORT_PP_1S_1S_1S_CMD_Pos (6UL)              /* The position of the Support for Page Program Command 1S-1S-1S 
                                                        * in the JEDEC 4-byte Address Instruction Table, DWORD 1 
                                                        */                                                 
#define SUPPORT_PP_1S_1S_1S_CMD_Msk (0x00000040UL)     /* The mask of the Support for Page Program Command 1S-1S-1S
                                                        * in the JEDEC 4-byte Address Instruction Table, DWORD 1
                                                        */
#define SUPPORT_PP_1S_1S_4S_CMD_Pos (7UL)              /* The position of the Support for Page Program Command 1S-1S-4S 
                                                        * in the JEDEC 4-byte Address Instruction Table, DWORD 1 
                                                        */                                                        
#define SUPPORT_PP_1S_1S_4S_CMD_Msk (0x00000080UL)     /* The mask of the Support for Page Program Command 1S-1S-4S
                                                        * in the JEDEC 4-byte Address Instruction Table, DWORD 1
                                                        */
#define SUPPORT_PP_1S_4S_4S_CMD_Pos (8UL)              /* The position of the Support for Page Program Command 1S-4S-4S 
                                                        * in the JEDEC 4-byte Address Instruction Table, DWORD 1 
                                                        */                                                         
#define SUPPORT_PP_1S_4S_4S_CMD_Msk (0x00000100UL)     /* The mask of the Support for Page Program Command 1S-4S-4S
                                                        * in the JEDEC 4-byte Address Instruction Table, DWORD 1 
                                                        */                                               
#define FOUR_BYTE_ADDRESS_TABLE_BYTE_0 (0U)  /* Byte 0x00 of the JEDEC 4-byte Address Instruction Table */
#define FOUR_BYTE_ADDRESS_TABLE_BYTE_1 (1U)  /* Byte 0x01 of the JEDEC 4-byte Address Instruction Table */
#define ERASE_TYPE_COUNT               (4U)  /* The number of Erase Types  */

#define MEM_ADDR_VALID(addr, size) (0U == ((addr)%(size)))  /* This address must be a multiple of 
                                                             * the SMIF XIP memory size 
                                                             */
#define MEM_MAPPED_SIZE_VALID(size) (((size) >= 0x10000U) && (0U == ((size)&((size)-1U))) )
#define MEM_ADDR_SIZE_VALID(addrSize)  ((0U < (addrSize)) && ((addrSize) <= CY_SMIF_FOUR_BYTES_ADDR))


/***************************************
*     Internal enums
***************************************/
/** Specifies protocol mode. */
typedef enum
{
    PROTOCOL_MODE_1S_1S_1S        = 1U,     /**< One DQ signal used during command transfer,
                                             * address transfer, and data transfer. All phases are SDR.
                                             */
    PROTOCOL_MODE_1S_1S_2S        = 2U,     /**< One DQ signal used during command transfer, and address transfer,
                                             *  two DQ signals used during data transfer. All phases are SDR.
                                             */
    PROTOCOL_MODE_1S_2S_2S        = 3U,     /**< One DQ signal used during command transfer, two DQ signals used
                                             *  during address transfer, and data transfer. All phases are SDR.
                                             */
    PROTOCOL_MODE_1S_1S_4S        = 4U,     /**< One DQ signal used during command and address transfer, 
                                             * four DQ signals used during data transfer. All phases are SDR.
                                             */
    PROTOCOL_MODE_1S_4S_4S        = 5U,     /**< One DQ signal used during command transfer, four DQ signals used 
                                            * during address transfer, and data transfer. All phases are SDR.
                                            */
#if (CY_IP_MXSMIF_VERSION>=3)
    PROTOCOL_MODE_1S_4D_4D          = 6U,        /**< One DQ signal used during command transfer in single data rate,
                                        * four DQ signals used during address transfer and data transfer in
                                        * double data rate.
                                        */
#endif /* CY_IP_MXSMIF_VERSION */
    PROTOCOL_MODE_WRONG           = 0xFFU   /**< Unknown or unsupported mode */   
} cy_en_smif_protocol_mode_t;
/** \endcond */


/***************************************
*     Internal Structures
***************************************/

/**
* This internal structure is used to store data for erase types.
*/
typedef struct
{
    uint8_t eraseCmd;  /**< The instruction used for erase transaction */
    uint32_t eraseSize;    /**< The number of bytes to be erased at one erase transaction */
    uint32_t eraseTime;    /**< The maximum erase time for one erase transaction */
} cy_stc_smif_erase_type_t;


/***************************************
*     Internal Function Prototypes
***************************************/
static void XipRegInit(SMIF_DEVICE_Type volatile *dev,
                            cy_stc_smif_mem_config_t const * memCfg);
static cy_en_smif_status_t SfdpReadBuffer(SMIF_Type *base, 
                                         cy_stc_smif_mem_cmd_t const *cmdSfdp,
                                         uint8_t const sfdpAddress[],
                                         cy_en_smif_slave_select_t  slaveSelect,
                                         uint32_t size,
                                         uint8_t sfdpBuffer[],
                                         cy_stc_smif_context_t *context);
static uint32_t SfdpFindParameterHeader(uint32_t id, uint8_t const sfdpBuffer[]);
static cy_en_smif_status_t SfdpFindParameterTableAddress(uint32_t id,
                                                     uint8_t const sfdpBuffer[],
                                                     uint8_t address[],
                                                     uint32_t *tableLength);
static uint32_t SfdpGetNumOfAddrBytes(uint8_t const sfdpBuffer[]);
static uint32_t SfdpGetMemoryDensity(uint8_t const sfdpBuffer[]);
static void SfdpGetReadCmd_1_4_4(uint8_t const sfdpBuffer[], 
                             cy_stc_smif_mem_cmd_t* cmdRead);
static void SfdpGetReadCmd_1_1_4(uint8_t const sfdpBuffer[], 
                             cy_stc_smif_mem_cmd_t* cmdRead);
static void SfdpGetReadCmd_1_2_2(uint8_t const sfdpBuffer[], 
                             cy_stc_smif_mem_cmd_t* cmdRead);
static void SfdpGetReadCmd_1_1_2(uint8_t const sfdpBuffer[], 
                             cy_stc_smif_mem_cmd_t* cmdRead);
static void SfdpGetReadCmd_1_1_1(uint8_t const sfdpBuffer[], 
                             cy_stc_smif_mem_cmd_t* cmdRead);
static cy_en_smif_protocol_mode_t SfdpGetReadCmdParams(uint8_t const sfdpBuffer[], 
                                                       cy_en_smif_data_select_t dataSelect, 
                                                       cy_stc_smif_mem_cmd_t* cmdRead);
static void SfdpGetReadFourBytesCmd(uint8_t const sfdpBuffer[], 
                                    cy_en_smif_protocol_mode_t protocolMode, 
                                    cy_stc_smif_mem_cmd_t* cmdRead);                                
static uint32_t SfdpGetPageSize(uint8_t const sfdpBuffer[]);
static uint32_t SfdpGetEraseTime(uint32_t const eraseOffset, uint8_t const sfdpBuffer[], cy_stc_smif_erase_type_t eraseType[]);
static uint32_t SfdpGetChipEraseTime(uint8_t const sfdpBuffer[]);
static uint32_t SfdpGetPageProgramTime(uint8_t const sfdpBuffer[]);
static void SfdpSetWriteEnableCommand(cy_stc_smif_mem_cmd_t* cmdWriteEnable);
static void SfdpSetWriteDisableCommand(cy_stc_smif_mem_cmd_t* cmdWriteDisable);
static void SfdpSetProgramCommand_1_1_1(cy_stc_smif_mem_cmd_t* cmdProgram);
static void SfdpSetProgramCommandFourBytes_1_1_1(cy_stc_smif_mem_cmd_t* cmdProgram);
static void SfdpSetProgramCommandFourBytes_1_1_4(cy_stc_smif_mem_cmd_t* cmdProgram);
static void SfdpSetProgramCommandFourBytes_1_4_4(cy_stc_smif_mem_cmd_t* cmdProgram);
static void SfdpGetProgramFourBytesCmd(uint8_t const sfdpBuffer[], 
                                       cy_en_smif_protocol_mode_t protocolMode, 
                                       cy_stc_smif_mem_cmd_t* cmdProgram);
static void SfdpGetQuadEnableParameters(cy_stc_smif_mem_device_cfg_t *device, 
                                    uint8_t const sfdpBuffer[]);
static void SfdpSetChipEraseCommand(cy_stc_smif_mem_cmd_t* cmdChipErase);
static uint32_t SfdpGetSectorEraseCommand(cy_stc_smif_mem_device_cfg_t *device, 
                                          uint8_t const sfdpBuffer[],
                                          cy_stc_smif_erase_type_t eraseTypeStc[]);
static cy_en_smif_status_t ReadAnyReg(SMIF_Type *base, cy_en_smif_slave_select_t slaveSelect,
                                          uint8_t *value, uint8_t command, uint8_t const *address,
                                          uint32_t addressSize, cy_stc_smif_context_t const *context);
static cy_en_smif_status_t SfdpEnterFourByteAddressing(SMIF_Type *base, uint8_t entryMethodByte, 
                                                              cy_stc_smif_mem_device_cfg_t *device,
                                                              cy_en_smif_slave_select_t slaveSelect,
                                                              cy_stc_smif_context_t const *context);
static void SfdpGetEraseSizeAndCmd(uint8_t const sfdpBuffer[], cy_stc_smif_erase_type_t eraseType[]);
static cy_en_smif_status_t SfdpPopulateRegionInfo(SMIF_Type *base, uint8_t const sectorMapBuff[],
                                   uint32_t const buffLength, cy_stc_smif_mem_device_cfg_t *device,
                                    cy_en_smif_slave_select_t slaveSelect, const cy_stc_smif_context_t *context,
                                    cy_stc_smif_erase_type_t eraseType[]);
static void SfdpSetWipStatusRegisterCommand(cy_stc_smif_mem_cmd_t* readStsRegWipCmd);
static void ValueToByteArray(uint32_t value, uint8_t *byteArray, uint32_t startPos, uint32_t size);
static uint32_t ByteArrayToValue(uint8_t const *byteArray, uint32_t size);


/*******************************************************************************
* Function Name: Cy_SMIF_MemInit
****************************************************************************//**
*
* This function initializes the slots of the memory device in the SMIF
* configuration.
* This function must be called when a memory device is required to be used
* in memory-mapped (XIP) mode. This function can also be called instead of
* calling \ref Cy_SMIF_MemSfdpDetect when SFDP auto-discovery is enabled.
* Note that this function performs SFDP on all the external memories whereas
* \ref Cy_SMIF_MemSfdpDetect peforms it only on one memory that is specified
* through the arguments. This function configures the SMIF device slot registers
* with the configuration from \ref cy_stc_smif_mem_config_t structure which is 
* a member of the \ref cy_stc_smif_block_config_t structure. If SFDP discovery
* is enabled in the configuration strucutre through autoDetectSfdp field,
* this function calls \ref Cy_SMIF_MemSfdpDetect function for each memory,
* fills the structures with the discovered parameters, and configures the
* SMIF device slot registers accordingly. \ref Cy_SMIF_Init must have been 
* called prior to calling this funciton.
* The \ref cy_stc_smif_context_t context structure returned from \ref Cy_SMIF_Init
* is passed as a parameter to this function.
*
* \note 4-byte addressing mode is set when the memory device supports 
*       3- or 4-byte addressing mode.
*
* \param base
* The address of the slave-slot device register to initialize.
*
* \param blockConfig
* The configuration structure array that configures the SMIF memory device to be
* mapped into the PSoC memory map. \ref cy_stc_smif_mem_config_t
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return The memory slot initialization status.
*       - \ref CY_SMIF_SUCCESS
*       - \ref CY_SMIF_BAD_PARAM
*       - \ref CY_SMIF_SFDP_SS0_FAILED
*       - \ref CY_SMIF_SFDP_SS1_FAILED
*       - \ref CY_SMIF_SFDP_SS2_FAILED
*       - \ref CY_SMIF_SFDP_SS3_FAILED
*
*******************************************************************************/
cy_en_smif_status_t Cy_SMIF_MemInit(SMIF_Type *base,
                            cy_stc_smif_block_config_t const * blockConfig,
                            cy_stc_smif_context_t *context)
{
    SMIF_DEVICE_Type volatile * device;
    cy_stc_smif_mem_config_t const * memCfg;
    uint32_t result = (uint32_t)CY_SMIF_BAD_PARAM;
    uint32_t sfdpRes =(uint32_t)CY_SMIF_SUCCESS;
    uint32_t idx;

    if ((NULL != base) && (NULL != blockConfig) && (NULL != blockConfig->memConfig) 
        && (NULL != context) && (0U != blockConfig->memCount))
    {
        uint32_t size = blockConfig->memCount;
        cy_stc_smif_mem_config_t** extMemCfg = blockConfig->memConfig;

        result = (uint32_t)CY_SMIF_SUCCESS;
        for(idx = 0UL; idx < size; idx++)
        {
            memCfg = extMemCfg[idx];
            if (NULL != memCfg)
            {
                /* Check smif memory slot configuration */
                CY_ASSERT_L3(CY_SMIF_SLAVE_SEL_VALID(memCfg->slaveSelect));
                CY_ASSERT_L3(CY_SMIF_DATA_SEL_VALID(memCfg->dataSelect));
                CY_ASSERT_L1(NULL != memCfg->deviceCfg);
                
                device = Cy_SMIF_GetDeviceBySlot(base, memCfg->slaveSelect);
                if (NULL != device)
                {
                    /* The slave-slot initialization of the device control register.
                     * Cy_SMIF_MemSfdpDetect() must work */
                    SMIF_DEVICE_CTL(device)  = _CLR_SET_FLD32U(SMIF_DEVICE_CTL(device),
                                                               SMIF_DEVICE_CTL_DATA_SEL,
                                                              (uint32_t)memCfg->dataSelect);
                    uint32_t sfdpRet = (uint32_t)CY_SMIF_SUCCESS;
                    if (0U != (memCfg->flags & CY_SMIF_FLAG_DETECT_SFDP))
                    {
                        sfdpRet = (uint32_t)Cy_SMIF_MemSfdpDetect(base,
                                                memCfg->deviceCfg,
                                                memCfg->slaveSelect,
                                                memCfg->dataSelect,
                                                context);
                        if((uint32_t)CY_SMIF_SUCCESS != sfdpRet)
                        {
                            sfdpRes |=  ((uint32_t)CY_SMIF_SFDP_FAIL << idx);
                        }
                    }
                    /* Check the size of the smif memory slot address */
                    CY_ASSERT_L2(MEM_ADDR_SIZE_VALID(memCfg->deviceCfg->numOfAddrBytes));

                    if (((uint32_t)CY_SMIF_SUCCESS == sfdpRet) &&
                            (0U != (memCfg->flags & CY_SMIF_FLAG_MEMORY_MAPPED)))
                    {
                        /* Check valid parameters for XIP */
                        CY_ASSERT_L3(MEM_ADDR_VALID( memCfg->baseAddress, memCfg->memMappedSize));
                        CY_ASSERT_L3(MEM_MAPPED_SIZE_VALID( memCfg->memMappedSize));
                        
                        XipRegInit(device, memCfg);
                        
#if(CY_IP_MXSMIF_VERSION>=3)
                        context->preXIPDataRate = memCfg->deviceCfg->readCmd->dataRate;
#endif /* CY_IP_MXSMIF_VERSION */

                        /* The device control register initialization */
                        SMIF_DEVICE_CTL(device) = (memCfg->flags & CY_SMIF_FLAG_WRITE_ENABLE) |
                                      (memCfg->flags & CY_SMIF_FLAG_CRYPTO_ENABLE) |
                                      _VAL2FLD(SMIF_DEVICE_CTL_DATA_SEL,  (uint32_t)memCfg->dataSelect) |
                                      SMIF_DEVICE_CTL_ENABLED_Msk;
                    }
                }
                else
                {
                    result = (uint32_t)CY_SMIF_BAD_PARAM;
                    break;
                }
            }
        }
    }
    if((uint32_t)CY_SMIF_SUCCESS != sfdpRes)
    {
        result = CY_SMIF_ID | CY_PDL_STATUS_ERROR | sfdpRes;
    }
    return (cy_en_smif_status_t) result;
}


/*******************************************************************************
* Function Name: XipRegInit
****************************************************************************//**
*
* \internal
* This function initializes the memory device registers used for the XIP mode of
* the specified device.
*
* \param dev
* The SMIF memory device registers structure. \ref SMIF_DEVICE_Type
*
* \param memCfg
* The memory configuration structure that configures the SMIF memory device to
*  map into the PSoC memory map. \ref cy_stc_smif_mem_config_t
*
*******************************************************************************/
static void XipRegInit(SMIF_DEVICE_Type volatile *dev, cy_stc_smif_mem_config_t const * memCfg)
{
    cy_stc_smif_mem_device_cfg_t const * devCfg = memCfg->deviceCfg;
    cy_stc_smif_mem_cmd_t const * read = devCfg->readCmd;
    cy_stc_smif_mem_cmd_t const * prog = devCfg->programCmd;

    SMIF_DEVICE_ADDR(dev) = (SMIF_DEVICE_ADDR_ADDR_Msk & memCfg->baseAddress);

    /* Convert the size in the mask */
    SMIF_DEVICE_MASK(dev)= (SMIF_DEVICE_MASK_MASK_Msk & (~(memCfg->memMappedSize) + 1UL));

#if (CY_IP_MXSMIF_VERSION>=3)
    SMIF_DEVICE_ADDR_CTL(dev) = _VAL2FLD(SMIF_DEVICE_ADDR_CTL_SIZE3, (devCfg->numOfAddrBytes - 1UL)) |
                                ((0UL != memCfg->dualQuadSlots)? SMIF_DEVICE_ADDR_CTL_DIV2_Msk: 0UL);


    if(memCfg->flags & CY_SMIF_FLAG_SMIF_REV_3)
    {
        if(NULL != read)
        {
            SMIF_DEVICE_RD_CMD_CTL(dev) = (CY_SMIF_NO_COMMAND_OR_MODE != read->command) ?
                                        (_VAL2FLD(SMIF_DEVICE_RD_CMD_CTL_CODE,  (uint32_t)read->command)  |
                                        _VAL2FLD(SMIF_DEVICE_RD_CMD_CTL_CODEH,  (uint32_t)read->commandH)  |
                                        _VAL2FLD(SMIF_DEVICE_RD_CMD_CTL_DDR_MODE,  (uint32_t)read->cmdRate)  |
                                        _VAL2FLD(SMIF_DEVICE_RD_CMD_CTL_WIDTH, (uint32_t)read->cmdWidth) |
                                        _VAL2FLD(SMIF_DEVICE_RD_CMD_CTL_PRESENT2, (uint32_t)read->cmdPresence))
                                        : 0U;
            SMIF_DEVICE_RD_ADDR_CTL(dev) = _VAL2FLD(SMIF_DEVICE_RD_ADDR_CTL_WIDTH, (uint32_t)read->addrWidth) |
                                           _VAL2FLD(SMIF_DEVICE_RD_ADDR_CTL_DDR_MODE, (uint32_t)read->addrRate);

            SMIF_DEVICE_RD_MODE_CTL(dev) = (CY_SMIF_NO_COMMAND_OR_MODE != read->mode) ?
                                        (_VAL2FLD(SMIF_DEVICE_RD_MODE_CTL_CODE,  (uint32_t)read->mode)     |
                                            _VAL2FLD(SMIF_DEVICE_RD_MODE_CTL_CODEH, (uint32_t)read->modeH) |
                                            _VAL2FLD(SMIF_DEVICE_RD_MODE_CTL_WIDTH, (uint32_t)read->modeWidth) |
                                            _VAL2FLD(SMIF_DEVICE_RD_MODE_CTL_DDR_MODE, (uint32_t)read->modeRate) |
                                            _VAL2FLD(SMIF_DEVICE_RD_MODE_CTL_PRESENT2, read->modePresence))
                                        : 0U;

            SMIF_DEVICE_RD_DUMMY_CTL(dev) = (0UL != read->dummyCycles)?
                                            (_VAL2FLD(SMIF_DEVICE_RD_DUMMY_CTL_SIZE5, (read->dummyCycles - 1UL)) |
                                            _VAL2FLD(SMIF_DEVICE_RD_DUMMY_CTL_PRESENT2,read->dummyCyclesPresence))
                                            : 0U;

            SMIF_DEVICE_RD_DATA_CTL(dev) = _VAL2FLD(SMIF_DEVICE_RD_DATA_CTL_WIDTH, (uint32_t)read->dataWidth) |
                                           _VAL2FLD(SMIF_DEVICE_RD_DATA_CTL_DDR_MODE, (uint32_t)read->dataRate);
        }

        if(NULL != prog)
        {
            SMIF_DEVICE_WR_CMD_CTL(dev) = (CY_SMIF_NO_COMMAND_OR_MODE != prog->command) ?
                                        _VAL2FLD(SMIF_DEVICE_WR_CMD_CTL_CODE,  (uint32_t)prog->command) |
                                        _VAL2FLD(SMIF_DEVICE_WR_CMD_CTL_CODEH,  (uint32_t)prog->commandH) |
                                        _VAL2FLD(SMIF_DEVICE_WR_CMD_CTL_DDR_MODE,  (uint32_t)prog->cmdRate) |
                                        _VAL2FLD(SMIF_DEVICE_WR_CMD_CTL_WIDTH, (uint32_t)prog->cmdWidth) |
                                        _VAL2FLD(SMIF_DEVICE_WR_CMD_CTL_PRESENT2, prog->cmdPresence)
                                        : 0U;

            SMIF_DEVICE_WR_ADDR_CTL(dev) = _VAL2FLD(SMIF_DEVICE_WR_ADDR_CTL_WIDTH, (uint32_t)prog->addrWidth) |
                                                          _VAL2FLD(SMIF_DEVICE_WR_ADDR_CTL_DDR_MODE, (uint32_t)prog->addrRate);

            SMIF_DEVICE_WR_MODE_CTL(dev) = (CY_SMIF_NO_COMMAND_OR_MODE != prog->mode) ?
                                            _VAL2FLD(SMIF_DEVICE_WR_MODE_CTL_CODE,  (uint32_t)prog->mode)     |
                                            _VAL2FLD(SMIF_DEVICE_WR_MODE_CTL_CODEH,  (uint32_t)prog->modeH)     |
                                            _VAL2FLD(SMIF_DEVICE_WR_MODE_CTL_WIDTH, (uint32_t)prog->modeWidth) |
                                            _VAL2FLD(SMIF_DEVICE_WR_MODE_CTL_DDR_MODE, (uint32_t)prog->modeRate) |
                                            _VAL2FLD(SMIF_DEVICE_WR_MODE_CTL_PRESENT2, prog->modePresence)
                                            : 0UL;

            SMIF_DEVICE_WR_DUMMY_CTL(dev) = (0UL != prog->dummyCycles) ?
                                            (_VAL2FLD(SMIF_DEVICE_WR_DUMMY_CTL_SIZE5, (prog->dummyCycles - 1UL)) |
                                            (_VAL2FLD(SMIF_DEVICE_WR_DUMMY_CTL_PRESENT2, prog->dummyCyclesPresence)))
                                            : 0U;

            SMIF_DEVICE_WR_DATA_CTL(dev) = _VAL2FLD(SMIF_DEVICE_WR_DATA_CTL_WIDTH, (uint32_t)prog->dataWidth) |
                                                          _VAL2FLD(SMIF_DEVICE_WR_DATA_CTL_WIDTH, (uint32_t)prog->dataRate);
        }
    }
    else
    {
        if(NULL != read)
        {
            SMIF_DEVICE_RD_CMD_CTL(dev) = (CY_SMIF_NO_COMMAND_OR_MODE != read->command) ?
                                        (_VAL2FLD(SMIF_DEVICE_RD_CMD_CTL_CODE,  (uint32_t)read->command)  |
                                        _VAL2FLD(SMIF_DEVICE_RD_CMD_CTL_WIDTH, (uint32_t)read->cmdWidth) |
                                        _VAL2FLD(SMIF_DEVICE_RD_CMD_CTL_PRESENT2, 1UL))
                                        : 0U;

            SMIF_DEVICE_RD_ADDR_CTL(dev) = _VAL2FLD(SMIF_DEVICE_RD_ADDR_CTL_WIDTH, (uint32_t)read->addrWidth);

            SMIF_DEVICE_RD_MODE_CTL(dev) = (CY_SMIF_NO_COMMAND_OR_MODE != read->mode) ?
                                        (_VAL2FLD(SMIF_DEVICE_RD_MODE_CTL_CODE,  (uint32_t)read->mode)     |
                                            _VAL2FLD(SMIF_DEVICE_RD_MODE_CTL_WIDTH, (uint32_t)read->modeWidth)|
                                            _VAL2FLD(SMIF_DEVICE_RD_MODE_CTL_PRESENT2, 1UL))
                                        : 0U;

            SMIF_DEVICE_RD_DUMMY_CTL(dev) = (0UL != read->dummyCycles)?
                                            (_VAL2FLD(SMIF_DEVICE_RD_DUMMY_CTL_SIZE5, (read->dummyCycles - 1UL)) |
                                            _VAL2FLD(SMIF_DEVICE_RD_DUMMY_CTL_PRESENT2, 1UL))
                                            : 0U;

            SMIF_DEVICE_RD_DATA_CTL(dev) = _VAL2FLD(SMIF_DEVICE_RD_DATA_CTL_WIDTH, (uint32_t)read->dataWidth);
        }

        if(NULL != prog)
        {
            SMIF_DEVICE_WR_CMD_CTL(dev) = (CY_SMIF_NO_COMMAND_OR_MODE != prog->command) ?
                                        (_VAL2FLD(SMIF_DEVICE_WR_CMD_CTL_CODE,  (uint32_t)prog->command) |
                                        _VAL2FLD(SMIF_DEVICE_WR_CMD_CTL_WIDTH, (uint32_t)prog->cmdWidth)|
                                        _VAL2FLD(SMIF_DEVICE_WR_CMD_CTL_PRESENT2, 1UL))
                                        : 0U;

            SMIF_DEVICE_WR_ADDR_CTL(dev) = _VAL2FLD(SMIF_DEVICE_WR_ADDR_CTL_WIDTH, (uint32_t)prog->addrWidth);

            SMIF_DEVICE_WR_MODE_CTL(dev) = (CY_SMIF_NO_COMMAND_OR_MODE != prog->mode) ?
                                            (_VAL2FLD(SMIF_DEVICE_WR_MODE_CTL_CODE,  (uint32_t)prog->mode)     |
                                            _VAL2FLD(SMIF_DEVICE_WR_MODE_CTL_WIDTH, (uint32_t)prog->modeWidth)|
                                            _VAL2FLD(SMIF_DEVICE_WR_MODE_CTL_PRESENT2, 1UL))
                                            : 0UL;

            SMIF_DEVICE_WR_DUMMY_CTL(dev) = (0UL != prog->dummyCycles) ?
                                            (_VAL2FLD(SMIF_DEVICE_WR_DUMMY_CTL_SIZE5, (prog->dummyCycles - 1UL)) |
                                            (_VAL2FLD(SMIF_DEVICE_WR_DUMMY_CTL_PRESENT2, 1UL)))
                                            : 0U;

            SMIF_DEVICE_WR_DATA_CTL(dev) = _VAL2FLD(SMIF_DEVICE_WR_DATA_CTL_WIDTH, (uint32_t)prog->dataWidth);
        }
    }
#else
    SMIF_DEVICE_ADDR_CTL(dev) = _VAL2FLD(SMIF_DEVICE_ADDR_CTL_SIZE2, (devCfg->numOfAddrBytes - 1UL)) |
                                ((0UL != memCfg->dualQuadSlots)? SMIF_DEVICE_ADDR_CTL_DIV2_Msk: 0UL);

    if(NULL != read)
    {
        SMIF_DEVICE_RD_CMD_CTL(dev) = (CY_SMIF_NO_COMMAND_OR_MODE != read->command) ?
                                    (_VAL2FLD(SMIF_DEVICE_RD_CMD_CTL_CODE,  (uint32_t)read->command)  |
                                    _VAL2FLD(SMIF_DEVICE_RD_CMD_CTL_WIDTH, (uint32_t)read->cmdWidth) |
                                    SMIF_DEVICE_RD_CMD_CTL_PRESENT_Msk)
                                    : 0U;

        SMIF_DEVICE_RD_ADDR_CTL(dev) = _VAL2FLD(SMIF_DEVICE_RD_ADDR_CTL_WIDTH, (uint32_t)read->addrWidth);

        SMIF_DEVICE_RD_MODE_CTL(dev) = (CY_SMIF_NO_COMMAND_OR_MODE != read->mode) ?
                                    (_VAL2FLD(SMIF_DEVICE_RD_CMD_CTL_CODE,  (uint32_t)read->mode)     |
                                        _VAL2FLD(SMIF_DEVICE_RD_CMD_CTL_WIDTH, (uint32_t)read->modeWidth)|
                                        SMIF_DEVICE_RD_CMD_CTL_PRESENT_Msk)
                                    : 0U;

        SMIF_DEVICE_RD_DUMMY_CTL(dev) = (0UL != read->dummyCycles)?
                                        (_VAL2FLD(SMIF_DEVICE_RD_DUMMY_CTL_SIZE5, (read->dummyCycles - 1UL)) |
                                        SMIF_DEVICE_RD_DUMMY_CTL_PRESENT_Msk)
                                        : 0U;

        SMIF_DEVICE_RD_DATA_CTL(dev) = _VAL2FLD(SMIF_DEVICE_RD_DATA_CTL_WIDTH, (uint32_t)read->dataWidth);
    }

    if(NULL != prog)
    {
        SMIF_DEVICE_WR_CMD_CTL(dev) = (CY_SMIF_NO_COMMAND_OR_MODE != prog->command) ?
                                    (_VAL2FLD(SMIF_DEVICE_WR_CMD_CTL_CODE,  (uint32_t)prog->command) |
                                    _VAL2FLD(SMIF_DEVICE_WR_CMD_CTL_WIDTH, (uint32_t)prog->cmdWidth)|
                                    SMIF_DEVICE_WR_CMD_CTL_PRESENT_Msk)
                                    : 0U;

        SMIF_DEVICE_WR_ADDR_CTL(dev) = _VAL2FLD(SMIF_DEVICE_WR_ADDR_CTL_WIDTH, (uint32_t)prog->addrWidth);

        SMIF_DEVICE_WR_MODE_CTL(dev) = (CY_SMIF_NO_COMMAND_OR_MODE != prog->mode) ?
                                        (_VAL2FLD(SMIF_DEVICE_WR_CMD_CTL_CODE,  (uint32_t)prog->mode)     |
                                        _VAL2FLD(SMIF_DEVICE_WR_CMD_CTL_WIDTH, (uint32_t)prog->modeWidth)|
                                        SMIF_DEVICE_WR_CMD_CTL_PRESENT_Msk)
                                        : 0UL;

        SMIF_DEVICE_WR_DUMMY_CTL(dev) = (0UL != prog->dummyCycles) ?
                                        (_VAL2FLD(SMIF_DEVICE_WR_DUMMY_CTL_SIZE5, (prog->dummyCycles - 1UL)) |
                                        SMIF_DEVICE_WR_DUMMY_CTL_PRESENT_Msk)
                                        : 0U;

        SMIF_DEVICE_WR_DATA_CTL(dev) = _VAL2FLD(SMIF_DEVICE_WR_DATA_CTL_WIDTH, (uint32_t)prog->dataWidth);
    }
#endif /* CY_IP_MXSMIF_VERSION */
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemDeInit
****************************************************************************//**
*
* This function de-initializes all slave slots of the memory device to their default
* values.
*
* \param base
* Holds the base address of the SMIF block registers.
*
*******************************************************************************/
void Cy_SMIF_MemDeInit(SMIF_Type *base)
{
    /* Configure the SMIF device slots to the default values. The default value is 0 */
    uint32_t deviceIndex;

    for(deviceIndex = 0UL; deviceIndex < (uint32_t)SMIF_DEVICE_NR; deviceIndex++)
    {
        SMIF_DEVICE_IDX_CTL(base, deviceIndex)           = 0U;
        SMIF_DEVICE_IDX_ADDR(base, deviceIndex)          = 0U;
        SMIF_DEVICE_IDX_MASK(base, deviceIndex)          = 0U;
        SMIF_DEVICE_IDX_ADDR_CTL(base, deviceIndex)      = 0U;
        SMIF_DEVICE_IDX_RD_CMD_CTL(base, deviceIndex)    = 0U;
        SMIF_DEVICE_IDX_RD_ADDR_CTL(base, deviceIndex)   = 0U;
        SMIF_DEVICE_IDX_RD_MODE_CTL(base, deviceIndex)   = 0U;
        SMIF_DEVICE_IDX_RD_DUMMY_CTL(base, deviceIndex)  = 0U;
        SMIF_DEVICE_IDX_RD_DATA_CTL(base, deviceIndex)   = 0U;
        SMIF_DEVICE_IDX_WR_CMD_CTL(base, deviceIndex)    = 0U;
        SMIF_DEVICE_IDX_WR_ADDR_CTL(base, deviceIndex)   = 0U;
        SMIF_DEVICE_IDX_WR_MODE_CTL(base, deviceIndex)   = 0U;
        SMIF_DEVICE_IDX_WR_DUMMY_CTL(base, deviceIndex)  = 0U;
        SMIF_DEVICE_IDX_WR_DATA_CTL(base, deviceIndex)   = 0U;
    }
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemCmdWriteEnable
****************************************************************************//**
*
* This function sends the Write Enable command to the memory device.
*
* \note This function uses the low-level Cy_SMIF_TransmitCommand() API.
* The Cy_SMIF_TransmitCommand() API works in a blocking mode. In the dual quad mode,
* this API is called for each memory.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param memDevice
* The device to which the command is sent.
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return A status of the command transmission.
*       - \ref CY_SMIF_SUCCESS
*       - \ref CY_SMIF_EXCEED_TIMEOUT
*       - \ref CY_SMIF_CMD_NOT_FOUND
*
*******************************************************************************/
cy_en_smif_status_t Cy_SMIF_MemCmdWriteEnable(SMIF_Type *base,
                                        cy_stc_smif_mem_config_t const *memDevice,
                                        cy_stc_smif_context_t const *context)
{
    /* The memory Write Enable */
    cy_stc_smif_mem_cmd_t* writeEn = memDevice->deviceCfg->writeEnCmd;
    
    cy_en_smif_status_t result = CY_SMIF_CMD_NOT_FOUND;
    
    if(NULL != writeEn)
    {
        result = Cy_SMIF_TransmitCommand( base, (uint8_t) writeEn->command,
                                        writeEn->cmdWidth,
                                        NULL,
                                        CY_SMIF_CMD_WITHOUT_PARAM,
                                        CY_SMIF_WIDTH_NA,
                                        memDevice->slaveSelect,
                                        CY_SMIF_TX_LAST_BYTE,
                                        context);
    }

    return result;
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemCmdWriteDisable
****************************************************************************//**
*
* This function sends a Write Disable command to the memory device.
*
* \note This function uses the low-level Cy_SMIF_TransmitCommand() API.
* Cy_SMIF_TransmitCommand() API works in a blocking mode. In the dual quad mode
* this API should be called for each memory.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param memDevice
* The device to which the command is sent.
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return A status of the command transmission.
*       - \ref CY_SMIF_SUCCESS
*       - \ref CY_SMIF_EXCEED_TIMEOUT
*       - \ref CY_SMIF_CMD_NOT_FOUND
*
*******************************************************************************/
cy_en_smif_status_t Cy_SMIF_MemCmdWriteDisable(SMIF_Type *base,
                                    cy_stc_smif_mem_config_t const *memDevice,
                                    cy_stc_smif_context_t const *context)
{
    cy_stc_smif_mem_cmd_t* writeDis = memDevice->deviceCfg->writeDisCmd;

    cy_en_smif_status_t result = CY_SMIF_CMD_NOT_FOUND;
    
    if(NULL != writeDis)
    {
        /* The memory write disable */
        result = Cy_SMIF_TransmitCommand( base, (uint8_t)writeDis->command,
                                          writeDis->cmdWidth,
                                          NULL,
                                          CY_SMIF_CMD_WITHOUT_PARAM,
                                          CY_SMIF_WIDTH_NA,
                                          memDevice->slaveSelect,
                                          CY_SMIF_TX_LAST_BYTE,
                                          context);
    }
    
    return result;
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemIsBusy
****************************************************************************//**
*
* This function checks if the status of the memory device is busy.
* This is done by reading the status register and the corresponding bit
* (stsRegBusyMask). This function is a blocking function until the status
* register from the memory is read.
*
* \note In the dual quad mode, this API is called for each memory.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param memDevice
*  The device to which the command is sent.
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return A status of the memory device.
*       - True - The device is busy or a timeout occurs.
*       - False - The device is not busy.
*
* \note Check \ref group_smif_usage_rules for any usage restriction 
*
*******************************************************************************/
bool Cy_SMIF_MemIsBusy(SMIF_Type *base, cy_stc_smif_mem_config_t const *memDevice,
                            cy_stc_smif_context_t const *context)
{
    uint8_t  status = 1U;
    cy_en_smif_status_t readStsResult = CY_SMIF_CMD_NOT_FOUND;
    cy_stc_smif_mem_device_cfg_t* device =  memDevice->deviceCfg;

    if(NULL != device->readStsRegWipCmd)
    {
        readStsResult = Cy_SMIF_MemCmdReadStatus(base, memDevice, &status,
                            (uint8_t)device->readStsRegWipCmd->command,
                            context);
    }  

    if (CY_SMIF_SUCCESS == readStsResult)
    {
        /* Masked not busy bits in returned status */
        status &= (uint8_t)device->stsRegBusyMask;
    }

    return (0U != status);
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemQuadEnable
****************************************************************************//**
*
* This function enables the memory device for the quad mode of operation.
* This command must be executed before sending quad SPI commands to the
* memory device.
*
* \note In the dual quad mode, this API is called for each memory.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param memDevice
* The device to which the command is sent.
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return A status of the command.
*   - \ref CY_SMIF_SUCCESS
*   - \ref CY_SMIF_NO_QE_BIT
*   - \ref CY_SMIF_CMD_FIFO_FULL
*   - \ref CY_SMIF_BAD_PARAM
*   - \ref CY_SMIF_CMD_NOT_FOUND
*
* \note Check \ref group_smif_usage_rules for any usage restriction 
*
*******************************************************************************/
cy_en_smif_status_t Cy_SMIF_MemQuadEnable(SMIF_Type *base,
                                    cy_stc_smif_mem_config_t const *memDevice,
                                    cy_stc_smif_context_t const *context)
{
    cy_en_smif_status_t result= CY_SMIF_CMD_NOT_FOUND;
    uint8_t statusReg[CY_SMIF_QE_BIT_STATUS_REG2_T1] = {0U};  
    cy_stc_smif_mem_device_cfg_t* device =  memDevice->deviceCfg;

    /* Check that command exists */
    if((NULL != device->readStsRegQeCmd)  &&
       (NULL != device->writeStsRegQeCmd) &&
       (NULL != device->readStsRegWipCmd))
    {
        uint8_t readQeCmd  = (uint8_t)device->readStsRegQeCmd->command;
        uint8_t writeQeCmd = (uint8_t)device->writeStsRegQeCmd->command;
        uint8_t readWipCmd = (uint8_t)device->readStsRegWipCmd->command;

        result = Cy_SMIF_MemCmdReadStatus(base, memDevice, &statusReg[0U],
                    readQeCmd, context);
        if (CY_SMIF_SUCCESS == result)
        {
            uint32_t qeMask = device->stsRegQuadEnableMask;

            switch(qeMask)
            {
                case CY_SMIF_SFDP_QE_BIT_6_OF_SR_1:
                    statusReg[0U] |= (uint8_t)qeMask;
                    result = Cy_SMIF_MemCmdWriteStatus(base, memDevice,
                                &statusReg[0U], writeQeCmd, context);
                    break;
                case CY_SMIF_SFDP_QE_BIT_1_OF_SR_2:
                    /* Read status register 1 with the assumption that WIP is always in
                    * status register 1 */
                    result = Cy_SMIF_MemCmdReadStatus(base, memDevice,
                                &statusReg[0U], readWipCmd, context);
                    if (CY_SMIF_SUCCESS == result)
                    {
                        result = Cy_SMIF_MemCmdReadStatus(base, memDevice,
                                    &statusReg[1U], readQeCmd, context);
                        if (CY_SMIF_SUCCESS == result)
                        {
                            statusReg[1U] |= (uint8_t)qeMask;
                            result = Cy_SMIF_MemCmdWriteStatus(base, memDevice,
                                        statusReg, writeQeCmd, context);
                        }
                    }
                    break;
                case CY_SMIF_SFDP_QE_BIT_7_OF_SR_2:
                    result = Cy_SMIF_MemCmdReadStatus(base, memDevice,
                                &statusReg[1U], readQeCmd, context);
                    if (CY_SMIF_SUCCESS == result)
                    {
                        statusReg[1U] |= (uint8_t)qeMask;
                        result = Cy_SMIF_MemCmdWriteStatus(base, memDevice,
                                    &statusReg[1U], writeQeCmd, context);
                    }
                    break;
                default:
                    result = CY_SMIF_NO_QE_BIT;
                    break;
            }
        }
    }
    return(result);
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemCmdReadStatus
****************************************************************************//**
*
* This function reads the status register. This function is a blocking function,
* it will block the execution flow until the status register is read.
*
* \note This function uses the low-level Cy_SMIF_TransmitCommand() API.
* the Cy_SMIF_TransmitCommand() API works in a blocking mode. In the dual quad mode,
* this API is called for each memory.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param memDevice
* The device to which the command is sent.
*
* \param status
* The status register value returned by the external memory.
*
* \param command
* The command required to read the status/configuration register.
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return A status of the command reception.
*       - \ref CY_SMIF_SUCCESS
*       - \ref CY_SMIF_CMD_FIFO_FULL
*       - \ref CY_SMIF_EXCEED_TIMEOUT
*       - \ref CY_SMIF_CMD_NOT_FOUND
*
* \note Check \ref group_smif_usage_rules for any usage restriction 
*
*******************************************************************************/
cy_en_smif_status_t Cy_SMIF_MemCmdReadStatus(SMIF_Type *base,
                                    cy_stc_smif_mem_config_t const *memDevice,
                                    uint8_t *status,
                                    uint8_t command,
                                    cy_stc_smif_context_t const *context)
{
    cy_en_smif_status_t result = CY_SMIF_CMD_NOT_FOUND;

    /* Read the memory status register */
    result = Cy_SMIF_TransmitCommand( base, command, CY_SMIF_WIDTH_SINGLE,
                NULL, CY_SMIF_CMD_WITHOUT_PARAM,
                CY_SMIF_WIDTH_NA, memDevice->slaveSelect, 
                CY_SMIF_TX_NOT_LAST_BYTE, context);

    if (CY_SMIF_SUCCESS == result)
    {
        result = Cy_SMIF_ReceiveDataBlocking( base, status,
                    CY_SMIF_READ_ONE_BYTE, CY_SMIF_WIDTH_SINGLE, context);
    }

    return(result);
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemCmdWriteStatus
****************************************************************************//**
*
* This function writes the status register. This is a blocking function, it will
* block the execution flow until the command transmission is completed.
*
* \note This function uses the low-level Cy_SMIF_TransmitCommand() API.
* The Cy_SMIF_TransmitCommand() API works in a blocking mode. In the dual quad mode,
* this API is called for each memory.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param memDevice
* The device to which the command is sent.
*
* \param status
* The status to write into the status register.
*
* \param command
* The command to write into the status/configuration register.
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return A status of the command transmission.
*       - \ref CY_SMIF_SUCCESS
*       - \ref CY_SMIF_EXCEED_TIMEOUT
*       - \ref CY_SMIF_CMD_NOT_FOUND
*
*******************************************************************************/
cy_en_smif_status_t Cy_SMIF_MemCmdWriteStatus(SMIF_Type *base,
                                    cy_stc_smif_mem_config_t const *memDevice,
                                    void const *status,
                                    uint8_t command,
                                    cy_stc_smif_context_t const *context)
{
    cy_en_smif_status_t result;

    /* The Write Enable */
    result =  Cy_SMIF_MemCmdWriteEnable(base, memDevice, context);

    /* The Write Status */
    if (CY_SMIF_SUCCESS == result)
    {
        uint32_t size;
        uint32_t qeMask = memDevice->deviceCfg->stsRegQuadEnableMask;

        size = ( CY_SMIF_SFDP_QE_BIT_1_OF_SR_2 == qeMask)? CY_SMIF_WRITE_TWO_BYTES:
                                                        CY_SMIF_WRITE_ONE_BYTE;
        result = Cy_SMIF_TransmitCommand( base, command, CY_SMIF_WIDTH_SINGLE,
                    (uint8_t const *)status, size, CY_SMIF_WIDTH_SINGLE,
                    memDevice->slaveSelect, CY_SMIF_TX_LAST_BYTE, context);
    }

    return(result);
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemCmdChipErase
****************************************************************************//**
*
* This function performs a chip erase of the external memory. The Write Enable
* command is called before this API.
*
* \note This function uses the low-level Cy_SMIF_TransmitCommand() API.
* Cy_SMIF_TransmitCommand() API works in a blocking mode. In the dual quad mode,
* this API is called for each memory.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param memDevice
* The device to which the command is sent
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return A status of the command transmission.
*       - \ref CY_SMIF_SUCCESS
*       - \ref CY_SMIF_EXCEED_TIMEOUT
*       - \ref CY_SMIF_CMD_NOT_FOUND
*
*******************************************************************************/
cy_en_smif_status_t Cy_SMIF_MemCmdChipErase(SMIF_Type *base,
                cy_stc_smif_mem_config_t const *memDevice,
                cy_stc_smif_context_t const *context)
{
    cy_en_smif_status_t result= CY_SMIF_CMD_NOT_FOUND;

    cy_stc_smif_mem_cmd_t *cmdErase = memDevice->deviceCfg->chipEraseCmd;
    if(NULL != cmdErase)
    {
        result = Cy_SMIF_TransmitCommand( base, (uint8_t)cmdErase->command,
                cmdErase->cmdWidth, NULL,
                CY_SMIF_CMD_WITHOUT_PARAM, CY_SMIF_WIDTH_NA,
                memDevice->slaveSelect, CY_SMIF_TX_LAST_BYTE, context);
    }

    return(result);
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemCmdSectorErase
****************************************************************************//**
*
* This function performs a block Erase of the external memory. The Write Enable
* command is called before this API.
*
* \note This function uses the low-level Cy_SMIF_TransmitCommand() API.
* The Cy_SMIF_TransmitCommand() API works in a blocking mode. In the dual quad mode,
* this API is called for each memory.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param memDevice
* The device to which the command is sent.
*
* \param sectorAddr
* The sector address to erase.
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return A status of the command transmission.
*       - \ref CY_SMIF_SUCCESS
*       - \ref CY_SMIF_BAD_PARAM
*       - \ref CY_SMIF_EXCEED_TIMEOUT
*       - \ref CY_SMIF_CMD_NOT_FOUND
*
*******************************************************************************/
cy_en_smif_status_t Cy_SMIF_MemCmdSectorErase(SMIF_Type *base,
                                        cy_stc_smif_mem_config_t const *memDevice,
                                        uint8_t const *sectorAddr,
                                        cy_stc_smif_context_t const *context)
{
    cy_en_smif_status_t result = CY_SMIF_BAD_PARAM;

    CY_ASSERT_L1(NULL != memDevice);

    if (NULL != sectorAddr)
    {
        cy_stc_smif_mem_device_cfg_t *device = memDevice->deviceCfg;
        cy_stc_smif_mem_cmd_t *cmdErase = device->eraseCmd;
        cy_stc_smif_hybrid_region_info_t* hybrInfo = NULL;

        result = Cy_SMIF_MemLocateHybridRegion(memDevice, &hybrInfo,
                ByteArrayToValue(sectorAddr, device->numOfAddrBytes));

        if ((NULL != cmdErase) && (CY_SMIF_WIDTH_NA != cmdErase->cmdWidth) && (result != CY_SMIF_BAD_PARAM))
        {
            uint8_t eraseCommand = (uint8_t)((result == CY_SMIF_SUCCESS) ? (hybrInfo->eraseCmd) : (cmdErase->command));
            result = Cy_SMIF_TransmitCommand( base, eraseCommand,
                    cmdErase->cmdWidth, sectorAddr, device->numOfAddrBytes,
                    cmdErase->cmdWidth, memDevice->slaveSelect,
                    CY_SMIF_TX_LAST_BYTE, context);
        }
        else
        {
            result = CY_SMIF_CMD_NOT_FOUND;
        }
    }
    return(result);
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemCmdProgram
****************************************************************************//**
*
* This function performs the Program operation. 
*
* \note This function uses the  Cy_SMIF_TransmitCommand() API.
* The Cy_SMIF_TransmitCommand() API works in the blocking mode. In the dual quad mode,
* this API works with both types of memory simultaneously.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param memDevice
* The device to which the command is sent.
*
* \param addr
* The address to program.
*
* \param writeBuff
* The pointer to the data to program. If this pointer is a NULL, then the
* function does not enable the interrupt. This use case is  typically used when
* the FIFO is handled outside the interrupt and is managed in either a 
* polling-based code or a DMA. The user would handle the FIFO management 
* in a DMA or a polling-based code. 
* If the user provides a NULL pointer in this function and does not handle 
* the FIFO transaction, this could either stall or timeout the operation 
* \ref Cy_SMIF_TransmitData().
*
* \param size
* The size of data to program. The user must ensure that the data size
* does not exceed the page size.
*
* \param cmdCompleteCb
* The callback function to call after the transfer completion. NULL interpreted
* as no callback.
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return A status of a transmission.
*       - \ref CY_SMIF_SUCCESS
*       - \ref CY_SMIF_CMD_FIFO_FULL
*       - \ref CY_SMIF_BAD_PARAM
*       - \ref CY_SMIF_EXCEED_TIMEOUT
*       - \ref CY_SMIF_CMD_NOT_FOUND
*
*******************************************************************************/
cy_en_smif_status_t Cy_SMIF_MemCmdProgram(SMIF_Type *base,
                                    cy_stc_smif_mem_config_t const *memDevice,
                                    uint8_t const *addr,
                                    uint8_t const *writeBuff,
                                    uint32_t size,
                                    cy_smif_event_cb_t cmdCompleteCb,
                                    cy_stc_smif_context_t *context)
{
    cy_en_smif_status_t result = CY_SMIF_SUCCESS;
    cy_en_smif_slave_select_t slaveSelected;

    cy_stc_smif_mem_device_cfg_t *device = memDevice->deviceCfg;
    cy_stc_smif_mem_cmd_t *cmdProg = device->programCmd;
    
    if(NULL == cmdProg)
    {
        result = CY_SMIF_CMD_NOT_FOUND;
    }
    else if ((NULL == addr) || (size > device->programSize))
    {
        result = CY_SMIF_BAD_PARAM;
    }
    else
    {
        slaveSelected = (0U == memDevice->dualQuadSlots)?  memDevice->slaveSelect :
                                                        (cy_en_smif_slave_select_t)memDevice->dualQuadSlots;
                                                      
        /* The page program command */
        result = Cy_SMIF_TransmitCommand( base, (uint8_t)cmdProg->command,
                cmdProg->cmdWidth, addr, device->numOfAddrBytes,
                cmdProg->addrWidth, slaveSelected, CY_SMIF_TX_NOT_LAST_BYTE,
                context);

        if((CY_SMIF_SUCCESS == result) && (CY_SMIF_NO_COMMAND_OR_MODE != cmdProg->mode))
        {
            result = Cy_SMIF_TransmitCommand(base, (uint8_t)cmdProg->mode,
                        cmdProg->modeWidth, NULL,
                        CY_SMIF_CMD_WITHOUT_PARAM, CY_SMIF_WIDTH_NA,
                        (cy_en_smif_slave_select_t)slaveSelected,
                        CY_SMIF_TX_NOT_LAST_BYTE, context);
        }

        if((CY_SMIF_SUCCESS == result) && (cmdProg->dummyCycles > 0U))
        {
            result = Cy_SMIF_SendDummyCycles(base, cmdProg->dummyCycles);
        }

        if(CY_SMIF_SUCCESS == result)
        {
            result = Cy_SMIF_TransmitData( base, writeBuff, size,
                    cmdProg->dataWidth, cmdCompleteCb, context);
        }
    }

    return(result);
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemCmdRead
****************************************************************************//**
*
* This function performs the Read operation.
*
* \note This function uses the Cy_SMIF_TransmitCommand() API.
* The Cy_SMIF_TransmitCommand() API works in the blocking mode. In the dual quad mode,
* this API works with both types of memory simultaneously.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param memDevice
* The device to which the command is sent.
*
* \param addr
* The address to read.
*
* \param readBuff
* The pointer to the variable where the read data is stored. If this pointer is 
* a NULL, then the function does not enable the interrupt. This use case is 
* typically used when the FIFO is handled outside the interrupt and is managed
* in either a  polling-based code or a DMA. The user would handle the FIFO
* management in a DMA or a polling-based code. 
* If the user provides a NULL pointer in this function and does not handle 
* the FIFO transaction, this could either stall or timeout the operation 
* \ref Cy_SMIF_TransmitData().
*
* \param size
* The size of data to read.
*
* \param cmdCompleteCb
* The callback function to call after the transfer completion. NULL interpreted
* as no callback.
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return A status of the transmission.
*       - \ref CY_SMIF_SUCCESS
*       - \ref CY_SMIF_CMD_FIFO_FULL
*       - \ref CY_SMIF_BAD_PARAM
*       - \ref CY_SMIF_EXCEED_TIMEOUT
*       - \ref CY_SMIF_CMD_NOT_FOUND
*
* \note Check \ref group_smif_usage_rules for any usage restriction 
*
*******************************************************************************/
cy_en_smif_status_t Cy_SMIF_MemCmdRead(SMIF_Type *base,
                                cy_stc_smif_mem_config_t const *memDevice,
                                uint8_t const *addr,
                                uint8_t* readBuff,
                                uint32_t size,
                                cy_smif_event_cb_t cmdCompleteCb,
                                cy_stc_smif_context_t *context)
{
    cy_en_smif_status_t result = CY_SMIF_BAD_PARAM;
    cy_en_smif_slave_select_t slaveSelected;
    cy_stc_smif_mem_device_cfg_t *device = memDevice->deviceCfg;
    cy_stc_smif_mem_cmd_t *cmdRead = device->readCmd;

    if(NULL == cmdRead)
    {
        result = CY_SMIF_CMD_NOT_FOUND;
    }
    else if(NULL == addr)
    {
        result = CY_SMIF_BAD_PARAM;
    }
    else
    {
        slaveSelected = (0U == memDevice->dualQuadSlots)?  memDevice->slaveSelect :
                               (cy_en_smif_slave_select_t)memDevice->dualQuadSlots;
                               
        result = Cy_SMIF_TransmitCommand( base, (uint8_t)cmdRead->command,
                    cmdRead->cmdWidth, addr, device->numOfAddrBytes,
                    cmdRead->addrWidth, slaveSelected, CY_SMIF_TX_NOT_LAST_BYTE,
                    context);

        if((CY_SMIF_SUCCESS == result) && (CY_SMIF_NO_COMMAND_OR_MODE != cmdRead->mode))
        {
            result = Cy_SMIF_TransmitCommand(base, (uint8_t)cmdRead->mode,
                        cmdRead->modeWidth, NULL,
                        CY_SMIF_CMD_WITHOUT_PARAM, CY_SMIF_WIDTH_NA,
                        (cy_en_smif_slave_select_t)slaveSelected,
                        CY_SMIF_TX_NOT_LAST_BYTE, context);
        }

        if((CY_SMIF_SUCCESS == result) && (0U < cmdRead->dummyCycles))
        {
            result = Cy_SMIF_SendDummyCycles(base, cmdRead->dummyCycles);
        }

        if(CY_SMIF_SUCCESS == result)
        {
            result = Cy_SMIF_ReceiveData(base, readBuff, size,
                        cmdRead->dataWidth, cmdCompleteCb, context);
        }
    }

    return(result);
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemLocateHybridRegion
****************************************************************************//**
*
* This function locates the region structure by the address which belongs to it.
*
* \note This function is valid for the memories with hybrid sectors.
*
* \param memDevice
* The memory device configuration.
*
* \param regionInfo
* Places a hybrid region configuration structure that contains the region 
* specific parameters. See \ref cy_stc_smif_hybrid_region_info_t for
* reference.
*
* \param address
* The address for which a region is searched.
*
* \return A status of the region location.
*       - \ref CY_SMIF_SUCCESS
*       - \ref CY_SMIF_NOT_HYBRID_MEM
*       - \ref CY_SMIF_BAD_PARAM
*
* \funcusage 
* \snippet smif/snippet/main.c snippet_Cy_SMIF_MemLocateHybridRegion
*
*******************************************************************************/
cy_en_smif_status_t Cy_SMIF_MemLocateHybridRegion(cy_stc_smif_mem_config_t const *memDevice,
                                               cy_stc_smif_hybrid_region_info_t** regionInfo,
                                               uint32_t address)
{
    cy_en_smif_status_t result = CY_SMIF_BAD_PARAM;
    cy_stc_smif_hybrid_region_info_t* currInfo = NULL;
    CY_ASSERT_L1(NULL != memDevice);
    cy_stc_smif_mem_device_cfg_t *device = memDevice->deviceCfg;

    /* Check if the address exceeds the memory size */
    if(address < device->memSize)
    {
        result = CY_SMIF_NOT_HYBRID_MEM;
        /* Check if the memory is hybrid */
        if(NULL != device->hybridRegionInfo)
        {
            uint32_t idx;
            uint32_t regionStartAddr;
            uint32_t regionEndAddr;
            for(idx = 0UL; idx < device->hybridRegionCount; idx++)
            {
                currInfo = device->hybridRegionInfo[idx];
                regionStartAddr = currInfo->regionAddress;
                regionEndAddr = regionStartAddr + (currInfo->sectorsCount * currInfo->eraseSize);
                if ((address >= regionStartAddr) && (address < regionEndAddr))
                {
                    *regionInfo = currInfo;
                    result = CY_SMIF_SUCCESS;
                    break;
                }
            }
        }
    }

    return result;
}


/*******************************************************************************
* Function Name: SfdpReadBuffer
****************************************************************************//**
*
* This function reads the tables in the SDFP database into the buffer.
*
* \note This function is a blocking function and blocks until the structure data
* is read and returned. This function uses \ref Cy_SMIF_TransmitCommand()
*
* \param *base
* Holds the base address of the SMIF block registers.
*
* \param *cmdSfdp
*  The command structure to store the Read/Write command
*  configuration.
*
* \param sfdpAddress
* The pointer to an array with the address bytes
* associated with the memory command.
*
* \param slaveSelect
* Denotes the number of the slave device to which the transfer is made.
* (0, 1, 2 or 4 - the bit defines which slave to enable). The two-bit enable
* is possible only for the double quad SPI mode.
*
* \param size
* The size of data to be received. Must be > 0 and not greater than 65536.
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer.
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return A status of the transmission.
*       - \ref CY_SMIF_SUCCESS
*       - \ref CY_SMIF_CMD_FIFO_FULL
*       - \ref CY_SMIF_NO_SFDP_SUPPORT
*       - \ref CY_SMIF_EXCEED_TIMEOUT
*
*******************************************************************************/
static cy_en_smif_status_t SfdpReadBuffer(SMIF_Type *base, 
                                         cy_stc_smif_mem_cmd_t const *cmdSfdp,
                                         uint8_t const sfdpAddress[],
                                         cy_en_smif_slave_select_t  slaveSelect,
                                         uint32_t size,
                                         uint8_t sfdpBuffer[],
                                         cy_stc_smif_context_t *context)
{
    cy_en_smif_status_t result = CY_SMIF_NO_SFDP_SUPPORT;

    result = Cy_SMIF_TransmitCommand( base, (uint8_t)cmdSfdp->command,
                cmdSfdp->cmdWidth, sfdpAddress, CY_SMIF_SFDP_ADDRESS_LENGTH,
                cmdSfdp->addrWidth, slaveSelect, CY_SMIF_TX_NOT_LAST_BYTE,
                context);

    if(CY_SMIF_SUCCESS == result)
    {
        result = Cy_SMIF_SendDummyCycles(base, cmdSfdp->dummyCycles);
        
        /* Get data from SFDP and 1st Basic Flash Parameter Headers only */
        if(CY_SMIF_SUCCESS == result)
        {
#if (CY_IP_MXSMIF_VERSION>=3)
            result = Cy_SMIF_ReceiveDataBlocking(base,
                                                sfdpBuffer,
                                                size,
                                                cmdSfdp->dataWidth,
                                                context);
#else
            result = Cy_SMIF_ReceiveData( base, sfdpBuffer, size,
                                         cmdSfdp->dataWidth, NULL, context);
                                         
            if (CY_SMIF_SUCCESS == result)
            {
                uint32_t cmdTimeout = context->timeout;
                while (((uint32_t) CY_SMIF_RX_COMPLETE != context->transferStatus) &&
                        (CY_SMIF_EXCEED_TIMEOUT != result))
                {
                    /* Wait until the Read of the SFDP operation is completed */
                    result = Cy_SMIF_TimeoutRun(&cmdTimeout);
                }
            }
#endif /* CY_IP_MXSMIF_VERSION */
        }   
    }

    return(result);
}


/*******************************************************************************
* Function Name: SfdpFindParameterHeader
****************************************************************************//**
*
* Finds the Parameter Header offset from the JEDEC basic flash parameter table. 
*
* \param id
* The parameter ID.
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer.
*
* \return The relative parameter header offset in bytes.
*  Returns 0 when the parameter header is not found.
*
*******************************************************************************/
static uint32_t SfdpFindParameterHeader(uint32_t id, uint8_t const sfdpBuffer[])
{
    uint32_t headerOffset = PARAMETER_IS_NOT_FOUND;
    uint32_t maxMinorRevison = 0UL;
    uint32_t sfdpAddress = FIRST_HEADER_OFFSET; /* Begin from 1st Parameter Header */
    
    while (sfdpAddress <= (((uint32_t)sfdpBuffer[PARAM_HEADERS_NUM] * 
                                        HEADER_LENGTH) +
                                        FIRST_HEADER_OFFSET))
    {
        /* Check parameter ID */
        if (((id & PARAM_ID_LSB_MASK) == sfdpBuffer[sfdpAddress]) &&  /* Parameter ID LSB */ 
            (((id >> PARAM_ID_MSB_OFFSET) & PARAM_ID_LSB_MASK) == 
                    sfdpBuffer[sfdpAddress +  /* Parameter ID MSB */
                    PARAM_ID_MSB_REL_OFFSET]))
        {       
            /* Check parameter major and minor revisions */        
            if ((sfdpBuffer[sfdpAddress + PARAM_MINOR_REV_REL_OFFSET] >= maxMinorRevison) &&
                (sfdpBuffer[sfdpAddress + PARAM_MAJOR_REV_REL_OFFSET] == CY_SMIF_SFDP_MAJOR_REV_1))
            {
                /* Get the maximum minor revision */   
                maxMinorRevison = sfdpBuffer[sfdpAddress + PARAM_MINOR_REV_REL_OFFSET];
                
                /* Save the the Parameter Header offset with the maximum minor revision */
                headerOffset = sfdpAddress;
            } 
        }
    
        sfdpAddress += HEADER_LENGTH;       
    }

    return(headerOffset);
}


/*******************************************************************************
* Function Name: SfdpFindParameterTableAddress
****************************************************************************//**
*
* Reads the address and length of the Parameter Table from 
* the JEDEC basic flash parameter table. 
*
* \param id
* The parameter ID.
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer.
*
* \param address
* The Parameter Table address.
*
* \param *tableLength
* The Parameter Table length.
*
* \return The command reception status.
*       - \ref CY_SMIF_SUCCESS
*       - \ref CY_SMIF_CMD_NOT_FOUND
*
*******************************************************************************/
static cy_en_smif_status_t SfdpFindParameterTableAddress(uint32_t id,
                                                    uint8_t const sfdpBuffer[],
                                                    uint8_t address[],
                                                    uint32_t *tableLength)
{
    cy_en_smif_status_t result = CY_SMIF_CMD_NOT_FOUND;
    uint32_t headerOffset;
    
    headerOffset = SfdpFindParameterHeader(id, sfdpBuffer);

    if (PARAMETER_IS_NOT_FOUND != headerOffset)
    {
        /* The Parameter Table address */
        address[2] = sfdpBuffer[headerOffset +
                                PARAM_TABLE_PRT_OFFSET];
        address[1] = sfdpBuffer[headerOffset +
                                PARAM_TABLE_PRT_OFFSET + 1UL];
        address[0] = sfdpBuffer[headerOffset +
                                PARAM_TABLE_PRT_OFFSET + 2UL];

        /* The Parameter Table length */
        *tableLength = (uint32_t)sfdpBuffer[headerOffset + PARAM_TABLE_LENGTH_OFFSET] * 
                       BYTES_IN_DWORD;
                       
        result = CY_SMIF_SUCCESS;              
    }
 
    return(result);
}


/*******************************************************************************
* Function Name: SfdpGetNumOfAddrBytes
****************************************************************************//**
*
* Reads the number of address bytes from the JEDEC basic flash parameter table.
*
* \note 4-byte addressing mode is set when the memory device supports 
*       3- or 4-byte addressing mode.
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer.
*
* \return The number of address bytes used by the memory slave device.
*
*******************************************************************************/
static uint32_t SfdpGetNumOfAddrBytes(uint8_t const sfdpBuffer[])
{
    uint32_t addrBytesNum = 0UL;
    uint32_t sfdpAddrCode = _FLD2VAL(CY_SMIF_SFDP_ADDRESS_BYTES,
                                        (uint32_t)sfdpBuffer
                                        [CY_SMIF_SFDP_BFPT_BYTE_02]);
    switch(sfdpAddrCode)
    {
        case CY_SMIF_SFDP_THREE_BYTES_ADDR_CODE:
            addrBytesNum = CY_SMIF_THREE_BYTES_ADDR;
            break;
        case CY_SMIF_SFDP_THREE_OR_FOUR_BYTES_ADDR_CODE:
            addrBytesNum = CY_SMIF_FOUR_BYTES_ADDR;
            break;
        case CY_SMIF_SFDP_FOUR_BYTES_ADDR_CODE:
            addrBytesNum = CY_SMIF_FOUR_BYTES_ADDR;
            break;
        default:
            /* Invalid Address code */
            break;
    }
            
    return(addrBytesNum);
}


/*******************************************************************************
* Function Name: SfdpGetMemoryDensity
****************************************************************************//**
*
* Reads the Memory Density from the JEDEC basic flash parameter table. 
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer.
*
* \return The external memory size:
* For densities of 2 gigabits or less - the size in bytes;
* For densities 4 gigabits and above - bit-31 is set to 1b to define that
* this memory is 4 gigabits and above; and other 30:0 bits define N where 
* the density is computed as 2^N bytes. 
* For example, 0x80000021 corresponds to 2^30 = 1 gigabyte. 
*
*******************************************************************************/
static uint32_t SfdpGetMemoryDensity(uint8_t const sfdpBuffer[])
{
    uint32_t memorySize;
    uint32_t locSize = Cy_SMIF_PackBytesArray(&sfdpBuffer[CY_SMIF_SFDP_BFPT_BYTE_04], true);

    if (0UL == (locSize & CY_SMIF_SFDP_SIZE_ABOVE_4GB_Msk))
    {
        memorySize = (locSize + 1UL)/BITS_IN_BYTE;
    }
    else
    {
        memorySize = (locSize - BITS_IN_BYTE_ABOVE_4GB) |
                CY_SMIF_SFDP_SIZE_ABOVE_4GB_Msk;
    }
                
    return(memorySize);
}

#if (CY_IP_MXSMIF_VERSION>=3) || defined (CY_DOXYGEN)
/*******************************************************************************
* Function Name: SfdpGetReadCmd_1S_4D_4D
****************************************************************************//**
*
* Reads the FAST_READ_1S_4D_4D read command parameters from the JEDEC basic flash 
* parameter table. 
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer.
*
* \param cmdRead
* The pointer to the read command parameters structure.
*
* \note
* This API is available for CAT1B devices.
*
*******************************************************************************/
static void SfdpGetReadCmd_1S_4D_4D(uint8_t const sfdpBuffer[], 
                             cy_stc_smif_mem_cmd_t* cmdRead)
{
    /* 8-bit command. 4 x I/O Read command */
    cmdRead->command = CY_SMIF_FAST_READ_4_BYTES_CMD_1S_4D_4D;
    
    /* command transfer rate */
    cmdRead->cmdRate = CY_SMIF_SDR;
    
    /* command presence - 1 byte transfer */
    cmdRead->cmdPresence = CY_SMIF_PRESENT_1BYTE;

    /* The command transfer width */
    cmdRead->cmdWidth = CY_SMIF_WIDTH_SINGLE;

    /* The address transfer width */
    cmdRead->addrWidth = CY_SMIF_WIDTH_QUAD;
    cmdRead->addrRate = CY_SMIF_DDR;

    /* The 8-bit mode byte. This value is 0xFFFFFFFF when there is no mode present */
    if (0U == (_FLD2VAL(CY_SMIF_SFDP_1_4_4_MODE_CYCLES,
               (uint32_t) sfdpBuffer[CY_SMIF_SFDP_BFPT_BYTE_08])))
    {
        cmdRead->mode = CY_SMIF_NO_COMMAND_OR_MODE;
    }
    else
    {
        cmdRead->mode = READ_ENHANCED_MODE_DISABLED;
        cmdRead->modeWidth = CY_SMIF_WIDTH_QUAD;
        cmdRead->modeRate = CY_SMIF_DDR;
        cmdRead->modePresence = CY_SMIF_PRESENT_1BYTE;
    }

    /* The dummy cycles number. A zero value suggests no dummy cycles */
    cmdRead->dummyCycles = _FLD2VAL(CY_SMIF_SFDP_1_4_4_DUMMY_CYCLES, 
                           (uint32_t) sfdpBuffer[CY_SMIF_SFDP_BFPT_BYTE_08]);

    /* dummy cycles present - 1 byte transfer */
    cmdRead->dummyCyclesPresence = CY_SMIF_PRESENT_1BYTE;

    /* The data transfer width */
    cmdRead->dataWidth = CY_SMIF_WIDTH_QUAD;    

    /* The data rate - DDR */
    cmdRead->dataRate = CY_SMIF_DDR;
    
    
}
#endif /* CY_IP_MXSMIF_VERSION */

/*******************************************************************************
* Function Name: SfdpGetReadCmd_1_4_4
****************************************************************************//**
*
* Reads the FAST_READ_1_4_4 read command parameters from the JEDEC basic flash 
* parameter table. 
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer.
*
* \param cmdRead
* The pointer to the read command parameters structure.
*
*******************************************************************************/
static void SfdpGetReadCmd_1_4_4(uint8_t const sfdpBuffer[], 
                             cy_stc_smif_mem_cmd_t* cmdRead)
{
    /* 8-bit command. 4 x I/O Read command */
    cmdRead->command = sfdpBuffer[CY_SMIF_SFDP_BFPT_BYTE_09];

#if (CY_IP_MXSMIF_VERSION>=3)
    /* command presence - 1 byte transfer */
    cmdRead->cmdPresence = CY_SMIF_PRESENT_1BYTE;
#endif /* CY_IP_MXSMIF_VERSION */

    /* The command transfer width */
    cmdRead->cmdWidth = CY_SMIF_WIDTH_SINGLE;

    /* The address transfer width */
    cmdRead->addrWidth = CY_SMIF_WIDTH_QUAD;

    /* The 8-bit mode byte. This value is 0xFFFFFFFF when there is no mode present */
    if (0U == (_FLD2VAL(CY_SMIF_SFDP_1_4_4_MODE_CYCLES,
               (uint32_t) sfdpBuffer[CY_SMIF_SFDP_BFPT_BYTE_08])))
    {
        cmdRead->mode = CY_SMIF_NO_COMMAND_OR_MODE;
    }
    else
    {
        cmdRead->mode = READ_ENHANCED_MODE_DISABLED;
        cmdRead->modeWidth = CY_SMIF_WIDTH_QUAD;
#if (CY_IP_MXSMIF_VERSION>=3)
        cmdRead->modePresence = CY_SMIF_PRESENT_1BYTE;
#endif /* CY_IP_MXSMIF_VERSION */
    }

    /* The dummy cycles number. A zero value suggests no dummy cycles */
    cmdRead->dummyCycles = _FLD2VAL(CY_SMIF_SFDP_1_4_4_DUMMY_CYCLES, 
                           (uint32_t) sfdpBuffer[CY_SMIF_SFDP_BFPT_BYTE_08]);

#if (CY_IP_MXSMIF_VERSION>=3)
    /* dummy cycles present - 1 byte transfer */
    if(cmdRead->dummyCycles > 0)
            cmdRead->dummyCyclesPresence = CY_SMIF_PRESENT_1BYTE;
#endif /* CY_IP_MXSMIF_VERSION */

    /* The data transfer width */
    cmdRead->dataWidth = CY_SMIF_WIDTH_QUAD;    
}


/*******************************************************************************
* Function Name: SfdpGetReadCmd_1_1_4
****************************************************************************//**
*
* Reads the FAST_READ_1_1_4 read command parameters from the JEDEC basic flash 
* parameter table. 
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer.
*
* \param cmdRead
* The pointer to the read command parameters structure.
*
*******************************************************************************/
static void SfdpGetReadCmd_1_1_4(uint8_t const sfdpBuffer[], 
                             cy_stc_smif_mem_cmd_t* cmdRead)
{
    /* 8-bit command. 4 x I/O Read command */
    cmdRead->command = sfdpBuffer[CY_SMIF_SFDP_BFPT_BYTE_0B];

    /* The command transfer width */
    cmdRead->cmdWidth = CY_SMIF_WIDTH_SINGLE;

    /* The address transfer width */
    cmdRead->addrWidth = CY_SMIF_WIDTH_SINGLE;

    /* The 8-bit mode byte. This value is 0xFFFFFFFF when there is no mode present */
    if ((0U == _FLD2VAL(CY_SMIF_SFDP_1_1_4_MODE_CYCLES, (uint32_t) sfdpBuffer
                    [CY_SMIF_SFDP_BFPT_BYTE_0A])))
    {
        cmdRead->mode = CY_SMIF_NO_COMMAND_OR_MODE;
    }
    else
    {
        cmdRead->mode = READ_ENHANCED_MODE_DISABLED;
        cmdRead->modeWidth = CY_SMIF_WIDTH_SINGLE;
#if (CY_IP_MXSMIF_VERSION>=3)
        cmdRead->modePresence = CY_SMIF_PRESENT_1BYTE;
#endif /* CY_IP_MXSMIF_VERSION */
    }

    /* The dummy cycles number. A zero value suggests no dummy cycles */
    cmdRead->dummyCycles = _FLD2VAL(CY_SMIF_SFDP_1_1_4_DUMMY_CYCLES,
                          (uint32_t)sfdpBuffer[CY_SMIF_SFDP_BFPT_BYTE_0A]);

#if (CY_IP_MXSMIF_VERSION>=3)
    /* dummy cycles present - 1 byte transfer */
    if(cmdRead->dummyCycles > 0)
            cmdRead->dummyCyclesPresence = CY_SMIF_PRESENT_1BYTE;
#endif /* CY_IP_MXSMIF_VERSION */

    /* The data transfer width */
    cmdRead->dataWidth = CY_SMIF_WIDTH_QUAD;  
}


/*******************************************************************************
* Function Name: SfdpGetReadCmd_1_2_2
****************************************************************************//**
*
* Reads the FAST_READ_1_2_2 read command parameters from the JEDEC basic flash 
* parameter table. 
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer.
*
* \param cmdRead
* The pointer to the read command parameters structure.
*
*******************************************************************************/
static void SfdpGetReadCmd_1_2_2(uint8_t const sfdpBuffer[], 
                             cy_stc_smif_mem_cmd_t* cmdRead)
{
    /* 8-bit command. 2 x I/O Read command */
    cmdRead->command  = sfdpBuffer[CY_SMIF_SFDP_BFPT_BYTE_0F];

    /* The command transfer width */
    cmdRead->cmdWidth = CY_SMIF_WIDTH_SINGLE;

    /* The address transfer width */
    cmdRead->addrWidth = CY_SMIF_WIDTH_DUAL;

    /* The 8-bit mode byte. This value is 0xFFFFFFFF when there is no mode present */
    if (0U == _FLD2VAL(CY_SMIF_SFDP_1_2_2_MODE_CYCLES, (uint32_t)
              sfdpBuffer[CY_SMIF_SFDP_BFPT_BYTE_0E]))
    {
        cmdRead->mode = CY_SMIF_NO_COMMAND_OR_MODE;
    }
    else
    {
        cmdRead->mode = READ_ENHANCED_MODE_DISABLED;
        cmdRead->modeWidth = CY_SMIF_WIDTH_DUAL;
#if (CY_IP_MXSMIF_VERSION>=3)
        cmdRead->modePresence = CY_SMIF_PRESENT_1BYTE;
#endif /* CY_IP_MXSMIF_VERSION */
    }

    /* The dummy cycles number. A zero value suggests no dummy cycles. */
    cmdRead->dummyCycles = _FLD2VAL(CY_SMIF_SFDP_1_2_2_DUMMY_CYCLES,
                            (uint32_t) sfdpBuffer [CY_SMIF_SFDP_BFPT_BYTE_0E]);

#if (CY_IP_MXSMIF_VERSION>=3)
    /* dummy cycles present - 1 byte transfer */
    if(cmdRead->dummyCycles > 0)
            cmdRead->dummyCyclesPresence = CY_SMIF_PRESENT_1BYTE;
#endif /* CY_IP_MXSMIF_VERSION */

    /* The data transfer width */
    cmdRead->dataWidth = CY_SMIF_WIDTH_DUAL;
}


/*******************************************************************************
* Function Name: SfdpGetReadCmd_1_1_2
****************************************************************************//**
*
* Reads the FAST_READ_1_1_2 read command parameters from the JEDEC basic flash 
* parameter table. 
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer.
*
* \param cmdRead
* The pointer to the read command parameters structure.
*
*******************************************************************************/
static void SfdpGetReadCmd_1_1_2(uint8_t const sfdpBuffer[], 
                             cy_stc_smif_mem_cmd_t* cmdRead)
{
    /* 8-bit command. 2 x I/O Read command */
    cmdRead->command  = sfdpBuffer[CY_SMIF_SFDP_BFPT_BYTE_0D];

    /* The command transfer width */
    cmdRead->cmdWidth = CY_SMIF_WIDTH_SINGLE;

    /* The address transfer width */
    cmdRead->addrWidth = CY_SMIF_WIDTH_SINGLE;

    /* The 8-bit mode byte. This value is 0xFFFFFFFF when there is no mode present */
    if (0U == (_FLD2VAL(CY_SMIF_SFDP_1_1_2_MODE_CYCLES, (uint32_t)
        sfdpBuffer[CY_SMIF_SFDP_BFPT_BYTE_0C])))
    {
        cmdRead->mode = CY_SMIF_NO_COMMAND_OR_MODE;
    }
    else
    {
        cmdRead->mode = READ_ENHANCED_MODE_DISABLED;
        cmdRead->modeWidth = CY_SMIF_WIDTH_SINGLE;
#if (CY_IP_MXSMIF_VERSION>=3)
        cmdRead->modePresence = CY_SMIF_PRESENT_1BYTE;        
#endif /* CY_IP_MXSMIF_VERSION */
    }

    /* The dummy cycles number. A zero value suggests no dummy cycles. */
    cmdRead->dummyCycles = _FLD2VAL(CY_SMIF_SFDP_1_1_2_DUMMY_CYCLES,
            (uint32_t)sfdpBuffer[CY_SMIF_SFDP_BFPT_BYTE_0C]);

#if (CY_IP_MXSMIF_VERSION>=3)
    /* dummy cycles present - 1 byte transfer */
    if(cmdRead->dummyCycles > 0)
        cmdRead->dummyCyclesPresence = CY_SMIF_PRESENT_1BYTE;
#endif /* CY_IP_MXSMIF_VERSION */

    /* The data transfer width */
    cmdRead->dataWidth = CY_SMIF_WIDTH_DUAL;
}


/*******************************************************************************
* Function Name: SfdpGetReadCmd_1_1_1
****************************************************************************//**
*
* Reads the FAST_READ_1_1_1 read command parameters from the JEDEC basic flash 
* parameter table. 
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer.
*
* \param cmdRead
* The pointer to the read command parameters structure.
*
*******************************************************************************/
static void SfdpGetReadCmd_1_1_1(uint8_t const sfdpBuffer[], 
                             cy_stc_smif_mem_cmd_t* cmdRead)
{
    (void)sfdpBuffer; /* Suppress warning */
    
    /* 8-bit command. 1 x I/O Read command */
    cmdRead->command  = CY_SMIF_SINGLE_READ_CMD;

    /* The command transfer width */
    cmdRead->cmdWidth = CY_SMIF_WIDTH_SINGLE;

    /* The address transfer width */
    cmdRead->addrWidth = CY_SMIF_WIDTH_SINGLE;

    /* The 8 bit-mode byte. This value is 0xFFFFFFFF when there is no mode present */
    cmdRead->mode = CY_SMIF_NO_COMMAND_OR_MODE;

    /* The dummy cycles number. A zero value suggests no dummy cycles. */
    cmdRead->dummyCycles = 0UL;

    /* The data transfer width */
    cmdRead->dataWidth = CY_SMIF_WIDTH_SINGLE;
}


/*******************************************************************************
* Function Name: SfdpGetReadCmdParams
****************************************************************************//**
*
* Reads the read command parameters from the JEDEC basic flash parameter table. 
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer.
*
* \param dataSelect
* The data line selection options for a slave device.
*
* \param cmdRead
* The pointer to the read command parameters structure.
*
* \return Protocol Mode.
*
*******************************************************************************/
static cy_en_smif_protocol_mode_t SfdpGetReadCmdParams(uint8_t const sfdpBuffer[], 
                                     cy_en_smif_data_select_t dataSelect, 
                                      cy_stc_smif_mem_cmd_t* cmdRead)
{
    cy_en_smif_protocol_mode_t protocolMode = PROTOCOL_MODE_WRONG;
    uint32_t sfdpDataIndex = CY_SMIF_SFDP_BFPT_BYTE_02;
    bool quadEnabled = ((CY_SMIF_DATA_SEL1 != dataSelect) &&
                        (CY_SMIF_DATA_SEL3 != dataSelect));

    if (quadEnabled)
    {
        if (_FLD2BOOL(CY_SMIF_SFDP_FAST_READ_1_4_4,
                      ((uint32_t) sfdpBuffer[sfdpDataIndex])))
        {
#if (CY_IP_MXSMIF_VERSION>=3)
            if(_FLD2BOOL(CY_SMIF_SFDP_DTR_SUPPORT, (uint32_t) sfdpBuffer[sfdpDataIndex]))
            {
                SfdpGetReadCmd_1S_4D_4D(sfdpBuffer, cmdRead);
                protocolMode = PROTOCOL_MODE_1S_4D_4D;
            }
            else
            {
                SfdpGetReadCmd_1_4_4(sfdpBuffer, cmdRead);
                protocolMode = PROTOCOL_MODE_1S_4S_4S;
            }
#else
            SfdpGetReadCmd_1_4_4(sfdpBuffer, cmdRead);
            protocolMode = PROTOCOL_MODE_1S_4S_4S;
#endif /* CY_IP_MXSMIF_VERSION */
        }
        else if (_FLD2BOOL(CY_SMIF_SFDP_FAST_READ_1_1_4,
                            ((uint32_t)sfdpBuffer[sfdpDataIndex])))
        {
            SfdpGetReadCmd_1_1_4(sfdpBuffer, cmdRead);
            protocolMode = PROTOCOL_MODE_1S_1S_4S;
        }
        else
        {
            /* Wrong mode */
            CY_ASSERT_L2(true);
            protocolMode = PROTOCOL_MODE_WRONG;
        }
    }
    else
    {
        if ((_FLD2BOOL(CY_SMIF_SFDP_FAST_READ_1_2_2,
                       (uint32_t)sfdpBuffer[sfdpDataIndex])))
        {
            SfdpGetReadCmd_1_2_2(sfdpBuffer, cmdRead);
            protocolMode = PROTOCOL_MODE_1S_2S_2S;
        }
        else
        {
            if (_FLD2BOOL(CY_SMIF_SFDP_FAST_READ_1_1_2,
                          (uint32_t)sfdpBuffer[sfdpDataIndex]))
            {
                SfdpGetReadCmd_1_1_2(sfdpBuffer, cmdRead);
                protocolMode = PROTOCOL_MODE_1S_1S_2S;
            }
            else
            {
                SfdpGetReadCmd_1_1_1(sfdpBuffer, cmdRead);
                protocolMode = PROTOCOL_MODE_1S_1S_1S;
            }
        }
    }
    
    return protocolMode;
}


/*******************************************************************************
* Function Name: SfdpGetReadFourBytesCmd
****************************************************************************//**
*
* Reads the read command instruction from the 4-byte Address Instruction Table.  
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer with the 4-byte Address
* Instruction Table.
*
* \param protocolMode
* Protocol Mode.
*
* \param cmdRead
* The pointer to the read command parameters structure.
*
*******************************************************************************/
static void SfdpGetReadFourBytesCmd(uint8_t const sfdpBuffer[], 
                                      cy_en_smif_protocol_mode_t protocolMode, 
                                      cy_stc_smif_mem_cmd_t* cmdRead)
{
    CY_MISRA_DEVIATE_BLOCK_START('MISRA C-2012 Rule 11.3', 7, \
'Pointer type conversion is intentional.');
    /* Get the mask which contains the Support for Fast Read Commands
     * from 4-byte Address Instruction Table, DWORD 1 
     */
    uint32_t sfdpForBytesTableDword1 = ((uint32_t*)sfdpBuffer)[FOUR_BYTE_ADDRESS_TABLE_BYTE_0];
 
    switch (protocolMode)
    {
        case PROTOCOL_MODE_1S_4S_4S:
            if (_FLD2BOOL(SUPPORT_FAST_READ_1S_4S_4S_CMD, sfdpForBytesTableDword1))
            {
                cmdRead->command = CY_SMIF_FAST_READ_4_BYTES_CMD_1S_4S_4S;
            }
            break;
        case PROTOCOL_MODE_1S_1S_4S:
            if (_FLD2BOOL(SUPPORT_FAST_READ_1S_1S_4S_CMD, sfdpForBytesTableDword1))
            {
                cmdRead->command = CY_SMIF_FAST_READ_4_BYTES_CMD_1S_1S_4S;
            }
            break;
        case PROTOCOL_MODE_1S_2S_2S:
            if (_FLD2BOOL(SUPPORT_FAST_READ_1S_2S_2S_CMD, sfdpForBytesTableDword1))
            {
                cmdRead->command = CY_SMIF_FAST_READ_4_BYTES_CMD_1S_2S_2S;
            }
            break;
        case PROTOCOL_MODE_1S_1S_2S:
            if (_FLD2BOOL(SUPPORT_FAST_READ_1S_1S_2S_CMD, sfdpForBytesTableDword1))
            {
                cmdRead->command = CY_SMIF_FAST_READ_4_BYTES_CMD_1S_1S_2S;
            }
            break;
        case PROTOCOL_MODE_1S_1S_1S:
            if (_FLD2BOOL(SUPPORT_FAST_READ_1S_1S_1S_CMD, sfdpForBytesTableDword1))
            {
                cmdRead->command = CY_SMIF_FAST_READ_4_BYTES_CMD_1S_1S_1S;
            }
            break;
        default:
            /* There are no instructions for 4-byte mode. Use instruction for 3-byte mode */
            break;
    }  
}


/*******************************************************************************
* Function Name: SfdpGetPageSize
****************************************************************************//**
*
* Reads the page size from the JEDEC basic flash parameter table. 
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer.
*
* \return The page size in bytes.
*
*******************************************************************************/
static uint32_t SfdpGetPageSize(uint8_t const sfdpBuffer[])
{
    uint32_t size;

    /* The page size */
    size = 0x01UL << _FLD2VAL(CY_SMIF_SFDP_PAGE_SIZE,
        (uint32_t) sfdpBuffer[CY_SMIF_SFDP_BFPT_BYTE_28]);

    return(size);
}


/*******************************************************************************
* Function Name: SfdpGetEraseTime
****************************************************************************//**
*
* Calculates erase time. 
*
* \param eraseOffset
* The offset of the Sector Erase command in the SFDP buffer.
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer.
*
* \param eraseTypeTime
* The pointer to an array with the erase time in us for different erase types.
*
* \return Default erase time in us.
*
*******************************************************************************/
static uint32_t SfdpGetEraseTime(uint32_t const eraseOffset, uint8_t const sfdpBuffer[], cy_stc_smif_erase_type_t eraseType[])
{
    /* Get the value of 10th DWORD from the JEDEC basic flash parameter table */
    uint32_t readEraseTime = ((uint32_t*)sfdpBuffer)[CY_SMIF_JEDEC_BFPT_10TH_DWORD];

    uint32_t eraseTimeDefaultIndex = (((eraseOffset - CY_SMIF_SFDP_BFPT_BYTE_1D) + TYPE_STEP) / TYPE_STEP);
    uint32_t eraseMul = _FLD2VAL(CY_SMIF_SFDP_ERASE_MUL_COUNT, readEraseTime);
    uint32_t eraseUnits = 0UL;
    uint32_t eraseCount = 0UL;
    uint32_t eraseMs = 0UL;
    uint32_t eraseTypeTypicalTime;

    for (uint32_t idx = 0UL; idx < ERASE_TYPE_COUNT; idx++){
        eraseTypeTypicalTime = (readEraseTime >> (idx * ERASE_T_LENGTH))>> ERASE_T_COUNT_OFFSET;
        eraseUnits = _FLD2VAL(ERASE_T_UNITS, eraseTypeTypicalTime);
        eraseCount = _FLD2VAL(ERASE_T_COUNT, eraseTypeTypicalTime);

        switch (eraseUnits)
        {
            case CY_SMIF_SFDP_UNIT_0:
                eraseMs = CY_SMIF_SFDP_ERASE_TIME_1MS;
                break;
            case CY_SMIF_SFDP_UNIT_1:
                eraseMs = CY_SMIF_SFDP_ERASE_TIME_16MS;
                break;
            case CY_SMIF_SFDP_UNIT_2:
                eraseMs = CY_SMIF_SFDP_ERASE_TIME_128MS;
                break;
            case CY_SMIF_SFDP_UNIT_3:
                eraseMs = CY_SMIF_SFDP_ERASE_TIME_1S;
                break;
            default:
                /* An unsupported SFDP value */
                break;
        }

        /* Convert typical time to max time */
        eraseType[idx].eraseTime = ((eraseCount + 1UL) * eraseMs) * (2UL * (eraseMul + 1UL));
    }

    return(eraseType[eraseTimeDefaultIndex - 1UL].eraseTime);
}


/*******************************************************************************
* Function Name: SfdpGetChipEraseTime
****************************************************************************//**
*
* Calculates chip erase time. 
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer.
*
* \return Chip erase time in us.
*
*******************************************************************************/
static uint32_t SfdpGetChipEraseTime(uint8_t const sfdpBuffer[])
{
    /* Get the value of 10th DWORD from the JEDEC basic flash parameter table */
    uint32_t readEraseTime = ((uint32_t*)sfdpBuffer)[CY_SMIF_JEDEC_BFPT_10TH_DWORD];

    /* Get the value of 11th DWORD from the JEDEC basic flash parameter table */
    uint32_t chipEraseProgTime = ((uint32_t*)sfdpBuffer)[CY_SMIF_JEDEC_BFPT_11TH_DWORD];

    uint32_t chipEraseTimeMax;
    uint32_t chipEraseUnits = _FLD2VAL(CY_SMIF_SFDP_CHIP_ERASE_UNITS, chipEraseProgTime);
    uint32_t chipEraseCount = _FLD2VAL(CY_SMIF_SFDP_CHIP_ERASE_COUNT, chipEraseProgTime);
    uint32_t chipEraseMs = 0UL;
    uint32_t eraseMul = _FLD2VAL(CY_SMIF_SFDP_ERASE_MUL_COUNT, readEraseTime);

    switch (chipEraseUnits)
    {
        case CY_SMIF_SFDP_UNIT_0:
            chipEraseMs = CY_SMIF_SFDP_CHIP_ERASE_TIME_16MS;
            break;
        case CY_SMIF_SFDP_UNIT_1:
            chipEraseMs = CY_SMIF_SFDP_CHIP_ERASE_TIME_256MS;
            break;
        case CY_SMIF_SFDP_UNIT_2:
            chipEraseMs = CY_SMIF_SFDP_CHIP_ERASE_TIME_4S;
            break;
        case CY_SMIF_SFDP_UNIT_3:
            chipEraseMs = CY_SMIF_SFDP_CHIP_ERASE_TIME_64S;
            break;
        default:
            /* An unsupported SFDP value */
            break;
    }

    /* Convert typical time to max time */
    chipEraseTimeMax = ((chipEraseCount + 1UL)*chipEraseMs) * (2UL *(eraseMul + 1UL));

    return(chipEraseTimeMax);
}


/*******************************************************************************
* Function Name: SfdpGetPageProgramTime
****************************************************************************//**
*
* Calculates page program time. 
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer.
*
* \return Page program time in us.
*
*******************************************************************************/
static uint32_t SfdpGetPageProgramTime(uint8_t const sfdpBuffer[])
{
    /* Get the value of 11th DWORD from the JEDEC basic flash parameter table */
    uint32_t chipEraseProgTime = ((uint32_t*)sfdpBuffer)[CY_SMIF_JEDEC_BFPT_11TH_DWORD];
    uint32_t programTimeMax;
    uint32_t programTimeUnits = _FLD2VAL(CY_SMIF_SFDP_PAGE_PROG_UNITS, chipEraseProgTime);
    uint32_t programTimeCount  = _FLD2VAL(CY_SMIF_SFDP_PAGE_PROG_COUNT, chipEraseProgTime);
    uint32_t progMul = _FLD2VAL(CY_SMIF_SFDP_PROG_MUL_COUNT, chipEraseProgTime);
    uint32_t progUs;
    
    if (CY_SMIF_SFDP_UNIT_0 == programTimeUnits)
    {
        progUs = CY_SMIF_SFDP_PROG_TIME_8US;
    }
    else
    {
        progUs = CY_SMIF_SFDP_PROG_TIME_64US;
    }

    /* Convert typical time to max time */
    programTimeMax = ((programTimeCount + 1UL) * progUs) * (2UL * (progMul + 1UL));

    return(programTimeMax);
}


/*******************************************************************************
* Function Name: SfdpSetWriteEnableCommand
****************************************************************************//**
*
* Sets the Write Enable command and the width of the command transfer.
*
* \param cmdWriteEnable
* The pointer to the Write Enable command parameters structure.
*
*******************************************************************************/
static void SfdpSetWriteEnableCommand(cy_stc_smif_mem_cmd_t* cmdWriteEnable)
{
    /* 8-bit command. Write Enable */
    cmdWriteEnable->command = CY_SMIF_WRITE_ENABLE_CMD;

    /* The width of the command transfer */
    cmdWriteEnable->cmdWidth = CY_SMIF_WIDTH_SINGLE;

#if (CY_IP_MXSMIF_VERSION>=3)
    cmdWriteEnable->cmdPresence = CY_SMIF_PRESENT_1BYTE;
#endif /* CY_IP_MXSMIF_VERSION */
}


/*******************************************************************************
* Function Name: SfdpSetWriteDisableCommand
****************************************************************************//**
*
* Sets the Write Disable command and the width of the command transfer.
*
* \param cmdWriteDisable
* The pointer to the Write Disable command parameters structure.
*
*******************************************************************************/
static void SfdpSetWriteDisableCommand(cy_stc_smif_mem_cmd_t* cmdWriteDisable)
{
    /* The 8-bit command. Write Disable */
    cmdWriteDisable->command = CY_SMIF_WRITE_DISABLE_CMD;

    /* The width of the command transfer */
    cmdWriteDisable->cmdWidth = CY_SMIF_WIDTH_SINGLE;
}


/*******************************************************************************
* Function Name: SfdpSetProgramCommand_1_1_1 
****************************************************************************//**
*
* Sets the Program command parameters for 1S-1S-1S Protocol mode and 
* 3-byte addressing mode.
*
* \param cmdProgram
* The pointer to the Program command parameters structure.
*
*******************************************************************************/
static void SfdpSetProgramCommand_1_1_1(cy_stc_smif_mem_cmd_t* cmdProgram)
{
    /* 8-bit command. 1 x I/O Program command */
    cmdProgram->command = CY_SMIF_SINGLE_PROGRAM_CMD;
#if (CY_IP_MXSMIF_VERSION>=3)
    /* command presence - 1 byte */
    cmdProgram->cmdPresence = CY_SMIF_PRESENT_1BYTE;
#endif /* CY_IP_MXSMIF_VERSION */
    /* The command transfer width */
    cmdProgram->cmdWidth = CY_SMIF_WIDTH_SINGLE;
    /* The address transfer width */
    cmdProgram->addrWidth = CY_SMIF_WIDTH_SINGLE;
    /* 8-bit mode byte. This value is 0xFFFFFFFF when there is no mode present */
    cmdProgram->mode = CY_SMIF_NO_COMMAND_OR_MODE;
    /* The width of the mode command transfer */
    cmdProgram->modeWidth = CY_SMIF_WIDTH_SINGLE;
    /* The dummy cycles number. A zero value suggests no dummy cycles */
    cmdProgram->dummyCycles = 0UL;
    /* The data transfer width */
    cmdProgram->dataWidth = CY_SMIF_WIDTH_SINGLE;
}


/*******************************************************************************
* Function Name: SfdpSetProgramCommandFourBytes_1_1_1
****************************************************************************//**
*
* Sets the Program command parameters for 1S-1S-1S Protocol mode and 
* 4-byte addressing mode.
*
* \param cmdProgram
* The pointer to the Program command parameters structure.
*
*******************************************************************************/
static void SfdpSetProgramCommandFourBytes_1_1_1(cy_stc_smif_mem_cmd_t* cmdProgram)
{
    /* 8-bit command. 1 x I/O Program command */
    cmdProgram->command = CY_SMIF_PAGE_PROGRAM_4_BYTES_CMD_1S_1S_1S;
#if (CY_IP_MXSMIF_VERSION>=3)
    /* command presence - 1 byte */
    cmdProgram->cmdPresence = CY_SMIF_PRESENT_1BYTE;
#endif /* CY_IP_MXSMIF_VERSION */
    /* The command transfer width */
    cmdProgram->cmdWidth = CY_SMIF_WIDTH_SINGLE;
    /* The address transfer width */
    cmdProgram->addrWidth = CY_SMIF_WIDTH_SINGLE;
    /* 8-bit mode byte. This value is 0xFFFFFFFF when there is no mode present */
    cmdProgram->mode = CY_SMIF_NO_COMMAND_OR_MODE;
    /* The width of the mode command transfer */
    cmdProgram->modeWidth = CY_SMIF_WIDTH_SINGLE;
    /* The dummy cycles number. A zero value suggests no dummy cycles */
    cmdProgram->dummyCycles = 0UL;
    /* The data transfer width */
    cmdProgram->dataWidth = CY_SMIF_WIDTH_SINGLE;
}


/*******************************************************************************
* Function Name: SfdpSetProgramCommandFourBytes_1_1_4
****************************************************************************//**
*
* Sets the Program command parameters for 1S-1S-4S Protocol mode and 
* 4-byte addressing mode.
*
* \param cmdProgram
* The pointer to the Program command parameters structure.
*
*******************************************************************************/
static void SfdpSetProgramCommandFourBytes_1_1_4(cy_stc_smif_mem_cmd_t* cmdProgram)
{
    /* 8-bit command. 1 x I/O Program command */
    cmdProgram->command = CY_SMIF_PAGE_PROGRAM_4_BYTES_CMD_1S_1S_4S;
#if (CY_IP_MXSMIF_VERSION>=3)
    /* command presence - 1 byte */
    cmdProgram->cmdPresence = CY_SMIF_PRESENT_1BYTE;
#endif /* CY_IP_MXSMIF_VERSION */
    /* The command transfer width */
    cmdProgram->cmdWidth = CY_SMIF_WIDTH_SINGLE;
    /* The address transfer width */
    cmdProgram->addrWidth = CY_SMIF_WIDTH_SINGLE;
    /* 8-bit mode byte. This value is 0xFFFFFFFF when there is no mode present */
    cmdProgram->mode = CY_SMIF_NO_COMMAND_OR_MODE;
    /* The width of the mode command transfer */
    cmdProgram->modeWidth = CY_SMIF_WIDTH_SINGLE;
    /* The dummy cycles number. A zero value suggests no dummy cycles */
    cmdProgram->dummyCycles = 0UL;
    /* The data transfer width */
    cmdProgram->dataWidth = CY_SMIF_WIDTH_QUAD;
}


/*******************************************************************************
* Function Name: SfdpSetProgramCommandFourBytes_1_4_4
****************************************************************************//**
*
* Sets the Program command parameters for 1S-4S-4S Protocol mode and 
* 4-byte addressing mode.
*
* \param cmdProgram
* The pointer to the Program command parameters structure.
*
*******************************************************************************/
static void SfdpSetProgramCommandFourBytes_1_4_4(cy_stc_smif_mem_cmd_t* cmdProgram)
{
    /* 8-bit command. 1 x I/O Program command */
    cmdProgram->command = CY_SMIF_PAGE_PROGRAM_4_BYTES_CMD_1S_4S_4S;
#if (CY_IP_MXSMIF_VERSION>=3)
    cmdProgram->cmdPresence = CY_SMIF_PRESENT_1BYTE;
#endif /* CY_IP_MXSMIF_VERSION */
    /* The command transfer width */
    cmdProgram->cmdWidth = CY_SMIF_WIDTH_SINGLE;
    /* The address transfer width */
    cmdProgram->addrWidth = CY_SMIF_WIDTH_QUAD;
    /* 8-bit mode byte. This value is 0xFFFFFFFF when there is no mode present */
    cmdProgram->mode = CY_SMIF_NO_COMMAND_OR_MODE;
    /* The width of the mode command transfer */
    cmdProgram->modeWidth = CY_SMIF_WIDTH_QUAD;
    /* The dummy cycles number. A zero value suggests no dummy cycles */
    cmdProgram->dummyCycles = 0UL;
    /* The data transfer width */
    cmdProgram->dataWidth = CY_SMIF_WIDTH_QUAD;
}

/*******************************************************************************
* Function Name: SfdpGetProgramFourBytesCmd
****************************************************************************//**
*
* Sets the Page Program command instruction for 4-byte addressing mode.
*
* \note When the Program command is not found for 4 byte addressing mode 
* the Program command instruction is set for 1S-1S-1S Protocol mode and 
* 3-byte addressing mode.
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer with the 4-byte Address
* Instruction table.
*
* \param protocolMode
* Protocol Mode.
*
* \param cmdProgram
* The pointer to the Program command parameters structure.
*
*******************************************************************************/
static void SfdpGetProgramFourBytesCmd(uint8_t const sfdpBuffer[], 
                                       cy_en_smif_protocol_mode_t protocolMode, 
                                       cy_stc_smif_mem_cmd_t* cmdProgram)  
{
    /* Get the mask which contains the Support for Page Program Commands
     * from 4-byte Address Instruction Table, DWORD 1 
     */
    uint32_t sfdpForBytesTableDword1 = ((uint32_t*)sfdpBuffer)[FOUR_BYTE_ADDRESS_TABLE_BYTE_0];
    
    switch (protocolMode)
    {
        case PROTOCOL_MODE_1S_4S_4S:
#if (CY_IP_MXSMIF_VERSION>=3)
        case PROTOCOL_MODE_1S_4D_4D:
#endif /* CY_IP_MXSMIF_VERSION */
            if (_FLD2BOOL(SUPPORT_PP_1S_4S_4S_CMD, sfdpForBytesTableDword1))
            {
                SfdpSetProgramCommandFourBytes_1_4_4(cmdProgram);
            }
            else if (_FLD2BOOL(SUPPORT_PP_1S_1S_4S_CMD, sfdpForBytesTableDword1))
            {
                SfdpSetProgramCommandFourBytes_1_1_4(cmdProgram);
            }
            else if (_FLD2BOOL(SUPPORT_PP_1S_1S_1S_CMD, sfdpForBytesTableDword1))
            {
                SfdpSetProgramCommandFourBytes_1_1_1(cmdProgram);
            }
            else
            {
                /* There are no instructions for 4-byte mode. Use the instruction for 3-byte mode */
                SfdpSetProgramCommand_1_1_1(cmdProgram);
            }
            break;
        case PROTOCOL_MODE_1S_1S_4S:
            if (_FLD2BOOL(SUPPORT_PP_1S_1S_4S_CMD, sfdpForBytesTableDword1))
            {
                SfdpSetProgramCommandFourBytes_1_1_4(cmdProgram); 
            }
            else if (_FLD2BOOL(SUPPORT_PP_1S_1S_1S_CMD, sfdpForBytesTableDword1))
            {
                SfdpSetProgramCommandFourBytes_1_1_1(cmdProgram);
            }
            else
            {
                /* There are no instructions for 4-byte mode. Use the instruction for 3-byte mode */
                SfdpSetProgramCommand_1_1_1(cmdProgram);
            }
            break;
        case PROTOCOL_MODE_1S_2S_2S:
        case PROTOCOL_MODE_1S_1S_2S:
        case PROTOCOL_MODE_1S_1S_1S:
            if (_FLD2BOOL(SUPPORT_PP_1S_1S_1S_CMD, sfdpForBytesTableDword1))
            {
                SfdpSetProgramCommandFourBytes_1_1_1(cmdProgram);
            }
            else
            {
                /* There are no instructions for 4-byte mode. Use the instruction for 3-byte mode */
                SfdpSetProgramCommand_1_1_1(cmdProgram);
            }
            break;
        default:
            /* Wrong mode */
            CY_ASSERT_L2(true);  
            break;
    }
}


/*******************************************************************************
* Function Name: SfdpSetWipStatusRegisterCommand
****************************************************************************//**
*
* Sets the WIP-containing status register command and 
* the width of the command transfer.
*
* \param readStsRegWipCmd
* The pointer to the WIP-containing status register command parameters structure.
*
*******************************************************************************/
static void SfdpSetWipStatusRegisterCommand(cy_stc_smif_mem_cmd_t* readStsRegWipCmd)
{
    /* 8-bit command. WIP RDSR */
    readStsRegWipCmd->command  = CY_SMIF_READ_STATUS_REG1_CMD;
    /* The command transfer width */
    readStsRegWipCmd->cmdWidth = CY_SMIF_WIDTH_SINGLE;
}


/*******************************************************************************
* Function Name: SfdpGetQuadEnableParameters
****************************************************************************//**
*
* Gets the Quad Enable parameters.
*
* \param device
* The device structure instance declared by the user. This is where the detected
* parameters are stored and returned.
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer.
*
*******************************************************************************/
static void SfdpGetQuadEnableParameters(cy_stc_smif_mem_device_cfg_t *device, 
                                    uint8_t const sfdpBuffer[])
{
    CY_ASSERT_L1(NULL != device->readStsRegQeCmd);
    CY_ASSERT_L1(NULL != device->writeStsRegQeCmd);

    /* The command transfer width */
    device->writeStsRegQeCmd->cmdWidth = CY_SMIF_WIDTH_SINGLE;

    /* The QE mask for the status registers */
    switch (_FLD2VAL(CY_SMIF_SFDP_QE_REQUIREMENTS, (uint32_t)sfdpBuffer
        [CY_SMIF_SFDP_BFPT_BYTE_3A]))
    {
        case CY_SMIF_SFDP_QER_0:
            device->stsRegQuadEnableMask = CY_SMIF_NO_COMMAND_OR_MODE;
            device->writeStsRegQeCmd->command  = CY_SMIF_NO_COMMAND_OR_MODE;
            device->readStsRegQeCmd->command  = CY_SMIF_NO_COMMAND_OR_MODE;
#if (CY_IP_MXSMIF_VERSION>=3)
            device->writeStsRegQeCmd->cmdPresence  = CY_SMIF_NOT_PRESENT;
            device->readStsRegQeCmd->cmdPresence  = CY_SMIF_NOT_PRESENT;
#endif /* CY_IP_MXSMIF_VERSION */
            break;
        case CY_SMIF_SFDP_QER_1:
        case CY_SMIF_SFDP_QER_4:
        case CY_SMIF_SFDP_QER_5:
            device->stsRegQuadEnableMask = CY_SMIF_SFDP_QE_BIT_1_OF_SR_2;

            /* The command to write into the QE-containing status register */
            /* The 8-bit command. QE WRSR */
            device->writeStsRegQeCmd->command  = CY_SMIF_WRITE_STATUS_REG1_CMD;
            device->readStsRegQeCmd->command  = CY_SMIF_READ_STATUS_REG2_T1_CMD;
#if (CY_IP_MXSMIF_VERSION>=3)
            device->writeStsRegQeCmd->cmdPresence  = CY_SMIF_PRESENT_1BYTE;
            device->readStsRegQeCmd->cmdPresence  = CY_SMIF_PRESENT_1BYTE;
#endif /* CY_IP_MXSMIF_VERSION */
            break;
        case CY_SMIF_SFDP_QER_2:
            device->stsRegQuadEnableMask = CY_SMIF_SFDP_QE_BIT_6_OF_SR_1;

            /* The command to write into the QE-containing status register */
            /* The 8-bit command. QE WRSR */
            device->writeStsRegQeCmd->command  = CY_SMIF_WRITE_STATUS_REG1_CMD;
            device->readStsRegQeCmd->command  = CY_SMIF_READ_STATUS_REG1_CMD;
#if (CY_IP_MXSMIF_VERSION>=3)
            device->writeStsRegQeCmd->cmdPresence  = CY_SMIF_PRESENT_1BYTE;
            device->readStsRegQeCmd->cmdPresence  = CY_SMIF_PRESENT_1BYTE;
#endif /* CY_IP_MXSMIF_VERSION */
            break;
        case CY_SMIF_SFDP_QER_3:
            device->stsRegQuadEnableMask = CY_SMIF_SFDP_QE_BIT_7_OF_SR_2;

            /* The command to write into the QE-containing status register */
            /* The 8-bit command. QE WRSR */
            device->writeStsRegQeCmd->command  = CY_SMIF_WRITE_STATUS_REG2_CMD;
            device->readStsRegQeCmd->command  = CY_SMIF_READ_STATUS_REG2_T2_CMD;
#if (CY_IP_MXSMIF_VERSION>=3)
            device->writeStsRegQeCmd->cmdPresence  = CY_SMIF_PRESENT_1BYTE;
            device->readStsRegQeCmd->cmdPresence  = CY_SMIF_PRESENT_1BYTE;
#endif /* CY_IP_MXSMIF_VERSION */
            break;
        default:
            /* Unsupported quad enable requirement */
            break;
    }
}


/*******************************************************************************
* Function Name: SfdpSetChipEraseCommand
****************************************************************************//**
*
* Sets the Chip Erase command and the width of the command transfer.
*
* \param cmdChipErase
* The pointer to the Chip Erase command parameters structure.
*
*******************************************************************************/
static void SfdpSetChipEraseCommand(cy_stc_smif_mem_cmd_t* cmdChipErase)
{
    /* 8-bit command. Chip Erase */
    cmdChipErase->command  = CY_SMIF_CHIP_ERASE_CMD;
    /* The width of the command transfer */
    cmdChipErase->cmdWidth = CY_SMIF_WIDTH_SINGLE;
}


/*******************************************************************************
* Function Name: SfdpGetSectorEraseCommand
****************************************************************************//**
*
* Sets the Sector Erase command and the width of the command transfer.
*
* \note When the Erase command is not found the width of the command 
*  transfer (cmdWidth) is set to CY_SMIF_WIDTH_NA.
*
* \param device
* The device structure instance declared by the user. This is where the detected
* parameters are stored and returned.
*
* \param sfdpBuffer
* The pointer to an array with the SDFP buffer.
*
* \param eraseTypeCmd
* The pointer to an array with the erase commands for different erase types.
*
* \return The offset of the Sector Erase command in the SFDP buffer. 
*  Returns 0 when the Sector Erase command is not found.
*
*******************************************************************************/
static uint32_t SfdpGetSectorEraseCommand(cy_stc_smif_mem_device_cfg_t *device, 
                                          uint8_t const sfdpBuffer[],
                                          cy_stc_smif_erase_type_t eraseTypeStc[])
{
    uint32_t eraseOffset;
    if (FOUR_BYTE_ADDRESS == device->numOfAddrBytes)
    {
        uint32_t eraseType;     /* Erase Type decreased to 1 */
        uint32_t eraseTypeMask;

        eraseOffset = COMMAND_IS_NOT_FOUND;
        device->eraseCmd->command = CY_SMIF_NO_COMMAND_OR_MODE;

        /* Get the mask which contains the Support for Erase Commands (Types 1-4) 
         * from 4-byte Address Instruction Table, DWORD 1 
         */
        eraseTypeMask = _FLD2VAL(SUPPORT_ERASE_COMMAND, (uint32_t)sfdpBuffer[FOUR_BYTE_ADDRESS_TABLE_BYTE_1]);

        /* Find Erase Type (decreased to 1) */ 
        for (eraseType = 0UL; eraseType <= ERASE_TYPE_COUNT; eraseType++)
        {
            if ((1UL << eraseType) == (eraseTypeMask & (1UL << eraseType)))
            {
                /* Erase Type found */
                break;
            }
        }
        
        if (eraseType < ERASE_TYPE_COUNT)
        {
            /* Calculate the offset for the sector Erase command in the 4-byte Address Instruction Table, DWORD 2 */
            eraseOffset = FOUR_BYTE_ADDR_ERASE_TYPE_1 + eraseType;  

            /* Update all erase commands for 4-bytes */
            for(uint32_t i = 0UL; i< ERASE_TYPE_COUNT; i++)
            {
                eraseTypeStc[i].eraseCmd = sfdpBuffer[FOUR_BYTE_ADDR_ERASE_TYPE_1 + i];
            }
            /* Get the sector Erase command
             * from the 4-byte Address Instruction Table, DWORD 2 
             */
            device->eraseCmd->command = sfdpBuffer[eraseOffset];
#if (CY_IP_MXSMIF_VERSION>=3)
            device->eraseCmd->cmdPresence = CY_SMIF_PRESENT_1BYTE;
#endif /* CY_IP_MXSMIF_VERSION */
            
            /* Recalculate eraseOffset for the 3-byte Address Instruction Table 
             * to find the device->eraseSize and device->eraseTime parameters based on Erase Type.
             */
            eraseOffset = CY_SMIF_SFDP_BFPT_BYTE_1D + (eraseType * TYPE_STEP);
        }       
    }
    else
    {
        eraseOffset = CY_SMIF_SFDP_BFPT_BYTE_1D;
        while (INSTRUCTION_NOT_SUPPORTED == sfdpBuffer[eraseOffset])
        {
            if (eraseOffset >= CY_SMIF_SFDP_BFPT_BYTE_23)
            {
                /* The Sector Erase command is not found */
                eraseOffset = COMMAND_IS_NOT_FOUND;
                break;
            }
            eraseOffset += TYPE_STEP; /* Check the next Erase Type */
        }

        if (COMMAND_IS_NOT_FOUND != eraseOffset)
        {
            /* Get the sector Erase command from the JEDEC basic flash parameter table */
            device->eraseCmd->command = sfdpBuffer[eraseOffset];
#if (CY_IP_MXSMIF_VERSION>=3)
            device->eraseCmd->cmdPresence = CY_SMIF_PRESENT_1BYTE;
#endif /* CY_IP_MXSMIF_VERSION */
        }  
    }

    if (COMMAND_IS_NOT_FOUND != eraseOffset)
    {
        /* The command transfer width */
        device->eraseCmd->cmdWidth = CY_SMIF_WIDTH_SINGLE;

        /* The address transfer width */
        device->eraseCmd->addrWidth = CY_SMIF_WIDTH_SINGLE;
    }
    else
    {
        device->eraseCmd->cmdWidth = CY_SMIF_WIDTH_NA;
    }

    return(eraseOffset);
}


/*******************************************************************************
* Function Name: ReadAnyReg
****************************************************************************//**
*
* This function reads any registers by address. This function is a blocking 
* function, it will block the execution flow until the status register is read.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param slaveSelect
* The slave select line for the device.
*
* \param value
* The value of the register.
*
* \param command
* The command required to read the status/configuration register.
*
* \param address
* The register address array.
*
* \param addressSize
* The size of the address array.
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return A status of the command reception.
*       - \ref CY_SMIF_SUCCESS
*       - \ref CY_SMIF_CMD_FIFO_FULL
*       - \ref CY_SMIF_EXCEED_TIMEOUT
*       - \ref CY_SMIF_CMD_NOT_FOUND
*
*******************************************************************************/
static cy_en_smif_status_t ReadAnyReg(SMIF_Type *base,
                                    cy_en_smif_slave_select_t  slaveSelect,
                                    uint8_t *value,
                                    uint8_t command,
                                    uint8_t const *address,
                                    uint32_t addressSize,
                                    cy_stc_smif_context_t const *context)
{
    cy_en_smif_status_t result = CY_SMIF_CMD_NOT_FOUND;

    /* Read the memory register */
    result = Cy_SMIF_TransmitCommand(base, command, CY_SMIF_WIDTH_SINGLE,
                address, addressSize,
                CY_SMIF_WIDTH_SINGLE, slaveSelect,
                CY_SMIF_TX_NOT_LAST_BYTE, context);

    if (CY_SMIF_SUCCESS == result)
    {
        result = Cy_SMIF_ReceiveDataBlocking( base, value,
                    CY_SMIF_READ_ONE_BYTE, CY_SMIF_WIDTH_SINGLE, context);
    }

    return(result);
}


/*******************************************************************************
* Function Name: SfdpEnterFourByteAddressing
****************************************************************************//**
*
* This function sets 4-byte address mode for a memory device as defined in 
* 16th DWORD of JEDEC Basic Flash Parameter Table. 
*
* \note The entry methods which do not support the required
* operation of writing into the register.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param entryMethodByte
* The byte which defines the supported method to enter 4-byte addressing mode.
*
* \param device
* The device structure instance declared by the user. This is where the detected
* parameters are stored and returned.
*
* \param slaveSelect
* The slave select line for the device.
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return A status of 4-byte addressing mode command transmit.
*       - \ref CY_SMIF_SUCCESS
*       - \ref CY_SMIF_EXCEED_TIMEOUT
*       - \ref CY_SMIF_CMD_NOT_FOUND
*******************************************************************************/
static cy_en_smif_status_t SfdpEnterFourByteAddressing(SMIF_Type *base, uint8_t entryMethodByte, 
                                                       cy_stc_smif_mem_device_cfg_t *device,
                                                       cy_en_smif_slave_select_t slaveSelect,
                                                       cy_stc_smif_context_t const *context)
{
    cy_en_smif_status_t result = CY_SMIF_CMD_NOT_FOUND;
    if ((entryMethodByte & CY_SMIF_SFDP_ENTER_4_BYTE_METHOD_ALWAYS_4_BYTE) != 0U)
    {
        /* Memory always operates in 4-byte mode */
        result = CY_SMIF_SUCCESS;
    }
    if ((entryMethodByte & CY_SMIF_SFDP_ENTER_4_BYTE_METHOD_B7) != 0U)
    {
        if ((entryMethodByte & CY_SMIF_SFDP_ENTER_4_BYTE_METHOD_WR_EN_B7) != 0U)
        {
            /* To enter a 4-byte addressing write enable is required */
            cy_stc_smif_mem_cmd_t* writeEn = device->writeEnCmd;
            if(NULL != writeEn)
            {
                result = Cy_SMIF_TransmitCommand(base,
                                                (uint8_t) writeEn->command,
                                                writeEn->cmdWidth,
                                                NULL,
                                                CY_SMIF_CMD_WITHOUT_PARAM,
                                                CY_SMIF_WIDTH_NA,
                                                slaveSelect,
                                                CY_SMIF_TX_LAST_BYTE,
                                                context);
            }
        }
        if ((CY_SMIF_CMD_NOT_FOUND == result) || (CY_SMIF_SUCCESS == result))
        {
            /* To enter a 4-byte addressing B7 instruction is required */
            result = Cy_SMIF_TransmitCommand(base,
                                             CY_SMIF_SFDP_ENTER_4_BYTE_METHOD_B7_CMD,
                                             CY_SMIF_WIDTH_SINGLE,
                                             NULL,
                                             CY_SMIF_CMD_WITHOUT_PARAM,
                                             CY_SMIF_WIDTH_NA,
                                             slaveSelect,
                                             CY_SMIF_TX_LAST_BYTE,
                                             context);
        }
    }

    return result;
}


/*******************************************************************************
* Function Name: SfdpGetEraseSizeAndCmd
****************************************************************************//**
*
* Fills arrays with an erase size and cmd for all erase types.
*
* \param sfdpBuffer
* The pointer to an array with the Basic Flash Parameter table buffer.
*
* \param eraseTypeCmd
* The pointer to an array with the erase commands for all erase types.
*
* \param eraseTypeSize
* The pointer to an array with the erase size for all erase types.
*
*******************************************************************************/
static void SfdpGetEraseSizeAndCmd(uint8_t const sfdpBuffer[],
                                   cy_stc_smif_erase_type_t eraseType[])
{
    uint32_t idx = 0UL;
    for (uint32_t currET = 0UL; currET < ERASE_TYPE_COUNT; currET++)
    {
        /* The erase size in the SFDP buffer defined as power of two */
        eraseType[currET].eraseSize = 1UL << sfdpBuffer[CY_SMIF_SFDP_BFPT_BYTE_1C + idx];
        eraseType[currET].eraseCmd = sfdpBuffer[CY_SMIF_SFDP_BFPT_BYTE_1D + idx];
        idx += TYPE_STEP;
    }
}


/*******************************************************************************
* Function Name: SfdpPopulateRegionInfo
****************************************************************************//**
*
* Reads the current configuration for regions and populates regionInfo
* structures.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param sectorMapBuff
* The pointer to an array with the Sector Map Parameter Table buffer.
*
* \param device
* The device structure instance declared by the user. This is where the detected
* parameters are stored and returned.
*
* \param slaveSelect
* The slave select line for the device.
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \param eraseTypeSize
* The pointer to an array with the erase size for all erase types.
*
* \param eraseTypeCmd
* The pointer to an array with the erase commands for all erase types.
*
* \param eraseTypeTime
*  The pointer to an array with the erase time for all erase types.
*
* \return A status of the Sector Map Parameter Table parsing.
*       - \ref CY_SMIF_SUCCESS
*       - \ref CY_SMIF_SFDP_CORRUPTED_TABLE
*       - \ref CY_SMIF_NOT_HYBRID_MEM
*
*******************************************************************************/
static cy_en_smif_status_t SfdpPopulateRegionInfo(SMIF_Type *base,
                                   uint8_t const sectorMapBuff[],
                                   uint32_t const buffLength,
                                   cy_stc_smif_mem_device_cfg_t *device,
                                   cy_en_smif_slave_select_t slaveSelect,
                                   const cy_stc_smif_context_t *context,
                                   cy_stc_smif_erase_type_t eraseType[])
{
    uint8_t currCmd;
    uint8_t regMask;
    uint8_t regValue;
    uint8_t currRegisterAddr[ERASE_TYPE_COUNT] = {0U};
    uint8_t regionInfoIdx = 0U;
    uint32_t currTableIdx = 0UL;
    uint32_t addrBytesNum = 0UL;
    uint32_t addrCode = 0UL;
    cy_en_smif_status_t result = CY_SMIF_NOT_HYBRID_MEM;

    /* Loop across all command descriptors to find current configuration */
    while(SECTOR_MAP_COMAND_DESCRIPTOR_TYPE == (sectorMapBuff[currTableIdx] & SECTOR_MAP_DESCRIPTOR_MASK))
    {
        currCmd = sectorMapBuff[currTableIdx + CY_SMIF_SFDP_SECTOR_MAP_CMD_OFFSET];
        regMask = sectorMapBuff[currTableIdx + CY_SMIF_SFDP_SECTOR_MAP_REG_MSK_OFFSET];
        regValue = 0U;
        
        /* Get the address length for configuration detection */
        addrCode = _FLD2VAL(CY_SMIF_SFDP_SECTOR_MAP_ADDR_BYTES, sectorMapBuff[currTableIdx + CY_SMIF_SFDP_SECTOR_MAP_ADDR_CODE_OFFSET]);
        switch(addrCode) 
        {
            case CY_SMIF_SFDP_THREE_BYTES_ADDR_CODE:
                /* No address cycle */
                addrBytesNum = 0UL;
                break;
            case CY_SMIF_SFDP_THREE_OR_FOUR_BYTES_ADDR_CODE:
                addrBytesNum = CY_SMIF_THREE_BYTES_ADDR;
                break;
            case CY_SMIF_SFDP_FOUR_BYTES_ADDR_CODE:
                addrBytesNum = CY_SMIF_FOUR_BYTES_ADDR;
                break;
            default:
                /* Use the current settings */
                addrBytesNum = device->numOfAddrBytes; 
                break;
        }

        /* Get the control register address */
        for(uint32_t i = 0UL; i < addrBytesNum; i++)
        {
            /* Offset for control register in SFDP has little-endian byte order, need to swap it */
            currRegisterAddr[i] = sectorMapBuff[(currTableIdx + CY_SMIF_SFDP_SECTOR_MAP_REG_ADDR_OFFSET + addrBytesNum) - i - 1UL];
        }

        /* Read the value of the register for the current configuration detection */
        result = ReadAnyReg(base, slaveSelect, &regValue, currCmd, &currRegisterAddr[0], addrBytesNum, context);

        if (CY_SMIF_SUCCESS == result)
        {
            /* Set the bit of the region idx to 1 if the config matches */
            regionInfoIdx = ((uint8_t)(regionInfoIdx << 1U)) | (((regValue & regMask) == 0U)?(0U):(1U));
        }

        currTableIdx += HEADER_LENGTH;
        if (currTableIdx > buffLength)
        {
            result = CY_SMIF_SFDP_CORRUPTED_TABLE;
            break;
        }
    }

    if (CY_SMIF_SUCCESS == result)
    {
        /* Find the matching configuration map descriptor */
        while(regionInfoIdx != sectorMapBuff[currTableIdx + 1UL])
        {
            /* Increment the table index to the next map */
            currTableIdx += (sectorMapBuff[currTableIdx + CY_SMIF_SFDP_SECTOR_MAP_CONFIG_ID_OFFSET] + 2UL) * BYTES_IN_DWORD;
            if (currTableIdx > buffLength)
            {
                result = CY_SMIF_SFDP_CORRUPTED_TABLE;
                break;
            }
        }
    }

    if (CY_SMIF_SUCCESS == result)
    {
        /* Populate region data from the sector map */
        uint8_t numOfRegions = sectorMapBuff[currTableIdx + CY_SMIF_SFDP_SECTOR_MAP_REGION_COUNT_OFFSET] + 1U;
        device->hybridRegionCount = (uint32_t) numOfRegions;

        if(numOfRegions <= 1U)
        {
            result = CY_SMIF_NOT_HYBRID_MEM;
        }
        else
        {
            uint8_t eraseTypeCode;
            uint32_t currRegionAddr = 0UL;
            uint32_t regionSize = 0UL;
            uint8_t supportedEraseType;
            uint8_t eraseTypeMask;
            cy_stc_smif_hybrid_region_info_t *currRegionPtr;
            for(uint8_t currRegion = 0U; currRegion< numOfRegions; currRegion++)
            {
                currRegionAddr = currRegionAddr + regionSize;
                currTableIdx += BYTES_IN_DWORD;

                supportedEraseType = 0U;
                eraseTypeMask = 1U;
                eraseTypeCode = sectorMapBuff[currTableIdx] & CY_SMIF_SFDP_SECTOR_MAP_SUPPORTED_ET_MASK;
                while(0U == (eraseTypeCode & eraseTypeMask))
                {
                    /* Erase type number defined as a bit position */
                    eraseTypeMask = eraseTypeMask << 1;
                    supportedEraseType++;
                    if(supportedEraseType > ERASE_TYPE_COUNT)
                    {
                        result = CY_SMIF_SFDP_CORRUPTED_TABLE;
                        break;
                    }
                }

                /* The region size as a zero-based count of 256 byte units */
                regionSize = ((*( (uint32_t*) &sectorMapBuff[currTableIdx]) >> BITS_IN_BYTE) + 1UL) * SECTOR_MAP_REGION_SIZE_MULTIPLIER;
                CY_MISRA_BLOCK_END('MISRA C-2012 Rule 11.3');
                currRegionPtr = device->hybridRegionInfo[currRegion];

                currRegionPtr->regionAddress = currRegionAddr;
                currRegionPtr->eraseCmd = (uint32_t)eraseType[supportedEraseType].eraseCmd;
                currRegionPtr->eraseTime = eraseType[supportedEraseType].eraseTime;
                if(regionSize < eraseType[supportedEraseType].eraseSize)
                {
                    /* One region with a single sector */
                    currRegionPtr->eraseSize = regionSize;
                    currRegionPtr->sectorsCount = 1UL;
                }
                else
                {
                    currRegionPtr->eraseSize = eraseType[supportedEraseType].eraseSize;
                    currRegionPtr->sectorsCount = regionSize / eraseType[supportedEraseType].eraseSize;
                }
            }
        }
    }
    return result;
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemSfdpDetect
****************************************************************************//**
*
* This function detects the device signature for SFDP devices.
* Refer to the SFDP spec (JESD216B) for details.
* The function asks the device using an SPI and then populates the relevant
* parameters for \ref cy_stc_smif_mem_device_cfg_t.
*
* \note This function is a blocking function and blocks until the structure data
* is read and returned. This function uses \ref Cy_SMIF_TransmitCommand()
* If there is no support for SFDP in the memory device, the API returns an
* error condition. The function requires:
*   - SMIF initialized and enabled to work in the normal mode;
*   - readSfdpCmd field of \ref cy_stc_smif_mem_device_cfg_t is enabled.
*
* \note The SFDP detect takes into account the types of the SPI supported by the
* memory device and also the dataSelect option selected to choose which SPI mode
* (SPI, DSPI, QSPI) to load into the structures. The algorithm prefers
* QSPI>DSPI>SPI, provided there is support for it in the memory device and the
* dataSelect selected by the user.
*
* \note 4-byte addressing mode is set when the memory device supports 
*       3- or 4-byte addressing mode.
*
* \note When the Erase command is not found the width of the command 
*  transfer (cmdWidth) is set to CY_SMIF_WIDTH_NA. When the Program command 
*  is not found for 4 byte addressing mode the Program command instruction 
*  is set for 1S-1S-1S Protocol mode and 3-byte addressing mode.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param device
* The device structure instance declared by the user. This is where the detected
* parameters are stored and returned.
*
* \param slaveSelect
* The slave select line for the device.
*
* \param dataSelect
* The data line selection options for a slave device.
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return A status of the transmission.
*       - \ref CY_SMIF_SUCCESS
*       - \ref CY_SMIF_CMD_FIFO_FULL
*       - \ref CY_SMIF_NO_SFDP_SUPPORT
*       - \ref CY_SMIF_EXCEED_TIMEOUT
*
*******************************************************************************/
cy_en_smif_status_t Cy_SMIF_MemSfdpDetect(SMIF_Type *base,
                                    cy_stc_smif_mem_device_cfg_t *device,
                                    cy_en_smif_slave_select_t slaveSelect,
                                    cy_en_smif_data_select_t dataSelect,
                                    cy_stc_smif_context_t *context)
{
    /* Check the input parameters */
    CY_ASSERT_L1(NULL != device);
    
    uint8_t sfdpBuffer[CY_SMIF_SFDP_LENGTH];
    uint8_t sfdpAddress[CY_SMIF_SFDP_ADDRESS_LENGTH] = {0x00U, 0x00U, 0x00U};
    uint8_t addr4ByteAddress[CY_SMIF_SFDP_ADDRESS_LENGTH] = {0x00U, 0x00U, 0x00U};
    uint8_t sectorMapAddr[CY_SMIF_SFDP_ADDRESS_LENGTH] = {0x00U, 0x00U, 0x00U};
    cy_en_smif_status_t result = CY_SMIF_NO_SFDP_SUPPORT;
    cy_stc_smif_mem_cmd_t *cmdSfdp = device->readSfdpCmd;
    cy_stc_smif_erase_type_t eraseType[ERASE_TYPE_COUNT];

    /* Initialize the SFDP buffer */
    for (uint32_t i = 0U; i < CY_SMIF_SFDP_LENGTH; i++)
    {
        sfdpBuffer[i] = 0U;
    }
    
    /* Slave slot initialization */
    Cy_SMIF_SetDataSelect(base, slaveSelect, dataSelect);

    if (NULL != cmdSfdp)
    {
        /* Get the SDFP header and all parameter headers content into sfdpBuffer[] */
        CY_MISRA_DEVIATE_LINE('MISRA C-2012 Rule 18.6','Data receive is disabled after function return.');
        result = SfdpReadBuffer(base, 
                               cmdSfdp,
                               sfdpAddress,
                               slaveSelect,
                               HEADERS_LENGTH,
                               sfdpBuffer,
                               context);
    }
    
    /* Check if we support all parameter headers */
    if ((CY_SMIF_SUCCESS == result) && 
       (sfdpBuffer[PARAM_HEADERS_NUM] > PARAM_HEADER_NUM))
    {
        result = CY_SMIF_NO_SFDP_SUPPORT;
    }

    if (CY_SMIF_SUCCESS == result)
    {
        if((sfdpBuffer[CY_SMIF_SFDP_SIGNATURE_BYTE_00] == (uint8_t)'S') &&
         (sfdpBuffer[CY_SMIF_SFDP_SIGNATURE_BYTE_01] == (uint8_t)'F') &&
         (sfdpBuffer[CY_SMIF_SFDP_SIGNATURE_BYTE_02] == (uint8_t)'D') &&
         (sfdpBuffer[CY_SMIF_SFDP_SIGNATURE_BYTE_03] == (uint8_t)'P') &&
         (sfdpBuffer[CY_SMIF_SFDP_MINOR_REV] >= CY_SMIF_SFDP_JEDEC_REV_B) &&
         (sfdpBuffer[CY_SMIF_SFDP_MAJOR_REV] == CY_SMIF_SFDP_MAJOR_REV_1))
        {
            /* Find the 4-byte Address Instruction Parameter Header */
            uint32_t id = (FOUR_BYTE_ADDR_ID_MSB << BITS_IN_BYTE) | FOUR_BYTE_ADDR_ID_LSB;
            uint32_t addr4ByteTableLength = 0UL;
            result = SfdpFindParameterTableAddress(id, sfdpBuffer, addr4ByteAddress, &addr4ByteTableLength);

            /* Find the Sector Map Parameter Header */
            id = (SECTOR_MAP_ID_MSB << BITS_IN_BYTE) | SECTOR_MAP_ID_LSB;
            uint32_t sectorMapTableLength = 0UL;
            result = SfdpFindParameterTableAddress(id, sfdpBuffer, sectorMapAddr, &sectorMapTableLength);
            if (CY_SMIF_CMD_NOT_FOUND == result)
            {
                device->hybridRegionCount = 0UL;
                device->hybridRegionInfo = NULL;
            }

            /* Find the JEDEC SFDP Basic SPI Flash Parameter Header */
            id = (BASIC_SPI_ID_MSB << BITS_IN_BYTE) | BASIC_SPI_ID_LSB;
            uint32_t basicSpiTableLength = 0UL;
            result = SfdpFindParameterTableAddress(id, sfdpBuffer, sfdpAddress, &basicSpiTableLength);

            if (CY_SMIF_SUCCESS == result)
            { 
                CY_ASSERT_L1(NULL != device->readCmd);
                CY_ASSERT_L1(NULL != device->writeEnCmd);
                CY_ASSERT_L1(NULL != device->writeDisCmd);
                CY_ASSERT_L1(NULL != device->eraseCmd);
                CY_ASSERT_L1(NULL != device->chipEraseCmd);
                CY_ASSERT_L1(NULL != device->programCmd);
                CY_ASSERT_L1(NULL != device->readStsRegWipCmd);
        
                /* Get the JEDEC basic flash parameter table content into sfdpBuffer[] */
                result = SfdpReadBuffer(base,
                                       cmdSfdp,
                                       sfdpAddress,
                                       slaveSelect,
                                       basicSpiTableLength,
                                       sfdpBuffer,
                                       context);

                /* The erase size and erase time for all 4 erase types */
                SfdpGetEraseSizeAndCmd(sfdpBuffer, eraseType);

                /* The number of address bytes used by the memory slave device */
                device->numOfAddrBytes = SfdpGetNumOfAddrBytes(sfdpBuffer);

                /* The external memory size */
                device->memSize = SfdpGetMemoryDensity(sfdpBuffer);

                /* The page size */
                device->programSize = SfdpGetPageSize(sfdpBuffer);

                /* The Write Enable command */
                SfdpSetWriteEnableCommand(device->writeEnCmd);

                /* The Write Disable command */
                SfdpSetWriteDisableCommand(device->writeDisCmd); 

                /* The busy mask for the status registers */
                device->stsRegBusyMask = CY_SMIF_STATUS_REG_BUSY_MASK;

                /* The command to read the WIP-containing status register */
                SfdpSetWipStatusRegisterCommand(device->readStsRegWipCmd);

                /* The command to write into the QE-containing status register */
                SfdpGetQuadEnableParameters(device, sfdpBuffer);

                /* Chip Erase command */
                SfdpSetChipEraseCommand(device->chipEraseCmd);

                /* Chip Erase Time */
                device->chipEraseTime = SfdpGetChipEraseTime(sfdpBuffer);

                /* Page Program Time */
                device->programTime = SfdpGetPageProgramTime(sfdpBuffer);

                /* The Read command for 3-byte addressing. The preference order quad > dual > single SPI */
                cy_stc_smif_mem_cmd_t *cmdRead = device->readCmd;
                cy_en_smif_protocol_mode_t pMode = SfdpGetReadCmdParams(sfdpBuffer, dataSelect, cmdRead);
                
                /* Read, Erase, and Program commands */
                uint32_t eraseTypeOffset = 1UL;
                if (FOUR_BYTE_ADDRESS == device->numOfAddrBytes)
                {
                    /* Enter 4-byte addressing mode */
                    result = SfdpEnterFourByteAddressing(base, sfdpBuffer[CY_SMIF_SFDP_BFPT_BYTE_3C], device, slaveSelect, context);
                    uint8_t fourByteAddressBuffer[CY_SMIF_SFDP_LENGTH];
                    if (CY_SMIF_SUCCESS == result)
                    {
                        /* Get the JEDEC 4-byte Address Instruction Table content into sfdpBuffer[] */
                        result = SfdpReadBuffer(base, cmdSfdp, addr4ByteAddress, slaveSelect, 
                                                addr4ByteTableLength, fourByteAddressBuffer, context);
                    }
                    if (CY_SMIF_SUCCESS == result)
                    {
                        /* Rewrite the Read command instruction for 4-byte addressing mode */
                        SfdpGetReadFourBytesCmd(fourByteAddressBuffer, pMode, cmdRead);
                      
                        /* Get the Program command instruction for 4-byte addressing mode */
                        SfdpGetProgramFourBytesCmd(fourByteAddressBuffer, pMode, device->programCmd);
                        
                        /* Find the sector Erase command type with 4-byte addressing */
                        eraseTypeOffset = SfdpGetSectorEraseCommand(device, fourByteAddressBuffer, eraseType);
                    }
                }
                else
                {
                    /* The program command for 3-byte addressing mode */
                    SfdpSetProgramCommand_1_1_1(device->programCmd);

                    /* Find the sector Erase command type with 3-byte addressing */
                    eraseTypeOffset = SfdpGetSectorEraseCommand(device, sfdpBuffer, eraseType);
                }
                
                if (COMMAND_IS_NOT_FOUND != eraseTypeOffset)
                {
                    /* The Erase sector size (from the JEDEC basic flash parameter table) */
                    device->eraseSize = 0x01UL << sfdpBuffer[eraseTypeOffset - 1UL];

                    /* Erase Time Type (from the JEDEC basic flash parameter table) */
                    device->eraseTime = SfdpGetEraseTime(eraseTypeOffset, sfdpBuffer, eraseType);
                }

                if (NULL != device->hybridRegionInfo)
                {
                    /* Get the Sector Map Parameter Table into sfdpBuffer[] */
                    result = SfdpReadBuffer(base, cmdSfdp, sectorMapAddr, slaveSelect,
                                            sectorMapTableLength, sfdpBuffer, context);
                    if (CY_SMIF_SUCCESS == result)
                    {
                        result = SfdpPopulateRegionInfo(base, sfdpBuffer, sectorMapTableLength, device, slaveSelect, context, eraseType);
                        if(result == CY_SMIF_NOT_HYBRID_MEM)
                        {
                            device->hybridRegionCount = 0UL;
                            device->hybridRegionInfo = NULL;
                            result = CY_SMIF_SUCCESS;
                        }
                    }
                }
            }
        }
        else
        {
            result = CY_SMIF_NO_SFDP_SUPPORT;
        }
    }

    return(result);
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemIsReady
****************************************************************************//**
*
* Polls the memory device to check whether it is ready to accept new commands or
* not until either it is ready or the retries have exceeded the limit. 
* This is a blocking function, it will block the execution flow until
* the command transmission is completed.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param memConfig
* The memory device configuration.
*
* \param timeoutUs
*  The timeout value in microseconds to apply while polling the memory. 
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return The status of the operation.
* \ref CY_SMIF_SUCCESS        - Memory is ready to accept new commands.
* \ref CY_SMIF_EXCEED_TIMEOUT - Memory is busy.
*
* \funcusage 
* \snippet smif/snippet/main.c snippet_Cy_SMIF_MemIsReady
*
*******************************************************************************/
cy_en_smif_status_t Cy_SMIF_MemIsReady(SMIF_Type *base, cy_stc_smif_mem_config_t const *memConfig, 
                                       uint32_t timeoutUs, cy_stc_smif_context_t const *context)
{    
    uint32_t delayMs = 0UL;
    uint32_t timeoutSlice = 0UL;
    uint16_t delayUs = 0U;
    bool isBusy;
    
    /* Calculate the slice of time to split the timeoutUs delay into TIMEOUT_SLICE_DIV times */
    timeoutSlice = timeoutUs / TIMEOUT_SLICE_DIV; 
    
    /* Reduce the slice if needed to avoid too big idle period between checking the busy state */
    if (timeoutSlice > TIMEOUT_SLICE_MAX)
    {
        timeoutSlice = TIMEOUT_SLICE_MAX;
    }
    if(timeoutSlice == 0UL) 
    {
        timeoutSlice = 1UL;
    }

    do
    {
        delayMs = timeoutSlice / 1000UL;
        delayUs = (uint16_t) (timeoutSlice % 1000UL);

        Cy_SysLib_Rtos_Delay(delayMs);
        Cy_SysLib_Rtos_DelayUs(delayUs);

        isBusy = Cy_SMIF_Memslot_IsBusy(base, (cy_stc_smif_mem_config_t* )memConfig, context);

        timeoutUs = (timeoutUs > timeoutSlice) ? (timeoutUs - timeoutSlice) : 0UL;

    } while(isBusy && (timeoutUs > 0UL));

    return (isBusy ? CY_SMIF_EXCEED_TIMEOUT : CY_SMIF_SUCCESS);
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemIsQuadEnabled
****************************************************************************//**
*
* Checks whether the QE (Quad Enable) bit is set or not in the configuration
* register of the memory.
* This is a blocking function, it will block the execution flow until
* the command transmission is completed.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param memConfig
* The memory device configuration.
*
* \param isQuadEnabled
* This parameter is updated to indicate whether quad mode is enabled (true) or
* not (false). The value is valid only when the function returns
* CY_SMIF_SUCCESS.
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return The status of the operation. See \ref cy_en_smif_status_t.
*
* \funcusage 
* \snippet smif/snippet/main.c snippet_Cy_SMIF_MemIsQuadEnabled
*
*******************************************************************************/
cy_en_smif_status_t Cy_SMIF_MemIsQuadEnabled(SMIF_Type *base, cy_stc_smif_mem_config_t const *memConfig,
                                             bool *isQuadEnabled, cy_stc_smif_context_t const *context)
{
    cy_en_smif_status_t status;
    uint8_t readStatus = 0U;
    CY_ASSERT_L1(NULL !=  memConfig);
    uint32_t statusCmd = memConfig->deviceCfg->readStsRegQeCmd->command;
    uint8_t maskQE = (uint8_t) memConfig->deviceCfg->stsRegQuadEnableMask;

    status = Cy_SMIF_MemCmdReadStatus(base, memConfig, &readStatus, (uint8_t)statusCmd, context);

    *isQuadEnabled = false;
    if(CY_SMIF_SUCCESS == status)
    {
        /* Check whether quad mode is already enabled or not */
        *isQuadEnabled = (maskQE == (readStatus & maskQE));
    }

    return status;
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemEnableQuadMode
****************************************************************************//**
*
* Sets the QE (QUAD Enable) bit in the external memory
* configuration register to enable quad SPI mode.
* This is a blocking function, it will block the execution flow until
* the command transmission is completed.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param memConfig
* The memory device configuration.
*
* \param timeoutUs
*  The timeout value in microseconds to apply while polling the memory. 
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return The status of the operation. See \ref cy_en_smif_status_t.
*
* \funcusage 
* See \ref Cy_SMIF_MemIsQuadEnabled usage.
*
*******************************************************************************/
cy_en_smif_status_t Cy_SMIF_MemEnableQuadMode(SMIF_Type *base, cy_stc_smif_mem_config_t const *memConfig, 
                                              uint32_t timeoutUs, cy_stc_smif_context_t const *context)
{
    cy_en_smif_status_t status;

    CY_ASSERT_L1(NULL !=  memConfig);

    /* Send Write Enable to the external memory */
    status = Cy_SMIF_MemCmdWriteEnable(base, (cy_stc_smif_mem_config_t* )memConfig, context);

    if(CY_SMIF_SUCCESS == status)
    {
        status = Cy_SMIF_MemQuadEnable(base, (cy_stc_smif_mem_config_t* )memConfig, context);

        if(CY_SMIF_SUCCESS == status)
        {
            /* Poll the memory for the completion of the operation */
            status = Cy_SMIF_MemIsReady(base, memConfig, timeoutUs, context);
        }
    }

    return status;
}

/*******************************************************************************
* Function Name: ValueToByteArray
****************************************************************************//**
*
* Unpacks 0-numBytes from a 4-byte value into the byte array byteArray.
*
* \param value
*  The 4-byte value to unpack.
*
* \param byteArray
* The byte array to fill.
*
* \param startPos
* The start position of the array to begin filling from.
*
* \param size
* The size of the array.
*
*
*******************************************************************************/
static void ValueToByteArray(uint32_t value, uint8_t *byteArray, uint32_t startPos, uint32_t size)
{
    do
    {
        size--;
        byteArray[size + startPos] = (uint8_t)(value & PARAM_ID_LSB_MASK);
        value >>= PARAM_ID_MSB_OFFSET; /* Shift to get the next byte */
    } while (size > 0U);
}


/*******************************************************************************
* Function Name: ByteArrayToValue
****************************************************************************//**
*
* Packs the byte array into a single value.
*
* \param byteArray
* The byte array to unpack.
*
* \param size
* The size of the array.
*
* \return
* The 4-byte value filled from the array.
*
*
*******************************************************************************/
static uint32_t ByteArrayToValue(uint8_t const *byteArray, uint32_t size)
{
    uint32_t value = 0UL;
    uint32_t idx = 0UL;
    for (idx = 0UL; idx < size; idx++)
    {
        value <<= 8;
        value |= ((uint32_t) byteArray[idx]);
    }
    return value;
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemRead
****************************************************************************//**
*
* Reads data from the external memory and blocks until the read
* transfer is complete or a timeout occurs.
* This is a blocking function, it will block the execution flow until
* the command transmission is completed.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param memConfig
* The memory device configuration.
*
* \param address
* The address to read data from.
*
* \param rxBuffer
* The buffer for storing the read data.
*
* \param length
* The size of data to read.
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return The status of the operation. See \ref cy_en_smif_status_t.
*
* \funcusage 
* \snippet smif/snippet/main.c snippet_Cy_SMIF_MemRead
*
*******************************************************************************/
cy_en_smif_status_t Cy_SMIF_MemRead(SMIF_Type *base, cy_stc_smif_mem_config_t const *memConfig, 
                                    uint32_t address, uint8_t rxBuffer[], 
                                    uint32_t length, cy_stc_smif_context_t const *context)
{
    cy_en_smif_status_t status = CY_SMIF_BAD_PARAM;
    uint32_t chunk = 0UL;
    uint8_t addrArray[CY_SMIF_FOUR_BYTES_ADDR] = {0U};
    cy_stc_smif_mem_cmd_t *cmdRead;

    CY_ASSERT_L1(NULL != memConfig);
    CY_ASSERT_L1(NULL != rxBuffer);

    cmdRead = memConfig->deviceCfg->readCmd;

    if((address + length) <= memConfig->deviceCfg->memSize)  /* Check if the address exceeds the memory size */
    {
        /* SMIF can read only up to 65536 bytes in one go. Split the larger read into multiple chunks */
        while (length > 0UL)
        {
            /* Get the number of bytes which can be read during one operation */
            chunk = (length > SMIF_MAX_RX_COUNT) ? (SMIF_MAX_RX_COUNT) : length;
            ValueToByteArray(address, &addrArray[0], 0UL,
                             memConfig->deviceCfg->numOfAddrBytes);

#if (CY_IP_MXSMIF_VERSION>=3)
            status = Cy_SMIF_TransmitCommand_Ext(base,
                                             (uint16_t)(cmdRead->command | cmdRead->commandH << 8),
                                             cmdRead->commandH ? true:false,
                                             cmdRead->cmdWidth,
                                             cmdRead->cmdRate,
                                             (const uint8_t *)addrArray,
                                             memConfig->deviceCfg->numOfAddrBytes,
                                             cmdRead->addrWidth,
                                             cmdRead->addrRate,
                                             memConfig->slaveSelect,
                                             CY_SMIF_TX_NOT_LAST_BYTE,
                                             context);

            if((CY_SMIF_SUCCESS == status) && (CY_SMIF_NO_COMMAND_OR_MODE != cmdRead->mode))
            {
                status = Cy_SMIF_TransmitCommand_Ext(base,
                                                 (uint16_t)cmdRead->mode,
                                                 false,
                                                 cmdRead->modeWidth,
                                                 cmdRead->modeRate,
                                                 CY_SMIF_CMD_WITHOUT_PARAM,
                                                 CY_SMIF_CMD_WITHOUT_PARAM,
                                                 CY_SMIF_WIDTH_NA,
                                                 cmdRead->modeRate,
                                                 memConfig->slaveSelect,
                                                 CY_SMIF_TX_NOT_LAST_BYTE,
                                                 context);
            }

            if((CY_SMIF_SUCCESS == status) && (0U < cmdRead->dummyCycles))
            {
                status = Cy_SMIF_SendDummyCycles_Ext(base, cmdRead->dataWidth, cmdRead->dataRate, cmdRead->dummyCycles);
            }

            if(CY_SMIF_SUCCESS == status)
            {
                 status = Cy_SMIF_ReceiveDataBlocking_Ext(base,
                                            rxBuffer,
                                            chunk,
                                            cmdRead->dataWidth,
                                            cmdRead->dataRate,
                                            context);
            }
#else
            status = Cy_SMIF_TransmitCommand(base,
                                                (uint8_t)cmdRead->command,
                                                cmdRead->cmdWidth,
                                                (const uint8_t *)addrArray,
                                                memConfig->deviceCfg->numOfAddrBytes,
                                                cmdRead->addrWidth,
                                                memConfig->slaveSelect,
                                                CY_SMIF_TX_NOT_LAST_BYTE,
                                                context);

            if((CY_SMIF_SUCCESS == status) && (CY_SMIF_NO_COMMAND_OR_MODE != cmdRead->mode))
            {
                status = Cy_SMIF_TransmitCommand(base,
                                                    (uint8_t)cmdRead->mode,
                                                    cmdRead->modeWidth,
                                                    NULL,
                                                    CY_SMIF_CMD_WITHOUT_PARAM,
                                                    CY_SMIF_WIDTH_NA,
                                                    memConfig->slaveSelect,
                                                    CY_SMIF_TX_NOT_LAST_BYTE,
                                                    context);
            }

            if((CY_SMIF_SUCCESS == status) && (0U < cmdRead->dummyCycles))
            {
                status = Cy_SMIF_SendDummyCycles(base, cmdRead->dummyCycles);
            }

            if(CY_SMIF_SUCCESS == status)
            {
                    status = Cy_SMIF_ReceiveDataBlocking(base,
                                            rxBuffer,
                                            chunk,
                                            cmdRead->dataWidth,
                                            context);
            }
#endif /* CY_IP_MXSMIF_VERSION */

            if(CY_SMIF_SUCCESS != status)
            {
                break;  
            }
   
            /* Recalculate the next rxBuffer offset */
            length -= chunk;
            address += chunk;
            rxBuffer = (uint8_t *)rxBuffer + chunk;
        }  
    }

    return status;
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemWrite
****************************************************************************//**
*
* This function writes data to the external memory.
* This is a blocking function, it will block the execution flow until
* the command transmission is completed.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param memConfig
* The memory device configuration.
*
* \param address
* The address to write data at.
*
* \param txBuffer
* The buffer holding the data to write in the external memory.
*
* \param length
* The size of data to write.
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return The status of the operation. See \ref cy_en_smif_status_t.
*
* \funcusage 
* \snippet smif/snippet/main.c snippet_Cy_SMIF_MemWrite
*
*******************************************************************************/
cy_en_smif_status_t Cy_SMIF_MemWrite(SMIF_Type *base, cy_stc_smif_mem_config_t const *memConfig, 
                                     uint32_t address, uint8_t const txBuffer[], 
                                     uint32_t length, cy_stc_smif_context_t const *context)
{
    cy_en_smif_status_t status = CY_SMIF_BAD_PARAM;
    uint32_t offset = 0UL;
    uint32_t chunk = 0UL;
    uint32_t pageSize; 
    uint8_t addrArray[CY_SMIF_FOUR_BYTES_ADDR] = {0U};
    cy_stc_smif_mem_cmd_t *cmdProgram;

    CY_ASSERT_L1(NULL != memConfig);
    CY_ASSERT_L1(NULL != txBuffer);

    pageSize = memConfig->deviceCfg->programSize; /* Get the page size */
    cmdProgram = memConfig->deviceCfg->programCmd; /* Get the program command */

    if((address + length) <= memConfig->deviceCfg->memSize)  /* Check if the address exceeds the memory size */
    {
        /* SMIF can read only up to 65536 bytes in one go. Split the larger read into multiple chunks */
        while (length > 0UL)
        {
            /* Get the number of bytes which can be written during one operation */
            offset = address % pageSize; 
            chunk = ((offset + length) < pageSize) ? length : (pageSize - offset);

            /* The Write Enable bit may be cleared by the memory after every successful
             * operation of write or erase operations. Therefore, must be set for
             * every loop. 
             */
            status = Cy_SMIF_MemCmdWriteEnable(base, memConfig, context);

            if(CY_SMIF_SUCCESS == status)
            {
                ValueToByteArray(address, &addrArray[0], 0UL,
                                 memConfig->deviceCfg->numOfAddrBytes);

                status = Cy_SMIF_TransmitCommand(base,
                                                 (uint8_t)cmdProgram->command,
                                                 cmdProgram->cmdWidth,
                                                 (const uint8_t *)addrArray,
                                                 memConfig->deviceCfg->numOfAddrBytes,
                                                 cmdProgram->addrWidth,
                                                 memConfig->slaveSelect,
                                                 CY_SMIF_TX_NOT_LAST_BYTE,
                                                 context);

                if((CY_SMIF_SUCCESS == status) && (CY_SMIF_NO_COMMAND_OR_MODE != cmdProgram->mode))
                {
                    status = Cy_SMIF_TransmitCommand(base,
                                                     (uint8_t)cmdProgram->mode,
                                                     cmdProgram->modeWidth,
                                                     NULL,
                                                     CY_SMIF_CMD_WITHOUT_PARAM,
                                                     CY_SMIF_WIDTH_NA,
                                                     memConfig->slaveSelect,
                                                     CY_SMIF_TX_NOT_LAST_BYTE,
                                                     context);
                }

                if((CY_SMIF_SUCCESS == status) && (cmdProgram->dummyCycles > 0U))
                {
                    status = Cy_SMIF_SendDummyCycles(base, cmdProgram->dummyCycles);
                }

                if(CY_SMIF_SUCCESS == status)
                {
                    status = Cy_SMIF_TransmitDataBlocking(base,
                                                         (uint8_t *)txBuffer,
                                                         chunk,
                                                         cmdProgram->dataWidth,
                                                         context);
                }
                    
                if(CY_SMIF_SUCCESS == status)
                {
                    /* Check if the memory has completed the write operation. ProgramTime is in microseconds */
                    status = Cy_SMIF_MemIsReady(base, memConfig, memConfig->deviceCfg->programTime, context);
                }
                    }

            if(CY_SMIF_SUCCESS != status)
            {
                break;  
            }

            /* Recalculate the next rxBuffer offset */
            txBuffer = (uint8_t *)txBuffer + chunk;
            address += chunk;
            length -= chunk;
        }
    }

    return status;
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemEraseSector
****************************************************************************//**
*
* Erases a block/sector of the external memory.
* This is a blocking function, it will block the execution flow until
* the command transmission is completed.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param memConfig
* The memory device configuration.
*
* \param address
* The address of the block to be erased. The address should be aligned with 
* the start address of the sector.
*
* \param length
* The size of data to erase. The length should be equal to the sum of all sectors
* length to be erased. Otherwise, API returns \ref CY_SMIF_BAD_PARAM without
* performing erase operation.
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return The status of the operation. See \ref cy_en_smif_status_t.
*
* \note Memories like hybrid have sectors of different sizes. \n
* Check the adress and length parameters before calling this function.
*
* \funcusage 
* \snippet smif/snippet/main.c snippet_Cy_SMIF_MemEraseSector
*
*******************************************************************************/
cy_en_smif_status_t Cy_SMIF_MemEraseSector(SMIF_Type *base, cy_stc_smif_mem_config_t const *memConfig,
                                           uint32_t address, uint32_t length,
                                           cy_stc_smif_context_t const *context)
{
    cy_en_smif_status_t status = CY_SMIF_SUCCESS;
    uint32_t endAddress = address + length - 1UL;
    uint32_t eraseEnd = 0UL;
    uint32_t hybridRegionStart = 0UL;
    uint8_t addrArray[CY_SMIF_FOUR_BYTES_ADDR] = {0U};
    cy_stc_smif_hybrid_region_info_t* hybrInfo = NULL;
    CY_ASSERT_L1(NULL != memConfig);
    cy_stc_smif_mem_device_cfg_t *device = memConfig->deviceCfg;
    uint32_t eraseSectorSize = device->eraseSize;
    uint32_t maxEraseTime = device->eraseTime;

    /* Check if the address exceeds the memory size */
    if (endAddress < device->memSize)
    {
        /* In case of hybrid memory - update sector size and offset for first sector */
        status = Cy_SMIF_MemLocateHybridRegion(memConfig, &hybrInfo, address);
        if (CY_SMIF_SUCCESS == status)
        {
            hybridRegionStart = hybrInfo->regionAddress;
            eraseSectorSize = hybrInfo->eraseSize;
            eraseEnd = (hybrInfo->sectorsCount * eraseSectorSize) + hybridRegionStart - 1UL;
        }

        /* Check if the length is less than sector size */
        if(length < eraseSectorSize)
        {
            status = CY_SMIF_BAD_PARAM;
        }
    }
    else
    {
        status = CY_SMIF_BAD_PARAM;
    }

    /* Check if the start address and the sector size are aligned */
    if((status != CY_SMIF_BAD_PARAM) && (0UL == ((address - hybridRegionStart) % eraseSectorSize)))
    {
        /* If the memory is hybrid and there is more than one region to
         * erase - update the sector size and offset for the last sector */
        if(endAddress > eraseEnd)
        {
            status = Cy_SMIF_MemLocateHybridRegion(memConfig, &hybrInfo, endAddress);
            if (CY_SMIF_SUCCESS == status)
            {
                hybridRegionStart = hybrInfo->regionAddress;
                eraseSectorSize = hybrInfo->eraseSize;
            }
        }

        /* Check if the end address and the sector size are aligned */
        if((status != CY_SMIF_BAD_PARAM) && (0UL == ((endAddress - hybridRegionStart + 1UL) % eraseSectorSize)))
        {
            while(length > 0UL)
            {
                /* In case of hybrid memory - update erase size and time for current region */
                status = Cy_SMIF_MemLocateHybridRegion(memConfig, &hybrInfo, address);
                if (CY_SMIF_SUCCESS == status)
                {
                    maxEraseTime =  hybrInfo->eraseTime;
                    eraseSectorSize = hybrInfo->eraseSize;
                    hybridRegionStart = hybrInfo->regionAddress;
                    eraseEnd = (hybrInfo->sectorsCount * eraseSectorSize) + hybridRegionStart - 1UL;
                    if(endAddress < eraseEnd)
                    {
                        eraseEnd = endAddress;
                    }
                }
                else
                {
                    eraseEnd = endAddress;
                }

                while (address < eraseEnd)
                {
                    /* The Write Enable bit may be cleared by the memory after every successful
                    * operation of write/erase operations. Therefore, it must be set for
                    * every loop.
                    */
                    status = Cy_SMIF_MemCmdWriteEnable(base, memConfig, context);
                    if(CY_SMIF_SUCCESS == status)
                    {
                        ValueToByteArray(address, &addrArray[0], 0UL, device->numOfAddrBytes);

                        /* Send the command to erase one sector */
                        status = Cy_SMIF_MemCmdSectorErase(base, (cy_stc_smif_mem_config_t* )memConfig,
                                                           (const uint8_t *)addrArray, context);
                        if(CY_SMIF_SUCCESS == status)
                        {
                            /* Wait until the erase operation is completed or a timeout occurs.
                             * Note: eraseTime is in milliseconds */
                            status = Cy_SMIF_MemIsReady(base, memConfig, (maxEraseTime * ONE_MILLI_IN_MICRO), context);

                            /* Recalculate the next sector address offset */
                            if(length > eraseSectorSize)
                            {
                                address += eraseSectorSize;
                                length -= eraseSectorSize;
                            }
                            else
                            {
                                length = 0;
                                break;
                            }
                        }
                    }

                    if(CY_SMIF_SUCCESS != status)
                    {
                        break;
                    }
                }
            }
        }
        else
        {
            /* The end address and the sector size are not aligned */
            status = CY_SMIF_BAD_PARAM;
        }
    }
    else
    {
        /* The start address and the sector size are not aligned */
        status = CY_SMIF_BAD_PARAM;
    }

    return status;
}


/*******************************************************************************
* Function Name: Cy_SMIF_MemEraseChip
****************************************************************************//**
*
* Erases the entire chip of the external memory.
* This is a blocking function, it will block the execution flow until
* the command transmission is completed.
*
* \param base
* Holds the base address of the SMIF block registers.
*
* \param memConfig
* The memory device configuration.
*
* \param context
* This is the pointer to the context structure \ref cy_stc_smif_context_t
* allocated by the user. The structure is used during the SMIF
* operation for internal configuration and data retention. The user must not
* modify anything in this structure.
*
* \return The status of the operation. See \ref cy_en_smif_status_t.
*
* \funcusage 
* \snippet smif/snippet/main.c snippet_Cy_SMIF_MemEraseChip
*
*******************************************************************************/
cy_en_smif_status_t Cy_SMIF_MemEraseChip(SMIF_Type *base, cy_stc_smif_mem_config_t const *memConfig,
                                         cy_stc_smif_context_t const *context)
{
    cy_en_smif_status_t status;

    CY_ASSERT_L1(NULL != memConfig);

    /* The Write Enable bit may be cleared by the memory after every successful
    * operation of write/erase operations. Therefore, it must be set for
    * every loop 
    */
    status = Cy_SMIF_MemCmdWriteEnable(base, memConfig, context);

    if(CY_SMIF_SUCCESS == status)
    {
        /* Send the command to erase the entire chip */
        status = Cy_SMIF_MemCmdChipErase(base, memConfig, context);
        
        if(CY_SMIF_SUCCESS == status)
        {
            /* Wait until the erase operation is completed or a timeout occurs. chipEraseTime is in milliseconds */
            status = Cy_SMIF_MemIsReady(base, memConfig, 
                     (memConfig->deviceCfg->chipEraseTime * ONE_MILLI_IN_MICRO), context);   
        }
    }

    return status;
}

#if defined(__cplusplus)
}
#endif

#endif /* CY_IP_MXSMIF */

/* [] END OF FILE */