/* $Id: xflash.c,v 1.10 2002/06/26 20:15:29 linnj 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.c
*
* This module implements the base component for flash memory devices that
* conform to the "Common Flash Interface" (CFI) standard. CFI allows a single
* flash driver to be used for an entire family of parts.
*
* This is not a driver for a specific device, but for a set of command
* read/write/erase algorithms. CFI allows us to determine which algorithm to
* utilize at runtime. It is this set of command algorithms that will be
* implemented as the derived component.
*
* Flash memory space is segmented into areas called blocks. The size of each
* block is based on a power of 2. A region is defined as a contiguous set of
* blocks of the same size. Some parts have several regions while others have
* one. The arrangement of blocks and regions is refered to by this module
* as the part's geometry.
*
* The cells within the part can be programmed from a logic 1 to a logic 0 and
* not the other way around. To change a cell back to a logic 1, the entire
* block containing that cell must be erased. When a block is erased all bytes
* contain the value 0xFF. The number of times a block can be erased is
* finite. Eventually the block will wear out and will no longer be capable of
* erasure. As of this writing, the typical flash block can be erased 100,000
* or more times.
*
* Features provided by this module:
*   - Part timing, geometry, features, and command algorithm determined by
*     CFI query.
*   - Supported architectures include:
*        - 16-bit data bus: Single x16 part in word mode
*        - 32-bit data bus: Two x16 parts in word mode.
*   - Two read/write/erase APIs.
*   - Erase/write suspension.
*   - Self test diagnostics.
*   - Block locking (if supported by specific part).
*   - Chip erase (if supported by specific part).
*   - Non-blocking write & erase function calls.
*   - Part specific control. Supported features of individual parts are
*     listed within the driver module for that part.
*
* Features listed above not currently implemented include:
*   - Non-blocking write & erase function calls.
*   - Block locking.
*   - Support of more architectues.
*   - Self test diagnostics.
*
* This component exports two differing types of read/write/erase APIs. The
* geometry un-aware API allows the user to ignore the geometry of the
* underlying flash device. The geometry aware API operates on specific blocks
* The former API is designed for casual use while the latter may prove useful
* for designers wishing to use this driver under a flash file system.
* Both APIs can be used interchangeably.
*
* Write and erase function calls can be set to return immediately
* (non-blocking) even though the intended operation is incomplete. This is
* useful for systems that utilize a watchdog timer. It also facilitates the
* use of an interrupt driven programming algorithm. This feature is dependent
* upon the capabilities of the flash devices.
*
* If the geometry un-aware API is used, then the user requires no knowledge
* of the underlying hardware. Usage of this API along with non-blocking
* write/erase should be done carefully because non-blocking write/erase
* assumes some knowledge of the device(s) geometry.
*
* If part specific advanced features are required, then the
* XFlash_DeviceControl function is available provided the feature has been
* implemented by the part driver module.
*
* @note
*
* This driver is intended to be RTOS and processor independent. It works with
* physical addresses only. Any needs for dynamic memory management, threads,
* mutual exclusion, virtual memory, cache control, or HW write protection
* management must be satisfied by the layer above this driver.
* <br><br>
* Use of this driver by multiple threads must be carefully thought out taking
* into consideration the underlying flash devices in use. This driver does
* not use mutual exclusion or critical region control.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver   Who  Date     Changes
* ----- ---- -------- -----------------------------------------------
* 1.00a rmm  07/16/01 First release
* </pre>
*
* @internal
*
* This component is designed for devices external to the FPGA. As a result
* the following deviations from the software framework are noted:
*   - No IPIF interface.
*   - No Start or Stop function.
*   - Different versioning. The version for derived components will be the
*     command set algorithm derived from CFI.
*   - An area is defined within the base component class XFlash to store part
*     specific data managed by the subcomponent.
*
****************************************************************************/

/***************************** Include Files *********************************/
#include "xflash.h"
#include "xflash_cfi.h"
#include "xparameters.h"

#ifdef XPAR_FLASH_INTEL_SUPPORT
#include "xflash_intel.h"      /* Intel version of this component */
#endif

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


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


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


/************************** Function Prototypes ******************************/
static XStatus SetVTable(XFlash *InstancePtr);

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


