/* $Id: xflash_geometry.c,v 1.7 2002/04/19 16:19:42 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_geometry.c
*
* This module implements the helper component XFlashGeometry.
*
* The helper component is responsible for containing the geometry information
* for the flash part(s) and for converting from an absolute part offset to
* region/block/blockOffset coordinates.
*
* XFlashGeometry describes the geometry of the entire instance, not the
* individual parts of that instance. For example, if the user's board
* architecture uses two 16-bit parts in parallel for a 32-bit data path, then
* the size of erase blocks and device sizes are multiplied by a factor
* of two.
*
* @note
*
* This helper component 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, or cache control
* management must be satisfied by the layer above this driver.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver   Who  Date     Changes
* ----- ---- -------- -----------------------------------------------
* 1.00a rmm  07/16/01 First release
* </pre>
*
****************************************************************************/

/***************************** Include Files *********************************/
#include "xbasic_types.h"
#include "xflash.h"
#include "xflash_geometry.h"

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


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


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


/************************** Function Prototypes ******************************/


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

/*****************************************************************************/
/**
*
* Converts  block coordinates to a part offset. Region, Block, & BlockOffset
* are converted to PartOffset
*
* @param    InstancePtr is the pointer to the XFlash instance to be worked on.
* @param    Region is the erase region the physical address appears in.
* @param    Block is the block within Region the physical address appears in.
* @param    BlockOffset is the offset within Block where the physical address
*           appears.
* @param    AbsoluteOffsetPtr is the returned offset value
*
* @return
*
* - XST_SUCCESS                if successful.
* - XST_FLASH_ADDRESS_ERROR    if the block coordinates are invalid.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlashGeometry_ToAbsolute(XFlashGeometry *InstancePtr,
                                  Xuint16 Region,
                                  Xuint16 Block,
                                  Xuint32 BlockOffset,
                                  Xuint32 *AbsoluteOffsetPtr)
{
    /*
     * Verify inputs are valid
     */
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(AbsoluteOffsetPtr != XNULL);

    /*
     * Validate Region, Block, and BlockOffset parameters
     */
    if (!XFL_GEOMETRY_IS_BLOCK_VALID(InstancePtr, Region, Block, BlockOffset))
    {
        return (XST_FLASH_ADDRESS_ERROR);
    }

    /*
     * Calculate offset
     */
    *AbsoluteOffsetPtr = InstancePtr->EraseRegion[Region].AbsoluteOffset +
        (InstancePtr->EraseRegion[Region].Size * Block) + BlockOffset;

    return (XST_SUCCESS);
}

/*****************************************************************************/
/**
*
* Converts part offset block coordinates. PartOffset is converted to Region,
* Block, & BlockOffset
*
* @param    InstancePtr is the pointer to the XFlashGeometry instance to be
*           worked on.
* @param    AbsoluteOffset is the offset within part to find block coordinates for.
* @param    RegionPtr is the the region that corresponds to AbsoluteOffset.
*           This is a return parameter.
* @param    BlockPtr is the the block within Region that corresponds to
*           AbsoluteOffset. This is a return parameter.
* @param    BlockOffsetPtr is the the offset within Block that corresponds to
*           AbsoluteOffset. This is a return parameter.
*
* @return
*
* - XST_SUCCESS               if successful.
* - XST_FLASH_ADDRESS_ERROR   if the block coordinates are invalid.
*
* @note
*
* None.
*
******************************************************************************/
XStatus XFlashGeometry_ToBlock(XFlashGeometry *InstancePtr,
                               Xuint32 AbsoluteOffset,
                               Xuint16 *RegionPtr,
                               Xuint16 *BlockPtr,
                               Xuint32 *BlockOffsetPtr)
{
    int i;
    Xuint32 RemainderOffset;

    /*
     * Verify inputs are valid
     */
    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(RegionPtr != XNULL);
    XASSERT_NONVOID(BlockPtr != XNULL);
    XASSERT_NONVOID(BlockOffsetPtr != XNULL);

    /*
     * Determine if the offset exceeds the device's size
     */
    if (!XFL_GEOMETRY_IS_ABSOLUTE_VALID(InstancePtr, AbsoluteOffset))
    {
        return (XST_FLASH_ADDRESS_ERROR);
    }

    /*
     * Calculate the region. When the loop breaks, i will index one past
     * the region that the offset appears in.
     */
    for (i=1; i<XFL_MAX_ERASE_REGIONS; i++)
    {
        if (AbsoluteOffset < InstancePtr->EraseRegion[i].AbsoluteOffset)
        {
            break;
        }
    }
    i--;

    /*
     * Calculate the remaining offset from which block and block offset
     * are calculated
     */
    RemainderOffset = AbsoluteOffset -
        InstancePtr->EraseRegion[i].AbsoluteOffset;

    /*
     * Calculate block & offset, assign return values and return
     */
    *RegionPtr = i;
    *BlockPtr = RemainderOffset / InstancePtr->EraseRegion[i].Size;
    *BlockOffsetPtr = RemainderOffset -
        (*BlockPtr * InstancePtr->EraseRegion[i].Size);

    return (XST_SUCCESS);
}

/*****************************************************************************/
/**
*
* Converts array layout into an XFL_LAYOUT_Xa_Xb_Xc constant. This function
* is typically called during initialization to convert ordinal values
* delivered by a system generator into the XFL constants which are optimized
* for use by the flash driver.
*
* @param    NumParts - Number of parts in the array.
* @param    PartWidth - Width of each part in bytes.
* @param    PartMode - Operation mode of each part in bytes.
*
* @return
*
* - XFL_LAYOUT_*          - One of the supported layouts
* - XNULL                 if a layout cannot be found that supports
*                         the given arguments
*
* @note
*
* None.
*
******************************************************************************/
Xuint32 XFlashGeometry_ConvertLayout(Xuint8 NumParts, Xuint8 PartWidth,
                                     Xuint8 PartMode)
{
    if ((NumParts == 1) && (PartWidth == 2) && (PartMode == 2))
    {
        return(XFL_LAYOUT_X16_X16_X1);
    }
    else if ((NumParts == 2) && (PartWidth == 2) && (PartMode == 2))
    {
        return(XFL_LAYOUT_X16_X16_X2);
    }
    else if ((NumParts == 4) && (PartWidth == 2) && (PartMode == 2))
    {
        return(XFL_LAYOUT_X16_X16_X4);
    }
    else
    {
        return(XNULL);
    }
}
