/* $Id: xflash_geometry.h,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.h
*
* This is a helper component for XFlash. It contains the geometry information
* for an XFlash instance with utilities to translate from absolute to block
* coordinate systems.
*
* <b>Absolute coordinates</b>
*
*   This coordinate system is simply an offset into the address space of the
*   flash instance.
*
* <b>Block coordinates</b>
*
*   This coordinate system is dependent on the device's block geometry. All
*   flash devices are divisible by independent erase blocks which can be
*   addressed with this coordinate system. The coordinates are defined as:
*
*      - BlockOffset - The offset within an erase block
*      - Block - An erase block
*      - Region - An area containing erase blocks of the same size
*
*
*   The picture below shows the differences between the coordinate systems.
*   The sample part has two regions of three blocks each.
* <pre>
*                              Absolute      Region   Block   Offset
*                              --------      ------   -----   ------
*     +-----------------------+    0           0        0     0
*     |                       |                0        0     blocksizeA-1
*     +-----------------------+                0        1     0
*     |                       |                0        1     blocksizeA-1
*     +-----------------------+                0        2     0
*     |                       |                0        2     blocksizeA-1
*     +=======================+                1        0     0
*     |                       |
*     |                       |
*     |                       |
*     |                       |                1        0     blocksizeB-1
*     +-----------------------+                1        1     0
*     |                       |
*     |                       |
*     |                       |
*     |                       |                1        1     blocksizeB-1
*     +-----------------------+                1        2     0
*     |                       |
*     |                       |
*     |                       |
*     |                       |                1        2     blocksizeB-1
*     +-----------------------+                1        3     0
*     |                       |
*     |                       |
*     |                       |
*     |                       |
*     +-----------------------+  DevSize-1     1        3     blocksizeB-1
* </pre>
*
* <b>Multiple devices</b>
*
*  Some systems designs have more than one physical part wired in parallel
*  on the data bus with each part appearing to be interleaved in the address
*  space. The geometry takes these extra parts into consideration by
*  doubling the sizes of blocks and regions.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver   Who  Date     Changes
* ----- ---- -------- -----------------------------------------------
* 1.00a rmm  03/15/02 Added XFL_LAYOUT_X16_X16_X4
* 1.00a rmm  07/16/01 First release
* </pre>
*
***************************************************************************/

#ifndef XFLASH_GEOMETRY_H /* prevent circular inclusions */
#define XFLASH_GEOMETRY_H /* by using protection macros */

/***************************** Include Files *********************************/
#include "xbasic_types.h"
#include "xstatus.h"

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

/**
 * A block region is defined as a set of consecutive erase blocks of the
 * same size. Most flash devices only have a handful of regions. If a
 * part has more regions than defined by this constant, then the constant
 * must be modified to accomodate the part. The minimum value of this
 * constant is 1 and there is no maximum value. Note that increasing this
 * value also increases the amount of memory used by the geometry structure
 * approximately 12 bytes per increment.
 */
#define XFL_MAX_ERASE_REGIONS  16

/*
 * Supported part arrangements.
 * This enumeration defines the supported arrangements of parts on the
 * data-bus. The naming convention for these constants is as follows:
 *
 *    XFL_LAYOUT_Xa_Xb_Xc, where
 *
 * Xa is the part's physical data bus width. Xb is the is the part's selected
 * data bus width (this field is required because a x16 part can be placed in
 * x8 mode). Xc is the number of interleaved parts. For example one part can
 * be tied to D0-D15 and a second to data lines D15-D31.
 *
 * Parts arranged in series should be treated as separate instances. An example
 * of this layout: Two X16 parts operating in X16 mode. The first part occupies
 * address space FF000000 - FF0FFFFF and a second from FF100000 - FF1FFFFF.
 *
 * These constants are encoded using bitmasks defined in the next section.
 */
#define XFL_LAYOUT_X16_X16_X1 0x02020201UL  /* One 16-bit part operating in
                                               16-bit mode. Total data bus width
                                               is 16-bits */
#define XFL_LAYOUT_X16_X16_X2 0x04020202UL  /* Two 16-bit parts operating in
                                               16-bit mode. Total data bus width
                                               is 32-bits */
#define XFL_LAYOUT_X16_X16_X4 0x08020204UL  /* Four 16-bit parts operating in
                                               16-bit mode. Total data bus width
                                               is 64-bits */

/*
 * LAYOUT constants are used to parse the XFL_LAYOUT_X* constants defined
 * above
 */
#define XFL_LAYOUT_NUM_PARTS_MASK  0x000000FF
#define XFL_LAYOUT_PART_MODE_MASK  0x0000FF00
#define XFL_LAYOUT_PART_WIDTH_MASK 0x00FF0000
#define XFL_LAYOUT_CFI_INTERL_MASK 0xFF000000

#define XFL_LAYOUT_NUM_PARTS_1     0x00000001
#define XFL_LAYOUT_NUM_PARTS_2     0x00000002
#define XFL_LAYOUT_NUM_PARTS_4     0x00000004
#define XFL_LAYOUT_PART_MODE_8     0x00000100
#define XFL_LAYOUT_PART_MODE_16    0x00000200
#define XFL_LAYOUT_PART_WIDTH_8    0x00010000
#define XFL_LAYOUT_PART_WIDTH_16   0x00020000
#define XFL_LAYOUT_CFI_INTERL_1    0x01000000
#define XFL_LAYOUT_CFI_INTERL_2    0x02000000
#define XFL_LAYOUT_CFI_INTERL_4    0x04000000
#define XFL_LAYOUT_CFI_INTERL_8    0x08000000

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

/**
 * Flash geometry
 */