/*****************************************************************************/
/**
*
* Initializes a specific XFlash instance. The initialization entails:
*
* - Issuing the CFI query command
* - Get and translate relevent CFI query information.
* - Set default options for the instance.
* - Setup the VTable.
* - Call the initialize function of the instance, which does the following:
*   - Get and translate extended vendor CFI query information.
*   - Some VTable functions may be replaced with more efficient ones based on
*     data extracted from the extended CFI query. A replacement example would
*     be a buffered XFlash_WriteBlock replacing a non-buffered
*     XFlash_WriteBlock.
*   - Reset the device by clearing any status information and placing the
*     device in read mode.
*
* @param    InstancePtr is a pointer to the XFlash instance to be worked on.
* @param    DeviceId is the unique id of the device controlled by this
*           component. Passing in a device id associates the generic component
*           to a specific device, as chosen by the caller or application developer.
*
* @return
*
* The return value is XST_SUCCESS if successful.  On error, a code indicating
* the specific error is returned.  Possible error codes are:
* - XST_DEVICE_NOT_FOUND if device configuration information was not found for
*         a device with the supplied device ID.
* - XST_FLASH_PART_NOT_SUPPORTED if the command set algorithm or Layout is not
*         supported by any derived component compiled into the system.
* - XST_FLASH_TOO_MANY_REGIONS if the part contains too many erase regions. This
*         can be fixed by increasing the value of XFL_MAX_ERASE_REGIONS then re-
*         compiling the driver.
* - XST_FLASH_CFI_QUERY_ERROR if the device would not enter CFI query mode.
*         Either the device(s) do not support CFI, the wrong BaseAddress param
*         was used, an unsupported part layout exists, or a hardware problem
*         exists with the part.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlash_Initialize(XFlash *InstancePtr, Xuint16 DeviceId)
{
    XStatus Result;
    Xuint32 Layout;
    XFlash_Config *ConfigPtr;

    /*
     * Validate parameters
     */
    XASSERT_NONVOID(InstancePtr != XNULL);

    /*
     * Lookup the device configuration Use this info below when initializing
     * this component.
     */
    ConfigPtr = XFlash_LookupConfig(DeviceId);
    if (ConfigPtr == XNULL)
    {
        return(XST_DEVICE_NOT_FOUND);
    }

    /*
     * Setup instance before performing CFI query. BaseAddress & Layout must
     * be initialized prior to invoking query
     */
    InstancePtr->IsReady = 0;
    InstancePtr->Geometry.BaseAddress = ConfigPtr->BaseAddr;

    /*
     * Translate to the layout XFlashGeometry uses
     */
    Layout = XFlashGeometry_ConvertLayout(ConfigPtr->NumParts,
                                          ConfigPtr->PartWidth,
                                          ConfigPtr->PartMode);
    if (Layout == XNULL)
    {
        return(XST_FLASH_PART_NOT_SUPPORTED);
    }

    InstancePtr->Geometry.MemoryLayout = Layout;

    /*
     * Get CFI data
     */
    Result = XFlashCFI_ReadCommon(&InstancePtr->Geometry,
                                  &InstancePtr->Properties);

    if (Result != XST_SUCCESS)
    {
        return (XST_FLASH_CFI_QUERY_ERROR);
    }

    /*
     * Set the VTable function pointer based on the command set algorithm
     * discovered in the CFI query.
     */
    Result = SetVTable(InstancePtr);
    if (Result != XST_SUCCESS)
    {
        return Result;
    }

    /*
     * Initialize the derived component (initializes the device). If it
     * initializes successfully set the IsReady flag to indicate the device
     * is ready.
     */
    Result = InstancePtr->VTable.Initialize(InstancePtr);
    if (Result == XST_SUCCESS)
    {
        InstancePtr->IsReady = XCOMPONENT_IS_READY;
    }

    return Result;
}

/*****************************************************************************/
/**
*
* Looks up the device configuration based on the unique device ID.
*
* @param DeviceId is the unique device ID to be searched for in the table
*
* @return Returns a pointer to the configuration data for the device, or
*         XNULL if not device is found.
*
******************************************************************************/
XFlash_Config *XFlash_LookupConfig(Xuint16 DeviceId)
{
    extern XFlash_Config XFlash_ConfigTable[];
    XFlash_Config *CfgPtr = XNULL;
    int i;

    for (i=0; i < XPAR_XFLASH_NUM_INSTANCES; i++)
    {
        if (XFlash_ConfigTable[i].DeviceId == DeviceId)
        {
            CfgPtr = &XFlash_ConfigTable[i];
            break;
        }
    }

    return CfgPtr;
}

/*****************************************************************************/
/**
*
* Copy data from a specific device block to a user buffer. The source and
* destination addresses can be on any byte alignment supported by the
* target processor.
*
* @param    InstancePtr is a  pointer to the XFlash instance to be worked on.
* @param    Region is the erase region the block appears in.
* @param    Block is the block number within the erase region.
* @param    Offset is the starting offset in the block where reading will begin.
* @param    Bytes is the number of bytes to copy.
* @param    DestPtr is the destination address to copy data to.
*
* @return
*
* - XST_SUCCESS              if successful.
* - XST_FLASH_ADDRESS_ERROR  if Region, Block, and Offset parameters do not
*                            point to a valid block.
*
* @note
*
* The arguments point to a starting Region, Block, and Offset within that
* block. The Bytes parameter may cross over Region and Block boundaries.
* If Bytes extends past the end of the device's address space, then results
* are undefined.
*
******************************************************************************/
XStatus XFlash_ReadBlock(XFlash *InstancePtr, Xuint16 Region, Xuint16 Block,
                         Xuint32 Offset, Xuint32 Bytes, void* DestPtr)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.ReadBlock(InstancePtr, Region, Block, Offset,
                                         Bytes, DestPtr));
}

