/* $Id: xflash_intel.c,v 1.8 2003/05/13 20:11:22 robertm Exp $ */
/******************************************************************************
*
*       XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
*       AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
*       SOLUTIONS FOR XILINX DEVICES.  BY PROVIDING THIS DESIGN, CODE,
*       OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
*       APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
*       THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
*       AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
*       FOR YOUR IMPLEMENTATION.  XILINX EXPRESSLY DISCLAIMS ANY
*       WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
*       IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
*       REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
*       INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*       FOR A PARTICULAR PURPOSE.
*
*       (c) Copyright 2002 Xilinx Inc.
*       All rights reserved.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xflash_intel.c
*
* The implementation of the Intel CFI Version of the XFlash component.
*
* This module utilizes the XFlash base component, whose attributes have been
* defined mostly from a CFI data query. This data is used to define the geometry
* of the part(s), timeout values for write & erase operations, and optional
* features.
*
* @note
*
* - Special consideration has to be given to varying data bus widths. To boost
*   performance, multiple devices in parallel on the data bus are accessed in
*   parallel. Therefore to reduce complexity and increase performance, many
*   local primitive functions are duplicated with the only difference being
*   the width of writes to the devices.
*   <br><br>
*   Even with the performance boosting optimizations, the overhead associated
*   with this component is rather high due to the general purpose nature of its
*   design.
*   <br><br>
*   Flash block erasing is a time consuming operation with nearly all latency
*   occuring due to the devices' themselves. It takes on the order of 1 second
*   to erase each block.
*   <br><br>
*   Writes by comparison are much quicker so driver overhead becomes an issue.
*   The write algorithm has been optimized for bulk data programming and should
*   provide relatively better performance.
* - The code/comments refers to WSM frequently. This stands for Write State
*   Machine. WSM is the internal programming engine of the devices.
* - This driver and the underlying Intel flash memory does not allow re-
*   programming while code is executing from the same memory.
* - If hardware is flakey or fails, then this driver could hang a thread of
*   execution.
* - This module has some dependencies on whether it is being unit tested. These
*   areas are noted with conditional compilation based on whether XENV_UNITTEST
*   is defined. This is required because unit testing occurs without real flash
*   devices.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver   Who  Date     Changes
* ----- ---- -------- -----------------------------------------------
* 1.00a rmm  07/16/01 First release
* 1.00a rmm  03/14/02 Added 64 bit array support
* 1.00a rmm  05/13/03 Fixed diab compiler warnings relating to asserts.
* </pre>
*
******************************************************************************/

/***************************** Include Files *********************************/
#include "xflash_intel.h"
#include "xflash_intel_l.h"
#include "xflash_cfi.h"
#include "xflash_geometry.h"
#include "xenv.h"

/************************** Constant Definitions *****************************/


/**************************** Type Definitions *******************************/

/*
 * Define a single type used to access the status register irregardless of the
 * width of the devices
 */
typedef union
{
    Xuint8  Mask8;
    Xuint16 Mask16;
    Xuint32 Mask32;
    Xuint64 Mask64;
} StatReg;

/*
 * Define intel specific data to be part of the instance. This structure will
 * overlay the XFlash_PartData structure attribute of the base class.
 */
typedef struct XFlashVendorData_IntelTag
{
    Xuint32 WriteBufferWordCount; /* This value is written to the WSM when
                                     telling it how many words will be
                                     programmed (always will be the maximum
                                     allowed) */
    volatile StatReg *SR_Ptr;           /* Address of the status register(s) */
    StatReg SR_WsmReady;       /* Status register bitmask for WSM ready */
    StatReg SR_LastError;      /* Status register bitmask for error condition */

    /*
     * The following functions are specific to the width of the data bus and
     * will be assigned during initialization.
     *
     * SendCmd - Writes a single command to the devices.
     * SendCmdSeq - Writes two commands in successive bus cycles to the
     *   devices.
     * WriteBuffer - Programming algorithm optimized to perform bulk writes
     *   to devices.
     * GetStatus - Retrieve and interpret the status registers of the devices
     * PollSR - Poll the status register of the devices until the WSM signals
     *   ready.
     */
    void    (*SendCmd)(Xuint32 BaseAddr, Xuint32 Offset, Xuint32 Cmd);
    void    (*SendCmdSeq)(Xuint32 BaseAddr, Xuint32 Offset,
                          Xuint32 Cmd1, Xuint32 Cmd2);

    XStatus (*WriteBuffer)(XFlash *InstancePtr, void* DestPtr,
                           void *SrcPtr, Xuint32 Bytes);

    XStatus (*GetStatus)(struct XFlashVendorData_IntelTag *DevDataPtr);
    XStatus (*PollSR)(struct XFlashVendorData_IntelTag *DevDataPtr);

} XFlashVendorData_Intel;

/***************** Macros (Inline Functions) Definitions *********************/

/*
 *  GET_PARTDATA - Type safe way to convert the base component VendorData type
 *  to the derived VendorData_Intel type.
 *
 *  Macro signature:
 *
 *    XFlashVendorData_Intel *GET_PARTDATA(XFlash_PartData *BaseComponent)
 */
#define GET_PARTDATA(BaseComponent) \
    ((XFlashVendorData_Intel*)&((BaseComponent)->VendorData))


/************************** Function Prototypes ******************************/
static void SendCmd16(Xuint32 BaseAddr, Xuint32 Offset, Xuint32 Cmd);
static void SendCmd32(Xuint32 BaseAddr, Xuint32 Offset, Xuint32 Cmd);
static void SendCmd64(Xuint32 BaseAddr, Xuint32 Offset, Xuint32 Cmd);

static void SendCmdSeq16(Xuint32 BaseAddr, Xuint32 Offset, Xuint32 Cmd1,
                         Xuint32 Cmd2);
static void SendCmdSeq32(Xuint32 BaseAddr, Xuint32 Offset, Xuint32 Cmd1,
                         Xuint32 Cmd2);
static void SendCmdSeq64(Xuint32 BaseAddr, Xuint32 Offset, Xuint32 Cmd1,
                         Xuint32 Cmd2);

static XStatus GetStatus16(XFlashVendorData_Intel* DevDataPtr);
static XStatus GetStatus32(XFlashVendorData_Intel* DevDataPtr);
static XStatus GetStatus64(XFlashVendorData_Intel* DevDataPtr);

static XStatus WriteBuffer16(XFlash *InstancePtr, void* DestPtr,
                             void *SrcPtr, Xuint32 Bytes);
static XStatus WriteBuffer32(XFlash *InstancePtr, void* DestPtr,
                             void *SrcPtr, Xuint32 Bytes);
static XStatus WriteBuffer64(XFlash *InstancePtr, void* DestPtr,
                             void *SrcPtr, Xuint32 Bytes);

static XStatus PollSR16(struct XFlashVendorData_IntelTag *DevDataPtr);
static XStatus PollSR32(struct XFlashVendorData_IntelTag *DevDataPtr);
static XStatus PollSR64(struct XFlashVendorData_IntelTag *DevDataPtr);

static XStatus SetRYBY(XFlash *InstancePtr, Xuint32 Mode);
static void    GetPartID(XFlash *InstancePtr);

static Xuint16 EnqueueEraseBlocks(XFlash *InstancePtr, Xuint16 *RegionPtr,
                                  Xuint16 *BlockPtr, Xuint16 MaxBlocks);

/************************** Variable Definitions *****************************/


