/****************************************************************************** * * 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. * *
* * 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() * * ** ******************************************************************************/ /***************************** 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; }