/*****************************************************************************/
/**
*
* Programs the devices with data stored in the user buffer. The source and
* destination address can be on any alignment supported by the processor. This
* function will block until the operation completes or an error is detected.
*
* Returns immediately if the XFL_NON_BLOCKING_WRITE_OPTION option is set.
* If clear, the device(s) are polled until an error, timeout or the operation
* completes successfully.
*
* The XFL_NON_BLOCKING_WRITE_OPTION option has an impact on the number of bytes
* that can be written:
*
* - If clear, then the number of bytes to write can be any number as long as
*   it is within the bounds of the device(s).
* - If set, then the number of bytes depends on the alignment and size of
*   the device's write buffer. The rule is that the number of bytes being
*   written cannot cross over an alignment boundary. Alignment information
*   is obtained in the InstancePtr->Properties.ProgCap attribute.
*
* @param    InstancePtr is a pointer to the XFlash instance to be worked on.
* @param    Region is the erase region the block appears in.
* @param    Block is the block number within the erase region.
* @param    Offset is the starting offset in the block where writing will begin.
* @param    Bytes is the number of bytes to write.
* @param    SrcPtr is the source address containing data to be programmed
*
* @return
*
* If XFL_NON_BLOCKING_WRITE_OPTION option is set, then the return value is
* XST_SUCCESS if successful. On error, a code indicating the specific error
* is returned. Possible error codes are:
* - XST_FLASH_ADDRESS_ERROR      if Region, Block, and Offset parameters do not
*                                point to a valid block. Or, the Bytes
*                                parameter causes the read to go past the
*                                last addressible byte in the device(s).
* - XST_FLASH_ALIGNMENT_ERROR    if the Offset or SrcPtr is not aligned to the
*                                width of the flash's data bus.
* - XST_BLOCKING_CALL_ERROR      if the write would cross a write buffer
*                                boundary.
*.
* If XFL_NON_BLOCKING_WRITE_OPTION option is clear, then the following
* additional codes can be returned:
* - XST_FLASH_ERROR              if a write error occured. This error is
*                                usually device specific. Use
*                                XFlash_DeviceControl() to retrieve specific
*                                error conditions. When this error is
*                                returned, it is possible that the target
*                                address range was only partially programmed.
*
* @note
*
* The arguments point to a starting Region, Block, and Offset within that
* block. The Bytes parameter may cross over Region and Block boundaries as
* long as the entire range lies within the part(s) address range and the
* XFL_NON_BLOCKING_WRITE_OPTION option is not set.
*
******************************************************************************/
XStatus XFlash_WriteBlock(XFlash *InstancePtr, Xuint16 Region, Xuint16 Block,
                          Xuint32 Offset, Xuint32 Bytes, void* SrcPtr)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.WriteBlock(InstancePtr, Region, Block, Offset,
                                          Bytes, SrcPtr));
}

/*****************************************************************************/
/**
*
* Suspends a currently in progress write opearation and place the device(s)
* in read mode. When suspended, any block not being programmed can be read.
*
* This function should be used only when the XFL_NON_BLOCKING_WRITE_OPTION
* option is set and a previous call to XFlash_WriteBlock() has been made.
* Otherwise, undetermined results may occur.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Region is the region containing block
* @param    Block is the block that is being written
* @param    Offset is the offset in the device where suspension should occur
*
* @return
*
* - XST_SUCCESS               if successful.
* - XST_FLASH_NOT_SUPPORTED   if write suspension is not supported by the
*                             device(s)
*
* @note
*
* Some devices such as Intel do not require a block address to suspend
* erasure. Therefore Region & Block parameters are ignored in those cases.
*
******************************************************************************/
XStatus XFlash_WriteBlockSuspend(XFlash *InstancePtr, Xuint16 Region,
                                 Xuint16 Block, Xuint32 Offset)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.WriteBlockSuspend(InstancePtr, Region,
                                                 Block, Offset));
}

/*****************************************************************************/
/**
*
* Resumes a write operation that was suspended with XFlash_WriteBlockSuspend.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Region is the region containing block
* @param    Block is the block that is being erased
* @param    Offset is the offset in the device where resumption should occur
*
* @return
*
* - XST_SUCCESS               if successful.
* - XST_FLASH_NOT_SUPPORTED   if write suspension is not supported by the
*                             device(s)
*
* @note
*
* Some devices such as Intel do not require a block address to suspend
* erasure. Therefore Region & Block parameters are ignored.
*
******************************************************************************/
XStatus XFlash_WriteBlockResume(XFlash *InstancePtr, Xuint16 Region,
                                Xuint16 Block, Xuint32 Offset)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.WriteBlockResume(InstancePtr, Region,
                                                Block, Offset));
}