/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @param InstancePtr is a pointer to the flash instance to be worked on.
*
* @return
*
* - XST_SUCCESS if successful
* - XST_FLASH_PART_NOT_SUPPORTED if the part is not supported
*
* @note
*
* Two geometry attributes MUST be defined prior to invoking this function:
*   - BaseAddress
*   - MemoryLayout
*
******************************************************************************/
XStatus XFlashIntel_Initialize(XFlash *InstancePtr)
{
    XFlashVendorData_Intel *DevDataPtr;
    Xuint32 Layout;
    int BusWidthBytes;

    XASSERT_NONVOID(InstancePtr != XNULL);

    /*
     * Grab layout and get Vendor specific part information
     */
    Layout = InstancePtr->Geometry.MemoryLayout;
    DevDataPtr = GET_PARTDATA(InstancePtr);

    /*
     * For intel parts, the status register can be accessed from any addressible
     * location, so we pick the base address.
     */
    DevDataPtr->SR_Ptr = (StatReg*)InstancePtr->Geometry.BaseAddress;

    /*
     * Setup alignment of the write buffer
     */
    InstancePtr->Properties.ProgCap.WriteBufferAlignmentMask =
        InstancePtr->Properties.ProgCap.WriteBufferSize - 1;


    /*
     * Setup layout dependent attributes. These include:
     *   - Part access primitive functions optimized for a specific bus width.
     *   - SR_WsmRead.MaskX is set according to the SR_WSM_READY constant
     *     defined as 0x80. We don't use that constant here because it is
     *     simpler to define with a magic number rather than use complex masks
     *     and shifting operations.
     */
    switch (Layout)
    {
        case XFL_LAYOUT_X16_X16_X1:
            DevDataPtr->SR_WsmReady.Mask16 = 0x0080;
            DevDataPtr->GetStatus = GetStatus16;
            DevDataPtr->SendCmd = SendCmd16;
            DevDataPtr->SendCmdSeq = SendCmdSeq16;
            DevDataPtr->PollSR = PollSR16;
            DevDataPtr->WriteBuffer = WriteBuffer16;
            break;

        case XFL_LAYOUT_X16_X16_X2:
            DevDataPtr->SR_WsmReady.Mask32 = 0x00800080;
            DevDataPtr->GetStatus = GetStatus32;
            DevDataPtr->SendCmd = SendCmd32;
            DevDataPtr->SendCmdSeq = SendCmdSeq32;
            DevDataPtr->PollSR = PollSR32;
            DevDataPtr->WriteBuffer = WriteBuffer32;
            break;

        case XFL_LAYOUT_X16_X16_X4:
            DevDataPtr->SR_WsmReady.Mask32 = 0x00800080;
            DevDataPtr->GetStatus = GetStatus64;
            DevDataPtr->SendCmd = SendCmd64;
            DevDataPtr->SendCmdSeq = SendCmdSeq64;
            DevDataPtr->PollSR = PollSR64;
            DevDataPtr->WriteBuffer = WriteBuffer64;
            break;

        default:
            return (XST_FLASH_PART_NOT_SUPPORTED);
    }

    /*
     * Calculate datum written during a buffer write that tells the buffer
     * how many words are going to be written to the buffer. This value is based
     * on ProgCap.WriteBufferSize which was taken from the standard CFI query at
     * offset 2Ah. Dividing this value by the width of the data bus gives us
     * the maximum number of writes to the buffer per Intel literature.
     *
     * Once calculated, replicate the data on all nibbles just like
     * XFL_INTEL_CMD_* constants.
     */
    BusWidthBytes = (Layout & XFL_LAYOUT_NUM_PARTS_MASK) *
        ((Layout & XFL_LAYOUT_PART_WIDTH_MASK) >> 16);
    DevDataPtr->WriteBufferWordCount =
        (InstancePtr->Properties.ProgCap.WriteBufferSize / BusWidthBytes) - 1;
    DevDataPtr->WriteBufferWordCount |= (DevDataPtr->WriteBufferWordCount << 8);
    DevDataPtr->WriteBufferWordCount |= (DevDataPtr->WriteBufferWordCount << 16);
    DevDataPtr->WriteBufferWordCount |= (DevDataPtr->WriteBufferWordCount << 24);

    /*
     * Get part ID.
     * Reset the part
     */
    GetPartID(InstancePtr);
    XFlashIntel_Reset(InstancePtr);

    /*
     * Zero out error data and return
     */
    XUINT64_MSW(DevDataPtr->SR_LastError.Mask64) = 0;
    XUINT64_LSW(DevDataPtr->SR_LastError.Mask64) = 0;

    return (XST_SUCCESS);
}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* The part is assumed to be in read-array mode.
*
******************************************************************************/
XStatus XFlashIntel_ReadBlock(XFlash *InstancePtr, Xuint16 Region, Xuint16 Block,
                               Xuint32 Offset, Xuint32 Bytes, void* DestPtr)
{
    Xuint32 PartOffset;
    XStatus Status;

    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(DestPtr != XNULL);

    /*
     * Convert to absolute coordinates. This also verifies that the block
     * coordinates given are within the device
     */
    Status = XFlashGeometry_ToAbsolute(&InstancePtr->Geometry, Region,
                                       Block, Offset, &PartOffset);
    if (Status != XST_SUCCESS)
    {
        return (XST_FLASH_ADDRESS_ERROR);
    }

    /*
     * Perform copy
     */
    XENV_MEM_COPY(DestPtr,
                  (void*)(InstancePtr->Geometry.BaseAddress + PartOffset),
                  Bytes);

    return (XST_SUCCESS);
}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlashIntel_WriteBlock(XFlash *InstancePtr, Xuint16 Region, Xuint16 Block,
                                Xuint32 Offset, Xuint32 Bytes, void* SrcPtr)
{
    XFlashVendorData_Intel *DevDataPtr;
    XStatus Status;
    void    *PhysicalFlashAddress;
    Xuint32 PartOffset;

    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(SrcPtr != XNULL);

    /*
     * Nothing specified to be programmed
     */
    if (Bytes == 0)
    {
        return(XST_SUCCESS);
    }

    /*
     * Convertion to absolute coordinates. The call also verifies the
     * starting address is within the part
     */
    Status = XFlashGeometry_ToAbsolute(&InstancePtr->Geometry, Region, Block,
                                       Offset, &PartOffset);
    if (Status != XST_SUCCESS)
    {
        return (XST_FLASH_ADDRESS_ERROR);
    }

    /*
     * Verify the ending address is within the part
     */
    if (!XFL_GEOMETRY_IS_ABSOLUTE_VALID(&InstancePtr->Geometry, PartOffset +
                                        Bytes - 1))
    {
        return (XST_FLASH_ADDRESS_ERROR);
    }

    /*
     * Call the proper write buffer function
     */
    DevDataPtr = GET_PARTDATA(InstancePtr);
    PhysicalFlashAddress =
        (void*)(InstancePtr->Geometry.BaseAddress + PartOffset);

    Status = DevDataPtr->WriteBuffer(InstancePtr, PhysicalFlashAddress,
                                     SrcPtr, Bytes);
    /*
     * Reset the part and return
     */
    XFlashIntel_Reset(InstancePtr);
    return (Status);

}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* Region, Block, & Offset parameters are ignored.
* <br><br>
* Intel flash does not differentiate RESUME between erase and write. It
* depends on what the flash was doing at the time the SUSPEND command was
* issued.
*
******************************************************************************/
XStatus XFlashIntel_WriteBlockSuspend(XFlash *InstancePtr, Xuint16 Region,
                                      Xuint16 Block, Xuint32 Offset)
{
    XFlashVendorData_Intel *DevDataPtr;

    XASSERT_NONVOID(InstancePtr != XNULL);

    DevDataPtr = GET_PARTDATA(InstancePtr);
    DevDataPtr->SendCmd(InstancePtr->Geometry.BaseAddress, 0,
                        XFL_INTEL_CMD_SUSPEND);

    return (XST_SUCCESS);
}


/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* Region, Block, & Offset parameters are ignored.
* <br><br>
* Intel flash does not differentiate RESUME between erase and write. It
* depends on what the flash was doing at the time the SUSPEND command was
* issued.
*
******************************************************************************/
XStatus XFlashIntel_WriteBlockResume(XFlash *InstancePtr, Xuint16 Region,
                                     Xuint16 Block, Xuint32 Offset)
{
    XFlashVendorData_Intel *DevDataPtr;

    XASSERT_NONVOID(InstancePtr != XNULL);

    DevDataPtr = GET_PARTDATA(InstancePtr);
    DevDataPtr->SendCmd(InstancePtr->Geometry.BaseAddress, 0,
                        XFL_INTEL_CMD_RESUME);
    return (XST_SUCCESS);
}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlashIntel_EraseBlock(XFlash *InstancePtr, Xuint16 Region,
                                Xuint16 Block, Xuint16 NumBlocks)
{
    Xuint16 BlocksLeft, BlocksQueued;
    XFlashGeometry *Geom;
    XFlashVendorData_Intel *DevDataPtr;
    XStatus Status = XST_SUCCESS;

    XASSERT_NONVOID(InstancePtr != XNULL);

    Geom = &InstancePtr->Geometry;

    /*
     * Verify the starting block coordinates are valid
     */
    if (!XFL_GEOMETRY_IS_BLOCK_VALID(Geom, Region, Block, 0))
    {
        return (XST_FLASH_ADDRESS_ERROR);
    }

    /*
     * Verify the number of blocks to be erased doesn't go past the end of
     * the device's address space
     */
    if (NumBlocks > XFL_GEOMETRY_BLOCKS_LEFT(Geom, Region, Block))
    {
        return (XST_FLASH_ADDRESS_ERROR);
    }

    /*
     * Erase loop. Queue up as many blocks at a time until all are erased
     */
    DevDataPtr = GET_PARTDATA(InstancePtr);
    BlocksLeft = NumBlocks;

    while (BlocksLeft > 0)
    {
        BlocksQueued = EnqueueEraseBlocks(InstancePtr, &Region, &Block,
                                          BlocksLeft);
        BlocksLeft -= BlocksQueued;

        Status = DevDataPtr->PollSR(DevDataPtr);
        if (Status != XST_FLASH_READY)
        {
            XFlashIntel_Reset(InstancePtr);
            return (Status);
        }
    }

    /*
     * Reset the part and return
     */
    XFlashIntel_Reset(InstancePtr);
    return (XST_SUCCESS);
}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* Region & Block parameters are ignored.
* <br><br>
* Intel flash does not differentiate RESUME between erase and write. It
* depends on what the flash was doing at the time the SUSPEND command was
* issued.
*
******************************************************************************/
XStatus XFlashIntel_EraseBlockSuspend(XFlash *InstancePtr, Xuint16 Region,
                                      Xuint16 Block)
{
    XFlashVendorData_Intel *DevDataPtr;

    XASSERT_NONVOID(InstancePtr != XNULL);

    DevDataPtr = GET_PARTDATA(InstancePtr);
    DevDataPtr->SendCmd(InstancePtr->Geometry.BaseAddress, 0,
                        XFL_INTEL_CMD_SUSPEND);

    return (XST_SUCCESS);
}


/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* Region & Block parameters are ignored.
* <br><br>
* Intel flash does not differentiate RESUME between erase and write. It
* depends on what the flash was doing at the time the SUSPEND command was
* issued.
*
******************************************************************************/
XStatus XFlashIntel_EraseBlockResume(XFlash *InstancePtr, Xuint16 Region,
                                     Xuint16 Block)
{
    XFlashVendorData_Intel *DevDataPtr;

    XASSERT_NONVOID(InstancePtr != XNULL);

    DevDataPtr = GET_PARTDATA(InstancePtr);
    DevDataPtr->SendCmd(InstancePtr->Geometry.BaseAddress, 0,
                        XFL_INTEL_CMD_RESUME);

    return (XST_SUCCESS);
}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlashIntel_LockBlock(XFlash *InstancePtr, Xuint16 Region,
                               Xuint16 Block, Xuint16 NumBlocks)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    return (XST_FLASH_NOT_SUPPORTED);
}


