embeddedsw/lib/sw_services/xilisf/src/xilisf.c
Shakti Bhatnagar c2b6e79695 xiliisf: Updated xilisf lib
Updated the lib src files as well as the examples
for the major version change v5_0

Signed-off-by: Shakti Bhatnagar <shaktib@xilinx.com>
2014-09-02 11:21:18 +05:30

1806 lines
53 KiB
C
Executable file

/******************************************************************************
*
* Copyright (C) 2012 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xilisf.c
*
* This file contains the library functions to initialize, control and read the
* device information of the Serial Flash devices. Refer xilisf.h for detailed
* description.
*
* <pre>
*
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ------- -------- -----------------------------------------------
* 1.00a ksu/sdm 03/03/08 First release
* 1.00a sdm 07/02/08 Changed the initialization so that the SPI
* Master works in Spi Mode 3 as the In-System Flash
* works only in Spi Mode 3
* 2.00a ktn 11/27/09 Updated to use HAL processor APIs/definitions
* 2.01a sdm 01/04/10 Added Support for Winbond W25QXX/W25XX devices
* The parameter PagesPerBlock in the struct
* IntelStmDeviceGeometry has been renamed to
* PagesPerSector.
* 2.03a sdm 04/17/10 Updated to support Winbond memory W25Q128.
* 2.04a sdm 08/17/10 Updated to support Numonyx (N25QXX) and Spansion
* flash memories
* 3.00a srt 06/20/12 Updated to support interfaces SPI PS and QSPI PS.
* New API:
* XIsf_RegisterInterface()
* XIsf_SetSpiConfiguration()
* XIsf_SetTransferMode()
* Changed API:
* XIsf_Initialize()
* XIsf_Transfer()
* Added support to SST flash.
* 3.01a srt 02/06/13 Updated for changes made in QSPIPS driver
* (CR 698107).
* 5.0 sb 08/05/14 Updated for support for > 128 MB flash for PSQSPI
* Interface. Added Library Handler API which will
* register to driver interrupts, based upon the
* interface selected.
* New API:
* SpaMicWinFlashInitialize()
* GetRealAddr()
* SendBankSelect()
* XIsf_SetStatusHandler()
* void XIsf_IfaceHandler()
* Changed API:
* - XIsf_Initialize()
* Added Call back to lib interrupt handler
* after XIsf_Transfer Call
* - XIsf_Transfer()
* - XIsf_GetStatus()
* - XIsf_GetStatusReg2()
* - XIsf_GetDeviceInfo()
* - XIsf_WriteEnable()
* - XIsf_Ioctl()
*
*
* </pre>
*
******************************************************************************/
/***************************** Include Files *********************************/
#include "include/xilisf.h"
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
#if (XPAR_XISF_FLASH_FAMILY == ATMEL)
/**
* The following structure specifies the geometry of the Atmel Serial Flash.
*/
typedef struct {
u8 DeviceCode; /**< Device code */
u16 BytesPerPageDefaultMode; /**< Bytes per Page in Default mode */
u16 BytesPerPagePowerOf2Mode; /**< Bytes per Page in PowerOf2 mode */
u8 PagesPerBlock; /**< Number of Pages per Block */
u8 BlocksPerSector; /**< Number of Blocks per Sector */
u8 NumOfSectors; /**< Number of Sectors in the device */
} AtmelDeviceGeometry;
#endif /* (XPAR_XISF_FLASH_FAMILY == ATMEL) */
#if ((XPAR_XISF_FLASH_FAMILY == INTEL) || (XPAR_XISF_FLASH_FAMILY == STM) \
|| (XPAR_XISF_FLASH_FAMILY == SST))
/**
* The following structure specifies the geometry of the Intel/STM Serial Flash.
*/
typedef struct {
u8 ManufacturerID; /**< Manufacturer code */
u16 DeviceCode; /**< Device code */
u16 BytesPerPage; /**< Bytes per Page */
u16 PagesPerSector; /**< Number of Pages per Sector */
u16 NumOfSectors; /**< Number of Sectors in the device */
} IntelStmDeviceGeometry;
#endif /* ((XPAR_XISF_FLASH_FAMILY==INTEL) || (XPAR_XISF_FLASH_FAMILY==STM) \
|| (XPAR_XISF_FLASH_FAMILY == SST))*/
#if ((XPAR_XISF_FLASH_FAMILY == WINBOND) || \
(XPAR_XISF_FLASH_FAMILY == SPANSION))
/**
* The following structure specifies the geometry of the Spansion/Micron
* Serial Flash.
*/
typedef struct {
u32 SectSize; /**< Individual sector size or
* combined sector size in case of parallel
* config*/
u32 NumSect; /**< Total no. of sectors in one/two
* flash devices */
u32 PageSize; /**< Individual page size or
* combined page size in case of parallel
* config*/
u32 NumPage; /**< Total no. of pages in one/two flash
* devices */
u32 FlashDeviceSize; /**< This is the size of one flash device
* NOT the combination of both devices,
* if present */
u8 ManufacturerID; /**< Manufacturer ID - used to identify make */
u8 DeviceIDMemSize; /**< Byte of device ID indicating the memory
* size */
u32 SectMask; /**< Mask to get sector start address */
u8 NumDie; /**< No. of die forming a single flash */
} SpaMicWinDeviceGeometry;
#endif /* ((XPAR_XISF_FLASH_FAMILY == WINBOND) ||
(XPAR_XISF_FLASH_FAMILY == SPANSION)) */
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
int XIsf_Transfer(XIsf *InstancePtr, u8 *WritePtr, u8* ReadPtr,u32 ByteCount);
u32 GetRealAddr(XIsf_Iface *QspiPtr, u32 Address);
#ifdef XPAR_XISF_INTERFACE_PSQSPI
int SendBankSelect(XIsf *InstancePtr, u32 BankSel);
#endif
#if (XPAR_XISF_FLASH_FAMILY == ATMEL)
static int AtmelFlashInitialize(XIsf *InstancePtr, u8 *ReadBuf);
#endif /* (XPAR_XISF_FLASH_FAMILY == ATMEL) */
#if ((XPAR_XISF_FLASH_FAMILY == INTEL) || (XPAR_XISF_FLASH_FAMILY == STM) || \
(XPAR_XISF_FLASH_FAMILY == SST))
static int IntelStmFlashInitialize(XIsf *InstancePtr, u8 *ReadBuf);
#endif /* ((XPAR_XISF_FLASH_FAMILY == INTEL) || \
(XPAR_XISF_FLASH_FAMILY == STM) || \
(|| (XPAR_XISF_FLASH_FAMILY == SST)) */
#if ((XPAR_XISF_FLASH_FAMILY == WINBOND) || \
(XPAR_XISF_FLASH_FAMILY == SPANSION))
static int SpaMicWinFlashInitialize(XIsf *InstancePtr, u8 *BufferPtr);
#endif /* ((XPAR_XISF_FLASH_FAMILY == WINBOND) || \
(XPAR_XISF_FLASH_FAMILY == SPANSION)) */
/************************** Variable Definitions *****************************/
#if (XPAR_XISF_FLASH_FAMILY == ATMEL)
static const AtmelDeviceGeometry AtmelDevices[] = {
{XISF_ATMEL_DEV_AT45DB011D, XISF_BYTES264_PER_PAGE,
XISF_BYTES256_PER_PAGE, XISF_PAGES8_PER_BLOCK,
XISF_BLOCKS16_PER_SECTOR, XISF_NUM_OF_SECTORS4},
{XISF_ATMEL_DEV_AT45DB021D, XISF_BYTES264_PER_PAGE,
XISF_BYTES256_PER_PAGE, XISF_PAGES8_PER_BLOCK,
XISF_BLOCKS16_PER_SECTOR, XISF_NUM_OF_SECTORS8},
{XISF_ATMEL_DEV_AT45DB041D, XISF_BYTES264_PER_PAGE,
XISF_BYTES256_PER_PAGE, XISF_PAGES8_PER_BLOCK,
XISF_BLOCKS32_PER_SECTOR, XISF_NUM_OF_SECTORS8},
{XISF_ATMEL_DEV_AT45DB081D, XISF_BYTES264_PER_PAGE,
XISF_BYTES256_PER_PAGE, XISF_PAGES8_PER_BLOCK,
XISF_BLOCKS32_PER_SECTOR, XISF_NUM_OF_SECTORS16},
{XISF_ATMEL_DEV_AT45DB161D, XISF_BYTES528_PER_PAGE,
XISF_BYTES512_PER_PAGE, XISF_PAGES8_PER_BLOCK,
XISF_BLOCKS32_PER_SECTOR, XISF_NUM_OF_SECTORS16},
{XISF_ATMEL_DEV_AT45DB321D, XISF_BYTES528_PER_PAGE,
XISF_BYTES512_PER_PAGE, XISF_PAGES8_PER_BLOCK,
XISF_BLOCKS16_PER_SECTOR, XISF_NUM_OF_SECTORS64},
{XISF_ATMEL_DEV_AT45DB642D, XISF_BYTES1056_PER_PAGE,
XISF_BYTES1024_PER_PAGE, XISF_PAGES8_PER_BLOCK,
XISF_BLOCKS32_PER_SECTOR, XISF_NUM_OF_SECTORS32}
};
#endif /* (XPAR_XISF_FLASH_FAMILY == ATMEL) */
#if ((XPAR_XISF_FLASH_FAMILY == INTEL) || (XPAR_XISF_FLASH_FAMILY == STM) \
|| (XPAR_XISF_FLASH_FAMILY == SST))
static const IntelStmDeviceGeometry IntelStmDevices[] = {
{XISF_MANUFACTURER_ID_INTEL, XISF_INTEL_DEV_S3316MBIT,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS32},
{XISF_MANUFACTURER_ID_INTEL, XISF_INTEL_DEV_S3332MBIT,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS64},
{XISF_MANUFACTURER_ID_INTEL, XISF_INTEL_DEV_S3364MBIT,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS128},
{XISF_MANUFACTURER_ID_STM, XISF_STM_DEV_M25P05_A,
XISF_BYTES256_PER_PAGE, XISF_PAGES128_PER_SECTOR,
XISF_NUM_OF_SECTORS2},
{XISF_MANUFACTURER_ID_STM, XISF_STM_DEV_M25P10_A,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS2},
{XISF_MANUFACTURER_ID_STM, XISF_STM_DEV_M25P20,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS4},
{XISF_MANUFACTURER_ID_STM, XISF_STM_DEV_M25P40,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS8},
{XISF_MANUFACTURER_ID_STM, XISF_STM_DEV_M25P80,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS16},
{XISF_MANUFACTURER_ID_STM, XISF_STM_DEV_M25P16,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS32},
{XISF_MANUFACTURER_ID_STM, XISF_STM_DEV_M25P32,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS64},
{XISF_MANUFACTURER_ID_STM, XISF_STM_DEV_M25P64,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS128},
{XISF_MANUFACTURER_ID_STM, XISF_STM_DEV_M25P128,
XISF_BYTES256_PER_PAGE, XISF_PAGES1024_PER_SECTOR,
XISF_NUM_OF_SECTORS64},
{XISF_MANUFACTURER_ID_WINBOND, XISF_WB_DEV_W25Q80,
XISF_BYTES256_PER_PAGE, XISF_PAGES16_PER_SECTOR,
XISF_NUM_OF_SECTORS256},
{XISF_MANUFACTURER_ID_WINBOND, XISF_WB_DEV_W25Q16,
XISF_BYTES256_PER_PAGE, XISF_PAGES16_PER_SECTOR,
XISF_NUM_OF_SECTORS512},
{XISF_MANUFACTURER_ID_WINBOND, XISF_WB_DEV_W25Q32,
XISF_BYTES256_PER_PAGE, XISF_PAGES16_PER_SECTOR,
XISF_NUM_OF_SECTORS1024},
{XISF_MANUFACTURER_ID_WINBOND, XISF_WB_DEV_W25Q64,
XISF_BYTES256_PER_PAGE, XISF_PAGES16_PER_SECTOR,
XISF_NUM_OF_SECTORS2048},
{XISF_MANUFACTURER_ID_WINBOND, XISF_WB_DEV_W25Q128,
XISF_BYTES256_PER_PAGE, XISF_PAGES16_PER_SECTOR,
XISF_NUM_OF_SECTORS4096},
{XISF_MANUFACTURER_ID_WINBOND, XISF_WB_DEV_W25X10,
XISF_BYTES256_PER_PAGE, XISF_PAGES16_PER_SECTOR,
XISF_NUM_OF_SECTORS32},
{XISF_MANUFACTURER_ID_WINBOND, XISF_WB_DEV_W25X20,
XISF_BYTES256_PER_PAGE, XISF_PAGES16_PER_SECTOR,
XISF_NUM_OF_SECTORS64},
{XISF_MANUFACTURER_ID_WINBOND, XISF_WB_DEV_W25X40,
XISF_BYTES256_PER_PAGE, XISF_PAGES16_PER_SECTOR,
XISF_NUM_OF_SECTORS128},
{XISF_MANUFACTURER_ID_WINBOND, XISF_WB_DEV_W25X80,
XISF_BYTES256_PER_PAGE, XISF_PAGES16_PER_SECTOR,
XISF_NUM_OF_SECTORS256},
{XISF_MANUFACTURER_ID_WINBOND, XISF_WB_DEV_W25X16,
XISF_BYTES256_PER_PAGE, XISF_PAGES16_PER_SECTOR,
XISF_NUM_OF_SECTORS512},
{XISF_MANUFACTURER_ID_WINBOND, XISF_WB_DEV_W25X32,
XISF_BYTES256_PER_PAGE, XISF_PAGES16_PER_SECTOR,
XISF_NUM_OF_SECTORS1024},
{XISF_MANUFACTURER_ID_WINBOND, XISF_WB_DEV_W25X64,
XISF_BYTES256_PER_PAGE, XISF_PAGES16_PER_SECTOR,
XISF_NUM_OF_SECTORS2048},
{XISF_MANUFACTURER_ID_STM, XISF_NM_DEV_N25Q32,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS64},
{XISF_MANUFACTURER_ID_STM, XISF_NM_DEV_N25Q64,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS128},
{XISF_MANUFACTURER_ID_STM, XISF_NM_DEV_N25Q128,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS256},
{XISF_MANUFACTURER_ID_STM, XISF_MIC_DEV_N25Q128,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS256},
{XISF_MANUFACTURER_ID_SPANSION, XISF_SPANSION_DEV_S25FL004,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS8},
{XISF_MANUFACTURER_ID_SPANSION, XISF_SPANSION_DEV_S25FL008,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS16},
{XISF_MANUFACTURER_ID_SPANSION, XISF_SPANSION_DEV_S25FL016,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS32},
{XISF_MANUFACTURER_ID_SPANSION, XISF_SPANSION_DEV_S25FL032,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS64},
{XISF_MANUFACTURER_ID_SPANSION, XISF_SPANSION_DEV_S25FL064,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS128},
{XISF_MANUFACTURER_ID_SPANSION, XISF_SPANSION_DEV_S25FL128,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS256},
{XISF_MANUFACTURER_ID_SST, XISF_SST_DEV_SST25WF080,
XISF_BYTES256_PER_PAGE, XISF_PAGES256_PER_SECTOR,
XISF_NUM_OF_SECTORS256},
};
#endif /* ((XPAR_XISF_FLASH_FAMILY==INTEL) || (XPAR_XISF_FLASH_FAMILY==STM) \
|| (XPAR_XISF_FLASH_FAMILY == SST))*/
#if ((XPAR_XISF_FLASH_FAMILY == WINBOND) || \
(XPAR_XISF_FLASH_FAMILY == SPANSION))
static const SpaMicWinDeviceGeometry SpaMicWinDevices[] = {
{0x10000, 0x100, 256, 0x10000, 0x1000000,
XISF_MANUFACTURER_ID_SPANSION, XISF_SPANSION_ID_BYTE2_128,
0xFFFF0000, 1},
{0x10000, 0x200, 256, 0x20000, 0x1000000,
XISF_MANUFACTURER_ID_SPANSION, XISF_SPANSION_ID_BYTE2_128,
0xFFFF0000, 1},
{0x20000, 0x100, 512, 0x10000, 0x1000000,
XISF_MANUFACTURER_ID_SPANSION, XISF_SPANSION_ID_BYTE2_128,
0xFFFE0000, 1},
{0x10000, 0x200, 256, 0x20000, 0x2000000,
XISF_MANUFACTURER_ID_SPANSION, XISF_SPANSION_ID_BYTE2_256,
0xFFFF0000, 1},
{0x10000, 0x400, 256, 0x40000, 0x2000000,
XISF_MANUFACTURER_ID_SPANSION, XISF_SPANSION_ID_BYTE2_256,
0xFFFF0000, 1},
{0x20000, 0x200, 512, 0x20000, 0x2000000,
XISF_MANUFACTURER_ID_SPANSION, XISF_SPANSION_ID_BYTE2_256,
0xFFFE0000, 1},
{0x40000, 0x100, 512, 0x20000, 0x4000000,
XISF_MANUFACTURER_ID_SPANSION, XISF_SPANSION_ID_BYTE2_512,
0xFFFC0000, 1},
{0x40000, 0x200, 512, 0x40000, 0x4000000,
XISF_MANUFACTURER_ID_SPANSION, XISF_SPANSION_ID_BYTE2_512,
0xFFFC0000, 1},
{0x80000, 0x100, 1024, 0x20000, 0x4000000,
XISF_MANUFACTURER_ID_SPANSION, XISF_SPANSION_ID_BYTE2_512,
0xFFF80000, 1},
/* Spansion 1Gbit is handled as 512Mbit stacked */
/* Micron */
{0x10000, 0x100, 256, 0x10000, 0x1000000,
XISF_MANUFACTURER_ID_MICRON, XISF_MICRON_ID_BYTE2_128,
0xFFFF0000, 1},
{0x10000, 0x200, 256, 0x20000, 0x1000000,
XISF_MANUFACTURER_ID_MICRON, XISF_MICRON_ID_BYTE2_128,
0xFFFF0000, 1},
{0x20000, 0x100, 512, 0x10000, 0x1000000,
XISF_MANUFACTURER_ID_MICRON, XISF_MICRON_ID_BYTE2_128,
0xFFFE0000, 1},
{0x10000, 0x200, 256, 0x20000, 0x2000000,
XISF_MANUFACTURER_ID_MICRON, XISF_MICRON_ID_BYTE2_256,
0xFFFF0000, 1},
{0x10000, 0x400, 256, 0x40000, 0x2000000,
XISF_MANUFACTURER_ID_MICRON, XISF_MICRON_ID_BYTE2_256,
0xFFFF0000, 1},
{0x20000, 0x200, 512, 0x20000, 0x2000000,
XISF_MANUFACTURER_ID_MICRON, XISF_MICRON_ID_BYTE2_256,
0xFFFE0000, 1},
{0x10000, 0x400, 256, 0x40000, 0x4000000,
XISF_MANUFACTURER_ID_MICRON, XISF_MICRON_ID_BYTE2_512,
0xFFFF0000, 2},
{0x10000, 0x800, 256, 0x80000, 0x4000000,
XISF_MANUFACTURER_ID_MICRON, XISF_MICRON_ID_BYTE2_512,
0xFFFF0000, 2},
{0x20000, 0x400, 512, 0x40000, 0x4000000,
XISF_MANUFACTURER_ID_MICRON, XISF_MICRON_ID_BYTE2_512,
0xFFFE0000, 2},
{0x10000, 0x800, 256, 0x80000, 0x8000000,
XISF_MANUFACTURER_ID_MICRON, XISF_MICRON_ID_BYTE2_1G,
0xFFFF0000, 4},
{0x10000, 0x1000, 256, 0x100000, 0x8000000,
XISF_MANUFACTURER_ID_MICRON, XISF_MICRON_ID_BYTE2_1G,
0xFFFF0000, 4},
{0x20000, 0x800, 512, 0x80000, 0x8000000,
XISF_MANUFACTURER_ID_MICRON, XISF_MICRON_ID_BYTE2_1G,
0xFFFE0000, 4},
/* Winbond */
{0x10000, 0x100, 256, 0x10000, 0x1000000,
XISF_MANUFACTURER_ID_WINBOND, XISF_WINBOND_ID_BYTE2_128,
0xFFFF0000, 1},
{0x10000, 0x200, 256, 0x20000, 0x1000000,
XISF_MANUFACTURER_ID_WINBOND, XISF_WINBOND_ID_BYTE2_128,
0xFFFF0000, 1},
{0x20000, 0x100, 512, 0x10000, 0x1000000,
XISF_MANUFACTURER_ID_WINBOND, XISF_WINBOND_ID_BYTE2_128,
0xFFFE0000, 1}
};
#endif /* ((XPAR_XISF_FLASH_FAMILY == WINBOND) || \
(XPAR_XISF_FLASH_FAMILY == SPANSION)) */
/*
* The following variables are shared between non-interrupt processing and
* interrupt processing such that they must be global.
*/
volatile unsigned int XIsf_TransferInProgress;
u32 XIsf_StatusEventInfo;
unsigned int XIsf_ByteCountInfo;
static u32 XIsf_FCTIndex;
/************************** Function Definitions *****************************/
/*****************************************************************************/
/**
*
* The geometry of the underlying Serial Flash is determined by reading the
* Joint Electron Device Engineering Council (JEDEC) Device Information and
* the Status Register of the Serial Flash.
* This API when called initializes the SPI interface with default settings.
* With custom settings, user should call XIsf_SetSpiConfiguration() and then
* call this API.
*
* @param InstancePtr is a pointer to the XIsf instance.
* @param SpiInstPtr is a pointer to XIsf_Iface instance to be worked on.
* @param SlaveSelect is a 32-bit mask with a 1 in the bit position of
* slave being selected. Only one slave can be selected at a time.
* @param WritePtr is a pointer to the buffer allocated by the user to be
* used by the In-system and Serial Flash Library to perform any
* read/write operations on the Serial Flash device.
* User applications must pass the address of this buffer for the
* Library to work.
* - Write operations :
* - The size of this buffer should be equal to the Number
* of bytes to be written to the Serial Flash +
* XISF_CMD_MAX_EXTRA_BYTES.
* - The size of this buffer should be large enough for
* usage across all the applications that use a common
* instance of the Serial Flash.
* - A minimum of one byte and a maximum of ISF_PAGE_SIZE
* bytes can be written to the Serial Flash, through a
* single Write operation.
* - Read operations :
* - The size of this buffer should be equal to
* XISF_CMD_MAX_EXTRA_BYTES, if the application only reads
* from the Serial Flash (no write operations).
*
* @return - XST_SUCCESS if successful.
* - XST_DEVICE_IS_STOPPED if the device must be started before
* transferring data.
* - XST_FAILURE, otherwise.
*
* @note - The XIsf_Initialize() API is a blocking call (for both
* polled and interrupt modes of the Spi driver). It reads the
* JEDEC information of the device and waits till the transfer is
* complete before checking if the information is valid.
* - This library can support multiple instances of Serial Flash
* at a time, provided they are of the same device family (either
* Atmel, Intel or STM, Winbond or Spansion) as the device family
* is selected at compile time.
*
******************************************************************************/
int XIsf_Initialize(XIsf *InstancePtr, XIsf_Iface *SpiInstPtr, u8 SlaveSelect,
u8 *WritePtr)
{
int Status;
u8 ReadBuf[XISF_INFO_READ_BYTES + XISF_INFO_EXTRA_BYTES] = {0};
if (InstancePtr == NULL) {
return (int)(XST_FAILURE);
}
if (SpiInstPtr == NULL) {
return (int)(XST_FAILURE);
}
if (WritePtr == NULL) {
return (int)(XST_FAILURE);
}
InstancePtr->IsReady = FALSE;
InstancePtr->SpiSlaveSelect = SlaveSelect;
InstancePtr->WriteBufPtr = WritePtr;
#ifdef XPAR_XISF_INTERFACE_AXISPI
if (SpiInstPtr->IsStarted != XIL_COMPONENT_IS_STARTED) {
return XST_DEVICE_IS_STOPPED;
}
#endif
if ((!InstancePtr->RegDone) != 0) {
(void)XIsf_SetSpiConfiguration(InstancePtr, SpiInstPtr,
XISF_SPI_OPTIONS, XISF_SPI_PRESCALER);
}
/*
* Get the JEDEC Device Info.
* The IsReady is temporarily made TRUE and
* transfer is set in polling mode to fetch the JEDEC Info.
*/
XIsf_SetTransferMode(InstancePtr, XISF_POLLING_MODE);
InstancePtr->IsReady = TRUE;
Status = XIsf_GetDeviceInfo(InstancePtr, ReadBuf);
InstancePtr->IsReady = FALSE;
if (Status != (int)(XST_SUCCESS)) {
return (int)(XST_FAILURE);
}
#ifdef XPAR_XISF_INTERFACE_AXISPI
/*
* Wait until the transfer is complete.
*/
do {
Status =
InstancePtr->XIsf_Iface_SetSlaveSelect(InstancePtr->SpiInstPtr,
InstancePtr->SpiSlaveSelect);
} while(Status == XST_DEVICE_BUSY);
if (Status != (int)(XST_SUCCESS)) {
return (int)(XST_FAILURE);
}
#endif
#if (XPAR_XISF_FLASH_FAMILY == ATMEL)
/*
* Check for Atmel Serial Flash.
*/
Status = AtmelFlashInitialize(InstancePtr, ReadBuf);
#endif /* (XPAR_XISF_FLASH_FAMILY == ATMEL) */
#if ((XPAR_XISF_FLASH_FAMILY == INTEL) || (XPAR_XISF_FLASH_FAMILY == STM) \
|| (XPAR_XISF_FLASH_FAMILY == SST))
/*
* Check for Intel/STM/Winbond/Spansion Serial Flash.
*/
Status = IntelStmFlashInitialize(InstancePtr, ReadBuf);
#endif /* ((XPAR_XISF_FLASH_FAMILY==INTEL) || (XPAR_XISF_FLASH_FAMILY==STM) \
|| (XPAR_XISF_FLASH_FAMILY == SST))*/
#if ((XPAR_XISF_FLASH_FAMILY == WINBOND) || \
(XPAR_XISF_FLASH_FAMILY == SPANSION))
Status = SpaMicWinFlashInitialize(InstancePtr, ReadBuf);
#endif /*(XPAR_XISF_FLASH_FAMILY == WINBOND) ||
(XPAR_XISF_FLASH_FAMILY == SPANSION)) */
return Status;
}
/*****************************************************************************/
/**
*
* This API sets the configuration of SPI. This will set the options and
* clock prescaler (if applicable).
*
* @param InstancePtr is a pointer to the XIsf instance.
* @param SpiInstPtr is a pointer to XIsf_Iface instance to be worked on.
* @param Options contains specified options to be set.
* @param PreScaler is the value of the clock prescaler to set.
*
* @return XST_SUCCESS if successful else XST_FAILURE.
*
* @note This API can be called before calling XIsf_Initialize()
* to initialize the SPI interface in other than default options
* mode. PreScaler is only applicable to PS SPI/QSPI.
*
******************************************************************************/
int XIsf_SetSpiConfiguration(XIsf *InstancePtr, XIsf_Iface *SpiInstPtr,
u32 Options, u8 PreScaler)
{
int Status;
if ((!InstancePtr->RegDone) != 0) {
XIsf_RegisterInterface(InstancePtr);
InstancePtr->SpiInstPtr = SpiInstPtr;
InstancePtr->RegDone = TRUE;
}
Status = InstancePtr->XIsf_Iface_SetOptions(InstancePtr->SpiInstPtr,
Options);
if (Status != (int)(XST_SUCCESS)){
return (int)(XST_FAILURE);
}
if ((InstancePtr->XIsf_Iface_SetClkPrescaler) != NULL) {
Status = InstancePtr->XIsf_Iface_SetClkPrescaler(
InstancePtr->SpiInstPtr, PreScaler);
if (Status != (int)(XST_SUCCESS)){
return (int)(XST_FAILURE);
}
}
return (int)(XST_SUCCESS);
}
/*****************************************************************************/
/**
*
* This API reads the Serial Flash Status Register.
*
* @param InstancePtr is a pointer to the XIsf instance.
* @param ReadPtr is a pointer to the memory where the Status Register
* content is copied.
*
* @return XST_SUCCESS if successful else XST_FAILURE.
*
* @note The contents of the Status Register is stored at second byte
* pointed by the ReadPtr.
*
******************************************************************************/
int XIsf_GetStatus(XIsf *InstancePtr, u8 *ReadPtr)
{
int Status;
u8 Mode;
if (InstancePtr == NULL) {
return (int)(XST_FAILURE);
}
if (InstancePtr->IsReady != TRUE) {
return (int)(XST_FAILURE);
}
if (ReadPtr == NULL) {
return (int)(XST_FAILURE);
}
/*
* Prepare the Write Buffer.
*/
InstancePtr->WriteBufPtr[BYTE1] = XISF_CMD_STATUSREG_READ;
InstancePtr->WriteBufPtr[BYTE2] = XISF_DUMMYBYTE;
/*
* Initiate the Transfer.
*/
Status = XIsf_Transfer(InstancePtr, InstancePtr->WriteBufPtr, ReadPtr,
XISF_STATUS_RDWR_BYTES);
/*
* Get the Transfer Mode
*/
Mode = XIsf_GetTransferMode(InstancePtr);
if(Mode == XISF_INTERRUPT_MODE){
InstancePtr->StatusHandler(InstancePtr,
XIsf_StatusEventInfo, XIsf_ByteCountInfo);
}
if (Status != (int)(XST_SUCCESS)) {
return (int)(XST_FAILURE);
}
return (int)(XST_SUCCESS);
}
/*****************************************************************************/
/**
*
* This API reads the Serial Flash Status Register 2.
*
* @param InstancePtr is a pointer to the XIsf instance.
* @param ReadPtr is a pointer to the memory where the Status Register
* content is copied.
*
* @return XST_SUCCESS if successful else XST_FAILURE.
*
* @note The contents of the Status Register 2 is stored at the second
* byte pointed by the ReadPtr.
* This operation is available only in Winbond Serial Flash.
*
******************************************************************************/
#if (XPAR_XISF_FLASH_FAMILY == WINBOND)
int XIsf_GetStatusReg2(XIsf *InstancePtr, u8 *ReadPtr)
{
int Status;
u8 Mode;
if (InstancePtr == NULL) {
return (int)(XST_FAILURE);
}
if (InstancePtr->IsReady != TRUE) {
return (int)(XST_FAILURE);
}
if (ReadPtr == NULL) {
return (int)(XST_FAILURE);
}
/*
* Prepare the Write Buffer.
*/
InstancePtr->WriteBufPtr[BYTE1] = XISF_CMD_STATUSREG2_READ;
InstancePtr->WriteBufPtr[BYTE2] = XISF_DUMMYBYTE;
/*
* Initiate the Transfer.
*/
Status = XIsf_Transfer(InstancePtr, InstancePtr->WriteBufPtr, ReadPtr,
XISF_STATUS_RDWR_BYTES);
/*
* Get the Transfer Mode
*/
Mode = XIsf_GetTransferMode(InstancePtr);
if(Mode == XISF_INTERRUPT_MODE){
InstancePtr->StatusHandler(InstancePtr,
XIsf_StatusEventInfo, XIsf_ByteCountInfo);
}
if (Status != (int)(XST_SUCCESS)) {
return (int)(XST_FAILURE);
}
return (int)(XST_SUCCESS);
}
#endif
/*****************************************************************************/
/**
*
* This API reads the Joint Electron Device Engineering Council (JEDEC)
* information of the Serial Flash.
*
* @param InstancePtr is a pointer to the XIsf instance.
* @param ReadPtr is a pointer to the buffer where the Device information
* is copied.
*
* @return XST_SUCCESS if successful else XST_FAILURE.
*
* @note The Device information is stored at the second byte pointed
* by the ReadPtr.
*
******************************************************************************/
int XIsf_GetDeviceInfo(XIsf *InstancePtr, u8 *ReadPtr)
{
int Status;
u8 Mode;
if (InstancePtr == NULL) {
return (int)(XST_FAILURE);
}
if (InstancePtr->IsReady != TRUE) {
return (int)(XST_FAILURE);
}
if (ReadPtr == NULL) {
return (int)(XST_FAILURE);
}
/*
* Prepare the Write Buffer.
*/
InstancePtr->WriteBufPtr[BYTE1] = XISF_CMD_ISFINFO_READ;
InstancePtr->WriteBufPtr[BYTE2] = XISF_DUMMYBYTE;
InstancePtr->WriteBufPtr[BYTE3] = XISF_DUMMYBYTE;
InstancePtr->WriteBufPtr[BYTE4] = XISF_DUMMYBYTE;
InstancePtr->WriteBufPtr[BYTE5] = XISF_DUMMYBYTE;
/*
* Initiate the Transfer.
*/
Status = XIsf_Transfer(InstancePtr, InstancePtr->WriteBufPtr,
ReadPtr, XISF_INFO_READ_BYTES);
/*
* Get the Transfer Mode
*/
Mode = XIsf_GetTransferMode(InstancePtr);
if(Mode == XISF_INTERRUPT_MODE){
InstancePtr->StatusHandler(InstancePtr,
XIsf_StatusEventInfo, XIsf_ByteCountInfo);
}
if (Status != (int)(XST_SUCCESS)) {
return (int)(XST_FAILURE);
}
return Status;
}
/*****************************************************************************/
/**
*
* This API Enables/Disables writes to the Intel, STM, Winbond and Spansion
* Serial Flash.
*
* @param InstancePtr is a pointer to the XIsf instance.
* @param WriteEnable specifies whether to Enable (XISF_CMD_ENABLE_WRITE)
* or Disable (XISF_CMD_DISABLE_WRITE) the writes to the
* Serial Flash.
*
* @return XST_SUCCESS if successful else XST_FAILURE.
*
* @note This API works only for Intel, STM, Winbond and Spansion Serial
* Flash. If this API is called for Atmel Flash, XST_FAILURE is
* returned.
*
******************************************************************************/
int XIsf_WriteEnable(XIsf *InstancePtr, u8 WriteEnable)
{
int Status = (int)(XST_FAILURE);
u8 Mode;
u8 WriteEnableBuf[1] = {0};
u8 * NULLPtr = NULL;
#if ((XPAR_XISF_FLASH_FAMILY == INTEL) || (XPAR_XISF_FLASH_FAMILY == STM) || \
(XPAR_XISF_FLASH_FAMILY == WINBOND) || \
(XPAR_XISF_FLASH_FAMILY == SPANSION) || (XPAR_XISF_FLASH_FAMILY == SST))
if (InstancePtr == NULL) {
return (int)(XST_FAILURE);
}
if (InstancePtr->IsReady != TRUE) {
return (int)(XST_FAILURE);
}
if (WriteEnable == XISF_WRITE_ENABLE) {
WriteEnableBuf[BYTE1] = XISF_CMD_ENABLE_WRITE;
} else if (WriteEnable == XISF_WRITE_DISABLE) {
WriteEnableBuf[BYTE1] = XISF_CMD_DISABLE_WRITE;
} else {
return Status;
}
Xil_AssertNonvoid(NULLPtr == NULL);
/*
* Initiate the Transfer.
*/
Status = XIsf_Transfer(InstancePtr, WriteEnableBuf, NULLPtr,
XISF_CMD_WRITE_ENABLE_DISABLE_BYTES);
/*
* Get the Transfer Mode
*/
Mode = XIsf_GetTransferMode(InstancePtr);
if(Mode == XISF_INTERRUPT_MODE){
InstancePtr->StatusHandler(InstancePtr,
XIsf_StatusEventInfo, XIsf_ByteCountInfo);
}
#endif /* ((XPAR_XISF_FLASH_FAMILY==INTEL) || (XPAR_XISF_FLASH_FAMILY==STM) \
(XPAR_XISF_FLASH_FAMILY == WINBOND) || \
(XPAR_XISF_FLASH_FAMILY == SPANSION) || \
(XPAR_XISF_FLASH_FAMILY == SST)) */
return Status;
}
/*****************************************************************************/
/**
*
* This API configures and controls the Intel, STM, Winbond and Spansion Serial
* Flash.
*
* @param InstancePtr is a pointer to the XIsf instance.
* @param Operation is the type of Control operation to be performed
* on the Serial Flash.
* The different control operations are
- XISF_RELEASE_DPD: Release from Deep Power Down (DPD) Mode
- XISF_ENTER_DPD: Enter DPD Mode
- XISF_CLEAR_SR_FAIL_FLAGS: Clear Status Register Fail Flags
*
* @return XST_SUCCESS if successful else XST_FAILURE.
*
* @note
* - Atmel Serial Flash does not support any of these operations.
* - Intel Serial Flash support Enter/Release from DPD Mode and
* Clear Status Register Fail Flags.
* - STM, Winbond and Spansion Serial Flash support Enter/Release
* from DPD Mode.
* - Winbond (W25QXX) Serial Flash support Enable High Performance
* mode.
*
******************************************************************************/
int XIsf_Ioctl(XIsf *InstancePtr, XIsf_IoctlOperation Operation)
{
int Status;
u8 Mode;
u8* NULLPtr = NULL;
#if ((XPAR_XISF_FLASH_FAMILY == INTEL) || (XPAR_XISF_FLASH_FAMILY == STM) || \
(XPAR_XISF_FLASH_FAMILY == WINBOND) || \
(XPAR_XISF_FLASH_FAMILY == SPANSION) || (XPAR_XISF_FLASH_FAMILY == SST))
u8 NumBytes;
if (InstancePtr == NULL) {
return (int)(XST_FAILURE);
}
if (InstancePtr->IsReady != TRUE) {
return (int)(XST_FAILURE);
}
switch (Operation) {
case XISF_IOCTL_RELEASE_DPD:
InstancePtr->WriteBufPtr[BYTE1] =
XISF_CMD_RELEASE_FROM_DPD;
NumBytes = XISF_IOCTL_BYTES;
break;
case XISF_IOCTL_ENTER_DPD:
InstancePtr->WriteBufPtr[BYTE1] =
XISF_CMD_DEEP_POWER_DOWN;
NumBytes = XISF_IOCTL_BYTES;
break;
#if (XPAR_XISF_FLASH_FAMILY == INTEL)
case XISF_IOCTL_CLEAR_SR_FAIL_FLAGS:
InstancePtr->WriteBufPtr[BYTE1] =
XISF_CMD_CLEAR_SRFAIL_FLAGS;
NumBytes = XISF_IOCTL_BYTES;
break;
#endif /* (XPAR_XISF_FLASH_FAMILY == INTEL) */
#if (XPAR_XISF_FLASH_FAMILY == WINBOND)
case XISF_IOCTL_ENABLE_HI_PERF_MODE:
InstancePtr->WriteBufPtr[BYTE1] =
XISF_CMD_ENABLE_HPM;
NumBytes = XISF_HPM_BYTES;
break;
#endif /* (XPAR_XISF_FLASH_FAMILY == WINBOND) */
default:
return (int)(XST_FAILURE);
}
Xil_AssertNonvoid(NULLPtr == NULL);
/*
* Initiate the Transfer.
*/
Status = XIsf_Transfer(InstancePtr, InstancePtr->WriteBufPtr, NULLPtr,
NumBytes);
/*
* Get the Transfer Mode
*/
Mode = XIsf_GetTransferMode(InstancePtr);
if(Mode == XISF_INTERRUPT_MODE){
InstancePtr->StatusHandler(InstancePtr,
XIsf_StatusEventInfo, XIsf_ByteCountInfo);
}
#else
Status = (int)(XST_FAILURE);
#endif/* ((XPAR_XISF_FLASH_FAMILY==INTEL) || (XPAR_XISF_FLASH_FAMILY==STM) \
(XPAR_XISF_FLASH_FAMILY == WINBOND) ||
(XPAR_XISF_FLASH_FAMILY == SPANSION)) */
return Status;
}
/*****************************************************************************/
/*
*
* This function performs the SPI transfer.
*
* @param InstancePtr is a pointer to the XIsf instance.
* @param WritePtr is a pointer to the memory which contains the data to
* be transferred to the Serial Flash .
* @param ReadPtr is a pointer to the memory where the data read from the
* Serial Flash is stored.
* @param ByteCount is the number of bytes to be read from/written to the
* Serial Flash.
*
* @return XST_SUCCESS if successful else XST_FAILURE.
*
* @note This function is internal to the In-system and Serial Flash
* Library. It works with both interrupt mode and polled mode SPI
* transfers. In polled mode for AXI SPI, the user has to disable
* the Global Interrupts in the user application, after the Spi
* is Initialized and Spi driver is started
*
******************************************************************************/
int XIsf_Transfer(XIsf *InstancePtr, u8 *WritePtr, u8* ReadPtr, u32 ByteCount)
{
int Status;
/*
* Select the Serial Flash as a slave.
*/
#ifndef XPAR_XISF_INTERFACE_PSQSPI
Status = InstancePtr->XIsf_Iface_SetSlaveSelect(
InstancePtr->SpiInstPtr,InstancePtr->SpiSlaveSelect);
#else
Status = InstancePtr->XIsf_Iface_SetSlaveSelect(
InstancePtr->SpiInstPtr);
#endif
if (Status != (int)(XST_SUCCESS)) {
return (int)(XST_FAILURE);
}
/*
* Start the transfer.
*/
#ifdef XPAR_XISF_INTERFACE_AXISPI
if (InstancePtr->IntrMode == XISF_INTERRUPT_MODE) {
XIsf_TransferInProgress = TRUE;
}
Status = InstancePtr->XIsf_Iface_Transfer(InstancePtr->SpiInstPtr,
WritePtr, ReadPtr, ByteCount);
if (Status != (int)(XST_SUCCESS)) {
return (int)(XST_FAILURE);
}
if (InstancePtr->IntrMode == XISF_INTERRUPT_MODE) {
while (XIsf_TransferInProgress != 0){
/*NOP*/
}
}
return (int)(XST_SUCCESS);
#endif
if (InstancePtr->IntrMode == XISF_INTERRUPT_MODE) {
#if defined(XPAR_XISF_INTERFACE_PSQSPI) || defined(XPAR_XISF_INTERFACE_PSSPI)
XIsf_TransferInProgress = TRUE;
#endif
Status = InstancePtr->XIsf_Iface_Transfer(
InstancePtr->SpiInstPtr,
WritePtr, ReadPtr, ByteCount);
#if defined(XPAR_XISF_INTERFACE_PSQSPI) || defined(XPAR_XISF_INTERFACE_PSSPI)
while (XIsf_TransferInProgress != 0){
/*NOP*/
}
#endif
} else {
Status = InstancePtr->XIsf_Iface_PolledTransfer(
InstancePtr->SpiInstPtr,
WritePtr, ReadPtr, ByteCount);
}
if (Status != (int)(XST_SUCCESS)) {
return (int)(XST_FAILURE);
}
return (int)(XST_SUCCESS);
}
/*****************************************************************************/
/*
*
* This function registers the interface SPI/SPI PS/QSPI PS.
*
* @param InstancePtr is a pointer to the XIsf instance.
*
* @return None
*
*
******************************************************************************/
void XIsf_RegisterInterface(XIsf *InstancePtr)
{
#ifdef XPAR_XISF_INTERFACE_AXISPI
InstancePtr->XIsf_Iface_SetOptions = XSpi_SetOptions;
InstancePtr->XIsf_Iface_SetSlaveSelect = XSpi_SetSlaveSelect;
InstancePtr->XIsf_Iface_Transfer = XSpi_Transfer;
InstancePtr->XIsf_Iface_Start = XSpi_Start;
#elif XPAR_XISF_INTERFACE_PSSPI
InstancePtr->XIsf_Iface_SetOptions = XSpiPs_SetOptions;
InstancePtr->XIsf_Iface_SetSlaveSelect = XSpiPs_SetSlaveSelect;
InstancePtr->XIsf_Iface_Transfer = XSpiPs_Transfer;
InstancePtr->XIsf_Iface_PolledTransfer = XSpiPs_PolledTransfer;
InstancePtr->XIsf_Iface_SetClkPrescaler = XSpiPs_SetClkPrescaler;
#elif XPAR_XISF_INTERFACE_PSQSPI
InstancePtr->XIsf_Iface_SetOptions = XQspiPs_SetOptions;
InstancePtr->XIsf_Iface_SetSlaveSelect = XQspiPs_SetSlaveSelect;
InstancePtr->XIsf_Iface_Transfer = XQspiPs_Transfer;
InstancePtr->XIsf_Iface_PolledTransfer = XQspiPs_PolledTransfer;
InstancePtr->XIsf_Iface_SetClkPrescaler = XQspiPs_SetClkPrescaler;
#endif
}
#if (XPAR_XISF_FLASH_FAMILY == ATMEL)
/*****************************************************************************/
/**
*
* This function initializes the instance structure with the device geometry of
* the Atmel Serial Flash if it is an Atmel device.
*
* @param InstancePtr is a pointer to the XIsf instance.
* @param BufferPtr is a pointer to the memory where the device info of
* the Serial Flash is present.
*
* @return - XST_SUCCESS if device information matches the JEDEC
* information of the Atmel Serial Flash.
* - XST_FAILURE if device information doesn't match with Atmel
* Serial Flash.
*
* @note None
*
******************************************************************************/
static int AtmelFlashInitialize(XIsf *InstancePtr, u8 *BufferPtr)
{
int Status;
u32 Index;
u8 StatusRegister;
u8 NumOfDevices;
u8 ManufacturerID;
ManufacturerID = BufferPtr[BYTE2];
if (ManufacturerID == XISF_MANUFACTURER_ID_ATMEL) {
/*
* For Atmel Serial Flash the device code is the 3rd byte of
* JEDEC info.
*/
InstancePtr->DeviceCode = BufferPtr[BYTE3];
/*
* Get the Status Register contents.
* The IsReady is temporarily made TRUE to fetch the Status
* Register contents.
*/
InstancePtr->IsReady = TRUE;
Status = XIsf_GetStatus(InstancePtr, BufferPtr);
InstancePtr->IsReady = FALSE;
if (Status != (int)(XST_SUCCESS)) {
return (int)(XST_FAILURE);
}
/*
* Wait until the transfer is complete.
*/
do {
#ifndef XPAR_XISF_INTERFACE_PSQSPI
Status = InstancePtr->XIsf_Iface_SetSlaveSelect(
InstancePtr->SpiInstPtr,
InstancePtr->SpiSlaveSelect);
#else
Status = InstancePtr->XIsf_Iface_SetSlaveSelect(
InstancePtr->SpiInstPtr);
#endif
} while(Status == XST_DEVICE_BUSY);
if (Status != (int)(XST_SUCCESS)) {
return (int)(XST_FAILURE);
}
StatusRegister = BufferPtr[BYTE2];
/*
* Get the Address mode from the Status Register of Serial
* Flash.
*/
InstancePtr->AddrMode = StatusRegister &
XISF_SR_ADDR_MODE_MASK;
/*
* Update the Serial Flash instance structure with device
* geometry.
*/
NumOfDevices = sizeof(AtmelDevices) /
sizeof(AtmelDeviceGeometry);
for(Index = 0; Index < NumOfDevices; Index++) {
if (InstancePtr->DeviceCode == AtmelDevices[Index].
DeviceCode) {
/*
* Default address mode device.
*/
if (InstancePtr->AddrMode ==
XISF_DEFAULT_ADDRESS) {
InstancePtr->BytesPerPage =
AtmelDevices [Index].
BytesPerPageDefaultMode;
} else {
/*
* Power of 2 address mode device.
*/
InstancePtr->BytesPerPage =
AtmelDevices [Index].
BytesPerPagePowerOf2Mode;
}
InstancePtr->PagesPerBlock =
AtmelDevices[Index].PagesPerBlock;
InstancePtr->BlocksPerSector =
AtmelDevices[Index].BlocksPerSector;
InstancePtr->NumOfSectors =
AtmelDevices[Index].NumOfSectors;
if (InstancePtr->BytesPerPage >
XISF_BYTES1024_PER_PAGE ) {
InstancePtr->ByteMask =
XISF_BYTES2048_PER_PAGE_MASK;
}
else if (InstancePtr->BytesPerPage >
XISF_BYTES512_PER_PAGE ) {
InstancePtr->ByteMask =
XISF_BYTES1024_PER_PAGE_MASK;
}
else if (InstancePtr->BytesPerPage >
XISF_BYTES256_PER_PAGE ) {
InstancePtr->ByteMask =
XISF_BYTES512_PER_PAGE_MASK;
}
else {
InstancePtr->ByteMask =
XISF_BYTES256_PER_PAGE_MASK;
}
InstancePtr->IsReady = TRUE;
}
}
}
/*
* If the device is not supported, return Failure.
*/
if (InstancePtr->IsReady != TRUE) {
return (int)(XST_FAILURE);
}
return (int)(XST_SUCCESS);
}
#endif /* (XPAR_XISF_FLASH_FAMILY == ATMEL) */
#if ((XPAR_XISF_FLASH_FAMILY == INTEL) || (XPAR_XISF_FLASH_FAMILY == STM) \
|| (XPAR_XISF_FLASH_FAMILY == SST))
/*****************************************************************************/
/**
*
* This function initializes the instance structure with the device geometry of
* the Intel/Stm/Winbond Serial Flash if it is an Intel/Stm/Winbond device.
*
* @param InstancePtr is a pointer to the XIsf instance.
* @param BufferPtr is a pointer to the memory where the device info of
* the Serial Flash is present.
*
* @return - XST_SUCCESS if device information matches the JEDEC
* information of Intel or Stm or Winbond Serial Flash.
* - XST_FAILURE if device information doesn't match with Intel
* or Stm or Winbond Serial Flash.
*
* @note None
*
******************************************************************************/
static int IntelStmFlashInitialize(XIsf *InstancePtr, u8 *BufferPtr)
{
u32 Index;
u8 NumOfDevices;
u8 ManufacturerID;
ManufacturerID = BufferPtr[BYTE2];
#if (XPAR_XISF_FLASH_FAMILY == INTEL)
/*
* For Intel the device code is the 4th byte of the JEDEC info.
*/
InstancePtr->DeviceCode = BufferPtr[BYTE4];
#else
/*
* For STM/Winbond/Spansion Serial Flash the device code is 3rd/4th
* byte of the JEDEC info. The Third Byte is Memory Type and the 4th
* byte represents the capacity.
*/
InstancePtr->DeviceCode = (BufferPtr[BYTE3] << 8) | BufferPtr[BYTE4];
#endif
/*
* Check for Intel/STM/Winbond/Spansion Serial Flash.
*/
NumOfDevices = sizeof(IntelStmDevices) /
sizeof(IntelStmDeviceGeometry);
for(Index = 0; Index < NumOfDevices; Index++) {
if ((InstancePtr->DeviceCode ==
IntelStmDevices[Index].DeviceCode) &&
(ManufacturerID ==
IntelStmDevices[Index].ManufacturerID)) {
InstancePtr->BytesPerPage =
IntelStmDevices[Index].BytesPerPage;
/*
* This is number of pages per Sector.
*/
InstancePtr->PagesPerBlock =
IntelStmDevices[Index].PagesPerSector;
InstancePtr->BlocksPerSector = 0;
InstancePtr->NumOfSectors =
IntelStmDevices[Index].NumOfSectors;
InstancePtr->IsReady = TRUE;
}
}
/*
* If the device is not supported, return Failure.
*/
if (InstancePtr->IsReady != TRUE) {
return (int)(XST_FAILURE);
}
return (int)(XST_SUCCESS);
}
#endif /* ((XPAR_XISF_FLASH_FAMILY==INTEL) || (XPAR_XISF_FLASH_FAMILY==STM) \
|| (XPAR_XISF_FLASH_FAMILY == SST))*/
#if ((XPAR_XISF_FLASH_FAMILY == WINBOND) || \
(XPAR_XISF_FLASH_FAMILY == SPANSION))
/*****************************************************************************/
/**
*
* This function initializes the instance structure with the device geometry of
* the Spansion/Micron/Winbond Serial Flash if it is an Spansion/Micron/Winbond
* device.
*
* @param InstancePtr is a pointer to the XIsf instance.
* @param BufferPtr is a pointer to the memory where the device info of
* the Serial Flash is present.
*
* @return - XST_SUCCESS if device information matches the JEDEC
* information of Intel or Stm or Winbond Serial Flash.
* - XST_FAILURE if the device information doesn't match with
* Intel or Stm or Winbond Serial Flash.
*
* @note None
*
******************************************************************************/
static int SpaMicWinFlashInitialize(XIsf *InstancePtr, u8 *BufferPtr)
{
u32 Index;
u8 NumOfDevices;
u8 ManufacturerID;
unsigned int StartIndex;
u32 FlashMake;
u8 * WriteBfrPtr = InstancePtr->WriteBufPtr;
int Status;
/*
* Read ID in Auto mode.
*/
WriteBfrPtr[BYTE1] = READ_ID;
WriteBfrPtr[BYTE2] = 0x23U; /* 3 dummy bytes */
WriteBfrPtr[BYTE3] = 0x08U;
WriteBfrPtr[BYTE4] = 0x09U;
Status = XIsf_Transfer(InstancePtr, WriteBfrPtr, BufferPtr,
RD_ID_SIZE);
if (Status != (int)(XST_SUCCESS)) {
return (int)(XST_FAILURE);
}
/*
* Deduce flash make
*/
if(BufferPtr[1] == XISF_MANUFACTURER_ID_MICRON) {
FlashMake = XISF_MANUFACTURER_ID_MICRON;
StartIndex = MICRON_INDEX_START;
}
else if(BufferPtr[1] == XISF_MANUFACTURER_ID_SPANSION) {
FlashMake = XISF_MANUFACTURER_ID_SPANSION;
StartIndex = SPANSION_INDEX_START;
}
else if(BufferPtr[1] == XISF_MANUFACTURER_ID_WINBOND) {
FlashMake = XISF_MANUFACTURER_ID_WINBOND;
StartIndex = WINBOND_INDEX_START;
}
else{
FlashMake = 0;
StartIndex = 0;
}
/*
* If valid flash ID, then check connection mode & size and
* assign corresponding index in the Flash configuration table
*/
if(((FlashMake == XISF_MANUFACTURER_ID_MICRON) ||
(FlashMake == XISF_MANUFACTURER_ID_SPANSION)||
(FlashMake == XISF_MANUFACTURER_ID_WINBOND)) &&
(BufferPtr[3] == XISF_MICRON_ID_BYTE2_128)) {
switch(InstancePtr->SpiInstPtr->Config.ConnectionMode)
{
case XISF_QSPIPS_CONNECTION_MODE_SINGLE:
XIsf_FCTIndex =
(u32)FLASH_CFG_TBL_SINGLE_128_SP +
(u32)StartIndex;
break;
case XISF_QSPIPS_CONNECTION_MODE_PARALLEL:
XIsf_FCTIndex =
(u32)FLASH_CFG_TBL_PARALLEL_128_SP +
(u32)StartIndex;
break;
case XISF_QSPIPS_CONNECTION_MODE_STACKED:
XIsf_FCTIndex =
(u32)FLASH_CFG_TBL_STACKED_128_SP +
(u32)StartIndex;
break;
default:
XIsf_FCTIndex = 0;
break;
}
}
/*
* 256 and 512Mbit supported only for Micron and Spansion,
* not Winbond
*/
if(((FlashMake == XISF_MANUFACTURER_ID_MICRON) ||
(FlashMake == XISF_MANUFACTURER_ID_SPANSION)) &&
(BufferPtr[3] == XISF_MICRON_ID_BYTE2_256)) {
switch(InstancePtr->SpiInstPtr->Config.ConnectionMode)
{
case XISF_QSPIPS_CONNECTION_MODE_SINGLE:
XIsf_FCTIndex = FLASH_CFG_TBL_SINGLE_256_SP +
StartIndex;
break;
case XISF_QSPIPS_CONNECTION_MODE_PARALLEL:
XIsf_FCTIndex = FLASH_CFG_TBL_PARALLEL_256_SP +
StartIndex;
break;
case XISF_QSPIPS_CONNECTION_MODE_STACKED:
XIsf_FCTIndex = FLASH_CFG_TBL_STACKED_256_SP +
StartIndex;
break;
default:
XIsf_FCTIndex = 0;
break;
}
}
if(((FlashMake == XISF_MANUFACTURER_ID_MICRON) ||
(FlashMake == XISF_MANUFACTURER_ID_SPANSION)) &&
(BufferPtr[3] == XISF_MICRON_ID_BYTE2_512)) {
switch(InstancePtr->SpiInstPtr->Config.ConnectionMode)
{
case XISF_QSPIPS_CONNECTION_MODE_SINGLE:
XIsf_FCTIndex = FLASH_CFG_TBL_SINGLE_512_SP +
StartIndex;
break;
case XISF_QSPIPS_CONNECTION_MODE_PARALLEL:
XIsf_FCTIndex = FLASH_CFG_TBL_PARALLEL_512_SP +
StartIndex;
break;
case XISF_QSPIPS_CONNECTION_MODE_STACKED:
XIsf_FCTIndex = FLASH_CFG_TBL_STACKED_512_SP +
StartIndex;
break;
default:
XIsf_FCTIndex = 0;
break;
}
}
/*
* 1Gbit Single connection supported for Spansion.
* The ConnectionMode will indicate stacked as this part has 2 SS
* The device ID will indicate 512Mbit.
* This configuration is handled as the above 512Mbit stacked
* configuration.
*/
/* 1Gbit single, parallel and stacked supported for Micron */
if((FlashMake == XISF_MANUFACTURER_ID_MICRON) &&
(BufferPtr[3] == XISF_MICRON_ID_BYTE2_1G)) {
switch(InstancePtr->SpiInstPtr->Config.ConnectionMode)
{
case XISF_QSPIPS_CONNECTION_MODE_SINGLE:
XIsf_FCTIndex = FLASH_CFG_TBL_SINGLE_1GB_MC;
break;
case XISF_QSPIPS_CONNECTION_MODE_PARALLEL:
XIsf_FCTIndex = FLASH_CFG_TBL_PARALLEL_1GB_MC;
break;
case XISF_QSPIPS_CONNECTION_MODE_STACKED:
XIsf_FCTIndex = FLASH_CFG_TBL_STACKED_1GB_MC;
break;
default:
XIsf_FCTIndex = 0;
break;
}
}
/*
* Populate the InstancePtr members with the appropriate values
* based on the XIsf_FCTIndex
*/
InstancePtr->BytesPerPage =
(u16)(SpaMicWinDevices[XIsf_FCTIndex].PageSize);
InstancePtr->NumDie = SpaMicWinDevices[XIsf_FCTIndex].NumDie;
InstancePtr->DeviceIDMemSize =
SpaMicWinDevices[XIsf_FCTIndex].DeviceIDMemSize;
InstancePtr->ManufacturerID = FlashMake;
InstancePtr->SectorSize = SpaMicWinDevices[XIsf_FCTIndex].SectSize;
InstancePtr->NumSectors = SpaMicWinDevices[XIsf_FCTIndex].NumSect;
InstancePtr->IsReady = TRUE;
return (int)(XST_SUCCESS);
}
#endif /* (XPAR_XISF_FLASH_FAMILY == WINBOND) ||
(XPAR_XISF_FLASH_FAMILY == SPANSION)) */
/*****************************************************************************/
/**
* This functions translates the address based on the type of interconnection.
* In case of stacked, this function asserts the corresponding slave select.
*
* @param QspiPtr is a pointer to XIsf_Iface instance to be worked on.
* @param Address which is to be accessed (for erase, write or read)
*
* @return RealAddr is the translated address - for single it is unchanged
* for stacked, the lower flash size is subtracted
* for parallel the address is divided by 2.
*
* @note None.
*
******************************************************************************/
u32 GetRealAddr(XIsf_Iface *QspiPtr, u32 Address)
{
u32 LqspiCr;
u32 RealAddr = {0};
#ifdef XPAR_XISF_INTERFACE_PSQSPI
switch(QspiPtr->Config.ConnectionMode) {
case XISF_QSPIPS_CONNECTION_MODE_SINGLE:
RealAddr = Address;
break;
case XISF_QSPIPS_CONNECTION_MODE_STACKED:
/*
* Get the current LQSPI Config reg value
*/
LqspiCr = XQspiPs_GetLqspiConfigReg(QspiPtr);
/* Select lower or upper Flash based on sector address */
if(Address &
SpaMicWinDevices[XIsf_FCTIndex].FlashDeviceSize) {
/*
* Set selection to U_PAGE
*/
XQspiPs_SetLqspiConfigReg(QspiPtr,
LqspiCr | XQSPIPS_LQSPI_CR_U_PAGE_MASK);
/*
* Subtract first flash size when accessing second
* flash.
*/
RealAddr = Address &
(~SpaMicWinDevices[XIsf_FCTIndex].FlashDeviceSize);
}
else{
/*
* Set selection to L_PAGE
*/
XQspiPs_SetLqspiConfigReg(QspiPtr,
LqspiCr & (~XQSPIPS_LQSPI_CR_U_PAGE_MASK));
RealAddr = Address;
}
/*
* Assert the Flash chip select.
*/
(void)XQspiPs_SetSlaveSelect(QspiPtr);
break;
case XISF_QSPIPS_CONNECTION_MODE_PARALLEL:
/*
* The effective address in each flash is the actual
* address / 2
*/
RealAddr = Address / 2;
break;
default:
/* RealAddr wont be assigned in this case */
break;
}
#else
RealAddr = Address;
#endif
return(RealAddr);
}
#ifdef XPAR_XISF_INTERFACE_PSQSPI
/*****************************************************************************/
/**
* This functions selects the current bank
*
* @param InstancePtr is a pointer to the QSPI driver component to use.
* @param BankSel is the bank to be selected in the flash device(s).
*
* @return XST_SUCCESS if bank selected, otherwise XST_FAILURE.
*
* @note None.
*
******************************************************************************/
int SendBankSelect(XIsf *InstancePtr, u32 BankSel)
{
#define EXTADD_REG_WR 0xC5U
#define EXTADD_REG_RD 0xC8U
#define BANK_REG_WR 0x17U
#define BANK_SEL_SIZE 2U /**< BRWR or EARWR command +
* 1 byte bank value */
u8 WriteBuffer[5] = {0};
u8* NULLPtr= NULL;
u8 WriteEnableCmdBuf = { WRITE_ENABLE_CMD };
u32 FlashMake = InstancePtr->ManufacturerID;
int Status;
/*
* Bank select commands for Micron and Spansion are different
*/
if(FlashMake == XISF_MANUFACTURER_ID_MICRON) {
Xil_AssertNonvoid(NULLPtr == NULL);
/*
* For Micron command WREN should be sent first
* except for some specific feature set
*/
Status = XIsf_Transfer(InstancePtr,
&WriteEnableCmdBuf, NULLPtr,
(u32)sizeof(WriteEnableCmdBuf));
if(Status != (int)XST_SUCCESS){
return (int)XST_FAILURE;
}
WriteBuffer[BYTE1] = EXTADD_REG_WR;
WriteBuffer[BYTE2] = (u8)BankSel;
Xil_AssertNonvoid(NULLPtr == NULL);
/*
* Send the Extended address register write command
* written, no receive buffer required
*/
Status = XIsf_Transfer(InstancePtr, WriteBuffer, NULLPtr,
BANK_SEL_SIZE);
if(Status != (int)XST_SUCCESS){
return (int)XST_FAILURE;
}
}
if(FlashMake == XISF_MANUFACTURER_ID_SPANSION) {
WriteBuffer[BYTE1] = BANK_REG_WR;
WriteBuffer[BYTE2] = (u8)BankSel;
Xil_AssertNonvoid(NULLPtr == NULL);
/*
* Send the Extended address register write command
* written, no receive buffer required
*/
Status = XIsf_Transfer(InstancePtr, WriteBuffer, NULLPtr,
BANK_SEL_SIZE);
if(Status != (int)XST_SUCCESS){
return (int)XST_FAILURE;
}
}
/* Winbond can be added here */
return (int)(XST_SUCCESS);
}
#endif
/******************************************************************************
*
* This function is to set the Status Handler when an interrupt is registered
*
* @param InstancePtr is a pointer to the XIsf Instance.
* @param QspiInstancePtr is a pointer to the XIsf_Iface instance
* to be worked on.
* @param XilIsf_Handler is the status handler for the application.
*
* @return None
*
* @note None.
*
******************************************************************************/
void XIsf_SetStatusHandler(XIsf *InstancePtr, XIsf_Iface *XIfaceInstancePtr,
XIsf_StatusHandler XilIsf_Handler)
{
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(XIfaceInstancePtr != NULL);
Xil_AssertVoid(XilIsf_Handler != NULL);
/*
* Setup the handler for the QSPI that will be called from the
* interrupt context when an QSPI status occurs, specify a pointer to
* the QSPI driver instance as the callback reference so the handler
* is able to access the instance data
*/
#ifdef XPAR_XISF_INTERFACE_PSQSPI
XQspiPs_SetStatusHandler(XIfaceInstancePtr, XIfaceInstancePtr,
(XQspiPs_StatusHandler) XIsf_IfaceHandler);
#elif XPAR_XISF_INTERFACE_PSSPI
XSpiPs_SetStatusHandler(XIfaceInstancePtr, XIfaceInstancePtr,
(XSpiPs_StatusHandler) XIsf_IfaceHandler);
#elif XPAR_XISF_INTERFACE_AXISPI
XSpi_SetStatusHandler(XIfaceInstancePtr, XIfaceInstancePtr,
(XSpi_StatusHandler) XIsf_IfaceHandler);
#endif
InstancePtr->StatusHandler = XilIsf_Handler;
}
/******************************************************************************
*
* This function is the handler which performs processing for the QSPI driver.
* It is called from an interrupt context such that the amount of processing
* performed should be minimized. It is called when a transfer of QSPI data
* completes or an error occurs.
*
* This handler provides an example of how to handle QSPI interrupts but is
* application specific.
*
* @param CallBackRef is a reference passed to the handler.
* @param StatusEvent is the status of the QSPI .
* @param ByteCount is the number of bytes transferred.
*
* @return None
*
* @note None.
*
******************************************************************************/
void XIsf_IfaceHandler(void *CallBackRef, u32 StatusEvent,
unsigned int ByteCount)
{
Xil_AssertVoid(CallBackRef != NULL);
XIsf_TransferInProgress = FALSE;
XIsf_StatusEventInfo = StatusEvent;
XIsf_ByteCountInfo = ByteCount;
}