/*****************************************************************************/
/**
*
* Erases the specified block.
*
* Returns immediately if the XFL_NON_BLOCKING_ERASE_OPTION option is set.
* If clear, the device(s) are polled until an error, timeout or the operation
* completes successfully.
*
* The XFL_NON_BLOCKING_ERASE_OPTION option has an impact on the number of bytes
* that can be erased in a single call to this function:
*
* - If clear, then the number of bytes to erase can be any number as long as
*   it is within the bounds of the device(s).
*
* - If set, then the number of bytes depends on the the block size of the
*   device at the provided offset and whether the device(s) contains a block
*   erase queue.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Region is the erase region the block appears in.
* @param    Block is the block number within the erase region.
* @param    NumBlocks is the the number of blocks to erase.
*
* @return
*
* If XFL_NON_BLOCKING_ERASE_OPTION option is set, then the return value is
* one of the below.
* - XST_SUCCESS              if successfull.
* - XST_FLASH_ADDRESS_ERROR  if region and/or block do not specify a valid
*                            block within the device.
*.
* If XFL_NON_BLOCKING_ERASE_OPTION option is clear, then the following
* additional codes can be returned
* - XST_FLASH_ERROR          if an erase error occured. This error is usually
*                            device specific. Use XFlash_DeviceControl() to
*                            retrieve specific error conditions. When this
*                            error is returned, it is possible that the target
*                            address range was only partially erased.
*
* @note
*
* The arguments point to a starting Region and Block. The NumBlocks parameter
* may cross over Region boundaries as long as the entire range lies within the
* part(s) address range and the XFL_NON_BLOCKING_ERASE_OPTION option is not set.
*
******************************************************************************/
XStatus XFlash_EraseBlock(XFlash *InstancePtr, Xuint16 Region, Xuint16 Block,
                          Xuint16 NumBlocks)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.EraseBlock(InstancePtr, Region, Block,
                                          NumBlocks));
}

/*****************************************************************************/
/**
*
* Suspends a currently in progress erase operation and place the device(s)
* in read mode. When suspended, any block not being erased can be read.
*
* This function should be used only when the XFL_NON_BLOCKING_ERASE_OPTION
* option is set and a previous call to XFlash_EraseBlock() has been made.
* Otherwise, undetermined results may occur.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Region is the region containing block
* @param    Block is the block that is being erased
*
* @return
*
* - XST_SUCCESS               if successful.
* - XST_FLASH_NOT_SUPPORTED   if write suspension is not supported by the
*                             device(s)
*
* @note
*
* Some devices such as Intel do not require a block address to suspend
* erasure. Therefore Region & Block parameters are ignored.
*
******************************************************************************/
XStatus XFlash_EraseBlockSuspend(XFlash *InstancePtr, Xuint16 Region,
                                 Xuint16 Block)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.EraseBlockSuspend(InstancePtr, Region, Block));
}

/*****************************************************************************/
/**
*
* Resumes an erase operation that was suspended with XFlash_EraseBlockSuspend.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Region is the region containing block
* @param    Block is the block that is being erased
*
* @return
*
* - XST_SUCCESS               if successful.
* - XST_FLASH_NOT_SUPPORTED   if write suspension is not supported by the
*                             device(s)
*
* @note
*
* Some devices such as Intel do not require a block address to suspend
* erasure. Therefore Region & Block parameters are ignored.
*
******************************************************************************/
XStatus XFlash_EraseBlockResume(XFlash *InstancePtr, Xuint16 Region,
                                Xuint16 Block)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.EraseBlockResume(InstancePtr, Region, Block));
}

/*****************************************************************************/
/**
*
* Locks the specified block. Prevents it from being erased or written.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Region is the erase region the block appears in.
* @param    Block is the block number within the erase region.
* @param    NumBlocks is the the number of blocks to erase. The number may
*           extend into a different region.
*
* @return
*
* - XST_SUCCESS                  if successful.
* - XST_FLASH_ADDRESS_ERROR      if region and/or block do not specify a valid
*                                block within the device.
* - XST_FLASH_NOT_SUPPORTED      if the device(s) do not support block locking.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlash_LockBlock(XFlash *InstancePtr, Xuint16 Region, Xuint16 Block,
                         Xuint16 NumBlocks)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.LockBlock(InstancePtr, Region, Block,
                                         NumBlocks));
}

/*****************************************************************************/
/**
*
* Unlocks the specified block.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Region is the erase region the block appears in.
* @param    Block is the block number within the erase region.
* @param    NumBlocks is the the number of blocks to erase. The number may
*           extend into a different region.
*
* @return
*
* - XST_SUCCESS                  if successful.
* - XST_FLASH_ADDRESS_ERROR      if region and/or block do not specify a valid
*                                block within the device.
* - XST_FLASH_NOT_SUPPORTED      if the device(s) do not support block locking.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlash_UnlockBlock(XFlash *InstancePtr, Xuint16 Region, Xuint16 Block,
                           Xuint16 NumBlocks)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.UnlockBlock(InstancePtr, Region, Block,
                                           NumBlocks));
}

/*****************************************************************************/
/**
*
* Returns the status of the device. This function is intended to be used to
* poll the device in the following circumstances:
*
*  - After calling XFlash_WriteBlock with XFL_NON_BLOCKING_WRITE_OPTION option
*    set.
*  - After calling XFlash_EraseBlock with XFL_NON_BLOCKING_ERASE_OPTION option
*    set.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Region is the erase region the block appears in.
* @param    Block is the block number within the erase region.
*
* @return
*
* - XST_FLASH_READY      if the device(s) have completed the previous operation
*                        without error.
* - XST_FLASH_BUSY       if the device(s) are currently performing an erase or
*                        write operation.
* - XST_FLASH_ERROR      if the device(s) have experienced an internal error
*                        occuring during another operation such as write,
*                        erase, or block locking. XFlash_DeviceControl() must
*                        be used to access the cause of the device specific
*                        error condition.
*
* @note
*
* With some types of flash devices, there may be no difference between using
* XFlash_GetBlockStatus or XFlash_GetStatus. See your part data sheet for more
* information.
*
******************************************************************************/
XStatus XFlash_GetBlockStatus(XFlash *InstancePtr, Xuint16 Region,
                              Xuint16 Block)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.GetBlockStatus(InstancePtr, Region, Block));
}