/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlashIntel_UnlockBlock(XFlash *InstancePtr, Xuint16 Region,
                                 Xuint16 Block, Xuint16 NumBlocks)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    return (XST_FLASH_NOT_SUPPORTED);
}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* The Region & Block parameters are not used because the device's status
* register appears at every addressible location.
*
******************************************************************************/
XStatus XFlashIntel_GetBlockStatus(XFlash *InstancePtr, Xuint16 Region,
                                   Xuint16 Block)
{
    XFlashVendorData_Intel *DevDataPtr;
    XStatus Status;

    XASSERT_NONVOID(InstancePtr != XNULL);

    DevDataPtr = GET_PARTDATA(InstancePtr);

    DevDataPtr->SendCmd(InstancePtr->Geometry.BaseAddress, 8,
                        XFL_INTEL_CMD_READ_STATUS_REG);
    Status = DevDataPtr->GetStatus(DevDataPtr);
    DevDataPtr->SendCmd(InstancePtr->Geometry.BaseAddress, 8,
                        XFL_INTEL_CMD_READ_ARRAY);
    return (Status);
}


/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlashIntel_Read(XFlash *InstancePtr, Xuint32 Offset, Xuint32 Bytes,
                         void* DestPtr)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(DestPtr != XNULL);

    /*
     * Check to make shure start address is within the device
     */
    if (!XFL_GEOMETRY_IS_ABSOLUTE_VALID(&InstancePtr->Geometry, Offset))
    {
        return (XST_FLASH_ADDRESS_ERROR);
    }

    /*
     * Perform copy
     */
    XENV_MEM_COPY(DestPtr, (void*)(InstancePtr->Geometry.BaseAddress + Offset),
                  Bytes);

    return (XST_SUCCESS);
}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlashIntel_Write(XFlash *InstancePtr, Xuint32 Offset, Xuint32 Bytes,
                          void* SrcPtr)
{
    XFlashVendorData_Intel *DevDataPtr;
    XStatus Status;

    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(SrcPtr != XNULL);

    /*
     * Nothing specified to be programmed
     */
    if (Bytes == 0)
    {
        return(XST_SUCCESS);
    }

    /*
     * Verify the address range is within the part
     */
    if (!XFL_GEOMETRY_IS_ABSOLUTE_VALID(&InstancePtr->Geometry, Offset) ||
        !XFL_GEOMETRY_IS_ABSOLUTE_VALID(&InstancePtr->Geometry, Offset + Bytes - 1))
    {
        return (XST_FLASH_ADDRESS_ERROR);
    }

    /*
     * Call the proper write buffer function
     */
    DevDataPtr = GET_PARTDATA(InstancePtr);
    Status = DevDataPtr->WriteBuffer(InstancePtr, (void*)
                                     (InstancePtr->Geometry.BaseAddress + Offset),
                                     SrcPtr, Bytes);

    /*
     * Reset the part and return
     */
    XFlashIntel_Reset(InstancePtr);
    return (Status);
}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* Offset parameter is ignored.
* <br><br>
* Intel flash does not differentiate RESUME between erase and write. It
* depends on what the flash was doing at the time the SUSPEND command was
* issued.
*
******************************************************************************/
XStatus XFlashIntel_WriteSuspend(XFlash *InstancePtr, Xuint32 Offset)
{
    XFlashVendorData_Intel *DevDataPtr;

    XASSERT_NONVOID(InstancePtr != XNULL);

    DevDataPtr = GET_PARTDATA(InstancePtr);
    DevDataPtr->SendCmd(InstancePtr->Geometry.BaseAddress, 0,
                        XFL_INTEL_CMD_SUSPEND);

    return (XST_SUCCESS);
}


/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* Offset parameter is ignored.
* <br><br>
* Intel flash does not differentiate RESUME between erase and write. It
* depends on what the flash was doing at the time the SUSPEND command was
* issued.
*
******************************************************************************/
XStatus XFlashIntel_WriteResume(XFlash *InstancePtr, Xuint32 Offset)
{
    XFlashVendorData_Intel *DevDataPtr;

    XASSERT_NONVOID(InstancePtr != XNULL);

    DevDataPtr = GET_PARTDATA(InstancePtr);
    DevDataPtr->SendCmd(InstancePtr->Geometry.BaseAddress, 0,
                        XFL_INTEL_CMD_RESUME);

    return (XST_SUCCESS);
}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlashIntel_Erase(XFlash *InstancePtr, Xuint32 Offset, Xuint32 Bytes)
{
    Xuint16 StartRegion, EndRegion;
    Xuint16 StartBlock, EndBlock;
    Xint16 BlocksLeft, BlocksQueued;
    Xuint32 Dummy;
    XFlashGeometry *GeomPtr;
    XFlashVendorData_Intel *DevDataPtr;
    XStatus Status;

    XASSERT_NONVOID(InstancePtr != XNULL);

    GeomPtr = &InstancePtr->Geometry;

    /*
     * Handle case when zero bytes is provided
     */
    if (Bytes == 0)
    {
        return (XST_SUCCESS);
    }

    /*
     * Convert the starting address to block coordinates. This also verifies
     * the starting address is within the instance's address space
     */
    Status = XFlashGeometry_ToBlock(GeomPtr, Offset, &StartRegion, &StartBlock,
                                    &Dummy);
    if (Status != XST_SUCCESS)
    {
        return (XST_FLASH_ADDRESS_ERROR);
    }

    /*
     * Convert the ending address to block coordinates. This also verifies
     * the ending address is within the instance's address space
     */
    Status = XFlashGeometry_ToBlock(GeomPtr, Offset + Bytes - 1, &EndRegion,
                                    &EndBlock, &Dummy);
    if (Status != XST_SUCCESS)
    {
        return (XST_FLASH_ADDRESS_ERROR);
    }

    /*
     * Erase loop. Queue up as many blocks at a time until all are erased
     */
    DevDataPtr = GET_PARTDATA(InstancePtr);
    BlocksLeft = XFL_GEOMETRY_BLOCK_DIFF(GeomPtr, StartRegion, StartBlock,
                                         EndRegion, EndBlock);

    while (BlocksLeft > 0)
    {
        BlocksQueued = EnqueueEraseBlocks(InstancePtr, &StartRegion, &StartBlock,
                                          BlocksLeft);
        BlocksLeft -= BlocksQueued;

        Status = DevDataPtr->PollSR(DevDataPtr);
        if (Status != XST_FLASH_READY)
        {
            XFlashIntel_Reset(InstancePtr);
            return (Status);
        }
    }

    /*
     * Reset the part and return
     */
    XFlashIntel_Reset(InstancePtr);
    return (XST_SUCCESS);
}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* Offset parameter is ignored.
* <br><br>
* Intel flash does not differentiate RESUME between erase and write. It
* depends on what the flash was doing at the time the SUSPEND command was
* issued.
*
******************************************************************************/
XStatus XFlashIntel_EraseSuspend(XFlash *InstancePtr, Xuint32 Offset)
{
    XFlashVendorData_Intel *DevDataPtr;

    XASSERT_NONVOID(InstancePtr != XNULL);

    DevDataPtr = GET_PARTDATA(InstancePtr);
    DevDataPtr->SendCmd(InstancePtr->Geometry.BaseAddress, 0,
                        XFL_INTEL_CMD_SUSPEND);

    return (XST_SUCCESS);
}


/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* Offset parameter is ignored.
* <br><br>
* Intel flash does not differentiate RESUME between erase and write. It
* depends on what the flash was doing at the time the SUSPEND command was
* issued.
*
******************************************************************************/
XStatus XFlashIntel_EraseResume(XFlash *InstancePtr, Xuint32 Offset)
{
    XFlashVendorData_Intel *DevDataPtr;

    XASSERT_NONVOID(InstancePtr != XNULL);

    DevDataPtr = GET_PARTDATA(InstancePtr);
    DevDataPtr->SendCmd(InstancePtr->Geometry.BaseAddress, 0,
                        XFL_INTEL_CMD_RESUME);
    return (XST_SUCCESS);
}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlashIntel_Lock(XFlash *InstancePtr, Xuint32 Offset, Xuint32 Bytes)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    return (XST_FLASH_NOT_SUPPORTED);
}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlashIntel_Unlock(XFlash *InstancePtr, Xuint32 Offset, Xuint32 Bytes)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    return (XST_FLASH_NOT_SUPPORTED);
}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* The Offset parameter is not used because the device's status register
* appears at every addressible location.
*
******************************************************************************/
XStatus XFlashIntel_GetStatus(XFlash *InstancePtr, Xuint32 Offset)
{
    XFlashVendorData_Intel *DevDataPtr;
    XStatus Status;

    XASSERT_NONVOID(InstancePtr != XNULL);

    DevDataPtr = GET_PARTDATA(InstancePtr);

    DevDataPtr->SendCmd(InstancePtr->Geometry.BaseAddress, 8,
                        XFL_INTEL_CMD_READ_STATUS_REG);
    Status = DevDataPtr->GetStatus(DevDataPtr);
    DevDataPtr->SendCmd(InstancePtr->Geometry.BaseAddress, 8,
                        XFL_INTEL_CMD_READ_ARRAY);

    return (Status);
}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlashIntel_EraseChip(XFlash *InstancePtr)
{
    XASSERT_NONVOID(InstancePtr != XNULL);

    return (XST_FLASH_NOT_SUPPORTED);
}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlashIntel_SelfTest(XFlash *InstancePtr)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    return (XST_FLASH_NOT_SUPPORTED);
}