typedef struct
{
    Xuint32 BaseAddress;            /**< Base address of part(s) */
    Xuint32 MemoryLayout;           /**< How multiple parts are connected on
                                       the data bus. Choices are limited to
                                       XFL_LAYOUT_Xa_Xb_Xc constants */
    Xuint32 DeviceSize;             /**< Total device size in bytes */
    Xuint32 NumEraseRegions;        /**< Number of erase regions */
    Xuint16 NumBlocks;              /**< Total number of blocks in device */

    struct
    {
        Xuint32 AbsoluteOffset;     /**< Offset within part where region begins */
        Xuint16 AbsoluteBlock;      /**< Block number where region begins */
        Xuint16 Number;             /**< Number of blocks in this region */
        Xuint32 Size;               /**< Size of the block in bytes */
    } EraseRegion[XFL_MAX_ERASE_REGIONS+1];

} XFlashGeometry;

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

/*****************************************************************************/
/**
 *
 * Tests the given Region, Block, and Offset to verify they lie within the
 * address space defined by a geometry instance.
 *
 * @param   GeometryPtr is the geometry instance that defines flash addressing
 * @param   Region is the region to test
 * @param   Block is the block to test
 * @param   BlockOffset is the offset within block
 *
 * @return
 *
 * - 0 if Region, Block, & BlockOffset do not lie within the address space
 *   described by GeometryPtr.
 * - 1 if Region, Block, & BlockOffset are within the address space
 *
 */
#define XFL_GEOMETRY_IS_BLOCK_VALID(GeometryPtr, Region, Block, BlockOffset) \
  (((Region) < ( GeometryPtr)->NumEraseRegions) &&                           \
  ((Block) < (GeometryPtr)->EraseRegion[Region].Number) &&                   \
  ((BlockOffset) < (GeometryPtr)->EraseRegion[Region].Size))


/*****************************************************************************/
/**
 *
 * Tests the given absolute Offset to verify it lies within the bounds of the
 * address space defined by a geometry instance.
 *
 * @param   GeometryPtr is the geometry instance that defines flash addressing
 * @param   Offset is the offset to test
 *
 * @return
 *
 * - 0 if Offset do not lie within the address space described by GeometryPtr.
 * - 1 if Offset are within the address space
 *
 */
#define XFL_GEOMETRY_IS_ABSOLUTE_VALID(GeometryPtr, Offset)  \
  ((Offset) < (GeometryPtr)->DeviceSize)

/*****************************************************************************/
/**
 *
 * Calculates the number of blocks between the given coordinates and the end of
 * the device.
 *
 * @param   GeometryPtr is the geometry instance that defines flash addressing
 * @param   Region is the starting region
 * @param   Block is the starting block.
 *
 * @return
 *
 * The number of blocks between Region/Block and the end of the device
 * (inclusive)
 *
 */
#define XFL_GEOMETRY_BLOCKS_LEFT(GeometryPtr, Region, Block) \
  ((GeometryPtr)->NumBlocks - ((GeometryPtr)->EraseRegion[Region].AbsoluteBlock + Block))

/*****************************************************************************/
/**
 *
 * Calculates the number of blocks between the given start and end coordinates.
 *
 * @param   GeometryPtr is the geometry instance that defines flash addressing
 * @param   StartRegion is the starting region
 * @param   StartBlock is the starting block.
 * @param   EndRegion is the ending region
 * @param   EndBlock is the ending block.
 *
 * @return
 *
 * The number of blocks between start Region/Block and end Region/Block
 * (inclusive)
 *
 */
#define XFL_GEOMETRY_BLOCK_DIFF(GeometryPtr, StartRegion, StartBlock, EndRegion, EndBlock) \
  (((GeometryPtr)->EraseRegion[EndRegion].AbsoluteBlock + (EndBlock)) - \
  ((GeometryPtr)->EraseRegion[StartRegion].AbsoluteBlock + (StartBlock)) + 1)

/*****************************************************************************/
/**
 *
 * Increments the given Region and Block to the next block address.
 *
 * @param   GeometryPtr is the geometry instance that defines flash addressing
 * @param   Region is the starting region.
 * @param   Block is the starting block.
 *
 * @return
 *
 * Region parameter is incremented if the next block starts in a new region.
 * Block parameter is set to zero if the next block starts in a new region,
 * otherwise it is incremented by one.
 *
 */
#define XFL_GEOMETRY_INCREMENT(GeometryPtr, Region, Block)       \
{                                                                \
    if ((GeometryPtr)->EraseRegion[Region].Number <= ++(Block))  \
    {                                                            \
        (Region)++;                                              \
        (Block) = 0;                                             \
    }                                                            \
}

/************************** Function Prototypes ******************************/
XStatus XFlashGeometry_ToBlock(XFlashGeometry *InstancePtr,
                               Xuint32 AbsoluteOffset,
                               Xuint16 *Region,
                               Xuint16 *Block,
                               Xuint32 *BlockOffset);

XStatus XFlashGeometry_ToAbsolute(XFlashGeometry *InstancePtr,
                                  Xuint16 Region,
                                  Xuint16 Block,
                                  Xuint32 BlockOffset,
                                  Xuint32 *AbsoluteOffsetPtr);

unsigned int XFlashGeometry_DiffBlocks(XFlashGeometry *GeometryPtr,
                                       Xuint16 StartRegion, Xuint16 StartBlock,
                                       Xuint16 EndRegion, Xuint16 EndBlock);

Xuint32 XFlashGeometry_ConvertLayout(Xuint8 NumParts, Xuint8 PartWidth,
                                     Xuint8 PartMode);

#endif            /* end of protection macro */