/*****************************************************************************/
/**
*
* Copies data from the device(s) memory space to a user buffer. The source and
* destination addresses can be on any alignment supported by the processor.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Offset is the offset into the device(s) address space from which to read.
* @param    Bytes is the number of bytes to copy.
* @param    DestPtr is the destination address to copy data to.
*
* @return
*
* - XST_SUCCESS                  if successful.
* - XST_FLASH_ADDRESS_ERROR      if the source address does not start within
*                                the addressable areas of the device(s).
*
* @note
*
* This function allows the transfer of data past the end of the device's
* address space. If this occurs, then results are undefined.
*
******************************************************************************/
XStatus XFlash_Read(XFlash *InstancePtr, Xuint32 Offset, Xuint32 Bytes,
                    void* DestPtr)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.Read(InstancePtr, Offset, Bytes, DestPtr));
}

/*****************************************************************************/
/**
*
* Programs the devices with data stored in the user buffer. The source and
* destination address must be aligned to the width of the flash's data bus.
*
* Returns immediately if the XFL_NON_BLOCKING_WRITE_OPTION option is set. If
* clear, the device(s) are polled until an error, timeout or the operation
* completes successfully.
*
* The XFL_NON_BLOCKING_WRITE_OPTION option has an impact on the number of bytes
* that can be written:
*
* - If clear, then the number of bytes to write can be any number as long as
*   it is within the bounds of the device(s).
*
* - If set, then the number of bytes depends on the alignment and size of
*   the device's write buffer. The rule is that the number of bytes being
*   written cannot cross over an alignment boundary. Alignment information
*   is obtained in the InstancePtr->Properties.ProgCap attribute.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Offset is the offset into the device(s) address space from which
*           to begin programming. Must be aligned to the width of the flash's
*           data bus.
* @param    Bytes is the number of bytes to program.
* @param    SrcPtr is the source address containing data to be programmed.
*           Must be aligned to the width of the flash's data bus.
*
* @return
*
* If XFL_NON_BLOCKING_WRITE_OPTION option is set, then the return value is
* one of the following:
* - XST_SUCCESS                if successful.
* - XST_FLASH_ADDRESS_ERROR    if the destination address range is not
*                              completely within the addressable areas of
*                              the device(s).
* - XST_FLASH_ALIGNMENT_ERROR  if the Offset or SrcPtr is not aligned to the
*                              width of the flash's data bus.
* - XST_BLOCKING_CALL_ERROR    if the write would cross a write buffer boundary.
*.
* If XFL_NON_BLOCKING_WRITE_OPTION option is clear, then the following
* additional codes can be returned:
* - XST_FLASH_ERROR            if a write error occurred. This error is usually
*                              device specific. Use XFlash_DeviceControl() to
*                              retrieve specific error conditions. When this
*                              error is returned, it is possible that the
*                              target address range was only partially
*                              programmed.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlash_Write(XFlash *InstancePtr, Xuint32 Offset, Xuint32 Bytes,
                     void* SrcPtr)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.Write(InstancePtr, Offset, Bytes, SrcPtr));
}

/*****************************************************************************/
/**
*
* Suspends a currently in progress write operation and place the device(s)
* in read mode. When suspended, any block not being programmed can be read.
*
* This function should be used only when the XFL_NON_BLOCKING_ERASE_OPTION
* option is set and a previous call to XFlash_Write() has been made.
* Otherwise, undetermined results may occur.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Offset is the offset with the device where suspension should occur.
*
* @return
*
* - XST_SUCCESS               if successful.
* - XST_FLASH_NOT_SUPPORTED   if write suspension is not supported by the
*                             device(s)
*
* @note
*
* Some devices such as Intel do not require a block address to suspend
* erasure. Therefore the Offset parameter is ignored.
*
******************************************************************************/
XStatus XFlash_WriteSuspend(XFlash *InstancePtr, Xuint32 Offset)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.WriteSuspend(InstancePtr, Offset));
}

/*****************************************************************************/
/**
*
* Resumes a write operation that was suspended with XFlash_WriteSuspend.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Offset is the offset with the device where write resumption should occur.
*
* @return
*
* - XST_SUCCESS               if successful.
* - XST_FLASH_NOT_SUPPORTED   if write suspension is not supported by the
*                             device(s)
*
* @note
*
* Some devices such as Intel do not require a block address to suspend
* erasure. Therefore the Offset parameter is ignored.
*
******************************************************************************/
XStatus XFlash_WriteResume(XFlash *InstancePtr, Xuint32 Offset)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.WriteResume(InstancePtr, Offset));
}