/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlashIntel_Reset(XFlash *InstancePtr)
{
    XFlashVendorData_Intel* DevDataPtr;
    XStatus Status;

    XASSERT_NONVOID(InstancePtr != XNULL);

    DevDataPtr = GET_PARTDATA(InstancePtr);

    /*
     * Send the clear status register command. Use the max write width to
     * notify parts of all layouts
     */
    DevDataPtr->SendCmd(InstancePtr->Geometry.BaseAddress, 8,
                        XFL_INTEL_CMD_CLEAR_STATUS_REG);
    DevDataPtr->SendCmd(InstancePtr->Geometry.BaseAddress, 8,
                        XFL_INTEL_CMD_READ_STATUS_REG);

    /*
     * Sample the status of the parts, then place them into read-array
     * mode
     */
    Status = DevDataPtr->GetStatus(DevDataPtr);
    DevDataPtr->SendCmd(InstancePtr->Geometry.BaseAddress, 8,
                        XFL_INTEL_CMD_READ_ARRAY);

    /*
     * If the status is not ready, then something is wrong
     */
    if (Status != XST_FLASH_READY)
    {
        if (Status != XST_FLASH_BUSY)
        {
            return (XST_FLASH_ERROR);
        }
        else
        {
            return (XST_FLASH_BUSY);
        }
    }

    /*
     * Flash is reset and in read-array mode
     */
    return (XST_SUCCESS);
}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlashIntel_SetOptions(XFlash *InstancePtr, Xuint32 OptionsFlag)
{
    XASSERT_NONVOID(InstancePtr != XNULL);

    if (OptionsFlag &
        (XFL_NON_BLOCKING_ERASE_OPTION | XFL_NON_BLOCKING_WRITE_OPTION))
    {
        return(XST_FLASH_NOT_SUPPORTED);
    }

    InstancePtr->Options = OptionsFlag;
    return (XST_SUCCESS);
}


/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* None.
*
******************************************************************************/
Xuint32 XFlashIntel_GetOptions(XFlash *InstancePtr)
{
    XASSERT_NONVOID(InstancePtr != XNULL);

    return (InstancePtr->Options);
}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* None.
*
******************************************************************************/
XFlashGeometry *XFlashIntel_GetGeometry(XFlash *InstancePtr)
{
    XASSERT_NONVOID(InstancePtr != XNULL);

    return (&InstancePtr->Geometry);
}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* None.
*
******************************************************************************/
XFlashProperties *XFlashIntel_GetProperties(XFlash *InstancePtr)
{
    XASSERT_NONVOID(InstancePtr != XNULL);

    return (&InstancePtr->Properties);
}

/*****************************************************************************/
/**
*
* See the base component for a description of this function, its return
* values, and arguments.
*
* @note
*
* Intel specific commands:
*
* <pre>
* Command: XFL_INTEL_DEVCTL_SET_RYBY
*   Description:
*     Set the mode of the RYBY signal.
*
*   Param:
*     One of XFL_INTEL_RYBY_PULSE_OFF, XFL_INTEL_RYBY_PULSE_ON_ERASE,
*     XFL_INTEL_RYBY_PULSE_ON_PROG, XFL_INTEL_RYBY_PULSE_ON_ERASE_PROG
*
*   Return:
*     None
*
* Command: XFL_INTEL_DEVCTL_GET_LAST_ERROR
*   Description:
*     Retrieve the last error condition. The data is in the form of the
*     status register(s) read from the device(s) at the time the error
*     was detected. The registers are formatted verbatim as they are
*     seen on the data bus.
*
*   Param:
*     None
*
*   Return:
*     The contents of the Status registers at the time the last error was
*     detected.
* </pre>
*
******************************************************************************/
XStatus XFlashIntel_DeviceControl(XFlash *InstancePtr, Xuint32 Command,
                                  Xuint32 Param, Xuint32 *ReturnPtr)
{
    XStatus Status;
    XFlashVendorData_Intel *DevDataPtr;
    XASSERT_NONVOID(InstancePtr != XNULL);

    DevDataPtr = GET_PARTDATA(InstancePtr);

    switch (Command)
    {
        case XFL_INTEL_DEVCTL_GET_LAST_ERROR:
            XASSERT_NONVOID(ReturnPtr != XNULL);
            *ReturnPtr = DevDataPtr->SR_LastError.Mask32;
            return (XST_SUCCESS);

        case XFL_INTEL_DEVCTL_SET_RYBY:
            if (InstancePtr->Properties.PartID.CommandSet !=
                XFL_CMDSET_INTEL_EXTENDED)
            {
                return (XST_FLASH_NOT_SUPPORTED);
            }

            Status = SetRYBY(InstancePtr, Param);
            return (Status);

        default:
            return (XST_FLASH_NOT_SUPPORTED);
    }
}

/*****************************************************************************/
/**
*
* Retrieves and interprets status register data from part arrays that occupy a
* 16-bit bus.
*
* @param    DevDataPtr contains necessary information for accessing the status regs.
*
* @return
*
* See XFlash_GetStatus()
*
* @note
*
* No attempt is made to determine the exact cause of an error. Instead that
* determination is left up to the user.
*
******************************************************************************/
static XStatus GetStatus16(XFlashVendorData_Intel* DevDataPtr)
{
    Xuint16 RegData;

    /*
     * Sample the register(s)
     */
    RegData = READ_FLASH_16(&DevDataPtr->SR_Ptr->Mask16);

    /*
     * First, determine if the device(s) are ready without errors indicated
     */
    if (RegData == DevDataPtr->SR_WsmReady.Mask16)
    {
        return (XST_FLASH_READY);
    }

    /*
     * Next, determine if the device(s) are still busy
     */
    if ((RegData & DevDataPtr->SR_WsmReady.Mask16) !=
        DevDataPtr->SR_WsmReady.Mask16)
    {
        return (XST_FLASH_BUSY);
    }

    /*
     * If control reaches this point, then an error is pending. Copy the
     * entire set of registers to the SR_LastError attribute.
     */
    DevDataPtr->SR_LastError.Mask16 = RegData;
    return (XST_FLASH_ERROR);
}

/*****************************************************************************/
/**
*
* Retrieves and interprets status register data from part arrays that occupy a
* 32-bit bus.
*
* @param    DevDataPtr contains necessary information for accessing the status regs.
*
* @return
*
* See XFlash_GetStatus()
*
* @note
*
* No attempt is made to determine the exact cause of an error. Instead that
* determination is left up to the user.
*
******************************************************************************/
static XStatus GetStatus32(XFlashVendorData_Intel* DevDataPtr)
{
    Xuint32 RegData;

    /*
     * Sample the register(s)
     */
    RegData = READ_FLASH_32(&DevDataPtr->SR_Ptr->Mask32);

    /*
     * First, determine if the device(s) are ready without errors indicated
     */
    if (RegData == DevDataPtr->SR_WsmReady.Mask32)
    {
        return (XST_FLASH_READY);
    }

    /*
     * Next, determine if the device(s) are still busy
     */
    if ((RegData & DevDataPtr->SR_WsmReady.Mask32) !=
        DevDataPtr->SR_WsmReady.Mask32)
    {
        return (XST_FLASH_BUSY);
    }

    /*
     * If control reaches this point, then an error is pending. Copy the
     * entire set of registers to the SR_LastError attribute.
     */
    DevDataPtr->SR_LastError.Mask32 = RegData;
    return (XST_FLASH_ERROR);
}

/*****************************************************************************/
/**
*
* Retrieves and interprets status register data from part arrays that occupy a
* 64-bit bus.
*
* @param    DevDataPtr contains necessary information for accessing the status regs.
*
* @return
*
* See XFlash_GetStatus()
*
* @note
*
* No attempt is made to determine the exact cause of an error. Instead that
* determination is left up to the user.
*
******************************************************************************/
static XStatus GetStatus64(XFlashVendorData_Intel* DevDataPtr)
{
    Xuint64 RegData;

    /*
     * Sample the status register(s) and OR the 32 bit halves together
     */
    READ_FLASH_64(&DevDataPtr->SR_Ptr->Mask64, RegData);

    /*
     * First, determine if the device(s) are ready without errors indicated
     */
    if ((XUINT64_MSW(RegData) == DevDataPtr->SR_WsmReady.Mask32) &&
        (XUINT64_LSW(RegData) == DevDataPtr->SR_WsmReady.Mask32))
    {
        return (XST_FLASH_READY);
    }

    /*
     * Next, determine if the device(s) are still busy
     */
    if (((XUINT64_MSW(RegData) & DevDataPtr->SR_WsmReady.Mask32) !=
         DevDataPtr->SR_WsmReady.Mask32) &&
        ((XUINT64_LSW(RegData) & DevDataPtr->SR_WsmReady.Mask32) !=
         DevDataPtr->SR_WsmReady.Mask32))
    {
        return (XST_FLASH_BUSY);
    }

    /*
     * If control reaches this point, then an error is pending. Copy the
     * entire set of registers to the SR_LastError attribute.
     */
    XUINT64_MSW(DevDataPtr->SR_LastError.Mask64) = XUINT64_MSW(RegData);
    XUINT64_LSW(DevDataPtr->SR_LastError.Mask64) = XUINT64_LSW(RegData);
    return (XST_FLASH_ERROR);
}


/*****************************************************************************/
/**
*
* Polls the status register until the WSM is ready. The
* device(s) are polled by repeatedly reading the status register.
*
* @param    DevDataPtr contains necessary information for accessing the status regs.
*
* @return
*
* - XST_FLASH_READY if WSM is ready.
* - XST_FLASH_ERROR if WSM is ready, but an error condition exists.
*
* @note
*
* It is assumed that the status register is currently visible.
*
******************************************************************************/
static XStatus PollSR16(struct XFlashVendorData_IntelTag *DevDataPtr)
{
    Xuint16 StatusReg;
    Xuint16 ReadyMask;

    /*
     * Wait until WSM indicates that it is complete
     */
    ReadyMask = DevDataPtr->SR_WsmReady.Mask16;
    StatusReg = READ_FLASH_16(&DevDataPtr->SR_Ptr->Mask16);
    while ((StatusReg & ReadyMask) != ReadyMask)
    {
        StatusReg = READ_FLASH_16(&DevDataPtr->SR_Ptr->Mask16);
    }

    /*
     * WSM is ready, see if an error bit is set.
     */
    if (StatusReg != ReadyMask)
    {
        DevDataPtr->SR_LastError.Mask16 = StatusReg;
        return (XST_FLASH_ERROR);
    }
    else
    {
        return (XST_FLASH_READY);
    }
}