/*****************************************************************************/
/**
*
* Erases the specified address range.
*
* Returns immediately if the XFL_NON_BLOCKING_ERASE_OPTION option is set. If
* clear, the device(s) are polled until an error, timeout or the operation
* completes successfully.
*
* Erase the specified range of the device(s). Returns immediately if the
* XFL_NON_BLOCKING_ERASE_OPTION option is set. If clear, the device(s) are polled
* until an error, timeout or the operation completes successfully.
*
* The XFL_NON_BLOCKING_ERASE_OPTION option has an impact on the number of bytes
* that can be erased in a single call to this function:
*
* - If clear, then the number of bytes to erase can be any number as long as
*   it is within the bounds of the device(s).
*
* - If set, then the number of bytes depends on the the block size of the
*   device at the provided offset and whether the device(s) contains a block
*   erase queue.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Offset is the offset into the device(s) address space from which
*           to begin erasure.
* @param    Bytes is the number of bytes to erase.
*
* @return
*
* If XFL_NON_BLOCKING_ERASE_OPTION option is set, then the return value is
* one of the following:
* - XST_SUCCESS                   if successful.
* - XST_FLASH_ADDRESS_ERROR       if the destination address range is not
*                                 completely within the addressable areas of
*                                 the device(s).
* - XST_FLASH_BLOCKING_CALL_ERROR if the amount of data to be erased exceeds
*                                 the erase queue capacity of the device(s).
*.
* If XFL_NON_BLOCKING_ERASE_OPTION option is clear, then the following
* additional codes can be returned:
* - XST_FLASH_ERROR            if an erase error occurred. This error is usually
*                              device specific. Use XFlash_DeviceControl() to
*                              retrieve specific error conditions. When this
*                              error is returned, it is possible that the
*                              target address range was only partially
*                              erased.
*
* @note
*
* Due to flash memory design, the range actually erased may be larger than
* what was specified by the Offset & Bytes parameters. This will occur if
* the parameters do not align to block boundaries.
*
******************************************************************************/
XStatus XFlash_Erase(XFlash *InstancePtr, Xuint32 Offset, Xuint32 Bytes)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.Erase(InstancePtr, Offset, Bytes));
}


/*****************************************************************************/
/**
*
* Suspends a currently in progress erase operation and place the device(s)
* in read mode. When suspended, any block not being programmed can be read.
*
* This function should be used only when the XFL_NON_BLOCKING_ERASE_OPTION
* option is set and a previous call to XFlash_Erase() has been made.
* Otherwise, undetermined results may occur.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Offset is the offset with the device where suspension should occur.
*
* @return
*
* - XST_SUCCESS               if successful.
* - XST_FLASH_NOT_SUPPORTED   if write suspension is not supported by the
*                             device(s)
*
* @note
*
* Some devices such as Intel do not require a block address to suspend
* erasure. Therefore the Offset parameter is ignored.
*
******************************************************************************/
XStatus XFlash_EraseSuspend(XFlash *InstancePtr, Xuint32 Offset)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.EraseSuspend(InstancePtr, Offset));
}

/*****************************************************************************/
/**
*
* Resumes an erase operation that was suspended with XFlash_EraseSuspend.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Offset is the offset with the device where erase resumption should
*           be Resumed.
*
* @return
*
* - XST_SUCCESS               if successful.
* - XST_FLASH_NOT_SUPPORTED   if write suspension is not supported by the
*                             device(s)
*
* @note
*
* Some devices such as Intel do not require a block address to suspend
* erasure. Therefore the Offset parameter is ignored.
*
******************************************************************************/
XStatus XFlash_EraseResume(XFlash *InstancePtr, Xuint32 Offset)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.EraseResume(InstancePtr, Offset));
}

/*****************************************************************************/
/**
*
* Locks the blocks in the specified range of the device(s).
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Offset is the offset into the device(s) address space from which
*           to begin block locking.
* @param    Bytes is the number of bytes to lock.
*
* @return
*
* - XST_SUCCESS                  if successful.
* - XST_FLASH_ADDRESS_ERROR      if the destination address range is not
*                                completely within the addressable areas of
*                                the device(s).
* - XST_FLASH_NOT_SUPPORTED      if the device(s) do not support block locking.
*
* @note
*
* Due to flash memory design, the range actually locked may be larger than
* what was specified by the Offset & Bytes parameters. This will occur if
* the parameters do not align to block boundaries.
*
******************************************************************************/
XStatus XFlash_Lock(XFlash *InstancePtr, Xuint32 Offset, Xuint32 Bytes)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.Lock(InstancePtr, Offset, Bytes));
}

/*****************************************************************************/
/**
*
* Unlocks the blocks in the specified range of the device(s).
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Offset is the offset into the device(s) address space from which
*           to begin block unlocking.
* @param    Bytes is the number of bytes to unlock.
*
* @return
*
* - XST_SUCCESS                  if successful.
* - XST_FLASH_ADDRESS_ERROR      if the destination address range is not
*                                completely within the addressable areas of
*                                the device(s).
* - XST_FLASH_NOT_SUPPORTED      if the device(s) do not support block locking.
*
* @note
*
* Due to flash memory design, the range actually unlocked may be larger than
* what was specified by the Offset & Bytes parameters. This will occur if
* the parameters do not align to block boundaries.
*
******************************************************************************/
XStatus XFlash_Unlock(XFlash *InstancePtr, Xuint32 Offset, Xuint32 Bytes)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.Unlock(InstancePtr, Offset, Bytes));
}


/*****************************************************************************/
/**
*
* Returns the status of the device. This function is intended to be used to
* poll the device in the following circumstances:
*
*  - After calling XFlash_Write with XFL_NON_BLOCKING_WRITE_OPTION option set.
*  - After calling XFlash_Erase or XFlash_EraseChip with
*    XFL_NON_BLOCKING_ERASE_OPTION option set.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Offset is the offset into the part.
*
* @return
*
* - XST_FLASH_READY     if the device(s) have completed the previous operation
*                       without error.
* - XST_FLASH_BUSY      if the device(s) are currently performing an erase or
*                       write operation.
* - XST_FLASH_ERROR     if the device(s) have experienced an internal error
*                       occuring during another operation such as write,
*                       erase, or block locking. XFlash_DeviceControl() must be
*                       used to access the cause of the device specific error
*                       condition.
*
* @note
*
* With some types of flash devices, there may be no difference between using
* XFlash_GetBlockStatus or XFlash_GetStatus. See your part data sheet for more
* information.
*
******************************************************************************/
XStatus XFlash_GetStatus(XFlash *InstancePtr, Xuint32 Offset)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.GetStatus(InstancePtr, Offset));
}


/*****************************************************************************/
/**
*
* Erases the entire device(s).
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
*
* @return
*
* If XFL_NON_BLOCKING_ERASE_OPTION option is set, then the return value is
* always XST_SUCCESS.
*.
* If XFL_NON_BLOCKING_ERASE_OPTION option is clear, then the following
* additional codes can be returned:
* - XST_FLASH_NOT_SUPPORTED if the chip erase is not supported by the device(s).
* - XST_FLASH_ERROR if the device(s) have experienced an internal error during
*           the operation. XFlash_DeviceControl() must be used to access the
*           cause of the device specific error condition.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlash_EraseChip(XFlash *InstancePtr)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.EraseChip(InstancePtr));
}


/*****************************************************************************/
/**
*
* Runs a self-test on the driver/device. This is a destructive test. Tests
* performed include:
*
*   - Address bus test
*   - Data bus test
*
* When the tests are complete, the device is reset back into read mode.
*
* @param    InstancePtr is a pointer to the XComponent instance to be worked on.
*
* @return
*
* - XST_SUCCESS if successful.
* - XST_FLASH_ERROR if any test fails.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlash_SelfTest(XFlash *InstancePtr)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.SelfTest(InstancePtr));
}

/*****************************************************************************/
/**
*
* Clears the device(s) status register(s) and place the device(s) into read
* mode.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
*
* @return
*
* - XST_SUCCESS if successful.
* - XST_FLASH_BUSY if the flash devices were in the middle of an operation
*   and could not be reset.
* - XST_FLASH_ERROR if the device(s) have experienced an internal error during
*   the operation. XFlash_DeviceControl() must be used to access the cause of
*   the device specific error condition.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlash_Reset(XFlash *InstancePtr)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.Reset(InstancePtr));
}


/*****************************************************************************/
/**
*
* Sets interface options for this device instance.
*
* Here are the currently available options:
* <pre
*   XFL_NON_BLOCKING_WRITE_OPTION  Blocking write on or off
*   XFL_NON_BLOCKING_ERASE_OPTION  Blocking erase on or off
* </pre>
* To set multiple options, OR the option constants together.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    OptionsFlag is the options to set. 1=set option, 0=clear option.
*
* @return
*
* - XST_SUCCESS if options successfully set.
* - XST_FLASH_NOT_SUPPORTED if option is not supported.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlash_SetOptions(XFlash *InstancePtr, Xuint32 OptionsFlag)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.SetOptions(InstancePtr, OptionsFlag));
}


/*****************************************************************************/
/**
*
* Gets interface options for this device instance.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
*
* @return
*
* Current options flag
*
* @note
*
* None.
*
******************************************************************************/
Xuint32 XFlash_GetOptions(XFlash *InstancePtr)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.GetOptions(InstancePtr));
}

/*****************************************************************************/
/**
*
* Gets the instance's geometry data
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
*
* @return
*
* Instance's Geometry structure
*
* @note
*
* None.
*
******************************************************************************/
XFlashGeometry *XFlash_GetGeometry(XFlash *InstancePtr)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.GetGeometry(InstancePtr));
}