/*****************************************************************************/
/**
*
* Polls the status register until the WSM is ready. The
* device(s) are polled by repeatedly reading the status register.
*
* @param    DevDataPtr contains necessary information for accessing the status regs.
*
* @return
*
* - XST_FLASH_READY if WSM is ready.
* - XST_FLASH_ERROR if WSM is ready, but an error condition exists.
*
* @note
*
* It is assumed that the status register is currently visible.
*
******************************************************************************/
static XStatus PollSR32(struct XFlashVendorData_IntelTag *DevDataPtr)
{
    Xuint32 StatusReg;
    Xuint32 ReadyMask;

    /*
     * Wait until WSM indicates that it is complete
     */
    ReadyMask = DevDataPtr->SR_WsmReady.Mask32;
    StatusReg = READ_FLASH_32(&DevDataPtr->SR_Ptr->Mask32);
    while ((StatusReg & ReadyMask) != ReadyMask)
    {
        StatusReg = READ_FLASH_32(&DevDataPtr->SR_Ptr->Mask32);
    }

    /*
     * WSM is ready, see if an error bit is set.
     */
    if (StatusReg != ReadyMask)
    {
        DevDataPtr->SR_LastError.Mask32 = StatusReg;
        return (XST_FLASH_ERROR);
    }
    else
    {
        return (XST_FLASH_READY);
    }
}


/*****************************************************************************/
/**
*
* Polls the status register until the WSM is ready. The
* device(s) are polled by repeatedly reading the status register.
*
* @param    DevDataPtr contains necessary information for accessing the status regs.
*
* @return
*
* - XST_FLASH_READY if WSM is ready.
* - XST_FLASH_ERROR if WSM is ready, but an error condition exists.
*
* @note
*
* It is assumed that the status register is currently visible.
*
******************************************************************************/
static XStatus PollSR64(struct XFlashVendorData_IntelTag *DevDataPtr)
{
    Xuint64 StatusReg;
    Xuint32 ReadyMask;

    /*
     * Wait until WSM indicates that it is complete
     */
    ReadyMask = DevDataPtr->SR_WsmReady.Mask32;
    READ_FLASH_64(&DevDataPtr->SR_Ptr->Mask64, StatusReg);
    while (((XUINT64_MSW(StatusReg) & ReadyMask) != ReadyMask) ||
           ((XUINT64_LSW(StatusReg) & ReadyMask) != ReadyMask))
    {
        READ_FLASH_64(&DevDataPtr->SR_Ptr->Mask64, StatusReg);
    }

    /*
     * WSM is ready, see if an error bit is set.
     */
    if ((XUINT64_MSW(StatusReg) != ReadyMask) ||
        (XUINT64_LSW(StatusReg) != ReadyMask))
    {
        XUINT64_MSW(DevDataPtr->SR_LastError.Mask64) = XUINT64_MSW(StatusReg);
        XUINT64_LSW(DevDataPtr->SR_LastError.Mask64) = XUINT64_LSW(StatusReg);
        return (XST_FLASH_ERROR);
    }
    else
    {
        return (XST_FLASH_READY);
    }
}


/*****************************************************************************/
/**
*
* Writes a command using a 16-bit bus cycle
*
* @param    BaseAddress is the base address of device
* @param    Offset is the offset into device
* @param    Cmd is the command/data to write at BaseAddress + Offset
*
* @return
*
* None.
*
* @note
*
* None.
*
******************************************************************************/
static void SendCmd16(Xuint32 BaseAddress, Xuint32 Offset, Xuint32 Cmd)
{
    WRITE_FLASH_16(BaseAddress + Offset, Cmd);
}


/*****************************************************************************/
/**
*
* Writes a command using a 32-bit bus cycle
*
* @param    BaseAddress is the base address of device
* @param    Offset is the offset into device
* @param    Cmd is the command/data to write at BaseAddress + Offset
*
* @return
*
* None.
*
* @note
*
* None.
*
******************************************************************************/
static void SendCmd32(Xuint32 BaseAddress, Xuint32 Offset, Xuint32 Cmd)
{
    WRITE_FLASH_32(BaseAddress + Offset, Cmd);
}

/*****************************************************************************/
/**
*
* Writes a command using a 64-bit bus cycle. Depending on the architecture,
* this may be a single write or two 32 bit writes.
*
* @param    BaseAddress is the base address of device
* @param    Offset is the offset into device
* @param    Cmd is the command/data to write at BaseAddress + Offset
*
* @return
*
* None.
*
* @note
*
* None.
*
******************************************************************************/
static void SendCmd64(Xuint32 BaseAddress, Xuint32 Offset, Xuint32 Cmd)
{
    WRITE_FLASH_64x2(BaseAddress + Offset, Cmd, Cmd);
}

/*****************************************************************************/
/**
*
* Writes a command sequence using 16-bit bus cycles
*
* @param    BaseAddress is the base address of device
* @param    Offset is the offset into device
* @param    Cmd1 is the first command to write at BaseAddress + Offset
* @param    Cmd2 is the second command to write at BaseAddress + Offset
*
* @return
*
* None.
*
* @note
*
* None.
*
******************************************************************************/
static void SendCmdSeq16(Xuint32 BaseAddress, Xuint32 Offset, Xuint32 Cmd1,
                         Xuint32 Cmd2)
{
    WRITE_FLASH_16(BaseAddress + Offset, Cmd1);
    WRITE_FLASH_16(BaseAddress + Offset, Cmd2);
}


/*****************************************************************************/
/**
*
* Writes a command sequence using 32-bit bus cycles
*
* @param    BaseAddress is the base address of device
* @param    Offset is the offset into device
* @param    Cmd1 is the first command to write at BaseAddress + Offset
* @param    Cmd2 is the second command to write at BaseAddress + Offset
*
* @return
*
* None.
*
* @note
*
* None.
*
******************************************************************************/
static void SendCmdSeq32(Xuint32 BaseAddress, Xuint32 Offset, Xuint32 Cmd1,
                         Xuint32 Cmd2)
{
    WRITE_FLASH_32(BaseAddress + Offset, Cmd1);
    WRITE_FLASH_32(BaseAddress + Offset, Cmd2);
}

/*****************************************************************************/
/**
*
* Writes a command sequence using 64-bit bus cycles. Depending on the
* architecture, this may be a single write or two 32 bit writes.
*
* @param    BaseAddress is the base address of device
* @param    Offset is the offset into device
* @param    Cmd1 is the first command to write at BaseAddress + Offset
* @param    Cmd2 is the second command to write at BaseAddress + Offset
*
* @return
*
* None.
*
* @note
*
* None.
*
******************************************************************************/
static void SendCmdSeq64(Xuint32 BaseAddress, Xuint32 Offset, Xuint32 Cmd1,
                         Xuint32 Cmd2)
{
    WRITE_FLASH_64x2(BaseAddress + Offset, Cmd1, Cmd1);
    WRITE_FLASH_64x2(BaseAddress + Offset, Cmd2, Cmd2);
}