/*****************************************************************************/
/**
*
* Gets the instance's property data
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
*
* @return
*
* Instance's Properties structure
*
* @note
*
* None.
*
******************************************************************************/
XFlashProperties *XFlash_GetProperties(XFlash *InstancePtr)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.GetProperties(InstancePtr));
}

/*****************************************************************************/
/**
*
* Accesses device specific data or commands. For a list of commands, see
* derived component documentation.
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Command is the device specific command to issue
* @param    Param is the command parameter
* @param    ReturnPtr is the result of command (if any)
*
* @return
*
* - XST_SUCCESS if successful
* - XST_FLASH_NOT_SUPPORTED if the command is not recognized/supported by the
*   device(s).
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlash_DeviceControl(XFlash *InstancePtr, Xuint32 Command,
                             Xuint32 Param, Xuint32 *ReturnPtr)
{
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    return (InstancePtr->VTable.DeviceControl(InstancePtr, Command, Param,
                                             ReturnPtr));
}

/*****************************************************************************/
/**
*
* Checks the readiness of the device, which means it has been successfully
* initialized.
*
* @param    InstancePtr is a pointer to the XFlash instance to be worked on.
*
* @return
*
* XTRUE if the device has been initialized (but not necessarily started),
* and XFALSE otherwise.
*
* @note
*
* This function only exists in the base component since it is common
* across all derived components. Asserts based on the IsReady flag
* exist only in the base component.
*
******************************************************************************/
Xboolean XFlash_IsReady(XFlash *InstancePtr)
{
    XASSERT_NONVOID(InstancePtr != XNULL);

    return (InstancePtr->IsReady == XCOMPONENT_IS_READY);
}


/*****************************************************************************/
/**
*
* Sets up the VTable function pointers for the instance, based on the instance's
* Properties->CommandSet attribute.  This function allows multiple versions of
* a driver to be used simultaneously.
*
* @param    InstancePtr is a ointer to the Flash instance to be worked on.
*
* @return
*
* - XST_SUCCESS if successful.
* - XST_FLASH_NOT_SUPPORTED if no matching part is found.
*
* @note
*
* When a new version of a component is added, this function must be
* modified to appropriately set up the function pointers.
*
******************************************************************************/
static XStatus SetVTable(XFlash *InstancePtr)
{
    switch (InstancePtr->Properties.PartID.CommandSet)
    {
#ifdef XPAR_FLASH_INTEL_SUPPORT
        case XFL_CMDSET_INTEL_EXTENDED:
        case XFL_CMDSET_INTEL_STANDARD:
            InstancePtr->VTable.ReadBlock = XFlashIntel_ReadBlock;
            InstancePtr->VTable.WriteBlock = XFlashIntel_WriteBlock;
            InstancePtr->VTable.WriteBlockSuspend = XFlashIntel_WriteBlockSuspend;
            InstancePtr->VTable.WriteBlockResume = XFlashIntel_WriteBlockResume;
            InstancePtr->VTable.EraseBlock = XFlashIntel_EraseBlock;
            InstancePtr->VTable.EraseBlockSuspend = XFlashIntel_EraseBlockSuspend;
            InstancePtr->VTable.EraseBlockResume = XFlashIntel_EraseBlockResume;
            InstancePtr->VTable.LockBlock = XFlashIntel_LockBlock;
            InstancePtr->VTable.UnlockBlock = XFlashIntel_UnlockBlock;
            InstancePtr->VTable.GetBlockStatus = XFlashIntel_GetBlockStatus;
            InstancePtr->VTable.Read = XFlashIntel_Read;
            InstancePtr->VTable.Write = XFlashIntel_Write;
            InstancePtr->VTable.WriteSuspend = XFlashIntel_WriteSuspend;
            InstancePtr->VTable.WriteResume = XFlashIntel_WriteResume;
            InstancePtr->VTable.Erase = XFlashIntel_Erase;
            InstancePtr->VTable.EraseSuspend = XFlashIntel_EraseSuspend;
            InstancePtr->VTable.EraseResume = XFlashIntel_EraseResume;
            InstancePtr->VTable.Lock = XFlashIntel_Lock;
            InstancePtr->VTable.Unlock = XFlashIntel_Unlock;
            InstancePtr->VTable.GetStatus = XFlashIntel_GetStatus;
            InstancePtr->VTable.EraseChip = XFlashIntel_EraseChip;
            InstancePtr->VTable.Initialize = XFlashIntel_Initialize;
            InstancePtr->VTable.SelfTest = XFlashIntel_SelfTest;
            InstancePtr->VTable.Reset = XFlashIntel_Reset;
            InstancePtr->VTable.SetOptions = XFlashIntel_SetOptions;
            InstancePtr->VTable.GetOptions = XFlashIntel_GetOptions;
            InstancePtr->VTable.GetProperties = XFlashIntel_GetProperties;
            InstancePtr->VTable.GetGeometry = XFlashIntel_GetGeometry;
            InstancePtr->VTable.DeviceControl = XFlashIntel_DeviceControl;
            break;
#endif

        default:
            return (XST_FLASH_PART_NOT_SUPPORTED);
    }
    return (XST_SUCCESS);
}