/*****************************************************************************/
/**
*
* Program the device(s) using the faster write to buffer mechanism. The
* device(s) are programmed in parallel.
*
* @param    InstancePtr is the instance to work on
* @param    DestPtr is the physical destination address in flash memory space
* @param    SrcPtr is the source data
* @param    Bytes is the number of bytes to program
*
* @return
*
* See XFlash_Write()
*
* @note
*
* This algorithm programs only full buffers at a time and must take care
* of the following situations:
*   - Partial first buffer programming with pre and/or post padding required.
*   - Multiple full buffer programming.
*   - Partial last buffer programming with post padding.
* <br><br>
* When padding, 0xFF is written to each byte to be padded. This in effect does
* nothing to the current contents of the flash memory and saves us from having
* to merge real flash data with user data on partial buffer writes.
* <br><br>
* If hardware is failing, then this routine could get stuck in an endless loop.
*
******************************************************************************/
static XStatus WriteBuffer16(XFlash *InstancePtr, void* DestPtr,
                             void *SrcPtr, Xuint32 Bytes)
{
    XFlashVendorData_Intel* DevDataPtr;
    Xuint16 *SrcWordPtr = SrcPtr;
    Xuint16 *DestWordPtr = DestPtr;
    Xuint16 StatusReg;
    Xuint16 ReadyMask;
    Xuint32 BytesLeft = Bytes;
    Xuint32 PartialBytes;
    Xuint8  Count;
    XStatus Status= XST_SUCCESS;
    int i;

    DevDataPtr = GET_PARTDATA(InstancePtr);
    ReadyMask = DevDataPtr->SR_WsmReady.Mask16;

    /*
     * Make sure DestPtr and SrcPtr are aligned to a 16-bit word
     */
    if (((int)SrcWordPtr & 1) || ((int)DestWordPtr & 1))
    {
        return(XST_FLASH_ALIGNMENT_ERROR);
    }

    /*
     * Determine if a partial first buffer must be programmed
     */
    PartialBytes = (Xuint32)DestWordPtr &
        InstancePtr->Properties.ProgCap.WriteBufferAlignmentMask;

    /*
     * This write cycle programs the first partial write buffer
     */
    if (PartialBytes)
    {
        /*
         * Backup DestWord to the beginning of a buffer alignment area
         * Count is the number of write cycles left after pre-filling
         * the write buffer with 0xFFFF
         */
        DestWordPtr = (void*)((Xuint32)DestWordPtr - PartialBytes);
        Count = InstancePtr->Properties.ProgCap.WriteBufferSize >> 1;

        /*
         * Send command to write buffer. Wait for buffer to become available.
         * Write number of words to be written (always the maximum)
         */
        WRITE_FLASH_16(DestWordPtr, XFL_INTEL_CMD_WRITE_BUFFER);
        StatusReg = READ_FLASH_16(DestWordPtr);
        while ((StatusReg & ReadyMask) != ReadyMask)
        {
            StatusReg = READ_FLASH_16(DestWordPtr);
        }
        WRITE_FLASH_16(DestWordPtr, DevDataPtr->WriteBufferWordCount);

        /*
         * Write 0xFFFF padding until we get to the start of the original
         * DestWord
         */
        while (PartialBytes > 1)
        {
            WRITE_FLASH_16(DestWordPtr++, 0xFFFF);
            PartialBytes -= 2;
            Count--;
        }

        /*
         * Write the remainder of this write buffer
         */
        i = 0;
        while (Count--)
        {
            /* Full word */
            if (BytesLeft > 1)
            {
                WRITE_FLASH_16(&DestWordPtr[i], SrcWordPtr[i]);
                BytesLeft -= 2;
            }

            /* End of SrcWords */
            else if (BytesLeft == 0)
            {
                WRITE_FLASH_16(&DestWordPtr[i], 0xFFFF);
            }

            /* Partial word */
            else  /* BytesLeft == 1 */
            {
                WRITE_FLASH_16(&DestWordPtr[i], 0x00FF | SrcWordPtr[i]);
                BytesLeft--;
            }
            i++;
        }

        /*
         * Buffer write completed. Send confirmation command and wait for completion
         */
#ifdef XENV_UNITTEST
        Status = DevDataPtr->PollSR(DevDataPtr);
#else
        WRITE_FLASH_16(DestWordPtr, XFL_INTEL_CMD_CONFIRM);
        Status = PollSR16(DevDataPtr);
#endif
        if (Status != XST_FLASH_READY)
        {
            return (Status);
        }

        /*
         * Increment source and destination to next buffer
         */
        SrcWordPtr += i;
        DestWordPtr += i;
    }

    /*
     * At this point DestWordPtr and SrcWordPtr are aligned to a write buffer
     * boundary. The next batch of writes utilize write cycles full of
     * SrcData
     */
    Count = InstancePtr->Properties.ProgCap.WriteBufferSize >> 1;
    while (BytesLeft > InstancePtr->Properties.ProgCap.WriteBufferSize)
    {
        /*
         * Send command to write buffer. Wait for buffer to become available.
         * Write number of words to be written (always the maximum)
         */
        WRITE_FLASH_16(DestWordPtr, XFL_INTEL_CMD_WRITE_BUFFER);
        StatusReg = READ_FLASH_16(DestWordPtr);
        while ((StatusReg & ReadyMask) != ReadyMask)
        {
            StatusReg = READ_FLASH_16(DestWordPtr);
        }
        WRITE_FLASH_16(DestWordPtr, DevDataPtr->WriteBufferWordCount);

        /*
         * Fill the buffer
         */
        for (i=0; i<Count; i++)
        {
            WRITE_FLASH_16(&DestWordPtr[i], SrcWordPtr[i]);
            BytesLeft -= 2;
        }

        /*
         * Send confirmation and wait for status
         */
#ifdef XENV_UNITTEST
        Status = DevDataPtr->PollSR(DevDataPtr);
#else
        WRITE_FLASH_16(DestWordPtr, XFL_INTEL_CMD_CONFIRM);
        Status = PollSR16(DevDataPtr);
#endif
        if (Status != XST_FLASH_READY)
        {
            return (Status);
        }

        /*
         * Increment source and destination
         */
        SrcWordPtr += Count;
        DestWordPtr += Count;
    }

    /*
     * The last phase is to write a partial last buffer
     */
    if (BytesLeft)
    {
        /*
         * Send command to write buffer. Wait for buffer to become available.
         * Write number of words to be written (always the maximum)
         */
        WRITE_FLASH_16(DestWordPtr, XFL_INTEL_CMD_WRITE_BUFFER);

        StatusReg = READ_FLASH_16(DestWordPtr);
        while ((StatusReg & ReadyMask) != ReadyMask)
        {
            StatusReg = READ_FLASH_16(DestWordPtr);
        }

        WRITE_FLASH_16(DestWordPtr, DevDataPtr->WriteBufferWordCount);

        /*
         * Fill the buffer
         */
        i = 0;
        while (Count--)
        {
            /*
             * Full word
             */
            if (BytesLeft > 1)
            {
                WRITE_FLASH_16(&DestWordPtr[i], SrcWordPtr[i]);
                BytesLeft -= 2;
            }

            /* End of SrcWords */
            else if (BytesLeft == 0)
            {
                WRITE_FLASH_16(&DestWordPtr[i], 0xFFFF);
            }

            /* Partial word */
            else  /* BytesLeft == 1 */
            {
                WRITE_FLASH_16(&DestWordPtr[i], 0x00FF | SrcWordPtr[i]);
                BytesLeft--;
            }
            i++;
        }

        /*
         * Buffer write completed. Send confirmation command and wait for
         * completion
         */
#ifdef XENV_UNITTEST
        Status = DevDataPtr->PollSR(DevDataPtr);
#else
        WRITE_FLASH_16(DestWordPtr, XFL_INTEL_CMD_CONFIRM);
        Status = PollSR16(DevDataPtr);
#endif
        if (Status != XST_FLASH_READY)
        {
            return (Status);
        }
    }

    return (XST_SUCCESS);
}

/*****************************************************************************/
/**
*
* Programs the device(s) using the faster write to buffer mechanism. The
* device(s) are programmed in parallel.
*
* @param    InstancePtr is the instance to work on
* @param    DestPtr is the physical destination address in flash memory space
* @param    SrcPtr is the source data
* @param    Bytes is the number of bytes to program
*
* @return
*
* See XFlash_Write()
*
* @note
*
* This algorithm programs only full buffers at a time and must take care
* of the following situations:
*   - Partial first buffer programming with pre and/or post padding required.
*   - Multiple full buffer programming.
*   - Partial last buffer programming with post padding.
* <br><br>
* When padding, 0xFF is written to each byte to be padded. This in effect does
* nothing to the current contents of the flash memory and saves us from having
* to merge real flash data with user data on partial buffer writes.
* <br><br>
* If hardware is failing, then this routine could get stuck in an endless loop.
*
******************************************************************************/
static XStatus WriteBuffer32(XFlash *InstancePtr, void* DestPtr,
                             void *SrcPtr, Xuint32 Bytes)
{
    XFlashVendorData_Intel* DevDataPtr;
    Xuint32 *SrcWordPtr = SrcPtr;
    Xuint32 *DestWordPtr = DestPtr;
    Xuint32 StatusReg;
    Xuint32 ReadyMask;
    Xuint32 BytesLeft = Bytes;
    Xuint32 PartialBytes;
    Xuint8  Count;
    XStatus Status = XST_SUCCESS;
    int i;

    DevDataPtr = GET_PARTDATA(InstancePtr);
    ReadyMask = DevDataPtr->SR_WsmReady.Mask32;

    /*
     * Make sure DestPtr and SrcPtr are aligned to a 32-bit word
     */
    if (((int)SrcWordPtr & 3) || ((int)DestWordPtr & 3))
    {
        return(XST_FLASH_ALIGNMENT_ERROR);
    }

    /*
     * Determine if a partial first buffer must be programmed
     */
    PartialBytes = (Xuint32)DestWordPtr &
        InstancePtr->Properties.ProgCap.WriteBufferAlignmentMask;

    /*
     * This write cycle programs the first partial write buffer
     */
    if (PartialBytes)
    {
        /*
         * Backup DestWord to the beginning of a buffer alignment area
         * Count is the number of write cycles left after pre-filling
         * the write buffer with 0xFFFF
         */
        DestWordPtr = (void*)((Xuint32)DestWordPtr - PartialBytes);
        Count = InstancePtr->Properties.ProgCap.WriteBufferSize >> 2;

        /*
         * Send command to write buffer. Wait for buffer to become available.
         * Write number of words to be written (always the maximum)
         */
        WRITE_FLASH_32(DestWordPtr, XFL_INTEL_CMD_WRITE_BUFFER);
        StatusReg = READ_FLASH_32(DestWordPtr);
        while ((StatusReg & ReadyMask) != ReadyMask)
        {
            StatusReg = READ_FLASH_32(DestWordPtr);
        }
        WRITE_FLASH_32(DestWordPtr, DevDataPtr->WriteBufferWordCount);

        /*
         * Write 0xFFFFFFFF padding until we get to the start of the user
         * data
         */
        while (PartialBytes > 3)
        {
            WRITE_FLASH_32(DestWordPtr++, 0xFFFFFFFF);
            PartialBytes -= 4;
            Count--;
        }

        /*
         * Write the remainder of this write buffer
         */
        i = 0;
        while (Count--)
        {
            /* Full word */
            if (BytesLeft > 3)
            {
                WRITE_FLASH_32(&DestWordPtr[i], SrcWordPtr[i]);
                BytesLeft -= 4;
            }

            /* End of SrcWords */
            else if (BytesLeft == 0)
            {
                WRITE_FLASH_32(&DestWordPtr[i], 0xFFFFFFFF);
            }

            /* Partial word */
            else if (BytesLeft == 1)
            {
                WRITE_FLASH_32(&DestWordPtr[i], 0x00FFFFFF | SrcWordPtr[i]);
                BytesLeft--;
            }
            else if (BytesLeft == 2)
            {
                WRITE_FLASH_32(&DestWordPtr[i], 0x0000FFFF | SrcWordPtr[i]);
                BytesLeft -= 2;
            }
            else /* BytesLeft == 3 */
            {
                WRITE_FLASH_32(&DestWordPtr[i], 0x000000FF | SrcWordPtr[i]);
                BytesLeft -= 3;
            }
            i++;
        }

        /*
         * Buffer write completed. Send confirmation command and wait for completion
         */
#ifdef XENV_UNITTEST
        Status = DevDataPtr->PollSR(DevDataPtr);
#else
        WRITE_FLASH_32(DestWordPtr, XFL_INTEL_CMD_CONFIRM);
        Status = PollSR32(DevDataPtr);
#endif
        if (Status != XST_FLASH_READY)
        {
            return (Status);
        }

        /*
         * Increment source and destination to last access position
         */
        SrcWordPtr += i;
        DestWordPtr += i;
    }

    /*
     * At this point DestPtr and SrcPtr are aligned to a write buffer boundary.
     * The next batch of writes utilize a write cycle full of SrcData
     */
    Count = InstancePtr->Properties.ProgCap.WriteBufferSize >> 2;
    while (BytesLeft >= InstancePtr->Properties.ProgCap.WriteBufferSize)
    {
        /*
         * Send command to write buffer. Wait for buffer to become available.
         * Write number of words to be written (always the maximum)
         */
        WRITE_FLASH_32(DestWordPtr, XFL_INTEL_CMD_WRITE_BUFFER);
        StatusReg = READ_FLASH_32(DestWordPtr);
        while ((StatusReg & ReadyMask) != ReadyMask)
        {
            StatusReg = READ_FLASH_32(DestWordPtr);
        }
        WRITE_FLASH_32(DestWordPtr, DevDataPtr->WriteBufferWordCount);

        /*
         * Fill the buffer
         */
        for (i=0; i<Count; i++)
        {
            WRITE_FLASH_32(&DestWordPtr[i], SrcWordPtr[i]);
            BytesLeft -= 4;
        }

        /*
         * Send confirmation and wait for status
         */
#ifdef XENV_UNITTEST
        Status = DevDataPtr->PollSR(DevDataPtr);
#else
        WRITE_FLASH_32(DestWordPtr, XFL_INTEL_CMD_CONFIRM);
        Status = PollSR32(DevDataPtr);
#endif
        if (Status != XST_FLASH_READY)
        {
            return (Status);
        }

        /*
         * Increment source and destination
         */
        SrcWordPtr += Count;
        DestWordPtr += Count;
    }

    /*
     * The last phase is to write a partial last write buffer
     */
    if (BytesLeft)
    {
        /*
         * Send command to write buffer. Wait for buffer to become available.
         * Write number of words to be written (always the maximum)
         */
        WRITE_FLASH_32(DestWordPtr, XFL_INTEL_CMD_WRITE_BUFFER);
        StatusReg = READ_FLASH_32(DestWordPtr);
        while ((StatusReg & ReadyMask) != ReadyMask)
        {
            ReadyMask = READ_FLASH_32(DestWordPtr);
        }
        WRITE_FLASH_32(DestWordPtr, DevDataPtr->WriteBufferWordCount);

        /*
         * Fill the buffer
         */
        i = 0;
        while (Count--)
        {
            /*
             * Full word
             */
            if (BytesLeft > 3)
            {
                WRITE_FLASH_32(&DestWordPtr[i], SrcWordPtr[i]);
                BytesLeft -= 4;
            }

            /* End of SrcWords */
            else if (BytesLeft == 0)
            {
                WRITE_FLASH_32(&DestWordPtr[i], 0xFFFFFFFF);
            }

            /* Partial word */
            else if (BytesLeft == 1)
            {
                WRITE_FLASH_32(&DestWordPtr[i], 0x00FFFFFF | SrcWordPtr[i]);
                BytesLeft--;
            }
            else if (BytesLeft == 2)
            {
                WRITE_FLASH_32(&DestWordPtr[i], 0x0000FFFF | SrcWordPtr[i]);
                BytesLeft -= 2;
            }
            else /* BytesLeft == 3 */
            {
                WRITE_FLASH_32(&DestWordPtr[i], 0x000000FF | SrcWordPtr[i]);
                BytesLeft -= 3;
            }
            i++;
        }

        /*
         * Buffer write completed. Send confirmation command and wait for completion
         */
#ifdef XENV_UNITTEST
        Status = DevDataPtr->PollSR(DevDataPtr);
#else
        WRITE_FLASH_32(DestWordPtr, XFL_INTEL_CMD_CONFIRM);
        Status = PollSR32(DevDataPtr);
#endif
        if (Status != XST_FLASH_READY)
        {
            return (Status);
        }
    }

    return (XST_SUCCESS);
}


/*****************************************************************************/
/**
*
* Programs the device(s) using the faster write to buffer mechanism. The
* device(s) are programmed in parallel.
*
* @param    InstancePtr is the instance to work on
* @param    DestPtr is the physical destination address in flash memory space
* @param    SrcPtr is the source data
* @param    Bytes is the number of bytes to program
*
* @return
*
* See XFlash_Write()
*
* @note
*
* This algorithm programs only full buffers at a time and must take care
* of the following situations:
*   - Partial first buffer programming with pre and/or post padding required.
*   - Multiple full buffer programming.
*   - Partial last buffer programming with post padding.
* <br><br>
* When padding, 0xFF is written to each byte to be padded. This in effect does
* nothing to the current contents of the flash memory and saves us from having
* to merge real flash data with user data on partial buffer writes.
* <br><br>
* If hardware is failing, then this routine could get stuck in an endless loop.
*
******************************************************************************/
static XStatus WriteBuffer64(XFlash *InstancePtr, void* DestPtr,
                             void *SrcPtr, Xuint32 Bytes)
{
    XFlashVendorData_Intel* DevDataPtr;
    Xuint32 *SrcWordPtr = SrcPtr;
    Xuint32 *DestWordPtr = DestPtr;
    Xuint64 StatusReg;
    Xuint32 ReadyMask;
    Xuint32 BytesLeft = Bytes;
    Xuint32 PartialBytes;
    Xuint8  Count;
    XStatus Status = XST_SUCCESS;
    int i;

    DevDataPtr = GET_PARTDATA(InstancePtr);
    ReadyMask = DevDataPtr->SR_WsmReady.Mask32;

    /*
     * Make sure DestPtr and SrcPtr are aligned to a 32-bit word
     */
    if (((int)SrcWordPtr & 3) || ((int)DestWordPtr & 3))
    {
        return(XST_FLASH_ALIGNMENT_ERROR);
    }

    /*
     * Determine if a partial first buffer must be programmed
     */
    PartialBytes = (Xuint32)DestWordPtr &
        InstancePtr->Properties.ProgCap.WriteBufferAlignmentMask;

    /*
     * This write cycle programs the first partial write buffer
     */
    if (PartialBytes)
    {
        /*
         * Backup DestWord to the beginning of a buffer alignment area
         * Count is the number of write cycles left after pre-filling
         * the write buffer with 0xFFFF
         */
        DestWordPtr = (void*)((Xuint32)DestWordPtr - PartialBytes);
        Count = InstancePtr->Properties.ProgCap.WriteBufferSize >> 2;

        /*
         * Send command to write buffer. Wait for buffer to become available.
         * Write number of words to be written (always the maximum)
         */
        WRITE_FLASH_64x2(DestWordPtr, XFL_INTEL_CMD_WRITE_BUFFER,
                         XFL_INTEL_CMD_WRITE_BUFFER);
        READ_FLASH_64(DestWordPtr, StatusReg);
        while (((XUINT64_MSW(StatusReg) & ReadyMask) != ReadyMask) ||
               ((XUINT64_LSW(StatusReg) & ReadyMask) != ReadyMask))
        {
            READ_FLASH_64(DestWordPtr, StatusReg);
        }
        WRITE_FLASH_64x2(DestWordPtr, DevDataPtr->WriteBufferWordCount,
                         DevDataPtr->WriteBufferWordCount);

        /*
         * Write 0xFFFFFFFF padding until we get to the start of the user
         * data
         */
        while (PartialBytes > 3)
        {
            WRITE_FLASH_32(DestWordPtr++, 0xFFFFFFFF);
            PartialBytes -= 4;
            Count--;
        }

        /*
         * Write the remainder of this write buffer
         */
        i = 0;
        while (Count--)
        {
            /* Full word */
            if (BytesLeft > 3)
            {
                WRITE_FLASH_32(&DestWordPtr[i], SrcWordPtr[i]);
                BytesLeft -= 4;
            }

            /* End of SrcWords */
            else if (BytesLeft == 0)
            {
                WRITE_FLASH_32(&DestWordPtr[i], 0xFFFFFFFF);
            }

            /* Partial word */
            else if (BytesLeft == 1)
            {
                WRITE_FLASH_32(&DestWordPtr[i], 0x00FFFFFF | SrcWordPtr[i]);
                BytesLeft--;
            }
            else if (BytesLeft == 2)
            {
                WRITE_FLASH_32(&DestWordPtr[i], 0x0000FFFF | SrcWordPtr[i]);
                BytesLeft -= 2;
            }
            else /* BytesLeft == 3 */
            {
                WRITE_FLASH_32(&DestWordPtr[i], 0x000000FF | SrcWordPtr[i]);
                BytesLeft -= 3;
            }
            i++;
        }

        /*
         * Buffer write completed. Send confirmation command and wait for
         * completion.
         */
#ifdef XENV_UNITTEST
        Status = DevDataPtr->PollSR(DevDataPtr);
#else
        WRITE_FLASH_64x2((Xuint32)DestWordPtr & ~7,
                         XFL_INTEL_CMD_CONFIRM,
                         XFL_INTEL_CMD_CONFIRM);
        Status = PollSR64(DevDataPtr);
#endif
        if (Status != XST_FLASH_READY)
        {
            return (Status);
        }

        /*
         * Increment source and destination to last access position
         */
        SrcWordPtr += i;
        DestWordPtr += i;
    }

    /*
     * At this point DestPtr and SrcPtr are aligned to a write buffer boundary.
     * The next batch of writes utilize a write cycle full of SrcData
     */
    Count = InstancePtr->Properties.ProgCap.WriteBufferSize >> 2;
    while (BytesLeft >= InstancePtr->Properties.ProgCap.WriteBufferSize)
    {
        /*
         * Send command to write buffer. Wait for buffer to become available.
         * Write number of words to be written (always the maximum)
         */
        WRITE_FLASH_64x2(DestWordPtr, XFL_INTEL_CMD_WRITE_BUFFER,
                         XFL_INTEL_CMD_WRITE_BUFFER);

        READ_FLASH_64(DestWordPtr, StatusReg);
        while (((XUINT64_MSW(StatusReg) & ReadyMask) != ReadyMask) ||
               ((XUINT64_LSW(StatusReg) & ReadyMask) != ReadyMask))
        {
            READ_FLASH_64(DestWordPtr, StatusReg);
        }
        WRITE_FLASH_64x2(DestWordPtr, DevDataPtr->WriteBufferWordCount,
                         DevDataPtr->WriteBufferWordCount);

        /*
         * Fill the buffer
         */
        for (i=0; i<Count; i++)
        {
            WRITE_FLASH_32(&DestWordPtr[i], SrcWordPtr[i]);
            BytesLeft -= 4;
        }

        /*
         * Send confirmation and wait for status
         */
#ifdef XENV_UNITTEST
        Status = DevDataPtr->PollSR(DevDataPtr);
#else
        WRITE_FLASH_64x2((Xuint32)DestWordPtr & ~7,
                         XFL_INTEL_CMD_CONFIRM,
                         XFL_INTEL_CMD_CONFIRM);
        Status = PollSR64(DevDataPtr);
#endif
        if (Status != XST_FLASH_READY)
        {
            return (Status);
        }

        /*
         * Increment source and destination
         */
        SrcWordPtr += Count;
        DestWordPtr += Count;
    }

    /*
     * The last phase is to write a partial last write buffer
     */
    if (BytesLeft)
    {
        /*
         * Send command to write buffer. Wait for buffer to become available.
         * Write number of words to be written (always the maximum)
         */
        WRITE_FLASH_64x2(DestWordPtr, XFL_INTEL_CMD_WRITE_BUFFER,
                         XFL_INTEL_CMD_WRITE_BUFFER);

        while (((XUINT64_MSW(StatusReg) & ReadyMask) != ReadyMask) ||
               ((XUINT64_LSW(StatusReg) & ReadyMask) != ReadyMask))
        {
            READ_FLASH_64(DestWordPtr, StatusReg);
        }
        WRITE_FLASH_64x2(DestWordPtr, DevDataPtr->WriteBufferWordCount,
                         DevDataPtr->WriteBufferWordCount);

        /*
         * Fill the buffer
         */
        i = 0;
        while (Count--)
        {
            /*
             * Full word
             */
            if (BytesLeft > 3)
            {
                WRITE_FLASH_32(&DestWordPtr[i], SrcWordPtr[i]);
                BytesLeft -= 4;
            }

            /* End of SrcWords */
            else if (BytesLeft == 0)
            {
                WRITE_FLASH_32(&DestWordPtr[i], 0xFFFFFFFF);
            }

            /* Partial word */
            else if (BytesLeft == 1)
            {
                WRITE_FLASH_32(&DestWordPtr[i], 0x00FFFFFF | SrcWordPtr[i]);
                BytesLeft--;
            }
            else if (BytesLeft == 2)
            {
                WRITE_FLASH_32(&DestWordPtr[i], 0x0000FFFF | SrcWordPtr[i]);
                BytesLeft -= 2;
            }
            else /* BytesLeft == 3 */
            {
                WRITE_FLASH_32(&DestWordPtr[i], 0x000000FF | SrcWordPtr[i]);
                BytesLeft -= 3;
            }
            i++;
        }

        /*
         * Buffer write completed. Send confirmation command and wait for completion
         */
#ifdef XENV_UNITTEST
        Status = DevDataPtr->PollSR(DevDataPtr);
#else
        WRITE_FLASH_64x2((Xuint32)DestWordPtr & ~7,
                         XFL_INTEL_CMD_CONFIRM,
                         XFL_INTEL_CMD_CONFIRM);
        Status = PollSR64(DevDataPtr);
#endif
        if (Status != XST_FLASH_READY)
        {
            return (Status);
        }
    }

    return (XST_SUCCESS);
}


/*****************************************************************************/
/**
*
* Reads and interprets part identification data
*
* @param    InstancePtr is the instance to work on
*
* @return
*
* None.
*
* @note
*
* None.
*
******************************************************************************/
static void GetPartID(XFlash *InstancePtr)
{
    XFlashVendorData_Intel *DevDataPtr;
    Xuint32 CmdAddress;
    Xuint8* Ptr;
    Xuint8  Interleave;

    DevDataPtr = GET_PARTDATA(InstancePtr);
    CmdAddress = InstancePtr->Geometry.BaseAddress;
    Interleave = (InstancePtr->Geometry.MemoryLayout &
                  XFL_LAYOUT_CFI_INTERL_MASK) >> 24;

    /*
     * Send Read id codes command
     */
    DevDataPtr->SendCmd(InstancePtr->Geometry.BaseAddress, 8,
                        XFL_INTEL_CMD_READ_ID_CODES);

    /*
     * Retrieve Manufacturer ID located at word offset 0
     */
    XFL_CFI_POSITION_PTR(Ptr, CmdAddress, Interleave, 0);
    InstancePtr->Properties.PartID.ManufacturerID = XFL_CFI_READ8(Ptr, Interleave);

    /*
     * Retrieve Device Code located at word offset 1
     */
    XFL_CFI_ADVANCE_PTR8(Ptr, Interleave);
    InstancePtr->Properties.PartID.DeviceID = XFL_CFI_READ8(Ptr, Interleave);

    /*
     * Place device(s) back into read-array mode
     */
    DevDataPtr->SendCmd(InstancePtr->Geometry.BaseAddress, 8,
                        XFL_INTEL_CMD_READ_ARRAY);
}


/*****************************************************************************/
/**
*
* Sets the RYBY control signal.
*
* @param    InstancePtr is the instance to work on
* @param    Mode is the mode to set the RYBY signal to
*
* @return
*
* - XST_SUCCESS               if the mode was successfully changed.
* - XST_FLASH_NOT_SUPPORTED   if the mode given is unknown/unsupported
*
* @note
*
* None.
*
******************************************************************************/
static XStatus SetRYBY(XFlash *InstancePtr, Xuint32 Mode)
{
    Xuint32 Cmd;
    XFlashVendorData_Intel *DevDataPtr;

    /*
     * Determine which command code to use
     */
    switch (Mode)
    {
        case XFL_INTEL_RYBY_PULSE_OFF:
            Cmd = XFL_INTEL_CONFIG_RYBY_LEVEL;
            break;

        case XFL_INTEL_RYBY_PULSE_ON_ERASE:
            Cmd = XFL_INTEL_CONFIG_RYBY_PULSE_ERASE;
            break;

        case XFL_INTEL_RYBY_PULSE_ON_PROG:
            Cmd = XFL_INTEL_CONFIG_RYBY_PULSE_WRITE;
            break;

        case XFL_INTEL_RYBY_PULSE_ON_ERASE_PROG:
            Cmd = XFL_INTEL_CONFIG_RYBY_PULSE_ALL;
            break;

        default:
            return (XST_FLASH_NOT_SUPPORTED);
    }

    /*
     * Send the command to the devices
     */
    DevDataPtr = GET_PARTDATA(InstancePtr);
    DevDataPtr->SendCmdSeq(InstancePtr->Geometry.BaseAddress, 0,
                           XFL_INTEL_CMD_CONFIG, Cmd);

    return (XST_SUCCESS);
}


/*****************************************************************************/
/**
*
* Sends commands to erase blocks
*
* @param    InstancePtr is the pointer to xflash object to work on
* @param    Region is the region which the first block appears
* @param    Block is the starting block to erase
* @param    MaxBlocks is the number of consecutive blocks to erase
*
* @return
*
* The number of blocks enqueued to the part's erase buffer.
* Region and Block parameters are incremented the number of blocks
* queued.
*
* @note
*
* Limitation: Only support enqueuing one block at a time.
*
******************************************************************************/
static Xuint16 EnqueueEraseBlocks(XFlash *InstancePtr, Xuint16 *Region,
                                  Xuint16 *Block, Xuint16 MaxBlocks)
{
    XFlashGeometry *GeomPtr;
    XFlashVendorData_Intel *DevDataPtr;
    Xuint32 BlockAddress;

    /*
     * If for some reason the maximum number of blocks to enqueue is
     * zero, then don't do anything
     */
    if (MaxBlocks == 0)
    {
        return (0);
    }

    GeomPtr = &InstancePtr->Geometry;
    DevDataPtr = GET_PARTDATA(InstancePtr);

    /*
     * Get the physical address to write the command to and send command
     */
    (void)XFlashGeometry_ToAbsolute(GeomPtr, *Region, *Block, 0, &BlockAddress);
    DevDataPtr->SendCmdSeq(GeomPtr->BaseAddress, BlockAddress,
                           XFL_INTEL_CMD_BLOCK_ERASE, XFL_INTEL_CMD_CONFIRM);

    /*
     * Increment Region/Block
     */
    XFL_GEOMETRY_INCREMENT(GeomPtr, *Region, *Block);

    /*
     * Return the number of blocks enqueued
     */
    return (1);
}
