diff --git a/XilinxProcessorIPLib/drivers/qspipsu/data/qspipsu.mdd b/XilinxProcessorIPLib/drivers/qspipsu/data/qspipsu.mdd new file mode 100755 index 00000000..cca97de1 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/qspipsu/data/qspipsu.mdd @@ -0,0 +1,42 @@ +############################################################################### +# +# Copyright (C) 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. +# +############################################################################### +OPTION psf_version = 2.1; + +BEGIN driver qspipsu + + OPTION supported_peripherals = (ps8_qspi pss_qspi psu_qspi); + OPTION driver_state = ACTIVE; + OPTION copyfiles = all; + OPTION VERSION = 1.0; + OPTION NAME = qspipsu; + +END driver diff --git a/XilinxProcessorIPLib/drivers/qspipsu/data/qspipsu.tcl b/XilinxProcessorIPLib/drivers/qspipsu/data/qspipsu.tcl new file mode 100755 index 00000000..5d90a934 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/qspipsu/data/qspipsu.tcl @@ -0,0 +1,53 @@ +############################################################################### +# +# Copyright (C) 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. +# +############################################################################### +############################################################################## +# +# Modification History +# +# Ver Who Date Changes +# ----- ---- -------- ----------------------------------------------- +# 1.0 hk 08/21/14 First release +# +############################################################################## + +#uses "xillib.tcl" + +proc generate {drv_handle} { + puts "In qspipsu tcl \n" + puts " Driver is $drv_handle \n" + xdefine_zynq_include_file $drv_handle "xparameters.h" "XQspiPsu" "NUM_INSTANCES" "DEVICE_ID" "C_S_AXI_BASEADDR" "C_S_AXI_HIGHADDR" "C_QSPI_CLK_FREQ_HZ" "C_QSPI_MODE" + + xdefine_zynq_config_file $drv_handle "xqspipsu_g.c" "XQspiPsu" "DEVICE_ID" "C_S_AXI_BASEADDR" "C_QSPI_CLK_FREQ_HZ" "C_QSPI_MODE" + + xdefine_zynq_canonical_xpars $drv_handle "xparameters.h" "XQspiPsu" "DEVICE_ID" "C_S_AXI_BASEADDR" "C_S_AXI_HIGHADDR" "C_QSPI_CLK_FREQ_HZ" "C_QSPI_MODE" + +} diff --git a/XilinxProcessorIPLib/drivers/qspipsu/examples/xqspipsu_generic_flash_interrupt_example.c b/XilinxProcessorIPLib/drivers/qspipsu/examples/xqspipsu_generic_flash_interrupt_example.c new file mode 100755 index 00000000..f3bb31aa --- /dev/null +++ b/XilinxProcessorIPLib/drivers/qspipsu/examples/xqspipsu_generic_flash_interrupt_example.c @@ -0,0 +1,1654 @@ +/****************************************************************************** +* +* Copyright (C) 2014 Xilinx, Inc. All rights reserved. +* +* This file contains confidential and proprietary information of Xilinx, Inc. +* and is protected under U.S. and international copyright and other +* intellectual property laws. +* +* DISCLAIMER +* This disclaimer is not a license and does not grant any rights to the +* materials distributed herewith. Except as otherwise provided in a valid +* license issued to you by Xilinx, and to the maximum extent permitted by +* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL +* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, +* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF +* MERCHANTABILITY, NON- INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; +* and +* (2) Xilinx shall not be liable (whether in contract or tort, including +* negligence, or under any other theory of liability) for any loss or damage +* of any kind or nature related to, arising under or in connection with these +* materials, including for any direct, or any indirect, special, incidental, +* or consequential loss or damage (including loss of data, profits, +* goodwill, or any type of loss or damage suffered as a result of any +* action brought by a third party) even if such damage or loss was +* reasonably foreseeable or Xilinx had been advised of the possibility +* of the same. +* +* CRITICAL APPLICATIONS +* Xilinx products are not designed or intended to be fail- safe, or for use +* in any application requiring fail-safe performance, such as life-support +* or safety devices or systems, Class III medical devices, nuclear +* facilities, applications related to the deployment of airbags, or any +* other applications that could lead to death, personal injury, or severe +* property or environmental damage (individually and collectively, +* "Critical Applications"). Customer assumes the sole risk and liability +* of any use of Xilinx products in Critical Applications, subject only to +* applicable laws and regulations governing limitations on product liability. +* +* THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART +* OF THIS FILE AT ALL TIMES. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xqspipsu_generic_flash_interrupt_example.c +* +* +* This file contains a design example using the QSPIPSU driver (XQspiPsu) +* with a serial Flash device greater than or equal to 128Mb. +* The example writes to flash and reads it back in DMA mode. +* This examples runs with GENFIFO Manual start. It runs in interrupt mode. +* This example illustrates single, parallel and stacked modes. +* Both the flash devices have to be of the same make and size. +* The hardware which this example runs on, must have a serial Flash (Micron +* N25Q or Spansion S25FL) for it to run. In order to test in single, +* parallel or stacked flash configurations the necessary HW must be present +* and QSPI_MODE (also reflected in ConnectionMode in the instance) has +* to be in sync with HW flash configuration being tested. +* +* This example has been tested with the Micron Serial Flash (N25Q512) in +* single and parallel modes using A53 and R5 processors. +* +* @note +* +* None. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who Date     Changes
+* ----- --- -------- -----------------------------------------------
+* 1.0   hk  08/21/14 First release
+*
+*
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" /* SDK generated parameters */ +#include "xqspipsu.h" /* QSPIPSU device driver */ +#include "xscugic.h" /* Interrupt controller device driver */ +#include "xil_exception.h" +#include "xil_printf.h" +#include "xil_cache.h" + +/************************** Constant Definitions *****************************/ + +/* + * The following constants define the commands which may be sent to the Flash + * device. + */ +#define WRITE_STATUS_CMD 0x01 +#define WRITE_CMD 0x02 +#define READ_CMD 0x03 +#define WRITE_DISABLE_CMD 0x04 +#define READ_STATUS_CMD 0x05 +#define WRITE_ENABLE_CMD 0x06 +#define FAST_READ_CMD 0x0B +#define DUAL_READ_CMD 0x3B +#define QUAD_READ_CMD 0x6B +#define BULK_ERASE_CMD 0xC7 +#define SEC_ERASE_CMD 0xD8 +#define READ_ID 0x9F +#define READ_CONFIG_CMD 0x35 +#define WRITE_CONFIG_CMD 0x01 + +#define WRITE_CMD_4B 0x12 +#define READ_CMD_4B 0x13 +#define FAST_READ_CMD_4B 0x0C +#define DUAL_READ_CMD_4B 0x3C +#define QUAD_READ_CMD_4B 0x6C +#define SEC_ERASE_CMD_4B 0xDC + +#define BANK_REG_RD 0x16 +#define BANK_REG_WR 0x17 +/* Bank register is called Extended Address Register in Micron */ +#define EXTADD_REG_RD 0xC8 +#define EXTADD_REG_WR 0xC5 +#define DIE_ERASE_CMD 0xC4 +#define READ_FLAG_STATUS_CMD 0x70 + +/* + * The following constants define the offsets within a FlashBuffer data + * type for each kind of data. Note that the read data offset is not the + * same as the write data because the QSPIPSU driver is designed to allow full + * duplex transfers such that the number of bytes received is the number + * sent and received. + */ +#define COMMAND_OFFSET 0 /* Flash instruction */ +#define ADDRESS_1_OFFSET 1 /* MSB byte of address to read or write */ +#define ADDRESS_2_OFFSET 2 /* Middle byte of address to read or write */ +#define ADDRESS_3_OFFSET 3 /* LSB byte of address to read or write */ +#define ADDRESS_4_OFFSET 4 /* LSB byte of address to read or write when 4 byte address */ +#define DATA_OFFSET 5 /* Start of Data for Read/Write */ +#define DUMMY_OFFSET 4 /* Dummy byte offset for fast, dual and quad + reads */ +#define DUMMY_SIZE 1 /* Number of dummy bytes for fast, dual and + quad reads */ +#define DUMMY_CLOCKS 8 /* Number of dummy bytes for fast, dual and + quad reads */ +#define RD_ID_SIZE 4 /* Read ID command + 3 bytes ID response */ +#define BULK_ERASE_SIZE 1 /* Bulk Erase command size */ +#define SEC_ERASE_SIZE 4 /* Sector Erase command + Sector address */ +#define BANK_SEL_SIZE 2 /* BRWR or EARWR command + 1 byte bank value */ +#define RD_CFG_SIZE 2 /* 1 byte Configuration register + RD CFG command*/ +#define WR_CFG_SIZE 3 /* WRR command + 1 byte each Status and Config Reg*/ +#define DIE_ERASE_SIZE 4 /* Die Erase command + Die address */ + +/* + * The following constants specify the extra bytes which are sent to the + * Flash on the QSPIPSU interface, that are not data, but control information + * which includes the command and address + */ +#define OVERHEAD_SIZE 4 + +/* + * Base address of Flash1 + */ +#define FLASH1BASE 0x0000000 + +/* + * Sixteen MB + */ +#define SIXTEENMB 0x1000000 + + +/* + * Mask for quad enable bit in Flash configuration register + */ +#define FLASH_QUAD_EN_MASK 0x02 + +#define FLASH_SRWD_MASK 0x80 + +/* + * Bank mask + */ +#define BANKMASK 0xF000000 + +/* + * Identification of Flash + * Micron: + * Byte 0 is Manufacturer ID; + * Byte 1 is first byte of Device ID - 0xBB or 0xBA + * Byte 2 is second byte of Device ID describes flash size: + * 128Mbit : 0x18; 256Mbit : 0x19; 512Mbit : 0x20 + * Spansion: + * Byte 0 is Manufacturer ID; + * Byte 1 is Device ID - Memory Interface type - 0x20 or 0x02 + * Byte 2 is second byte of Device ID describes flash size: + * 128Mbit : 0x18; 256Mbit : 0x19; 512Mbit : 0x20 + */ +#define MICRON_ID_BYTE0 0x20 +#define MICRON_ID_BYTE2_128 0x18 +#define MICRON_ID_BYTE2_256 0x19 +#define MICRON_ID_BYTE2_512 0x20 +#define MICRON_ID_BYTE2_1G 0x21 + +#define SPANSION_ID_BYTE0 0x01 +#define SPANSION_ID_BYTE2_128 0x18 +#define SPANSION_ID_BYTE2_256 0x19 +#define SPANSION_ID_BYTE2_512 0x20 + +#define WINBOND_ID_BYTE0 0xEF +#define WINBOND_ID_BYTE2_128 0x18 + + +/* + * The index for Flash config table + */ +/* Spansion*/ +#define SPANSION_INDEX_START 0 +#define FLASH_CFG_TBL_SINGLE_128_SP SPANSION_INDEX_START +#define FLASH_CFG_TBL_STACKED_128_SP (SPANSION_INDEX_START + 1) +#define FLASH_CFG_TBL_PARALLEL_128_SP (SPANSION_INDEX_START + 2) +#define FLASH_CFG_TBL_SINGLE_256_SP (SPANSION_INDEX_START + 3) +#define FLASH_CFG_TBL_STACKED_256_SP (SPANSION_INDEX_START + 4) +#define FLASH_CFG_TBL_PARALLEL_256_SP (SPANSION_INDEX_START + 5) +#define FLASH_CFG_TBL_SINGLE_512_SP (SPANSION_INDEX_START + 6) +#define FLASH_CFG_TBL_STACKED_512_SP (SPANSION_INDEX_START + 7) +#define FLASH_CFG_TBL_PARALLEL_512_SP (SPANSION_INDEX_START + 8) + +/* Micron */ +#define MICRON_INDEX_START (FLASH_CFG_TBL_PARALLEL_512_SP + 1) +#define FLASH_CFG_TBL_SINGLE_128_MC MICRON_INDEX_START +#define FLASH_CFG_TBL_STACKED_128_MC (MICRON_INDEX_START + 1) +#define FLASH_CFG_TBL_PARALLEL_128_MC (MICRON_INDEX_START + 2) +#define FLASH_CFG_TBL_SINGLE_256_MC (MICRON_INDEX_START + 3) +#define FLASH_CFG_TBL_STACKED_256_MC (MICRON_INDEX_START + 4) +#define FLASH_CFG_TBL_PARALLEL_256_MC (MICRON_INDEX_START + 5) +#define FLASH_CFG_TBL_SINGLE_512_MC (MICRON_INDEX_START + 6) +#define FLASH_CFG_TBL_STACKED_512_MC (MICRON_INDEX_START + 7) +#define FLASH_CFG_TBL_PARALLEL_512_MC (MICRON_INDEX_START + 8) +#define FLASH_CFG_TBL_SINGLE_1GB_MC (MICRON_INDEX_START + 9) +#define FLASH_CFG_TBL_STACKED_1GB_MC (MICRON_INDEX_START + 10) +#define FLASH_CFG_TBL_PARALLEL_1GB_MC (MICRON_INDEX_START + 11) + +/* Winbond */ +#define WINBOND_INDEX_START (FLASH_CFG_TBL_PARALLEL_1GB_MC + 1) +#define FLASH_CFG_TBL_SINGLE_128_WB WINBOND_INDEX_START +#define FLASH_CFG_TBL_STACKED_128_WB (WINBOND_INDEX_START + 1) +#define FLASH_CFG_TBL_PARALLEL_128_WB (WINBOND_INDEX_START + 2) + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define QSPIPSU_DEVICE_ID XPAR_XQSPIPSU_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID +#define QSPIPSU_INTR_ID XPAR_XQSPIPS_0_INTR + +/* + * Number of flash pages to be written. + */ +#define PAGE_COUNT 32 + +/* + * Max page size to initialize write and read buffer + */ +#define MAX_PAGE_SIZE 1024 + +/* + * Flash address to which data is to be written. + */ +#define TEST_ADDRESS 0x000000 + + +#define UNIQUE_VALUE 0x07 + +/**************************** Type Definitions *******************************/ + +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 */ +}FlashInfo; + +u8 ReadCmd; +u8 WriteCmd; +u8 StatusCmd; +u8 SectorEraseCmd; +u8 FSRFlag; + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ +int QspiPsuInterruptFlashExample(XScuGic *IntcInstancePtr, XQspiPsu *QspiPsuInstancePtr, + u16 QspiPsuDeviceId, u16 QspiPsuIntrId); +int FlashReadID(XQspiPsu *QspiPsuPtr); +int FlashErase(XQspiPsu *QspiPsuPtr, u32 Address, u32 ByteCount, u8 *WriteBfrPtr); +int FlashWrite(XQspiPsu *QspiPsuPtr, u32 Address, u32 ByteCount, u8 Command, + u8 *WriteBfrPtr); +int FlashRead(XQspiPsu *QspiPsuPtr, u32 Address, u32 ByteCount, u8 Command, + u8 *WriteBfrPtr, u8 *ReadBfrPtr); +u32 GetRealAddr(XQspiPsu *QspiPsuPtr, u32 Address); +int BulkErase(XQspiPsu *QspiPsuPtr, u8 *WriteBfrPtr); +int DieErase(XQspiPsu *QspiPsuPtr, u8 *WriteBfrPtr); +static int QspiPsuSetupIntrSystem(XScuGic *IntcInstancePtr, + XQspiPsu *QspiPsuInstancePtr, u16 QspiPsuIntrId); +static void QspiPsuDisableIntrSystem(XScuGic *IntcInstancePtr, u16 QspiPsuIntrId); +void QspiPsuHandler(void *CallBackRef, u32 StatusEvent, unsigned int ByteCount); +/************************** Variable Definitions *****************************/ +u8 TxBfrPtr __attribute__ ((aligned(32))); +u8 ReadBfrPtr[4] __attribute__ ((aligned(32))); +FlashInfo Flash_Config_Table[24] = { + /* Spansion */ + {0x10000, 0x100, 256, 0x10000, 0x1000000, + SPANSION_ID_BYTE0, SPANSION_ID_BYTE2_128, 0xFFFF0000, 1}, + {0x10000, 0x200, 256, 0x20000, 0x1000000, + SPANSION_ID_BYTE0, SPANSION_ID_BYTE2_128, 0xFFFF0000, 1}, + {0x20000, 0x100, 512, 0x10000, 0x1000000, + SPANSION_ID_BYTE0, SPANSION_ID_BYTE2_128, 0xFFFE0000, 1}, + {0x10000, 0x200, 256, 0x20000, 0x2000000, + SPANSION_ID_BYTE0, SPANSION_ID_BYTE2_256, 0xFFFF0000, 1}, + {0x10000, 0x400, 256, 0x40000, 0x2000000, + SPANSION_ID_BYTE0, SPANSION_ID_BYTE2_256, 0xFFFF0000, 1}, + {0x20000, 0x200, 512, 0x20000, 0x2000000, + SPANSION_ID_BYTE0, SPANSION_ID_BYTE2_256, 0xFFFE0000, 1}, + {0x40000, 0x100, 512, 0x20000, 0x4000000, + SPANSION_ID_BYTE0, SPANSION_ID_BYTE2_512, 0xFFFC0000, 1}, + {0x40000, 0x200, 512, 0x40000, 0x4000000, + SPANSION_ID_BYTE0, SPANSION_ID_BYTE2_512, 0xFFFC0000, 1}, + {0x80000, 0x100, 1024, 0x20000, 0x4000000, + SPANSION_ID_BYTE0, SPANSION_ID_BYTE2_512, 0xFFF80000, 1}, + /* Spansion 1Gbit is handled as 512Mbit stacked */ + /* Micron */ + {0x10000, 0x100, 256, 0x10000, 0x1000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_128, 0xFFFF0000, 1}, + {0x10000, 0x200, 256, 0x20000, 0x1000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_128, 0xFFFF0000, 1}, + {0x20000, 0x100, 512, 0x10000, 0x1000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_128, 0xFFFE0000, 1}, + {0x10000, 0x200, 256, 0x20000, 0x2000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_256, 0xFFFF0000, 1}, + {0x10000, 0x400, 256, 0x40000, 0x2000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_256, 0xFFFF0000, 1}, + {0x20000, 0x200, 512, 0x20000, 0x2000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_256, 0xFFFE0000, 1}, + {0x10000, 0x400, 256, 0x40000, 0x4000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_512, 0xFFFF0000, 2}, + {0x10000, 0x800, 256, 0x80000, 0x4000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_512, 0xFFFF0000, 2}, + {0x20000, 0x400, 512, 0x40000, 0x4000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_512, 0xFFFE0000, 2}, + {0x10000, 0x800, 256, 0x80000, 0x8000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_1G, 0xFFFF0000, 4}, + {0x10000, 0x1000, 256, 0x100000, 0x8000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_1G, 0xFFFF0000, 4}, + {0x20000, 0x800, 512, 0x80000, 0x8000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_1G, 0xFFFE0000, 4}, + /* Winbond */ + {0x10000, 0x100, 256, 0x10000, 0x1000000, + WINBOND_ID_BYTE0, WINBOND_ID_BYTE2_128, 0xFFFF0000, 1}, + {0x10000, 0x200, 256, 0x20000, 0x1000000, + WINBOND_ID_BYTE0, WINBOND_ID_BYTE2_128, 0xFFFF0000, 1}, + {0x20000, 0x100, 512, 0x10000, 0x1000000, + WINBOND_ID_BYTE0, WINBOND_ID_BYTE2_128, 0xFFFE0000, 1} +}; + +u32 FlashMake; +u32 FCTIndex; /* Flash configuration table index */ + + +/* + * The instances to support the device drivers are global such that they + * are initialized to zero each time the program runs. They could be local + * but should at least be static so they are zeroed. + */ +static XScuGic IntcInstance; +static XQspiPsu QspiPsuInstance; + +static XQspiPsu_Msg FlashMsg[5]; + +/* + * The following variables are shared between non-interrupt processing and + * interrupt processing such that they must be global. + */ +volatile int TransferInProgress; + +/* + * The following variable tracks any errors that occur during interrupt + * processing + */ +int Error; + +/* + * The following variable allows a test value to be added to the values that + * are written to the Flash such that unique values can be generated to + * guarantee the writes to the Flash were successful + */ +int Test = 1; + +/* + * The following variables are used to read and write to the flash and they + * are global to avoid having large buffers on the stack + * The buffer size accounts for maximum page size and maximum banks - + * for each bank separate read will be performed leading to that many + * (overhead+dummy) bytes + */ +u8 ReadBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + (DATA_OFFSET + DUMMY_SIZE)*8] __attribute__ ((aligned(32))); +u8 WriteBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + DATA_OFFSET] __attribute__ ((aligned(32))); +u8 CmdBfr[8] __attribute__ ((aligned(32))); + +/* + * The following constants specify the max amount of data and the size of the + * the buffer required to hold the data and overhead to transfer the data to + * and from the Flash. Initialized to single flash page size. + */ +u32 MaxData = PAGE_COUNT*256; + +/*****************************************************************************/ +/** +* +* Main function to call the QSPIPSU Flash example. +* +* @param None +* +* @return XST_SUCCESS if successful, otherwise XST_FAILURE. +* +* @note None +* +******************************************************************************/ +int main(void) +{ + int Status; + + xil_printf("QSPIPSU Generic Flash Interrupt Example Test \r\n"); + + /* + * Run the QspiPsu Interrupt example. + */ + Status = QspiPsuInterruptFlashExample(&IntcInstance, &QspiPsuInstance, + QSPIPSU_DEVICE_ID, QSPIPSU_INTR_ID); + if (Status != XST_SUCCESS) { + xil_printf("QSPIPSU Generic Flash Interrupt Ex Failed\r\n"); + return XST_FAILURE; + } + + xil_printf("Successfully ran QSPIPSU Generic Interrupt Ex\r\n"); + return XST_SUCCESS; +} + +/***************************************************************************** +* +* The purpose of this function is to illustrate how to use the XQspiPsu +* device driver in single, parallel and stacked modes using +* flash devices greater than or equal to 128Mb. +* +* @param None. +* +* @return XST_SUCCESS if successful, else XST_FAILURE. +* +* @note None. +* +*****************************************************************************/ +int QspiPsuInterruptFlashExample(XScuGic *IntcInstancePtr, XQspiPsu *QspiPsuInstancePtr, + u16 QspiPsuDeviceId, u16 QspiPsuIntrId) +{ + int Status; + u8 UniqueValue; + int Count; + int Page; + XQspiPsu_Config *QspiPsuConfig; + int ReadBfrSize; + + Xil_DCacheDisable(); + + ReadBfrSize = (PAGE_COUNT * MAX_PAGE_SIZE) + + (DATA_OFFSET + DUMMY_SIZE)*8; + + /* + * Initialize the QSPIPSU driver so that it's ready to use + */ + QspiPsuConfig = XQspiPsu_LookupConfig(QspiPsuDeviceId); + if (NULL == QspiPsuConfig) { + return XST_FAILURE; + } + + /* To test, change connection mode here till we can get data from HDF */ + //QspiPsuConfig->ConnectionMode = 2; + + Status = XQspiPsu_CfgInitialize(QspiPsuInstancePtr, QspiPsuConfig, + QspiPsuConfig->BaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + xil_printf("Cfg Init done, Baseaddress: 0x%x \n\r", QspiPsuInstancePtr->Config.BaseAddress); + + /* + * Connect the QspiPsu device to the interrupt subsystem such that + * interrupts can occur. This function is application specific + */ + Status = QspiPsuSetupIntrSystem(IntcInstancePtr, QspiPsuInstancePtr, + QspiPsuIntrId); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Setup the handler for the QSPIPSU that will be called from the + * interrupt context when an QSPIPSU status occurs, specify a pointer to + * the QSPIPSU driver instance as the callback reference so the handler is + * able to access the instance data + */ + XQspiPsu_SetStatusHandler(QspiPsuInstancePtr, QspiPsuInstancePtr, + (XQspiPsu_StatusHandler) QspiPsuHandler); + + /* + * Set Manual Start + */ + XQspiPsu_SetOptions(QspiPsuInstancePtr, XQSPIPSU_MANUAL_START_OPTION); + + /* + * Set the prescaler for QSPIPSU clock + */ + XQspiPsu_SetClkPrescaler(QspiPsuInstancePtr, XQSPIPSU_CLK_PRESCALE_8); + + XQspiPsu_SelectFlash(QspiPsuInstancePtr, + XQSPIPSU_SELECT_FLASH_CS_LOWER, XQSPIPSU_SELECT_FLASH_BUS_LOWER); + + /* + * Read flash ID and obtain all flash related information + * It is important to call the read id function before + * performing proceeding to any operation, including + * preparing the WriteBuffer + */ + FlashReadID(QspiPsuInstancePtr); + + xil_printf("Flash connection mode : %d \n\r", + QspiPsuConfig->ConnectionMode); + xil_printf("where 0 - Single; 1 - Stacked; 2 - Parallel \n\r"); + xil_printf("FCTIndex: %d \n\r", FCTIndex); + /* + * Initialize MaxData according to page size. + */ + MaxData = PAGE_COUNT * (Flash_Config_Table[FCTIndex].PageSize); + + /* + * Address size and read command selection + * Micron flash on REMUS doesn't support these 4B write/erase commands + */ + if(Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) { + /* Use 4 byte address and 4 byte read commands */ + ReadCmd = QUAD_READ_CMD_4B; + WriteCmd = WRITE_CMD; + SectorEraseCmd = SEC_ERASE_CMD; + + /* If supported by flash, use 4B address write and erase */ +#ifdef COMMENT + WriteCmd = WRITE_CMD_4B; + SectorEraseCmd = SEC_ERASE_CMD_4B; +#endif + } else { + ReadCmd = QUAD_READ_CMD; + WriteCmd = WRITE_CMD; + SectorEraseCmd = SEC_ERASE_CMD; + } + + if((Flash_Config_Table[FCTIndex].NumDie > 1) && + (FlashMake == MICRON_ID_BYTE0)) { + StatusCmd = READ_FLAG_STATUS_CMD; + FSRFlag = 1; + } else { + StatusCmd = READ_STATUS_CMD; + FSRFlag = 0; + } + + xil_printf("ReadCmd: 0x%x, WriteCmd: 0x%x, StatusCmd: 0x%x, FSRFlag: %d \n\r", + ReadCmd, WriteCmd, StatusCmd, FSRFlag); + + for (UniqueValue = UNIQUE_VALUE, Count = 0; + Count < Flash_Config_Table[FCTIndex].PageSize; + Count++, UniqueValue++) { + WriteBuffer[Count] = (u8)(UniqueValue + Test); + } + + for (Count = 0; Count < ReadBfrSize; Count++) { + ReadBuffer[Count] = 0; + } + + FlashErase(QspiPsuInstancePtr, TEST_ADDRESS, MaxData, CmdBfr); + + for (Page = 0; Page < PAGE_COUNT; Page++) { + FlashWrite(QspiPsuInstancePtr, + (Page * Flash_Config_Table[FCTIndex].PageSize) + TEST_ADDRESS, + Flash_Config_Table[FCTIndex].PageSize, WriteCmd, WriteBuffer); + } + + FlashRead(QspiPsuInstancePtr, TEST_ADDRESS, MaxData, ReadCmd, + CmdBfr, ReadBuffer); + /* + * Setup a pointer to the start of the data that was read into the read + * buffer and verify the data read is the data that was written + */ + for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MaxData; + Count++, UniqueValue++) { + if (ReadBuffer[Count] != (u8)(UniqueValue + Test)) { + return XST_FAILURE; + } + } + + QspiPsuDisableIntrSystem(IntcInstancePtr, QspiPsuIntrId); + + return XST_SUCCESS; +} + +/***************************************************************************** +* +* Callback handler. +* +* @param None. +* +* @return None +* +* @note None. +* +*****************************************************************************/ +void QspiPsuHandler(void *CallBackRef, u32 StatusEvent, unsigned int ByteCount) +{ + /* + * Indicate the transfer on the QSPIPSU bus is no longer in progress + * regardless of the status event + */ + TransferInProgress = FALSE; + + /* + * If the event was not transfer done, then track it as an error + */ + if (StatusEvent != XST_SPI_TRANSFER_DONE) { + Error++; + } +} + +/***************************************************************************** +* +* Reads the flash ID and identifies the flash in FCT table. +* +* @param None. +* +* @return XST_SUCCESS if successful, else XST_FAILURE. +* +* @note None. +* +*****************************************************************************/ +int FlashReadID(XQspiPsu *QspiPsuPtr) +{ + int Status; + int StartIndex; + + /* + * Read ID + */ + TxBfrPtr = READ_ID; + FlashMsg[0].TxBfrPtr = &TxBfrPtr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = ReadBfrPtr; + FlashMsg[1].ByteCount = 4; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = 0; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while(TransferInProgress); + + xil_printf("FlashID=0x%x 0x%x 0x%x\n\r", ReadBfrPtr[0], ReadBfrPtr[1], + ReadBfrPtr[2]); + + /* In case of dual, read both and ensure they are same make/size */ + + /* + * Deduce flash make + */ + if(ReadBfrPtr[0] == MICRON_ID_BYTE0) { + FlashMake = MICRON_ID_BYTE0; + StartIndex = MICRON_INDEX_START; + }else if(ReadBfrPtr[0] == SPANSION_ID_BYTE0) { + FlashMake = SPANSION_ID_BYTE0; + StartIndex = SPANSION_INDEX_START; + }else if(ReadBfrPtr[0] == WINBOND_ID_BYTE0) { + FlashMake = WINBOND_ID_BYTE0; + StartIndex = WINBOND_INDEX_START; + } + + + /* + * If valid flash ID, then check connection mode & size and + * assign corresponding index in the Flash configuration table + */ + if(((FlashMake == MICRON_ID_BYTE0) || (FlashMake = SPANSION_ID_BYTE0)|| + (FlashMake == WINBOND_ID_BYTE0)) && + (ReadBfrPtr[2] == MICRON_ID_BYTE2_128)) { + + switch(QspiPsuPtr->Config.ConnectionMode) + { + case XQSPIPSU_CONNECTION_MODE_SINGLE: + FCTIndex = FLASH_CFG_TBL_SINGLE_128_SP + StartIndex; + break; + case XQSPIPSU_CONNECTION_MODE_PARALLEL: + FCTIndex = FLASH_CFG_TBL_PARALLEL_128_SP + StartIndex; + break; + case XQSPIPSU_CONNECTION_MODE_STACKED: + FCTIndex = FLASH_CFG_TBL_STACKED_128_SP + StartIndex; + break; + default: + FCTIndex = 0; + break; + } + } + /* 256 and 512Mbit supported only for Micron and Spansion, not Winbond */ + if(((FlashMake == MICRON_ID_BYTE0) || (FlashMake = SPANSION_ID_BYTE0)) && + (ReadBfrPtr[2] == MICRON_ID_BYTE2_256)) { + + switch(QspiPsuPtr->Config.ConnectionMode) + { + case XQSPIPSU_CONNECTION_MODE_SINGLE: + FCTIndex = FLASH_CFG_TBL_SINGLE_256_SP + StartIndex; + break; + case XQSPIPSU_CONNECTION_MODE_PARALLEL: + FCTIndex = FLASH_CFG_TBL_PARALLEL_256_SP + StartIndex; + break; + case XQSPIPSU_CONNECTION_MODE_STACKED: + FCTIndex = FLASH_CFG_TBL_STACKED_256_SP + StartIndex; + break; + default: + FCTIndex = 0; + break; + } + } + if(((FlashMake == MICRON_ID_BYTE0) || (FlashMake = SPANSION_ID_BYTE0)) && + (ReadBfrPtr[2] == MICRON_ID_BYTE2_512)) { + + switch(QspiPsuPtr->Config.ConnectionMode) + { + case XQSPIPSU_CONNECTION_MODE_SINGLE: + FCTIndex = FLASH_CFG_TBL_SINGLE_512_SP + StartIndex; + break; + case XQSPIPSU_CONNECTION_MODE_PARALLEL: + FCTIndex = FLASH_CFG_TBL_PARALLEL_512_SP + StartIndex; + break; + case XQSPIPSU_CONNECTION_MODE_STACKED: + FCTIndex = FLASH_CFG_TBL_STACKED_512_SP + StartIndex; + break; + default: + 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 == MICRON_ID_BYTE0) && + (ReadBfrPtr[2] == MICRON_ID_BYTE2_1G)) { + + switch(QspiPsuPtr->Config.ConnectionMode) + { + case XQSPIPSU_CONNECTION_MODE_SINGLE: + FCTIndex = FLASH_CFG_TBL_SINGLE_1GB_MC; + break; + case XQSPIPSU_CONNECTION_MODE_PARALLEL: + FCTIndex = FLASH_CFG_TBL_PARALLEL_1GB_MC; + break; + case XQSPIPSU_CONNECTION_MODE_STACKED: + FCTIndex = FLASH_CFG_TBL_STACKED_1GB_MC; + break; + default: + FCTIndex = 0; + break; + } + } + + return XST_SUCCESS; +} + +/****************************************************************************** +* +* +* This function writes to the serial Flash connected to the QSPIPSU interface. +* All the data put into the buffer must be in the same page of the device with +* page boundaries being on 256 byte boundaries. +* +* @param QspiPtr is a pointer to the QSPIPSU driver component to use. +* @param Address contains the address to write data to in the Flash. +* @param ByteCount contains the number of bytes to write. +* @param Command is the command used to write data to the flash. QSPIPSU +* device supports only Page Program command to write data to the +* flash. +* @param Pointer to the write buffer (which is to be transmitted) +* +* @return XST_SUCCESS if successful, else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int FlashWrite(XQspiPsu *QspiPsuPtr, u32 Address, u32 ByteCount, u8 Command, + u8 *WriteBfrPtr) +{ + u8 WriteEnableCmd __attribute__ ((aligned(32))); + u8 ReadStatusCmd __attribute__ ((aligned(32))); + u8 FlashStatus[4] __attribute__ ((aligned(32))); + u8 WriteCmd[5] __attribute__ ((aligned(32))); + u32 RealAddr; + u32 CmdByteCount; + int Status; + + WriteEnableCmd = WRITE_ENABLE_CMD; + /* + * Translate address based on type of connection + * If stacked assert the slave select based on address + */ + RealAddr = GetRealAddr(QspiPsuPtr, Address); + + /* + * Send the write enable command to the Flash so that it can be + * written to, this needs to be sent as a separate transfer before + * the write + */ + FlashMsg[0].TxBfrPtr = &WriteEnableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + TransferInProgress = TRUE; + + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + while(TransferInProgress); + + WriteCmd[COMMAND_OFFSET] = Command; + + /* To be used only if 4B address program cmd is supported by flash */ +#ifdef COMMENT + if(Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) { + WriteCmd[ADDRESS_1_OFFSET] = (u8)((RealAddr & 0xFF000000) >> 24); + WriteCmd[ADDRESS_2_OFFSET] = (u8)((RealAddr & 0xFF0000) >> 16); + WriteCmd[ADDRESS_3_OFFSET] = (u8)((RealAddr & 0xFF00) >> 8); + WriteCmd[ADDRESS_4_OFFSET] = (u8)(RealAddr & 0xFF); + CmdByteCount = 5; + } else { +#endif + WriteCmd[ADDRESS_1_OFFSET] = (u8)((RealAddr & 0xFF0000) >> 16); + WriteCmd[ADDRESS_2_OFFSET] = (u8)((RealAddr & 0xFF00) >> 8); + WriteCmd[ADDRESS_3_OFFSET] = (u8)(RealAddr & 0xFF); + CmdByteCount = 4; +#ifdef COMMENT + } +#endif + + FlashMsg[0].TxBfrPtr = WriteCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = CmdByteCount; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + FlashMsg[1].TxBfrPtr = WriteBfrPtr; + FlashMsg[1].RxBfrPtr = NULL; + FlashMsg[1].ByteCount = ByteCount; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = 0; + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_STRIPE; + } + + TransferInProgress = TRUE; + + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + while(TransferInProgress); + + /* + * Wait for the write command to the Flash to be completed, it takes + * some time for the data to be written + */ + while (1) { + ReadStatusCmd = StatusCmd; + FlashMsg[0].TxBfrPtr = &ReadStatusCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = FlashStatus; + FlashMsg[1].ByteCount = 4; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = 0; + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_STRIPE; + } + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while(TransferInProgress); + + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + if(FSRFlag) { + FlashStatus[3] &= FlashStatus[2]; + } else { + FlashStatus[3] |= FlashStatus[2]; + } + } + + if(FSRFlag) { + if ((FlashStatus[3] & 0x80) != 0) { + break; + } + } else { + if ((FlashStatus[3] & 0x01) == 0) { + break; + } + } + } + + return 0; +} + +/****************************************************************************** +* +* +* This function erases the sectors in the serial Flash connected to the +* QSPIPSU interface. +* +* @param QspiPtr is a pointer to the QSPIPSU driver component to use. +* @param Address contains the address of the first sector which needs to +* be erased. +* @param ByteCount contains the total size to be erased. +* @param Pointer to the write buffer (which is to be transmitted) +* +* @return XST_SUCCESS if successful, else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int FlashErase(XQspiPsu *QspiPsuPtr, u32 Address, u32 ByteCount, u8 *WriteBfrPtr) +{ + u8 WriteEnableCmd __attribute__ ((aligned(32))); + u8 ReadStatusCmd __attribute__ ((aligned(32))); + u8 FlashStatus[4] __attribute__ ((aligned(32))); + int Sector; + u32 RealAddr; + u32 NumSect; + int Status; + + WriteEnableCmd = WRITE_ENABLE_CMD; + /* + * If erase size is same as the total size of the flash, use bulk erase + * command or die erase command multiple times as required + */ + if (ByteCount == ((Flash_Config_Table[FCTIndex]).NumSect * + (Flash_Config_Table[FCTIndex]).SectSize) ) { + + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED){ + XQspiPsu_SelectFlash(QspiPsuPtr, + XQSPIPSU_SELECT_FLASH_CS_LOWER, XQSPIPSU_SELECT_FLASH_BUS_LOWER); + } + + if(Flash_Config_Table[FCTIndex].NumDie == 1) { + /* + * Call Bulk erase + */ + BulkErase(QspiPsuPtr, WriteBfrPtr); + } + + if(Flash_Config_Table[FCTIndex].NumDie > 1) { + /* + * Call Die erase + */ + DieErase(QspiPsuPtr, WriteBfrPtr); + } + /* + * If stacked mode, bulk erase second flash + */ + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED){ + + XQspiPsu_SelectFlash(QspiPsuPtr, + XQSPIPSU_SELECT_FLASH_CS_UPPER, XQSPIPSU_SELECT_FLASH_BUS_LOWER); + + if(Flash_Config_Table[FCTIndex].NumDie == 1) { + /* + * Call Bulk erase + */ + BulkErase(QspiPsuPtr, WriteBfrPtr); + } + + if(Flash_Config_Table[FCTIndex].NumDie > 1) { + /* + * Call Die erase + */ + DieErase(QspiPsuPtr, WriteBfrPtr); + } + } + + return 0; + } + + /* + * If the erase size is less than the total size of the flash, use + * sector erase command + */ + + /* + * Calculate no. of sectors to erase based on byte count + */ + NumSect = ByteCount/(Flash_Config_Table[FCTIndex].SectSize) + 1; + + /* + * If ByteCount to k sectors, + * but the address range spans from N to N+k+1 sectors, then + * increment no. of sectors to be erased + */ + + if( ((Address + ByteCount) & Flash_Config_Table[FCTIndex].SectMask) == + ((Address + (NumSect * Flash_Config_Table[FCTIndex].SectSize)) & + Flash_Config_Table[FCTIndex].SectMask) ) { + NumSect++; + } + + for (Sector = 0; Sector < NumSect; Sector++) { + + /* + * Translate address based on type of connection + * If stacked assert the slave select based on address + */ + RealAddr = GetRealAddr(QspiPsuPtr, Address); + + /* + * Send the write enable command to the Flash so that it can be + * written to, this needs to be sent as a separate transfer before + * the write + */ + FlashMsg[0].TxBfrPtr = &WriteEnableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while(TransferInProgress); + + WriteBfrPtr[COMMAND_OFFSET] = SectorEraseCmd; + + /* + * To be used only if 4B address sector erase cmd is + * supported by flash + */ +#ifdef COMMENT + if(Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) { + WriteBfrPtr[ADDRESS_1_OFFSET] = (u8)((RealAddr & 0xFF000000) >> 24); + WriteBfrPtr[ADDRESS_2_OFFSET] = (u8)((RealAddr & 0xFF0000) >> 16); + WriteBfrPtr[ADDRESS_3_OFFSET] = (u8)((RealAddr & 0xFF00) >> 8); + WriteBfrPtr[ADDRESS_4_OFFSET] = (u8)(RealAddr & 0xFF); + FlashMsg[0].ByteCount = 5; + } else { +#endif + WriteBfrPtr[ADDRESS_1_OFFSET] = (u8)((RealAddr & 0xFF0000) >> 16); + WriteBfrPtr[ADDRESS_2_OFFSET] = (u8)((RealAddr & 0xFF00) >> 8); + WriteBfrPtr[ADDRESS_3_OFFSET] = (u8)(RealAddr & 0xFF); + FlashMsg[0].ByteCount = 4; +#ifdef COMMENT + } +#endif + FlashMsg[0].TxBfrPtr = WriteBfrPtr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while(TransferInProgress); + + /* + * Wait for the erase command to be completed + */ + while (1) { + ReadStatusCmd = StatusCmd; + FlashMsg[0].TxBfrPtr = &ReadStatusCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = FlashStatus; + FlashMsg[1].ByteCount = 4; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = 0; + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_STRIPE; + } + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while(TransferInProgress); + + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + if(FSRFlag) { + FlashStatus[3] &= FlashStatus[2]; + } else { + FlashStatus[3] |= FlashStatus[2]; + } + } + + if(FSRFlag) { + if ((FlashStatus[3] & 0x80) != 0) { + break; + } + } else { + if ((FlashStatus[3] & 0x01) == 0) { + break; + } + } + } + Address += Flash_Config_Table[FCTIndex].SectSize; + } + + return 0; +} + + +/****************************************************************************** +* +* This function performs a read. Default setting is in DMA mode. +* +* @param QspiPtr is a pointer to the QSPIPSU driver component to use. +* @param Address contains the address of the first sector which needs to +* be erased. +* @param ByteCount contains the total size to be erased. +* @param Command is the command used to read data from the flash. Supports +* normal, fast, dual and quad read commands. +* @param Pointer to the write buffer which contains data to be transmitted +* @param Pointer to the read buffer to which valid received data should be +* written +* +* @return XST_SUCCESS if successful, else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int FlashRead(XQspiPsu *QspiPsuPtr, u32 Address, u32 ByteCount, u8 Command, + u8 *WriteBfrPtr, u8 *ReadBfrPtr) +{ + u32 RealAddr; + u32 DiscardByteCnt; + u32 FlashMsgCnt; + int Status; + + /* Check die boundary conditions if required for any flash */ + + /* For Dual Stacked, split and read for boundary crossing */ + /* + * Translate address based on type of connection + * If stacked assert the slave select based on address + */ + RealAddr = GetRealAddr(QspiPsuPtr, Address); + + WriteBfrPtr[COMMAND_OFFSET] = Command; + if(Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) { + WriteBfrPtr[ADDRESS_1_OFFSET] = (u8)((RealAddr & 0xFF000000) >> 24); + WriteBfrPtr[ADDRESS_2_OFFSET] = (u8)((RealAddr & 0xFF0000) >> 16); + WriteBfrPtr[ADDRESS_3_OFFSET] = (u8)((RealAddr & 0xFF00) >> 8); + WriteBfrPtr[ADDRESS_4_OFFSET] = (u8)(RealAddr & 0xFF); + DiscardByteCnt = 5; + } else { + WriteBfrPtr[ADDRESS_1_OFFSET] = (u8)((RealAddr & 0xFF0000) >> 16); + WriteBfrPtr[ADDRESS_2_OFFSET] = (u8)((RealAddr & 0xFF00) >> 8); + WriteBfrPtr[ADDRESS_3_OFFSET] = (u8)(RealAddr & 0xFF); + DiscardByteCnt = 4; + } + + FlashMsg[0].TxBfrPtr = WriteBfrPtr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = DiscardByteCnt; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + FlashMsgCnt = 1; + + /* It is recommended to have a separate entry for dummy */ + if ((Command == FAST_READ_CMD) || (Command == DUAL_READ_CMD) || + (Command == QUAD_READ_CMD) || (Command == FAST_READ_CMD_4B) || + (Command == DUAL_READ_CMD_4B) || (Command == QUAD_READ_CMD_4B)) { + /* Update Dummy cycles as per flash specs for QUAD IO */ + if ((Command == FAST_READ_CMD) || (Command == FAST_READ_CMD_4B)) { + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + } + + if ((Command == DUAL_READ_CMD) || (Command == DUAL_READ_CMD_4B)) { + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_DUALSPI; + } + + if ((Command == QUAD_READ_CMD) || (Command == QUAD_READ_CMD_4B)) { + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI; + } + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = NULL; + FlashMsg[1].ByteCount = DUMMY_CLOCKS; + FlashMsg[1].Flags = 0; + + FlashMsgCnt++; + } + + /* Dummy cycles need to be changed as per flash specs for QUAD IO */ + if ((Command == FAST_READ_CMD) || (Command == FAST_READ_CMD_4B)) { + FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + } + + if ((Command == DUAL_READ_CMD) || (Command == DUAL_READ_CMD_4B)) { + FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_DUALSPI; + } + + if ((Command == QUAD_READ_CMD) || (Command == QUAD_READ_CMD_4B)) { + FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI; + } + + FlashMsg[FlashMsgCnt].TxBfrPtr = NULL; + FlashMsg[FlashMsgCnt].RxBfrPtr = ReadBfrPtr; + FlashMsg[FlashMsgCnt].ByteCount = ByteCount; + FlashMsg[FlashMsgCnt].Flags = 0; + + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_STRIPE; + } + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, FlashMsgCnt+1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while(TransferInProgress); + + return 0; +} + +/****************************************************************************** +* +* This functions performs a bulk erase operation when the +* flash device has a single die. Works for both Spansion and Micron +* +* @param QspiPtr is a pointer to the QSPIPSU driver component to use. +* @param WritBfrPtr is the pointer to command+address to be sent +* +* @return XST_SUCCESS if successful, else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int BulkErase(XQspiPsu *QspiPsuPtr, u8 *WriteBfrPtr) +{ + u8 WriteEnableCmd __attribute__ ((aligned(32))); + u8 ReadStatusCmd __attribute__ ((aligned(32))); + u8 FlashStatus[4] __attribute__ ((aligned(32))); + int Status; + + WriteEnableCmd = WRITE_ENABLE_CMD; + /* + * Send the write enable command to the Flash so that it can be + * written to, this needs to be sent as a separate transfer before + * the write + */ + FlashMsg[0].TxBfrPtr = &WriteEnableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while(TransferInProgress); + + WriteBfrPtr[COMMAND_OFFSET] = BULK_ERASE_CMD; + FlashMsg[0].TxBfrPtr = WriteBfrPtr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while(TransferInProgress); + + /* + * Wait for the write command to the Flash to be completed, it takes + * some time for the data to be written + */ + while (1) { + ReadStatusCmd = StatusCmd; + FlashMsg[0].TxBfrPtr = &ReadStatusCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = FlashStatus; + FlashMsg[1].ByteCount = 4; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = 0; + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_STRIPE; + } + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while(TransferInProgress); + + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + if(FSRFlag) { + FlashStatus[3] &= FlashStatus[2]; + } else { + FlashStatus[3] |= FlashStatus[2]; + } + } + + if(FSRFlag) { + if ((FlashStatus[3] & 0x80) != 0) { + break; + } + } else { + if ((FlashStatus[3] & 0x01) == 0) { + break; + } + } + } + + return 0; +} + +/****************************************************************************** +* +* This functions performs a die erase operation on all the die in +* the flash device. This function uses the die erase command for +* Micron 512Mbit and 1Gbit +* +* @param QspiPtr is a pointer to the QSPIPSU driver component to use. +* @param WritBfrPtr is the pointer to command+address to be sent +* +* @return XST_SUCCESS if successful, else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int DieErase(XQspiPsu *QspiPsuPtr, u8 *WriteBfrPtr) +{ + u8 WriteEnableCmd __attribute__ ((aligned(32))); + u8 DieCnt; + u8 ReadStatusCmd __attribute__ ((aligned(32))); + u8 FlashStatus[4] __attribute__ ((aligned(32))); + int Status; + + WriteEnableCmd = WRITE_ENABLE_CMD; + for(DieCnt = 0; DieCnt < Flash_Config_Table[FCTIndex].NumDie; DieCnt++) { + /* + * Send the write enable command to the Flash so that it can be + * written to, this needs to be sent as a separate transfer before + * the write + */ + FlashMsg[0].TxBfrPtr = &WriteEnableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while(TransferInProgress); + + WriteBfrPtr[COMMAND_OFFSET] = DIE_ERASE_CMD; + /* Check these number of address bytes as per flash device */ + WriteBfrPtr[ADDRESS_1_OFFSET] = 0; + WriteBfrPtr[ADDRESS_2_OFFSET] = 0; + WriteBfrPtr[ADDRESS_3_OFFSET] = 0; + + FlashMsg[0].TxBfrPtr = WriteBfrPtr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 4; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while(TransferInProgress); + + /* + * Wait for the write command to the Flash to be completed, it takes + * some time for the data to be written + */ + while (1) { + ReadStatusCmd = StatusCmd; + FlashMsg[0].TxBfrPtr = &ReadStatusCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = FlashStatus; + FlashMsg[1].ByteCount = 4; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = 0; + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_STRIPE; + } + + TransferInProgress = TRUE; + Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + while(TransferInProgress); + + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + if(FSRFlag) { + FlashStatus[3] &= FlashStatus[2]; + } else { + FlashStatus[3] |= FlashStatus[2]; + } + } + + if(FSRFlag) { + if ((FlashStatus[3] & 0x80) != 0) { + break; + } + } else { + if ((FlashStatus[3] & 0x01) == 0) { + break; + } + } + } + } + + return 0; +} + +/****************************************************************************** +* +* 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 the QSPIPSU driver component to use. +* @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(XQspiPsu *QspiPsuPtr, u32 Address) +{ + u32 RealAddr; + + switch(QspiPsuPtr->Config.ConnectionMode) { + case XQSPIPSU_CONNECTION_MODE_SINGLE: + XQspiPsu_SelectFlash(QspiPsuPtr, + XQSPIPSU_SELECT_FLASH_CS_LOWER, XQSPIPSU_SELECT_FLASH_BUS_LOWER); + RealAddr = Address; + break; + case XQSPIPSU_CONNECTION_MODE_STACKED: + /* Select lower or upper Flash based on sector address */ + if(Address & Flash_Config_Table[FCTIndex].FlashDeviceSize) { + + XQspiPsu_SelectFlash(QspiPsuPtr, + XQSPIPSU_SELECT_FLASH_CS_UPPER, XQSPIPSU_SELECT_FLASH_BUS_LOWER); + /* + * Subtract first flash size when accessing second flash + */ + RealAddr = Address & + (~Flash_Config_Table[FCTIndex].FlashDeviceSize); + }else{ + /* + * Set selection to L_PAGE + */ + XQspiPsu_SelectFlash(QspiPsuPtr, + XQSPIPSU_SELECT_FLASH_CS_LOWER, XQSPIPSU_SELECT_FLASH_BUS_LOWER); + + RealAddr = Address; + + } + break; + case XQSPIPSU_CONNECTION_MODE_PARALLEL: + /* + * The effective address in each flash is the actual + * address / 2 + */ + XQspiPsu_SelectFlash(QspiPsuPtr, XQSPIPSU_SELECT_FLASH_CS_BOTH, XQSPIPSU_SELECT_FLASH_BUS_BOTH); + RealAddr = Address / 2; + break; + default: + /* RealAddr wont be assigned in this case; */ + break; + + } + + return(RealAddr); +} + +/*****************************************************************************/ +/** +* +* This function setups the interrupt system for a QspiPsu device. +* +* @param IntcInstancePtr is a pointer to the instance of the Intc device. +* @param QspiPsuInstancePtr is a pointer to the instance of the QspiPsu device. +* @param QspiPsuIntrId is the interrupt Id for an QSPIPSU device. +* +* @return XST_SUCCESS if successful, otherwise XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +static int QspiPsuSetupIntrSystem(XScuGic *IntcInstancePtr, + XQspiPsu *QspiPsuInstancePtr, u16 QspiPsuIntrId) +{ + int Status; + + XScuGic_Config *IntcConfig; /* Instance of the interrupt controller */ + + Xil_ExceptionInit(); + + /* + * Initialize the interrupt controller driver so that it is ready to + * use. + */ + IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); + if (NULL == IntcConfig) { + return XST_FAILURE; + } + + Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, + IntcConfig->CpuBaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Connect the interrupt controller interrupt handler to the hardware + * interrupt handling logic in the processor. + */ + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler)XScuGic_InterruptHandler, + IntcInstancePtr); + + /* + * Connect the device driver handler that will be called when an + * interrupt for the device occurs, the handler defined above performs + * the specific interrupt processing for the device. + */ + Status = XScuGic_Connect(IntcInstancePtr, QspiPsuIntrId, + (Xil_ExceptionHandler)XQspiPsu_InterruptHandler, + (void *)QspiPsuInstancePtr); + if (Status != XST_SUCCESS) { + return Status; + } + + /* + * Enable the interrupt for the QspiPsu device. + */ + XScuGic_Enable(IntcInstancePtr, QspiPsuIntrId); + + /* + * Enable interrupts in the Processor. + */ + Xil_ExceptionEnable(); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function disables the interrupts that occur for the QspiPsu device. +* +* @param IntcInstancePtr is a pointer to the instance of the Intc device. +* @param QspiPsuInstancePtr is a pointer to the instance of the QspiPsu device. +* @param QspiPsuIntrId is the interrupt Id for an QSPIPSU device. +* +* @return XST_SUCCESS if successful, otherwise XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +static void QspiPsuDisableIntrSystem(XScuGic *IntcInstancePtr, u16 QspiPsuIntrId) +{ + /* + * Disable the interrupt for the QSPIPSU device. + */ + XScuGic_Disable(IntcInstancePtr, QspiPsuIntrId); + + /* + * Disconnect and disable the interrupt for the QspiPsu device. + */ + XScuGic_Disconnect(IntcInstancePtr, QspiPsuIntrId); +} diff --git a/XilinxProcessorIPLib/drivers/qspipsu/examples/xqspipsu_generic_flash_polled_example.c b/XilinxProcessorIPLib/drivers/qspipsu/examples/xqspipsu_generic_flash_polled_example.c new file mode 100755 index 00000000..01f241fd --- /dev/null +++ b/XilinxProcessorIPLib/drivers/qspipsu/examples/xqspipsu_generic_flash_polled_example.c @@ -0,0 +1,1599 @@ +/****************************************************************************** +* +* Copyright (C) 2014 Xilinx, Inc. All rights reserved. +* +* This file contains confidential and proprietary information of Xilinx, Inc. +* and is protected under U.S. and international copyright and other +* intellectual property laws. +* +* DISCLAIMER +* This disclaimer is not a license and does not grant any rights to the +* materials distributed herewith. Except as otherwise provided in a valid +* license issued to you by Xilinx, and to the maximum extent permitted by +* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL +* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, +* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF +* MERCHANTABILITY, NON- INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; +* and +* (2) Xilinx shall not be liable (whether in contract or tort, including +* negligence, or under any other theory of liability) for any loss or damage +* of any kind or nature related to, arising under or in connection with these +* materials, including for any direct, or any indirect, special, incidental, +* or consequential loss or damage (including loss of data, profits, +* goodwill, or any type of loss or damage suffered as a result of any +* action brought by a third party) even if such damage or loss was +* reasonably foreseeable or Xilinx had been advised of the possibility +* of the same. +* +* CRITICAL APPLICATIONS +* Xilinx products are not designed or intended to be fail- safe, or for use +* in any application requiring fail-safe performance, such as life-support +* or safety devices or systems, Class III medical devices, nuclear +* facilities, applications related to the deployment of airbags, or any +* other applications that could lead to death, personal injury, or severe +* property or environmental damage (individually and collectively, +* "Critical Applications"). Customer assumes the sole risk and liability +* of any use of Xilinx products in Critical Applications, subject only to +* applicable laws and regulations governing limitations on product liability. +* +* THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART +* OF THIS FILE AT ALL TIMES. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xqspipsu_generic_flash_polled_example.c +* +* +* This file contains a design example using the QSPIPSU driver (XQspiPsu) +* with a serial Flash device greater than or equal to 128Mb. +* The example writes to flash and reads it back in DMA mode. +* This examples runs with GENFIFO Manual start. It runs in polled mode. +* This example illustrates single, parallel and stacked modes. +* Both the flash devices have to be of the same make and size. +* The hardware which this example runs on, must have a serial Flash (Micron +* N25Q or Spansion S25FL) for it to run. In order to test in single, +* parallel or stacked flash configurations the necessary HW must be present +* and QSPI_MODE (also reflected in ConnectionMode in the instance) has +* to be in sync with HW flash configuration being tested. +* +* This example has been tested with the Micron Serial Flash (N25Q512) in +* single and parallel modes using A53 and R5 processors. +* +* @note +* +* None. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who Date     Changes
+* ----- --- -------- -----------------------------------------------
+* 1.0   hk  08/21/14 First release
+*
+*
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" /* SDK generated parameters */ +#include "xqspipsu.h" /* QSPIPSU device driver */ +#include "xil_printf.h" +#include "xil_cache.h" + +/************************** Constant Definitions *****************************/ + +/* + * The following constants define the commands which may be sent to the Flash + * device. + */ +#define WRITE_STATUS_CMD 0x01 +#define WRITE_CMD 0x02 +#define READ_CMD 0x03 +#define WRITE_DISABLE_CMD 0x04 +#define READ_STATUS_CMD 0x05 +#define WRITE_ENABLE_CMD 0x06 +#define FAST_READ_CMD 0x0B +#define DUAL_READ_CMD 0x3B +#define QUAD_READ_CMD 0x6B +#define BULK_ERASE_CMD 0xC7 +#define SEC_ERASE_CMD 0xD8 +#define READ_ID 0x9F +#define READ_CONFIG_CMD 0x35 +#define WRITE_CONFIG_CMD 0x01 + +#define WRITE_CMD_4B 0x12 +#define READ_CMD_4B 0x13 +#define FAST_READ_CMD_4B 0x0C +#define DUAL_READ_CMD_4B 0x3C +#define QUAD_READ_CMD_4B 0x6C +#define SEC_ERASE_CMD_4B 0xDC + +#define BANK_REG_RD 0x16 +#define BANK_REG_WR 0x17 +/* Bank register is called Extended Address Register in Micron */ +#define EXTADD_REG_RD 0xC8 +#define EXTADD_REG_WR 0xC5 +#define DIE_ERASE_CMD 0xC4 +#define READ_FLAG_STATUS_CMD 0x70 + +/* + * The following constants define the offsets within a FlashBuffer data + * type for each kind of data. Note that the read data offset is not the + * same as the write data because the QSPIPSU driver is designed to allow full + * duplex transfers such that the number of bytes received is the number + * sent and received. + */ +#define COMMAND_OFFSET 0 /* Flash instruction */ +#define ADDRESS_1_OFFSET 1 /* MSB byte of address to read or write */ +#define ADDRESS_2_OFFSET 2 /* Middle byte of address to read or write */ +#define ADDRESS_3_OFFSET 3 /* LSB byte of address to read or write */ +#define ADDRESS_4_OFFSET 4 /* LSB byte of address to read or write when 4 byte address */ +#define DATA_OFFSET 5 /* Start of Data for Read/Write */ +#define DUMMY_OFFSET 4 /* Dummy byte offset for fast, dual and quad + reads */ +#define DUMMY_SIZE 1 /* Number of dummy bytes for fast, dual and + quad reads */ +#define DUMMY_CLOCKS 8 /* Number of dummy bytes for fast, dual and + quad reads */ +#define RD_ID_SIZE 4 /* Read ID command + 3 bytes ID response */ +#define BULK_ERASE_SIZE 1 /* Bulk Erase command size */ +#define SEC_ERASE_SIZE 4 /* Sector Erase command + Sector address */ +#define BANK_SEL_SIZE 2 /* BRWR or EARWR command + 1 byte bank value */ +#define RD_CFG_SIZE 2 /* 1 byte Configuration register + RD CFG command*/ +#define WR_CFG_SIZE 3 /* WRR command + 1 byte each Status and Config Reg*/ +#define DIE_ERASE_SIZE 4 /* Die Erase command + Die address */ + +/* + * The following constants specify the extra bytes which are sent to the + * Flash on the QSPIPSu interface, that are not data, but control information + * which includes the command and address + */ +#define OVERHEAD_SIZE 4 + +/* + * Base address of Flash1 + */ +#define FLASH1BASE 0x0000000 + +/* + * Sixteen MB + */ +#define SIXTEENMB 0x1000000 + + +/* + * Mask for quad enable bit in Flash configuration register + */ +#define FLASH_QUAD_EN_MASK 0x02 + +#define FLASH_SRWD_MASK 0x80 + +/* + * Bank mask + */ +#define BANKMASK 0xF000000 + +/* + * Identification of Flash + * Micron: + * Byte 0 is Manufacturer ID; + * Byte 1 is first byte of Device ID - 0xBB or 0xBA + * Byte 2 is second byte of Device ID describes flash size: + * 128Mbit : 0x18; 256Mbit : 0x19; 512Mbit : 0x20 + * Spansion: + * Byte 0 is Manufacturer ID; + * Byte 1 is Device ID - Memory Interface type - 0x20 or 0x02 + * Byte 2 is second byte of Device ID describes flash size: + * 128Mbit : 0x18; 256Mbit : 0x19; 512Mbit : 0x20 + */ +#define MICRON_ID_BYTE0 0x20 +#define MICRON_ID_BYTE2_128 0x18 +#define MICRON_ID_BYTE2_256 0x19 +#define MICRON_ID_BYTE2_512 0x20 +#define MICRON_ID_BYTE2_1G 0x21 + +#define SPANSION_ID_BYTE0 0x01 +#define SPANSION_ID_BYTE2_128 0x18 +#define SPANSION_ID_BYTE2_256 0x19 +#define SPANSION_ID_BYTE2_512 0x20 + +#define WINBOND_ID_BYTE0 0xEF +#define WINBOND_ID_BYTE2_128 0x18 + + +/* + * The index for Flash config table + */ +/* Spansion*/ +#define SPANSION_INDEX_START 0 +#define FLASH_CFG_TBL_SINGLE_128_SP SPANSION_INDEX_START +#define FLASH_CFG_TBL_STACKED_128_SP (SPANSION_INDEX_START + 1) +#define FLASH_CFG_TBL_PARALLEL_128_SP (SPANSION_INDEX_START + 2) +#define FLASH_CFG_TBL_SINGLE_256_SP (SPANSION_INDEX_START + 3) +#define FLASH_CFG_TBL_STACKED_256_SP (SPANSION_INDEX_START + 4) +#define FLASH_CFG_TBL_PARALLEL_256_SP (SPANSION_INDEX_START + 5) +#define FLASH_CFG_TBL_SINGLE_512_SP (SPANSION_INDEX_START + 6) +#define FLASH_CFG_TBL_STACKED_512_SP (SPANSION_INDEX_START + 7) +#define FLASH_CFG_TBL_PARALLEL_512_SP (SPANSION_INDEX_START + 8) + +/* Micron */ +#define MICRON_INDEX_START (FLASH_CFG_TBL_PARALLEL_512_SP + 1) +#define FLASH_CFG_TBL_SINGLE_128_MC MICRON_INDEX_START +#define FLASH_CFG_TBL_STACKED_128_MC (MICRON_INDEX_START + 1) +#define FLASH_CFG_TBL_PARALLEL_128_MC (MICRON_INDEX_START + 2) +#define FLASH_CFG_TBL_SINGLE_256_MC (MICRON_INDEX_START + 3) +#define FLASH_CFG_TBL_STACKED_256_MC (MICRON_INDEX_START + 4) +#define FLASH_CFG_TBL_PARALLEL_256_MC (MICRON_INDEX_START + 5) +#define FLASH_CFG_TBL_SINGLE_512_MC (MICRON_INDEX_START + 6) +#define FLASH_CFG_TBL_STACKED_512_MC (MICRON_INDEX_START + 7) +#define FLASH_CFG_TBL_PARALLEL_512_MC (MICRON_INDEX_START + 8) +#define FLASH_CFG_TBL_SINGLE_1GB_MC (MICRON_INDEX_START + 9) +#define FLASH_CFG_TBL_STACKED_1GB_MC (MICRON_INDEX_START + 10) +#define FLASH_CFG_TBL_PARALLEL_1GB_MC (MICRON_INDEX_START + 11) + +/* Winbond */ +#define WINBOND_INDEX_START (FLASH_CFG_TBL_PARALLEL_1GB_MC + 1) +#define FLASH_CFG_TBL_SINGLE_128_WB WINBOND_INDEX_START +#define FLASH_CFG_TBL_STACKED_128_WB (WINBOND_INDEX_START + 1) +#define FLASH_CFG_TBL_PARALLEL_128_WB (WINBOND_INDEX_START + 2) + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define QSPIPSU_DEVICE_ID XPAR_XQSPIPSU_0_DEVICE_ID + +/* + * Number of flash pages to be written. + */ +#define PAGE_COUNT 32 + +/* + * Max page size to initialize write and read buffer + */ +#define MAX_PAGE_SIZE 1024 + +/* + * Flash address to which data is to be written. + */ +#define TEST_ADDRESS 0x000000 + + +#define UNIQUE_VALUE 0x06 + +/**************************** Type Definitions *******************************/ + +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 */ +}FlashInfo; + +u8 ReadCmd; +u8 WriteCmd; +u8 StatusCmd; +u8 SectorEraseCmd; +u8 FSRFlag; + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +int QspiPsuPolledFlashExample(XQspiPsu *QspiPsuInstancePtr, u16 QspiPsuDeviceId); + +int FlashReadID(XQspiPsu *QspiPsuPtr); +int FlashErase(XQspiPsu *QspiPsuPtr, u32 Address, u32 ByteCount, u8 *WriteBfrPtr); +int FlashWrite(XQspiPsu *QspiPsuPtr, u32 Address, u32 ByteCount, u8 Command, + u8 *WriteBfrPtr); +int FlashRead(XQspiPsu *QspiPsuPtr, u32 Address, u32 ByteCount, u8 Command, + u8 *WriteBfrPtr, u8 *ReadBfrPtr); +u32 GetRealAddr(XQspiPsu *QspiPsuPtr, u32 Address); +int BulkErase(XQspiPsu *QspiPsuPtr, u8 *WriteBfrPtr); +int DieErase(XQspiPsu *QspiPsuPtr, u8 *WriteBfrPtr); +int FlashRegisterRead(XQspiPsu *QspiPsuPtr, u32 ByteCount, u8 Command, u8 *ReadBfrPtr); +int FlashRegisterWrite(XQspiPsu *QspiPsuPtr, u32 ByteCount, u8 Command, + u8 *WriteBfrPtr, u8 WrEn); +/************************** Variable Definitions *****************************/ +u8 TxBfrPtr __attribute__ ((aligned(32))); +u8 ReadBfrPtr[4] __attribute__ ((aligned(32))); +FlashInfo Flash_Config_Table[24] = { + /* Spansion */ + {0x10000, 0x100, 256, 0x10000, 0x1000000, + SPANSION_ID_BYTE0, SPANSION_ID_BYTE2_128, 0xFFFF0000, 1}, + {0x10000, 0x200, 256, 0x20000, 0x1000000, + SPANSION_ID_BYTE0, SPANSION_ID_BYTE2_128, 0xFFFF0000, 1}, + {0x20000, 0x100, 512, 0x10000, 0x1000000, + SPANSION_ID_BYTE0, SPANSION_ID_BYTE2_128, 0xFFFE0000, 1}, + {0x10000, 0x200, 256, 0x20000, 0x2000000, + SPANSION_ID_BYTE0, SPANSION_ID_BYTE2_256, 0xFFFF0000, 1}, + {0x10000, 0x400, 256, 0x40000, 0x2000000, + SPANSION_ID_BYTE0, SPANSION_ID_BYTE2_256, 0xFFFF0000, 1}, + {0x20000, 0x200, 512, 0x20000, 0x2000000, + SPANSION_ID_BYTE0, SPANSION_ID_BYTE2_256, 0xFFFE0000, 1}, + {0x40000, 0x100, 512, 0x20000, 0x4000000, + SPANSION_ID_BYTE0, SPANSION_ID_BYTE2_512, 0xFFFC0000, 1}, + {0x40000, 0x200, 512, 0x40000, 0x4000000, + SPANSION_ID_BYTE0, SPANSION_ID_BYTE2_512, 0xFFFC0000, 1}, + {0x80000, 0x100, 1024, 0x20000, 0x4000000, + SPANSION_ID_BYTE0, SPANSION_ID_BYTE2_512, 0xFFF80000, 1}, + /* Spansion 1Gbit is handled as 512Mbit stacked */ + /* Micron */ + {0x10000, 0x100, 256, 0x10000, 0x1000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_128, 0xFFFF0000, 1}, + {0x10000, 0x200, 256, 0x20000, 0x1000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_128, 0xFFFF0000, 1}, + {0x20000, 0x100, 512, 0x10000, 0x1000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_128, 0xFFFE0000, 1}, + {0x10000, 0x200, 256, 0x20000, 0x2000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_256, 0xFFFF0000, 1}, + {0x10000, 0x400, 256, 0x40000, 0x2000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_256, 0xFFFF0000, 1}, + {0x20000, 0x200, 512, 0x20000, 0x2000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_256, 0xFFFE0000, 1}, + {0x10000, 0x400, 256, 0x40000, 0x4000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_512, 0xFFFF0000, 2}, + {0x10000, 0x800, 256, 0x80000, 0x4000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_512, 0xFFFF0000, 2}, + {0x20000, 0x400, 512, 0x40000, 0x4000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_512, 0xFFFE0000, 2}, + {0x10000, 0x800, 256, 0x80000, 0x8000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_1G, 0xFFFF0000, 4}, + {0x10000, 0x1000, 256, 0x100000, 0x8000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_1G, 0xFFFF0000, 4}, + {0x20000, 0x800, 512, 0x80000, 0x8000000, + MICRON_ID_BYTE0, MICRON_ID_BYTE2_1G, 0xFFFE0000, 4}, + /* Winbond */ + {0x10000, 0x100, 256, 0x10000, 0x1000000, + WINBOND_ID_BYTE0, WINBOND_ID_BYTE2_128, 0xFFFF0000, 1}, + {0x10000, 0x200, 256, 0x20000, 0x1000000, + WINBOND_ID_BYTE0, WINBOND_ID_BYTE2_128, 0xFFFF0000, 1}, + {0x20000, 0x100, 512, 0x10000, 0x1000000, + WINBOND_ID_BYTE0, WINBOND_ID_BYTE2_128, 0xFFFE0000, 1} +}; + +u32 FlashMake; +u32 FCTIndex; /* Flash configuration table index */ + + +/* + * The instances to support the device drivers are global such that they + * are initialized to zero each time the program runs. They could be local + * but should at least be static so they are zeroed. + */ +static XQspiPsu QspiPsuInstance; + +static XQspiPsu_Msg FlashMsg[5]; + +/* + * The following variable allows a test value to be added to the values that + * are written to the Flash such that unique values can be generated to + * guarantee the writes to the Flash were successful + */ +int Test = 1; + +/* + * The following variables are used to read and write to the flash and they + * are global to avoid having large buffers on the stack + * The buffer size accounts for maximum page size and maximum banks - + * for each bank separate read will be performed leading to that many + * (overhead+dummy) bytes + */ +u8 ReadBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + (DATA_OFFSET + DUMMY_SIZE)*8] __attribute__ ((aligned(32))); +u8 WriteBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + DATA_OFFSET] __attribute__ ((aligned(32))); +u8 CmdBfr[8] __attribute__ ((aligned(32))); + +/* + * The following constants specify the max amount of data and the size of the + * the buffer required to hold the data and overhead to transfer the data to + * and from the Flash. Initialized to single flash page size. + */ +u32 MaxData = PAGE_COUNT*256; + +/*****************************************************************************/ +/** +* +* Main function to call the QSPIPSU Flash Polled example. +* +* @param None +* +* @return XST_SUCCESS if successful, otherwise XST_FAILURE. +* +* @note None +* +******************************************************************************/ +int main(void) +{ + int Status; + + xil_printf("QSPIPSU Generic Flash Polled Example Test \r\n"); + + /* + * Run the QspiPsu Polled example. + */ + Status = QspiPsuPolledFlashExample(&QspiPsuInstance, QSPIPSU_DEVICE_ID); + if (Status != XST_SUCCESS) { + xil_printf("QSPIPSU Generic Flash Polled Ex Failed\r\n"); + return XST_FAILURE; + } + + xil_printf("Successfully ran QSPIPSU Generic Flash Polled Ex\r\n"); + return XST_SUCCESS; +} + +/***************************************************************************** +* +* The purpose of this function is to illustrate how to use the XQspiPsu +* device driver in single, parallel and stacked modes using +* flash devices greater than or equal to 128Mb. +* This function reads data in DMA mode. +* +* @param None. +* +* @return XST_SUCCESS if successful, else XST_FAILURE. +* +* @note None. +* +*****************************************************************************/ +int QspiPsuPolledFlashExample(XQspiPsu *QspiPsuInstancePtr, u16 QspiPsuDeviceId) +{ + int Status; + u8 UniqueValue; + int Count; + int Page; + XQspiPsu_Config *QspiPsuConfig; + int ReadBfrSize; + + Xil_DCacheDisable(); + + ReadBfrSize = (PAGE_COUNT * MAX_PAGE_SIZE) + + (DATA_OFFSET + DUMMY_SIZE)*8; + + /* + * Initialize the QSPIPSU driver so that it's ready to use + */ + QspiPsuConfig = XQspiPsu_LookupConfig(QspiPsuDeviceId); + if (NULL == QspiPsuConfig) { + return XST_FAILURE; + } + + /* To test, change connection mode here if not obtained from HDF */ + //QspiPsuConfig->ConnectionMode = 2; + + Status = XQspiPsu_CfgInitialize(QspiPsuInstancePtr, QspiPsuConfig, + QspiPsuConfig->BaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Set Manual Start + */ + XQspiPsu_SetOptions(QspiPsuInstancePtr, XQSPIPSU_MANUAL_START_OPTION); + + /* + * Set the prescaler for QSPIPSU clock + */ + XQspiPsu_SetClkPrescaler(QspiPsuInstancePtr, XQSPIPSU_CLK_PRESCALE_8); + + XQspiPsu_SelectFlash(QspiPsuInstancePtr, + XQSPIPSU_SELECT_FLASH_CS_LOWER, XQSPIPSU_SELECT_FLASH_BUS_LOWER); + + /* + * Read flash ID and obtain all flash related information + * It is important to call the read id function before + * performing proceeding to any operation, including + * preparing the WriteBuffer + */ + FlashReadID(QspiPsuInstancePtr); + + xil_printf("Flash connection mode : %d \n\r", + QspiPsuConfig->ConnectionMode); + xil_printf("where 0 - Single; 1 - Stacked; 2 - Parallel \n\r"); + xil_printf("FCTIndex: %d \n\r", FCTIndex); + + /* + * Initialize MaxData according to page size. + */ + MaxData = PAGE_COUNT * (Flash_Config_Table[FCTIndex].PageSize); + + /* + * Address size and read command selection + * Micron flash on REMUS doesn't support this 4B write/erase cmd + */ + if(Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) { + /* Use 4 byte address and 4 byte read commands */ + ReadCmd = QUAD_READ_CMD_4B; + WriteCmd = WRITE_CMD; + SectorEraseCmd = SEC_ERASE_CMD; + + /* If supported by flash, use 4B address write and erase */ +#ifdef COMMENT + WriteCmd = WRITE_CMD_4B; + SectorEraseCmd = SEC_ERASE_CMD_4B; +#endif + } else { + ReadCmd = QUAD_READ_CMD; + WriteCmd = WRITE_CMD; + SectorEraseCmd = SEC_ERASE_CMD; + } + + /* Status cmd - SR or FSR selection */ + if((Flash_Config_Table[FCTIndex].NumDie > 1) && + (FlashMake == MICRON_ID_BYTE0)) { + StatusCmd = READ_FLAG_STATUS_CMD; + FSRFlag = 1; + } else { + StatusCmd = READ_STATUS_CMD; + FSRFlag = 0; + } + + xil_printf("ReadCmd: 0x%x, WriteCmd: 0x%x, StatusCmd: 0x%x, FSRFlag: %d \n\r", + ReadCmd, WriteCmd, StatusCmd, FSRFlag); + + for (UniqueValue = UNIQUE_VALUE, Count = 0; + Count < Flash_Config_Table[FCTIndex].PageSize; + Count++, UniqueValue++) { + WriteBuffer[Count] = (u8)(UniqueValue + Test); + } + + for (Count = 0; Count < ReadBfrSize; Count++) { + ReadBuffer[Count] = 0; + } + + FlashErase(QspiPsuInstancePtr, TEST_ADDRESS, MaxData, CmdBfr); + + for (Page = 0; Page < PAGE_COUNT; Page++) { + FlashWrite(QspiPsuInstancePtr, + (Page * Flash_Config_Table[FCTIndex].PageSize) + TEST_ADDRESS, + Flash_Config_Table[FCTIndex].PageSize, + WriteCmd, WriteBuffer); + } + + FlashRead(QspiPsuInstancePtr, TEST_ADDRESS, MaxData, ReadCmd, + CmdBfr, ReadBuffer); + /* + * Setup a pointer to the start of the data that was read into the read + * buffer and verify the data read is the data that was written + */ + for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MaxData; + Count++, UniqueValue++) { + if (ReadBuffer[Count] != (u8)(UniqueValue + Test)) { + return XST_FAILURE; + } + } + + return XST_SUCCESS; +} + +/***************************************************************************** +* +* Reads the flash ID and identifies the flash in FCT table. +* +* @param None. +* +* @return XST_SUCCESS if successful, else XST_FAILURE. +* +* @note None. +* +*****************************************************************************/ +int FlashReadID(XQspiPsu *QspiPsuPtr) +{ + int Status; + int StartIndex; + + /* + * Read ID + */ + TxBfrPtr = READ_ID; + FlashMsg[0].TxBfrPtr = &TxBfrPtr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = ReadBfrPtr; + FlashMsg[1].ByteCount = 4; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = 0; + + Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + xil_printf("FlashID=0x%x 0x%x 0x%x\n\r", ReadBfrPtr[0], ReadBfrPtr[1], + ReadBfrPtr[2]); + + /* In case of dual, read both and ensure they are same make/size */ + + /* + * Deduce flash make + */ + if(ReadBfrPtr[0] == MICRON_ID_BYTE0) { + FlashMake = MICRON_ID_BYTE0; + StartIndex = MICRON_INDEX_START; + }else if(ReadBfrPtr[0] == SPANSION_ID_BYTE0) { + FlashMake = SPANSION_ID_BYTE0; + StartIndex = SPANSION_INDEX_START; + }else if(ReadBfrPtr[0] == WINBOND_ID_BYTE0) { + FlashMake = WINBOND_ID_BYTE0; + StartIndex = WINBOND_INDEX_START; + } + + + /* + * If valid flash ID, then check connection mode & size and + * assign corresponding index in the Flash configuration table + */ + if(((FlashMake == MICRON_ID_BYTE0) || (FlashMake = SPANSION_ID_BYTE0)|| + (FlashMake == WINBOND_ID_BYTE0)) && + (ReadBfrPtr[2] == MICRON_ID_BYTE2_128)) { + + switch(QspiPsuPtr->Config.ConnectionMode) + { + case XQSPIPSU_CONNECTION_MODE_SINGLE: + FCTIndex = FLASH_CFG_TBL_SINGLE_128_SP + StartIndex; + break; + case XQSPIPSU_CONNECTION_MODE_PARALLEL: + FCTIndex = FLASH_CFG_TBL_PARALLEL_128_SP + StartIndex; + break; + case XQSPIPSU_CONNECTION_MODE_STACKED: + FCTIndex = FLASH_CFG_TBL_STACKED_128_SP + StartIndex; + break; + default: + FCTIndex = 0; + break; + } + } + /* 256 and 512Mbit supported only for Micron and Spansion, not Winbond */ + if(((FlashMake == MICRON_ID_BYTE0) || (FlashMake = SPANSION_ID_BYTE0)) && + (ReadBfrPtr[2] == MICRON_ID_BYTE2_256)) { + + switch(QspiPsuPtr->Config.ConnectionMode) + { + case XQSPIPSU_CONNECTION_MODE_SINGLE: + FCTIndex = FLASH_CFG_TBL_SINGLE_256_SP + StartIndex; + break; + case XQSPIPSU_CONNECTION_MODE_PARALLEL: + FCTIndex = FLASH_CFG_TBL_PARALLEL_256_SP + StartIndex; + break; + case XQSPIPSU_CONNECTION_MODE_STACKED: + FCTIndex = FLASH_CFG_TBL_STACKED_256_SP + StartIndex; + break; + default: + FCTIndex = 0; + break; + } + } + if(((FlashMake == MICRON_ID_BYTE0) || (FlashMake = SPANSION_ID_BYTE0)) && + (ReadBfrPtr[2] == MICRON_ID_BYTE2_512)) { + + switch(QspiPsuPtr->Config.ConnectionMode) + { + case XQSPIPSU_CONNECTION_MODE_SINGLE: + FCTIndex = FLASH_CFG_TBL_SINGLE_512_SP + StartIndex; + break; + case XQSPIPSU_CONNECTION_MODE_PARALLEL: + FCTIndex = FLASH_CFG_TBL_PARALLEL_512_SP + StartIndex; + break; + case XQSPIPSU_CONNECTION_MODE_STACKED: + FCTIndex = FLASH_CFG_TBL_STACKED_512_SP + StartIndex; + break; + default: + 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 == MICRON_ID_BYTE0) && + (ReadBfrPtr[2] == MICRON_ID_BYTE2_1G)) { + + switch(QspiPsuPtr->Config.ConnectionMode) + { + case XQSPIPSU_CONNECTION_MODE_SINGLE: + FCTIndex = FLASH_CFG_TBL_SINGLE_1GB_MC; + break; + case XQSPIPSU_CONNECTION_MODE_PARALLEL: + FCTIndex = FLASH_CFG_TBL_PARALLEL_1GB_MC; + break; + case XQSPIPSU_CONNECTION_MODE_STACKED: + FCTIndex = FLASH_CFG_TBL_STACKED_1GB_MC; + break; + default: + FCTIndex = 0; + break; + } + } + + return XST_SUCCESS; +} + +/****************************************************************************** +* +* +* This function writes to the serial Flash connected to the QSPIPSU interface. +* All the data put into the buffer must be in the same page of the device with +* page boundaries being on 256 byte boundaries. +* +* @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use. +* @param Address contains the address to write data to in the Flash. +* @param ByteCount contains the number of bytes to write. +* @param Command is the command used to write data to the flash. QSPIPSU +* device supports only Page Program command to write data to the +* flash. +* @param Pointer to the write buffer (which is to be transmitted) +* +* @return XST_SUCCESS if successful, else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int FlashWrite(XQspiPsu *QspiPsuPtr, u32 Address, u32 ByteCount, u8 Command, + u8 *WriteBfrPtr) +{ + u8 WriteEnableCmd __attribute__ ((aligned(32))); + u8 ReadStatusCmd __attribute__ ((aligned(32))); + u8 FlashStatus[4] __attribute__ ((aligned(32))); + u8 WriteCmd[5] __attribute__ ((aligned(32))); + u32 RealAddr; + u32 CmdByteCount; + int Status; + + WriteEnableCmd = WRITE_ENABLE_CMD; + /* + * Translate address based on type of connection + * If stacked assert the slave select based on address + */ + RealAddr = GetRealAddr(QspiPsuPtr, Address); + + /* + * Send the write enable command to the Flash so that it can be + * written to, this needs to be sent as a separate transfer before + * the write + */ + FlashMsg[0].TxBfrPtr = &WriteEnableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + WriteCmd[COMMAND_OFFSET] = Command; + + /* To be used only if 4B address program cmd is supported by flash */ +#ifdef COMMENT + if(Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) { + WriteCmd[ADDRESS_1_OFFSET] = (u8)((RealAddr & 0xFF000000) >> 24); + WriteCmd[ADDRESS_2_OFFSET] = (u8)((RealAddr & 0xFF0000) >> 16); + WriteCmd[ADDRESS_3_OFFSET] = (u8)((RealAddr & 0xFF00) >> 8); + WriteCmd[ADDRESS_4_OFFSET] = (u8)(RealAddr & 0xFF); + CmdByteCount = 5; + } else { +#endif + WriteCmd[ADDRESS_1_OFFSET] = (u8)((RealAddr & 0xFF0000) >> 16); + WriteCmd[ADDRESS_2_OFFSET] = (u8)((RealAddr & 0xFF00) >> 8); + WriteCmd[ADDRESS_3_OFFSET] = (u8)(RealAddr & 0xFF); + CmdByteCount = 4; +#ifdef COMMENT + } +#endif + + FlashMsg[0].TxBfrPtr = WriteCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = CmdByteCount; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + FlashMsg[1].TxBfrPtr = WriteBfrPtr; + FlashMsg[1].RxBfrPtr = NULL; + FlashMsg[1].ByteCount = ByteCount; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = 0; + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_STRIPE; + } + + Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait for the write command to the Flash to be completed, it takes + * some time for the data to be written + */ + while (1) { + ReadStatusCmd = StatusCmd; + FlashMsg[0].TxBfrPtr = &ReadStatusCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = FlashStatus; + FlashMsg[1].ByteCount = 4; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = 0; + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_STRIPE; + } + + Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + if(FSRFlag) { + FlashStatus[3] &= FlashStatus[2]; + } else { + FlashStatus[3] |= FlashStatus[2]; + } + } + + if(FSRFlag) { + if ((FlashStatus[3] & 0x80) != 0) { + break; + } + } else { + if ((FlashStatus[3] & 0x01) == 0) { + break; + } + } + } + + return 0; +} + +/****************************************************************************** +* +* +* This function erases the sectors in the serial Flash connected to the +* QSPIPSU interface. +* +* @param QspiPtr is a pointer to the QSPIPSU driver component to use. +* @param Address contains the address of the first sector which needs to +* be erased. +* @param ByteCount contains the total size to be erased. +* @param Pointer to the write buffer (which is to be transmitted) +* +* @return XST_SUCCESS if successful, else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int FlashErase(XQspiPsu *QspiPsuPtr, u32 Address, u32 ByteCount, + u8 *WriteBfrPtr) +{ + u8 WriteEnableCmd __attribute__ ((aligned(32))); + u8 ReadStatusCmd __attribute__ ((aligned(32))); + u8 FlashStatus[4] __attribute__ ((aligned(32))); + int Sector; + u32 RealAddr; + u32 NumSect; + int Status; + + WriteEnableCmd = WRITE_ENABLE_CMD; + /* + * If erase size is same as the total size of the flash, use bulk erase + * command or die erase command multiple times as required + */ + if (ByteCount == ((Flash_Config_Table[FCTIndex]).NumSect * + (Flash_Config_Table[FCTIndex]).SectSize) ) { + + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED){ + XQspiPsu_SelectFlash(QspiPsuPtr, + XQSPIPSU_SELECT_FLASH_CS_LOWER, XQSPIPSU_SELECT_FLASH_BUS_LOWER); + } + + if(Flash_Config_Table[FCTIndex].NumDie == 1) { + /* + * Call Bulk erase + */ + BulkErase(QspiPsuPtr, WriteBfrPtr); + } + + if(Flash_Config_Table[FCTIndex].NumDie > 1) { + /* + * Call Die erase + */ + DieErase(QspiPsuPtr, WriteBfrPtr); + } + /* + * If stacked mode, bulk erase second flash + */ + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED){ + + XQspiPsu_SelectFlash(QspiPsuPtr, + XQSPIPSU_SELECT_FLASH_CS_UPPER, XQSPIPSU_SELECT_FLASH_BUS_LOWER); + + if(Flash_Config_Table[FCTIndex].NumDie == 1) { + /* + * Call Bulk erase + */ + BulkErase(QspiPsuPtr, WriteBfrPtr); + } + + if(Flash_Config_Table[FCTIndex].NumDie > 1) { + /* + * Call Die erase + */ + DieErase(QspiPsuPtr, WriteBfrPtr); + } + } + + return 0; + } + + /* + * If the erase size is less than the total size of the flash, use + * sector erase command + */ + + /* + * Calculate no. of sectors to erase based on byte count + */ + NumSect = ByteCount/(Flash_Config_Table[FCTIndex].SectSize) + 1; + + /* + * If ByteCount to k sectors, + * but the address range spans from N to N+k+1 sectors, then + * increment no. of sectors to be erased + */ + + if( ((Address + ByteCount) & Flash_Config_Table[FCTIndex].SectMask) == + ((Address + (NumSect * Flash_Config_Table[FCTIndex].SectSize)) & + Flash_Config_Table[FCTIndex].SectMask) ) { + NumSect++; + } + + for (Sector = 0; Sector < NumSect; Sector++) { + + /* + * Translate address based on type of connection + * If stacked assert the slave select based on address + */ + RealAddr = GetRealAddr(QspiPsuPtr, Address); + + /* + * Send the write enable command to the Flash so that it can be + * written to, this needs to be sent as a separate transfer before + * the write + */ + FlashMsg[0].TxBfrPtr = &WriteEnableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + WriteBfrPtr[COMMAND_OFFSET] = SectorEraseCmd; + + /* + * To be used only if 4B address sector erase cmd is + * supported by flash + */ +#ifdef COMMENT + if(Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) { + WriteBfrPtr[ADDRESS_1_OFFSET] = (u8)((RealAddr & 0xFF000000) >> 24); + WriteBfrPtr[ADDRESS_2_OFFSET] = (u8)((RealAddr & 0xFF0000) >> 16); + WriteBfrPtr[ADDRESS_3_OFFSET] = (u8)((RealAddr & 0xFF00) >> 8); + WriteBfrPtr[ADDRESS_4_OFFSET] = (u8)(RealAddr & 0xFF); + FlashMsg[0].ByteCount = 5; + } else { +#endif + WriteBfrPtr[ADDRESS_1_OFFSET] = (u8)((RealAddr & 0xFF0000) >> 16); + WriteBfrPtr[ADDRESS_2_OFFSET] = (u8)((RealAddr & 0xFF00) >> 8); + WriteBfrPtr[ADDRESS_3_OFFSET] = (u8)(RealAddr & 0xFF); + FlashMsg[0].ByteCount = 4; +#ifdef COMMENT + } +#endif + FlashMsg[0].TxBfrPtr = WriteBfrPtr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait for the erase command to be completed + */ + while (1) { + ReadStatusCmd = StatusCmd; + FlashMsg[0].TxBfrPtr = &ReadStatusCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = FlashStatus; + FlashMsg[1].ByteCount = 4; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = 0; + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_STRIPE; + } + + Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + if(FSRFlag) { + FlashStatus[3] &= FlashStatus[2]; + } else { + FlashStatus[3] |= FlashStatus[2]; + } + } + + if(FSRFlag) { + if ((FlashStatus[3] & 0x80) != 0) { + break; + } + } else { + if ((FlashStatus[3] & 0x01) == 0) { + break; + } + } + } + Address += Flash_Config_Table[FCTIndex].SectSize; + } + + return 0; +} + + +/****************************************************************************** +* +* This function performs read. DMA is the default setting. +* +* @param QspiPtr is a pointer to the QSPIPSU driver component to use. +* @param Address contains the address of the first sector which needs to +* be erased. +* @param ByteCount contains the total size to be erased. +* @param Command is the command used to read data from the flash. Supports +* normal, fast, dual and quad read commands. +* @param Pointer to the write buffer which contains data to be transmitted +* @param Pointer to the read buffer to which valid received data should be +* written +* +* @return XST_SUCCESS if successful, else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int FlashRead(XQspiPsu *QspiPsuPtr, u32 Address, u32 ByteCount, u8 Command, + u8 *WriteBfrPtr, u8 *ReadBfrPtr) +{ + u32 RealAddr; + u32 DiscardByteCnt; + u32 FlashMsgCnt; + int Status; + + /* Check die boundary conditions if required for any flash */ + + /* For Dual Stacked, split and read for boundary crossing */ + /* + * Translate address based on type of connection + * If stacked assert the slave select based on address + */ + RealAddr = GetRealAddr(QspiPsuPtr, Address); + + WriteBfrPtr[COMMAND_OFFSET] = Command; + if(Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) { + WriteBfrPtr[ADDRESS_1_OFFSET] = (u8)((RealAddr & 0xFF000000) >> 24); + WriteBfrPtr[ADDRESS_2_OFFSET] = (u8)((RealAddr & 0xFF0000) >> 16); + WriteBfrPtr[ADDRESS_3_OFFSET] = (u8)((RealAddr & 0xFF00) >> 8); + WriteBfrPtr[ADDRESS_4_OFFSET] = (u8)(RealAddr & 0xFF); + DiscardByteCnt = 5; + } else { + WriteBfrPtr[ADDRESS_1_OFFSET] = (u8)((RealAddr & 0xFF0000) >> 16); + WriteBfrPtr[ADDRESS_2_OFFSET] = (u8)((RealAddr & 0xFF00) >> 8); + WriteBfrPtr[ADDRESS_3_OFFSET] = (u8)(RealAddr & 0xFF); + DiscardByteCnt = 4; + } + + FlashMsg[0].TxBfrPtr = WriteBfrPtr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = DiscardByteCnt; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + FlashMsgCnt = 1; + + /* It is recommended to have a separate entry for dummy */ + if ((Command == FAST_READ_CMD) || (Command == DUAL_READ_CMD) || + (Command == QUAD_READ_CMD) || (Command == FAST_READ_CMD_4B) || + (Command == DUAL_READ_CMD_4B) || (Command == QUAD_READ_CMD_4B)) { + /* Update Dummy cycles as per flash specs for QUAD IO */ + if ((Command == FAST_READ_CMD) || (Command == FAST_READ_CMD_4B)) { + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + } + + if ((Command == DUAL_READ_CMD) || (Command == DUAL_READ_CMD_4B)) { + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_DUALSPI; + } + + if ((Command == QUAD_READ_CMD) || (Command == QUAD_READ_CMD_4B)) { + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI; + } + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = NULL; + FlashMsg[1].ByteCount = DUMMY_CLOCKS; + FlashMsg[1].Flags = 0; + + FlashMsgCnt++; + } + + if ((Command == FAST_READ_CMD) || (Command == FAST_READ_CMD_4B)) { + FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + } + + if ((Command == DUAL_READ_CMD) || (Command == DUAL_READ_CMD_4B)) { + FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_DUALSPI; + } + + if ((Command == QUAD_READ_CMD) || (Command == QUAD_READ_CMD_4B)) { + FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI; + } + + FlashMsg[FlashMsgCnt].TxBfrPtr = NULL; + FlashMsg[FlashMsgCnt].RxBfrPtr = ReadBfrPtr; + FlashMsg[FlashMsgCnt].ByteCount = ByteCount; + FlashMsg[FlashMsgCnt].Flags = 0; + + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_STRIPE; + } + + Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, FlashMsgCnt+1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return 0; +} + + +/****************************************************************************** +* +* This API can be used to write to a flash register. +* +* @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use. +* @param ByteCount is the number of bytes to write. +* @param Command is specific register write command. +* @param WriteBfrPtr is the pointer to value to be written. +* @param WrEn is a flag to mention if WREN has to be sent before write. +* +* @return XST_SUCCESS if successful, else XST_FAILURE. +* +* @note This API can only be used for one flash at a time. +* +******************************************************************************/ +int FlashRegisterWrite(XQspiPsu *QspiPsuPtr, u32 ByteCount, u8 Command, + u8 *WriteBfrPtr, u8 WrEn) +{ + u8 WriteEnableCmd __attribute__ ((aligned(32))); + u8 ReadStatusCmd __attribute__ ((aligned(32))); + u8 FlashStatus[4] __attribute__ ((aligned(32))); + int Status; + + if(WrEn) { + WriteEnableCmd = WRITE_ENABLE_CMD; + + /* + * Send the write enable command to the Flash so that it can be + * written to, this needs to be sent as a separate transfer before + * the write + */ + FlashMsg[0].TxBfrPtr = &WriteEnableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + } + + WriteBfrPtr[COMMAND_OFFSET] = Command; + /* + * Value(s) is(are) expected to be written to the write buffer by calling API + * ByteCount is the count of the value(s) excluding the command. + */ + + FlashMsg[0].TxBfrPtr = WriteBfrPtr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = ByteCount + 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait for the register write command to the Flash to be completed. + */ + while (1) { + ReadStatusCmd = StatusCmd; + FlashMsg[0].TxBfrPtr = &ReadStatusCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = FlashStatus; + FlashMsg[1].ByteCount = 4; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = 0; + + Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + if(FSRFlag) { + if ((FlashStatus[3] & 0x80) != 0) { + break; + } + } else { + if ((FlashStatus[3] & 0x01) == 0) { + break; + } + } + } + + return 0; +} + +/****************************************************************************** +* +* This API can be used to write to a flash register. +* +* @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use. +* @param ByteCount is the number of bytes to write. +* @param Command is specific register write command. +* @param WriteBfrPtr is the pointer to value to be written. +* @param WrEn is a flag to mention if WREN has to be sent before write. +* +* @return XST_SUCCESS if successful, else XST_FAILURE. +* +* @note This API can only be used for one flash at a time. +* +******************************************************************************/ +int FlashRegisterRead(XQspiPsu *QspiPsuPtr, u32 ByteCount, u8 Command, u8 *ReadBfrPtr) +{ + u8 WriteCmd __attribute__ ((aligned(32))); + int Status; + + WriteCmd = Command; + FlashMsg[0].TxBfrPtr = &WriteCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = ReadBfrPtr; + //FlashMsg[1].ByteCount = ByteCount; + /* This is for DMA reasons; to be changed shortly */ + FlashMsg[1].ByteCount = 4; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = 0; + + Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return 0; +} + +/****************************************************************************** +* +* This functions performs a bulk erase operation when the +* flash device has a single die. Works for both Spansion and Micron +* +* @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use. +* @param WritBfrPtr is the pointer to command+address to be sent +* +* @return XST_SUCCESS if successful, else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int BulkErase(XQspiPsu *QspiPsuPtr, u8 *WriteBfrPtr) +{ + u8 WriteEnableCmd __attribute__ ((aligned(32))); + u8 ReadStatusCmd __attribute__ ((aligned(32))); + u8 FlashStatus[4] __attribute__ ((aligned(32))); + int Status; + + WriteEnableCmd = WRITE_ENABLE_CMD; + /* + * Send the write enable command to the Flash so that it can be + * written to, this needs to be sent as a separate transfer before + * the write + */ + FlashMsg[0].TxBfrPtr = &WriteEnableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + WriteBfrPtr[COMMAND_OFFSET] = BULK_ERASE_CMD; + FlashMsg[0].TxBfrPtr = WriteBfrPtr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait for the write command to the Flash to be completed, it takes + * some time for the data to be written + */ + while (1) { + ReadStatusCmd = StatusCmd; + FlashMsg[0].TxBfrPtr = &ReadStatusCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = FlashStatus; + FlashMsg[1].ByteCount = 4; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = 0; + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_STRIPE; + } + + + Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + if(FSRFlag) { + FlashStatus[3] &= FlashStatus[2]; + } else { + FlashStatus[3] |= FlashStatus[2]; + } + } + + if(FSRFlag) { + if ((FlashStatus[3] & 0x80) != 0) { + break; + } + } else { + if ((FlashStatus[3] & 0x01) == 0) { + break; + } + } + } + + return 0; +} + +/****************************************************************************** +* +* This functions performs a die erase operation on all the die in +* the flash device. This function uses the die erase command for +* Micron 512Mbit and 1Gbit +* +* @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use. +* @param WritBfrPtr is the pointer to command+address to be sent +* +* @return XST_SUCCESS if successful, else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int DieErase(XQspiPsu *QspiPsuPtr, u8 *WriteBfrPtr) +{ + u8 WriteEnableCmd __attribute__ ((aligned(32))); + u8 DieCnt; + u8 ReadStatusCmd __attribute__ ((aligned(32))); + u8 FlashStatus[4] __attribute__ ((aligned(32))); + int Status; + + WriteEnableCmd = WRITE_ENABLE_CMD; + for(DieCnt = 0; DieCnt < Flash_Config_Table[FCTIndex].NumDie; DieCnt++) { + /* + * Send the write enable command to the Flash so that it can be + * written to, this needs to be sent as a separate transfer before + * the write + */ + FlashMsg[0].TxBfrPtr = &WriteEnableCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + WriteBfrPtr[COMMAND_OFFSET] = DIE_ERASE_CMD; + /* Check these number of address bytes as per flash device */ + WriteBfrPtr[ADDRESS_1_OFFSET] = 0; + WriteBfrPtr[ADDRESS_2_OFFSET] = 0; + WriteBfrPtr[ADDRESS_3_OFFSET] = 0; + + FlashMsg[0].TxBfrPtr = WriteBfrPtr; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 4; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait for the write command to the Flash to be completed, it takes + * some time for the data to be written + */ + while (1) { + ReadStatusCmd = StatusCmd; + FlashMsg[0].TxBfrPtr = &ReadStatusCmd; + FlashMsg[0].RxBfrPtr = NULL; + FlashMsg[0].ByteCount = 1; + FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[0].Flags = 0; + + FlashMsg[1].TxBfrPtr = NULL; + FlashMsg[1].RxBfrPtr = FlashStatus; + FlashMsg[1].ByteCount = 4; + FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; + FlashMsg[1].Flags = 0; + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_STRIPE; + } + + Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 2); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ + if(FSRFlag) { + FlashStatus[3] &= FlashStatus[2]; + } else { + FlashStatus[3] |= FlashStatus[2]; + } + } + + if(FSRFlag) { + if ((FlashStatus[3] & 0x80) != 0) { + break; + } + } else { + if ((FlashStatus[3] & 0x01) == 0) { + break; + } + } + } + } + + return 0; +} + +/****************************************************************************** +* +* This functions translates the address based on the type of interconnection. +* In case of stacked, this function asserts the corresponding slave select. +* +* @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use. +* @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(XQspiPsu *QspiPsuPtr, u32 Address) +{ + u32 RealAddr; + + switch(QspiPsuPtr->Config.ConnectionMode) { + case XQSPIPSU_CONNECTION_MODE_SINGLE: + XQspiPsu_SelectFlash(QspiPsuPtr, XQSPIPSU_SELECT_FLASH_CS_LOWER, + XQSPIPSU_SELECT_FLASH_BUS_LOWER); + RealAddr = Address; + break; + case XQSPIPSU_CONNECTION_MODE_STACKED: + /* Select lower or upper Flash based on sector address */ + if(Address & Flash_Config_Table[FCTIndex].FlashDeviceSize) { + + XQspiPsu_SelectFlash(QspiPsuPtr, + XQSPIPSU_SELECT_FLASH_CS_UPPER, XQSPIPSU_SELECT_FLASH_BUS_LOWER); + /* + * Subtract first flash size when accessing second flash + */ + RealAddr = Address & + (~Flash_Config_Table[FCTIndex].FlashDeviceSize); + }else{ + /* + * Set selection to L_PAGE + */ + XQspiPsu_SelectFlash(QspiPsuPtr, + XQSPIPSU_SELECT_FLASH_CS_LOWER, XQSPIPSU_SELECT_FLASH_BUS_LOWER); + + RealAddr = Address; + + } + break; + case XQSPIPSU_CONNECTION_MODE_PARALLEL: + /* + * The effective address in each flash is the actual + * address / 2 + */ + XQspiPsu_SelectFlash(QspiPsuPtr, + XQSPIPSU_SELECT_FLASH_CS_BOTH, XQSPIPSU_SELECT_FLASH_BUS_BOTH); + RealAddr = Address / 2; + break; + default: + /* RealAddr wont be assigned in this case; */ + break; + + } + + return(RealAddr); +} diff --git a/XilinxProcessorIPLib/drivers/qspipsu/src/Makefile b/XilinxProcessorIPLib/drivers/qspipsu/src/Makefile new file mode 100755 index 00000000..88a66dd9 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/qspipsu/src/Makefile @@ -0,0 +1,40 @@ +COMPILER= +ARCHIVER= +CP=cp +COMPILER_FLAGS= +EXTRA_COMPILER_FLAGS= +LIB=libxil.a + +CC_FLAGS = $(COMPILER_FLAGS) +ECC_FLAGS = $(EXTRA_COMPILER_FLAGS) + +RELEASEDIR=../../../lib +INCLUDEDIR=../../../include +INCLUDES=-I./. -I${INCLUDEDIR} + +OUTS = *.o + +LIBSOURCES:=*.c +INCLUDEFILES:=*.h + +OBJECTS = $(addsuffix .o, $(basename $(wildcard *.c))) + +libs: banner xqspipsu_libs clean + +%.o: %.c + ${COMPILER} $(CC_FLAGS) $(ECC_FLAGS) $(INCLUDES) -o $@ $< + +banner: + echo "Compiling qspipsu" + +xqspipsu_libs: ${OBJECTS} + $(ARCHIVER) -r ${RELEASEDIR}/${LIB} ${OBJECTS} + +.PHONY: include +include: xqspipsu_includes + +xqspipsu_includes: + ${CP} ${INCLUDEFILES} ${INCLUDEDIR} + +clean: + rm -rf ${OBJECTS} diff --git a/XilinxProcessorIPLib/drivers/qspipsu/src/xqspipsu.c b/XilinxProcessorIPLib/drivers/qspipsu/src/xqspipsu.c new file mode 100755 index 00000000..a43adeea --- /dev/null +++ b/XilinxProcessorIPLib/drivers/qspipsu/src/xqspipsu.c @@ -0,0 +1,1051 @@ +/****************************************************************************** +* +* Copyright (C) 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 xqspipsu.c +* +* This file implements the functions required to use the QSPIPSU hardware to +* perform a transfer. These are accessible to the user via xqspipsu.h. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who Date     Changes
+* ----- --- -------- -----------------------------------------------
+* 1.0   hk  08/21/14 First release
+*
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xqspipsu.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ +static void StubStatusHandler(void *CallBackRef, u32 StatusEvent, + unsigned ByteCount); +static inline u32 XQspiPsu_SelectSpiMode(u8 SpiMode); +static inline void XQspiPsu_TXRXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 *GenFifoEntry); +static inline void XQspiPsu_FillTxFifo(XQspiPsu *InstancePtr, + XQspiPsu_Msg *Msg, int Size); +static inline void XQspiPsu_SetupRxDma(XQspiPsu *InstancePtr, + XQspiPsu_Msg *Msg); +static inline void XQspiPsu_GenFifoEntryCSAssert(XQspiPsu *InstancePtr); +static inline int XQspiPsu_GenFifoEntryData(XQspiPsu *InstancePtr, + XQspiPsu_Msg *Msg, int Index); +static inline void XQspiPsu_GenFifoEntryCSDeAssert(XQspiPsu *InstancePtr); + +/************************** Variable Definitions *****************************/ + +/*****************************************************************************/ +/** +* +* Initializes a specific XQspiPsu instance such that the driver is ready to use. +* +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param ConfigPtr is a reference to a structure containing information +* about a specific QSPIPSU device. This function initializes an +* InstancePtr object for a specific device specified by the +* contents of Config. +* @param EffectiveAddr is the device base address in the virtual memory +* address space. The caller is responsible for keeping the address +* mapping from EffectiveAddr to the device physical base address +* unchanged once this function is invoked. Unexpected errors may +* occur if the address mapping changes after this function is +* called. If address translation is not used, use +* ConfigPtr->Config.BaseAddress for this device. +* +* @return +* - XST_SUCCESS if successful. +* - XST_DEVICE_IS_STARTED if the device is already started. +* It must be stopped to re-initialize. +* +* @note None. +* +******************************************************************************/ +int XQspiPsu_CfgInitialize(XQspiPsu *InstancePtr, XQspiPsu_Config *ConfigPtr, + u32 EffectiveAddr) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(ConfigPtr != NULL); + + /* + * If the device is busy, disallow the initialize and return a status + * indicating it is already started. This allows the user to stop the + * device and re-initialize, but prevents a user from inadvertently + * initializing. This assumes the busy flag is cleared at startup. + */ + if (InstancePtr->IsBusy == TRUE) { + return XST_DEVICE_IS_STARTED; + } + + /* + * Set some default values. + */ + InstancePtr->IsBusy = FALSE; + + InstancePtr->Config.BaseAddress = EffectiveAddr + XQSPIPSU_OFFSET; + InstancePtr->Config.ConnectionMode = ConfigPtr->ConnectionMode; + InstancePtr->StatusHandler = StubStatusHandler; + + /* Other instance variable initializations */ + InstancePtr->SendBufferPtr = NULL; + InstancePtr->RecvBufferPtr = NULL; + InstancePtr->GenFifoBufferPtr = NULL; + InstancePtr->TxBytes = 0; + InstancePtr->RxBytes = 0; + InstancePtr->GenFifoEntries = 0; + InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA; + InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_LOWER; + InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_LOWER; + + /* Select QSPIPSU */ + XQspiPsu_Select(InstancePtr); + + /* + * Reset the QSPIPSU device to get it into its initial state. It is + * expected that device configuration will take place after this + * initialization is done, but before the device is started. + */ + XQspiPsu_Reset(InstancePtr); + + InstancePtr->IsReady = XIL_COMPONENT_IS_READY; + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* Resets the QSPIPSU device. Reset must only be called after the driver has +* been initialized. Any data transfer that is in progress is aborted. +* +* The upper layer software is responsible for re-configuring (if necessary) +* and restarting the QSPIPSU device after the reset. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XQspiPsu_Reset(XQspiPsu *InstancePtr) +{ + u32 ConfigReg; + + Xil_AssertVoid(InstancePtr != NULL); + + /* + * Abort any transfer that is in progress + */ + XQspiPsu_Abort(InstancePtr); + + /* + * Default value to config register + */ + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + + /* DMA mode */ + ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK; + ConfigReg |= XQSPIPSU_CFG_MODE_EN_DMA_MASK; + /* Manual start */ + ConfigReg |= XQSPIPSU_CFG_GEN_FIFO_START_MODE_MASK; + /* Little endain by default */ + ConfigReg &= ~XQSPIPSU_CFG_ENDIAN_MASK; + /* Disable poll timeout */ + ConfigReg &= ~XQSPIPSU_CFG_EN_POLL_TO_MASK; + /* Set hold bit */ + ConfigReg |= XQSPIPSU_CFG_WP_HOLD_MASK; + /* Clear prescalar by default */ + ConfigReg &= ~XQSPIPSU_CFG_BAUD_RATE_DIV_MASK; + /* CPOL CPHA 00 */ + ConfigReg &= ~XQSPIPSU_CFG_CLK_PHA_MASK; + ConfigReg &= ~XQSPIPSU_CFG_CLK_POL_MASK; + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET, ConfigReg); + + /* Set by default to allow for high frequencies */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_LPBK_DLY_ADJ_OFFSET, + XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_LPBK_DLY_ADJ_OFFSET) | + XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_MASK); + + /* Reset thresholds */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_TX_THRESHOLD_OFFSET, + XQSPIPSU_TX_FIFO_THRESHOLD_RESET_VAL); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_RX_THRESHOLD_OFFSET, + XQSPIPSU_RX_FIFO_THRESHOLD_RESET_VAL); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_GF_THRESHOLD_OFFSET, + XQSPIPSU_GEN_FIFO_THRESHOLD_RESET_VAL); + + /* DMA init */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_CTRL_OFFSET, + XQSPIPSU_QSPIDMA_DST_CTRL_RESET_VAL); + +} + +/*****************************************************************************/ +/** +* +* Aborts a transfer in progress by +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* +* @return None. +* +* @note +* +******************************************************************************/ +void XQspiPsu_Abort(XQspiPsu *InstancePtr) +{ + + /* + * Clear and disable interrupts + */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_ISR_OFFSET, + XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_ISR_OFFSET) | XQSPIPSU_ISR_WR_TO_CLR_MASK); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_IDR_OFFSET, XQSPIPSU_IDR_ALL_MASK); + + /* + * Clear FIFO + */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_FIFO_CTRL_OFFSET, + XQSPIPSU_FIFO_CTRL_RST_RX_FIFO_MASK | + XQSPIPSU_FIFO_CTRL_RST_TX_FIFO_MASK | + XQSPIPSU_FIFO_CTRL_RST_GEN_FIFO_MASK); + + /* + * Disable QSPIPSU + */ + XQspiPsu_Disable(InstancePtr); + + InstancePtr->TxBytes = 0; + InstancePtr->RxBytes = 0; + InstancePtr->GenFifoEntries = 0; + InstancePtr->IsBusy = FALSE; +} + +/*****************************************************************************/ +/** +* +* This function performs a transfer on the bus in polled mode. The messages +* passed are all transferred on the bus between one CS assert and de-assert. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Msg is a pointer to the structure containing transfer data. +* @param NumMsg is the number of messages to be transferred. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if transfer fails. +* - XST_DEVICE_BUSY if a transfer is already in progress. +* +* @note None. +* +******************************************************************************/ +int XQspiPsu_PolledTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + unsigned NumMsg) +{ + u32 StatusReg; + u32 ConfigReg; + int Index; + u8 IsManualStart = FALSE; + u32 QspiPsuStatusReg, DmaStatusReg; + u32 BaseAddress; + int Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + for(Index = 0; Index < NumMsg; Index++) { + Xil_AssertNonvoid(Msg[Index].ByteCount > 0); + } + + /* + * Check whether there is another transfer in progress. Not thread-safe + */ + if (InstancePtr->IsBusy) { + return XST_DEVICE_BUSY; + } + + /* + * Set the busy flag, which will be cleared when the transfer is + * entirely done. + */ + InstancePtr->IsBusy = TRUE; + + BaseAddress = InstancePtr->Config.BaseAddress; + + /* Start if manual start */ + IsManualStart = XQspiPsu_IsManualStart(InstancePtr); + + /* Enable */ + XQspiPsu_Enable(InstancePtr); + + /* Select slave */ + XQspiPsu_GenFifoEntryCSAssert(InstancePtr); + + /* list */ + for(Index = 0; Index < NumMsg; Index++) { + + Status = XQspiPsu_GenFifoEntryData(InstancePtr, Msg, Index); + if(Status != XST_SUCCESS) { + return Status; + } + + if(IsManualStart) { + XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET, + XQspiPsu_ReadReg(BaseAddress, + XQSPIPSU_CFG_OFFSET) | + XQSPIPSU_CFG_START_GEN_FIFO_MASK); + } + + /* Use thresholds here */ + /* If there is more data to be transmitted */ + do { + QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress, + XQSPIPSU_ISR_OFFSET); + + /* Transmit more data if left */ + if((QspiPsuStatusReg & XQSPIPSU_ISR_TXNOT_FULL_MASK) && + (Msg[Index].TxBfrPtr != NULL) && + (InstancePtr->TxBytes > 0)) { + XQspiPsu_FillTxFifo(InstancePtr, &Msg[Index], + XQSPIPSU_TXD_DEPTH); + } + + /* Check if DMA RX is complete and update RxBytes */ + if(Msg[Index].RxBfrPtr != NULL) { + if(!(XQspiPsu_ReadReg(BaseAddress, + XQSPIPSU_QSPIDMA_DST_STS_OFFSET) & + XQSPIPSU_QSPIDMA_DST_STS_BUSY_MASK)) { + XQspiPsu_WriteReg(BaseAddress, + XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET, + XQspiPsu_ReadReg(BaseAddress, + XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET) | + XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK); + InstancePtr->RxBytes = 0; + } + } + } while((!(QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK)) || + (InstancePtr->TxBytes != 0) || + (!(QspiPsuStatusReg & XQSPIPSU_ISR_TXEMPTY_MASK)) || + (InstancePtr->RxBytes != 0)); + } + + /* De-select slave */ + XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr); + + if(IsManualStart) { + XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET, + XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_CFG_OFFSET) | + XQSPIPSU_CFG_START_GEN_FIFO_MASK); + } + + QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_ISR_OFFSET); + while(!(QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK)) { + QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress, + XQSPIPSU_ISR_OFFSET); + } + + /* + * Clear the busy flag. + */ + InstancePtr->IsBusy = FALSE; + + /* + * Disable the device. + */ + XQspiPsu_Disable(InstancePtr); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function initiates a transfer on the bus and enables interrupts. +* The transfer is completed by the interrupt handler. The messages passed are +* all transferred on the bus between one CS assert and de-assert. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Msg is a pointer to the structure containing transfer data. +* @param NumMsg is the number of messages to be transferred. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if transfer fails. +* - XST_DEVICE_BUSY if a transfer is already in progress. +* +* @note None. +* +******************************************************************************/ +int XQspiPsu_InterruptTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + unsigned NumMsg) +{ + u32 StatusReg; + u32 ConfigReg; + int Index; + u8 IsManualStart = FALSE; + u32 BaseAddress; + int Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + for(Index = 0; Index < NumMsg; Index++) { + Xil_AssertNonvoid(Msg[Index].ByteCount > 0); + } + + /* + * Check whether there is another transfer in progress. Not thread-safe + */ + if (InstancePtr->IsBusy) { + return XST_DEVICE_BUSY; + } + + /* + * Set the busy flag, which will be cleared when the transfer is + * entirely done. + */ + InstancePtr->IsBusy = TRUE; + + BaseAddress = InstancePtr->Config.BaseAddress; + + /* Start if manual start */ + IsManualStart = XQspiPsu_IsManualStart(InstancePtr); + + InstancePtr->Msg = Msg; + InstancePtr->NumMsg = NumMsg; + InstancePtr->MsgCnt = 0; + + /* Enable */ + XQspiPsu_Enable(InstancePtr); + + /* Select slave */ + XQspiPsu_GenFifoEntryCSAssert(InstancePtr); + + /* This might not work if not manual start */ + /* Put first message in FIFO along with the above slave select */ + Status = XQspiPsu_GenFifoEntryData(InstancePtr, Msg, 0); + if(Status != XST_SUCCESS) { + return Status; + } + + if(IsManualStart) { + XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_CFG_OFFSET, + XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_CFG_OFFSET) | + XQSPIPSU_CFG_START_GEN_FIFO_MASK); + } + + /* Enable interrupts */ + XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_IER_OFFSET, + XQSPIPSU_IER_TXNOT_FULL_MASK | + XQSPIPSU_IER_TXEMPTY_MASK | + XQSPIPSU_IER_GENFIFOEMPTY_MASK); + XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_QSPIDMA_DST_I_EN_OFFSET, + XQSPIPSU_QSPIDMA_DST_I_EN_DONE_MASK); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* Handles interrupt based transfers by acting on GENFIFO and DMA interurpts. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if transfer fails. +* +* @note None. +* +******************************************************************************/ +int XQspiPsu_InterruptHandler(XQspiPsu *InstancePtr) +{ + u8 IsManualStart = FALSE; + u32 QspiPsuStatusReg, DmaIntrStatusReg; + u32 BaseAddress; + XQspiPsu_Msg *Msg; + int NumMsg; + int MsgCnt; + u8 DeltaMsgCnt = 0; + + Xil_AssertNonvoid(InstancePtr != NULL); + + BaseAddress = InstancePtr->Config.BaseAddress; + Msg = InstancePtr->Msg; + NumMsg = InstancePtr->NumMsg; + MsgCnt = InstancePtr->MsgCnt; + + /* Start if manual start */ + IsManualStart = XQspiPsu_IsManualStart(InstancePtr); + + /* QSPIPSU Intr cleared on read */ + QspiPsuStatusReg = XQspiPsu_ReadReg(BaseAddress, XQSPIPSU_ISR_OFFSET); + /* DMA Intr write to clear */ + DmaIntrStatusReg = XQspiPsu_ReadReg(BaseAddress, + XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET); + + XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET, + DmaIntrStatusReg); + + if((QspiPsuStatusReg & XQSPIPSU_ISR_POLL_TIME_EXPIRE_MASK) || + (DmaIntrStatusReg & XQSPIPSU_QSPIDMA_DST_INTR_ERR_MASK)) { + /* Call status handler to indicate error */ + InstancePtr->StatusHandler(InstancePtr->StatusRef, + XST_SPI_COMMAND_ERROR, 0); + } + + /* Fill more data to be txed if required */ + if((MsgCnt < NumMsg) && (Msg[MsgCnt].TxBfrPtr != NULL) && + (QspiPsuStatusReg & XQSPIPSU_ISR_TXNOT_FULL_MASK) && + (InstancePtr->TxBytes > 0)) { + XQspiPsu_FillTxFifo(InstancePtr, &Msg[MsgCnt], + XQSPIPSU_TXD_DEPTH); + } + + /* + * Check if the entry is ONLY TX and increase MsgCnt. + * This is to allow TX and RX together in one entry - corner case. + */ + if((MsgCnt < NumMsg) && (Msg[MsgCnt].TxBfrPtr != NULL) && + (QspiPsuStatusReg & XQSPIPSU_ISR_TXEMPTY_MASK) && + (QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) && + (InstancePtr->TxBytes == 0) && + (Msg[MsgCnt].RxBfrPtr == NULL)) { + MsgCnt += 1; + DeltaMsgCnt = 1; + } + + if((MsgCnt < NumMsg) && (Msg[MsgCnt].RxBfrPtr != NULL) && + (DmaIntrStatusReg & XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK)) { + InstancePtr->RxBytes = 0; + MsgCnt += 1; + DeltaMsgCnt = 1; + } + + /* + * Dummy byte transfer + * MsgCnt < NumMsg check is to ensure is it a valid dummy cycle message + * If one of the above conditions increased MsgCnt, then + * the new message is yet to be placed in the FIFO; hence !DeltaMsgCnt. + */ + if((MsgCnt < NumMsg) && !DeltaMsgCnt && + (Msg[MsgCnt].RxBfrPtr == NULL) && + (Msg[MsgCnt].TxBfrPtr == NULL) && + (QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK)) { + MsgCnt += 1; + DeltaMsgCnt = 1; + } + InstancePtr->MsgCnt = MsgCnt; + + /* + * DeltaMsgCnt is to handle conditions where genfifo empty can be set + * while tx is still not empty or rx dma is not yet done. + * MsgCnt > NumMsg indicates CS de-assert entry was also executed. + */ + if((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) && + (DeltaMsgCnt || (MsgCnt > NumMsg))) { + if(MsgCnt < NumMsg) { + /* This might not work if not manual start */ + XQspiPsu_GenFifoEntryData(InstancePtr, Msg, MsgCnt); + + if(IsManualStart) { + XQspiPsu_WriteReg(BaseAddress, + XQSPIPSU_CFG_OFFSET, + XQspiPsu_ReadReg(BaseAddress, + XQSPIPSU_CFG_OFFSET) | + XQSPIPSU_CFG_START_GEN_FIFO_MASK); + } + } else if(MsgCnt == NumMsg) { + /* This is just to keep track of the de-assert entry */ + MsgCnt += 1; + InstancePtr->MsgCnt = MsgCnt; + + /* De-select slave */ + XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr); + + if(IsManualStart) { + XQspiPsu_WriteReg(BaseAddress, + XQSPIPSU_CFG_OFFSET, + XQspiPsu_ReadReg(BaseAddress, + XQSPIPSU_CFG_OFFSET) | + XQSPIPSU_CFG_START_GEN_FIFO_MASK); + } + } else { + /* Disable interrupts */ + XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_IDR_OFFSET, + XQSPIPSU_IER_TXNOT_FULL_MASK | + XQSPIPSU_IER_TXEMPTY_MASK | + XQSPIPSU_IER_GENFIFOEMPTY_MASK); + XQspiPsu_WriteReg(BaseAddress, + XQSPIPSU_QSPIDMA_DST_I_DIS_OFFSET, + XQSPIPSU_QSPIDMA_DST_I_EN_DONE_MASK); + /* + * Clear the busy flag. + */ + InstancePtr->IsBusy = FALSE; + + /* + * Disable the device. + */ + XQspiPsu_Disable(InstancePtr); + + /* Call status handler to indicate completion */ + InstancePtr->StatusHandler(InstancePtr->StatusRef, + XST_SPI_TRANSFER_DONE, 0); + } + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* Sets the status callback function, the status handler, which the driver +* calls when it encounters conditions that should be reported to upper +* layer software. The handler executes in an interrupt context, so it must +* minimize the amount of processing performed. One of the following status +* events is passed to the status handler. +* +*
+*
+* XST_SPI_TRANSFER_DONE		The requested data transfer is done
+*
+* XST_SPI_TRANSMIT_UNDERRUN	As a slave device, the master clocked data
+*				but there were none available in the transmit
+*				register/FIFO. This typically means the slave
+*				application did not issue a transfer request
+*				fast enough, or the processor/driver could not
+*				fill the transmit register/FIFO fast enough.
+*
+* XST_SPI_RECEIVE_OVERRUN	The QSPIPSU device lost data. Data was received
+*				but the receive data register/FIFO was full.
+*
+* 
+* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param CallBackRef is the upper layer callback reference passed back +* when the callback function is invoked. +* @param FuncPtr is the pointer to the callback function. +* +* @return None. +* +* @note +* +* The handler is called within interrupt context, so it should do its work +* quickly and queue potentially time-consuming work to a task-level thread. +* +******************************************************************************/ +void XQspiPsu_SetStatusHandler(XQspiPsu *InstancePtr, void *CallBackRef, + XQspiPsu_StatusHandler FuncPtr) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(FuncPtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + InstancePtr->StatusHandler = FuncPtr; + InstancePtr->StatusRef = CallBackRef; +} + +/*****************************************************************************/ +/** +* +* This is a stub for the status callback. The stub is here in case the upper +* layers forget to set the handler. +* +* @param CallBackRef is a pointer to the upper layer callback reference +* @param StatusEvent is the event that just occurred. +* @param ByteCount is the number of bytes transferred up until the event +* occurred. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void StubStatusHandler(void *CallBackRef, u32 StatusEvent, + unsigned ByteCount) +{ + (void) CallBackRef; + (void) StatusEvent; + (void) ByteCount; + + Xil_AssertVoidAlways(); +} + +/*****************************************************************************/ +/** +* +* Selects SPI mode - x1 or x2 or x4. +* +* @param SpiMode - spi or dual or quad. +* @return Mask to set desired SPI mode in GENFIFO entry. +* +* @note None. +* +******************************************************************************/ +static inline u32 XQspiPsu_SelectSpiMode(u8 SpiMode) +{ + u32 Mask; + switch(SpiMode) { + case XQSPIPSU_SELECT_MODE_DUALSPI: + Mask = XQSPIPSU_GENFIFO_MODE_DUALSPI; + break; + case XQSPIPSU_SELECT_MODE_QUADSPI: + Mask = XQSPIPSU_GENFIFO_MODE_QUADSPI; + break; + case XQSPIPSU_SELECT_MODE_SPI: + default: + Mask = XQSPIPSU_GENFIFO_MODE_SPI; + } + + return Mask; +} + +/*****************************************************************************/ +/** +* +* This function checks the TX/RX buffers in the message and setups up the +* GENFIFO entries, TX FIFO or RX DMA as required. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Msg is a pointer to the structure containing transfer data. +* @param GenFifoEntry is pointer to the variable in which GENFIFO mask +* is returned to calling function +* +* @return None +* +* @note None. +* +******************************************************************************/ +static inline void XQspiPsu_TXRXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 *GenFifoEntry) +{ + Xil_AssertVoid(InstancePtr != NULL); + + /* Transmit */ + if((Msg->TxBfrPtr != NULL) && (Msg->RxBfrPtr == NULL)) { + /* Setup data to be TXed */ + *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER; + *GenFifoEntry |= XQSPIPSU_GENFIFO_TX; + InstancePtr->TxBytes = Msg->ByteCount; + XQspiPsu_FillTxFifo(InstancePtr, Msg, XQSPIPSU_TXD_DEPTH); + /* Discard RX data */ + *GenFifoEntry &= ~XQSPIPSU_GENFIFO_RX; + InstancePtr->RxBytes = 0; + } + + /* Receive */ + if((Msg->TxBfrPtr == NULL) && (Msg->RxBfrPtr != NULL)) { + /* TX auto fill */ + *GenFifoEntry &= ~XQSPIPSU_GENFIFO_TX; + InstancePtr->TxBytes = 0; + /* Setup RX */ + *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER; + *GenFifoEntry |= XQSPIPSU_GENFIFO_RX; + InstancePtr->RxBytes = Msg->ByteCount; + XQspiPsu_SetupRxDma(InstancePtr, Msg); + } + + /* If only dummy is requested as a separate entry */ + if((Msg->TxBfrPtr == NULL) && (Msg->RxBfrPtr == NULL)) { + *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER; + *GenFifoEntry &= ~(XQSPIPSU_GENFIFO_TX | XQSPIPSU_GENFIFO_RX); + InstancePtr->TxBytes = 0; + InstancePtr->RxBytes = 0; + } + + /* Dummy and cmd sent by upper layer to received data */ + if((Msg->TxBfrPtr != NULL) && (Msg->RxBfrPtr != NULL)) { + *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER; + *GenFifoEntry |= (XQSPIPSU_GENFIFO_TX | XQSPIPSU_GENFIFO_RX); + InstancePtr->TxBytes = Msg->ByteCount; + InstancePtr->RxBytes = Msg->ByteCount; + XQspiPsu_FillTxFifo(InstancePtr, Msg, XQSPIPSU_TXD_DEPTH); + /* Add check for DMA or PIO here */ + XQspiPsu_SetupRxDma(InstancePtr, Msg); + } +} + +/*****************************************************************************/ +/** +* +* Fills the TX FIFO as long as there is room in the FIFO or the bytes required +* to be transmitted. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Msg is a pointer to the structure containing transfer data. +* @param Size is the number of bytes to be transmitted. +* +* @return None +* +* @note None. +* +******************************************************************************/ +static inline void XQspiPsu_FillTxFifo(XQspiPsu *InstancePtr, + XQspiPsu_Msg *Msg, int Size) +{ + int Count = 0; + u32 Data; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg->TxBfrPtr != NULL); + + while((InstancePtr->TxBytes > 0) && (Count < Size)) { + Data = *((u32*)Msg->TxBfrPtr); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_TXD_OFFSET, Data); + Msg->TxBfrPtr += 4; + InstancePtr->TxBytes -= 4; + Count++; + } + if(InstancePtr->TxBytes < 0) + InstancePtr->TxBytes = 0; +} + +/*****************************************************************************/ +/** +* +* This function sets up the RX DMA operation. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Msg is a pointer to the structure containing transfer data. +* +* @return None +* +* @note None. +* +******************************************************************************/ +static inline void XQspiPsu_SetupRxDma(XQspiPsu *InstancePtr, + XQspiPsu_Msg *Msg) +{ + int Remainder; + int DmaRxBytes; + u64 AddrTemp; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg->RxBfrPtr != NULL); + + AddrTemp = (u64)(Msg->RxBfrPtr) & XQSPIPSU_QSPIDMA_DST_ADDR_MASK; + /* Check for RXBfrPtr to be word aligned */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_ADDR_OFFSET, + (u32)AddrTemp); + + AddrTemp = AddrTemp >> 32; + if(AddrTemp & 0xFFF) { + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_ADDR_MSB_OFFSET, + (u32)AddrTemp & + XQSPIPSU_QSPIDMA_DST_ADDR_MSB_MASK); + } + + Remainder = InstancePtr->RxBytes % 4; + DmaRxBytes = InstancePtr->RxBytes; + if(Remainder != 0) { + /* This is done to make Dma bytes aligned */ + DmaRxBytes = InstancePtr->RxBytes + 4 - Remainder; + /* Handle remaining bytes with IO or DMA to local buffer */ + } + + /* Write no. of words to DMA DST SIZE */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_SIZE_OFFSET, DmaRxBytes); + +} + +/*****************************************************************************/ +/** +* +* This function writes the GENFIFO entry to assert CS. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* +* @return None +* +* @note None. +* +******************************************************************************/ +static inline void XQspiPsu_GenFifoEntryCSAssert(XQspiPsu *InstancePtr) +{ + u32 GenFifoEntry; + + GenFifoEntry = 0x0; + GenFifoEntry &= ~(XQSPIPSU_GENFIFO_DATA_XFER | XQSPIPSU_GENFIFO_EXP); + GenFifoEntry &= ~XQSPIPSU_GENFIFO_MODE_MASK; + GenFifoEntry |= XQSPIPSU_GENFIFO_MODE_SPI; + GenFifoEntry |= InstancePtr->GenFifoCS; + GenFifoEntry &= ~XQSPIPSU_GENFIFO_BUS_MASK; + GenFifoEntry |= InstancePtr->GenFifoBus; + GenFifoEntry &= ~(XQSPIPSU_GENFIFO_TX | XQSPIPSU_GENFIFO_RX | + XQSPIPSU_GENFIFO_STRIPE | XQSPIPSU_GENFIFO_POLL); + GenFifoEntry |= XQSPIPSU_GENFIFO_CS_SETUP; + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry); +} + +/*****************************************************************************/ +/** +* +* This function writes the GENFIFO entries to transmit the messages requested. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Msg is a pointer to the structure containing transfer data. +* @param Index of the current message to be handled. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if transfer fails. +* - XST_DEVICE_BUSY if a transfer is already in progress. +* +* @note None. +* +******************************************************************************/ +static inline int XQspiPsu_GenFifoEntryData(XQspiPsu *InstancePtr, + XQspiPsu_Msg *Msg, int Index) +{ + u32 GenFifoEntry; + u32 BaseAddress; + + BaseAddress = InstancePtr->Config.BaseAddress; + + GenFifoEntry = 0x0; + /* Bus width */ + GenFifoEntry &= ~XQSPIPSU_GENFIFO_MODE_MASK; + GenFifoEntry |= XQspiPsu_SelectSpiMode(Msg[Index].BusWidth); + + GenFifoEntry |= InstancePtr->GenFifoCS; + GenFifoEntry &= ~XQSPIPSU_GENFIFO_BUS_MASK; + GenFifoEntry |= InstancePtr->GenFifoBus; + + /* Data */ + if(Msg[Index].Flags & XQSPIPSU_MSG_FLAG_STRIPE) + GenFifoEntry |= XQSPIPSU_GENFIFO_STRIPE; + else + GenFifoEntry &= ~XQSPIPSU_GENFIFO_STRIPE; + + XQspiPsu_TXRXSetup(InstancePtr, &Msg[Index], &GenFifoEntry); + + if(Msg[Index].ByteCount < XQSPIPSU_GENFIFO_IMM_DATA_MASK) { + GenFifoEntry &= ~XQSPIPSU_GENFIFO_IMM_DATA_MASK; + GenFifoEntry |= Msg[Index].ByteCount; + XQspiPsu_WriteReg(BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET, + GenFifoEntry); + } else { + int TempCount = Msg[Index].ByteCount; + u32 Exponent = 8; /* 2^8 = 256 */ + + /* Check for ByteCount upper limit - 2^28 for DMA */ + if(TempCount > XQSPIPSU_DMA_BYTES_MAX) { + return XST_FAILURE; + } + + /* Immediate entry */ + if(TempCount & 0xFF) { + GenFifoEntry &= ~XQSPIPSU_GENFIFO_IMM_DATA_MASK; + GenFifoEntry |= TempCount & 0xFF; + XQspiPsu_WriteReg(BaseAddress, + XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry); + } + + /* Exponent entries */ + GenFifoEntry |= XQSPIPSU_GENFIFO_EXP; + while(TempCount != 0) { + if(TempCount & XQSPIPSU_GENFIFO_EXP_START) { + GenFifoEntry &= ~XQSPIPSU_GENFIFO_IMM_DATA_MASK; + GenFifoEntry |= Exponent; + XQspiPsu_WriteReg(BaseAddress, + XQSPIPSU_GEN_FIFO_OFFSET, + GenFifoEntry); + } + TempCount = TempCount >> 1; + Exponent++; + } + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function writes the GENFIFO entry to de-assert CS. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* +* @return None +* +* @note None. +* +******************************************************************************/ +static inline void XQspiPsu_GenFifoEntryCSDeAssert(XQspiPsu *InstancePtr) +{ + u32 GenFifoEntry; + + GenFifoEntry = 0x0; + GenFifoEntry &= ~(XQSPIPSU_GENFIFO_DATA_XFER | XQSPIPSU_GENFIFO_EXP); + GenFifoEntry &= ~XQSPIPSU_GENFIFO_MODE_MASK; + GenFifoEntry |= XQSPIPSU_GENFIFO_MODE_SPI; + GenFifoEntry &= ~XQSPIPSU_GENFIFO_BUS_MASK; + GenFifoEntry |= InstancePtr->GenFifoBus; + GenFifoEntry &= ~(XQSPIPSU_GENFIFO_TX | XQSPIPSU_GENFIFO_RX | + XQSPIPSU_GENFIFO_STRIPE | XQSPIPSU_GENFIFO_POLL); + GenFifoEntry |= XQSPIPSU_GENFIFO_CS_HOLD; + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry); +} \ No newline at end of file diff --git a/XilinxProcessorIPLib/drivers/qspipsu/src/xqspipsu.h b/XilinxProcessorIPLib/drivers/qspipsu/src/xqspipsu.h new file mode 100755 index 00000000..1a4ed615 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/qspipsu/src/xqspipsu.h @@ -0,0 +1,255 @@ +/****************************************************************************** +* +* Copyright (C) 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 xqspipsu.h +* +* This is the header file for the implementation of QSPIPSU driver. +* Generic QSPI interface allows for communication to any QSPI slave device. +* GQSPI contains a GENFIFO into which the bus transfers required are to be +* pushed with appropriate configuration. The controller provides TX and RX +* FIFO's and a DMA to be used for RX transfers. The controller executes each +* GENFIFO entry noting the configuration and places data on the bus as required +* The differen options in GENFIFO are as follows: +* IMM_DATA : Can be one byte of data to be transmitted, number of clocks or +* number of bytes in transfer. +* DATA_XFER : Indicates that data/clocks need to be transmitted or received. +* EXPONENT : e when 2^e bytes are involved in transfer. +* SPI_MODE : SPI/Dual SPI/Quad SPI +* CS : Lower or Upper CS or Both +* Bus : Lower or Upper Bus or Both +* TX : When selected, controller transmits data in IMM or fetches number of +* bytes mentioned form TX FIFO. If not selected, dummies are pumped. +* RX : When selected, controller receives and fills the RX FIFO/allows RX DMA +* of requested number of bytes. If not selected, RX data is discarded. +* Stripe : Byte stripe over lower and upper bus or not. +* Poll : Polls response to match for to a set value (used along with POLL_CFG +* registers) and then proceeds to next GENFIFO entry. +* This feature is not currently used in the driver. +* GENFIFO has manual and auto start options. +* All DMA requests need a 4-byte aligned destination address buffer and +* size of transfer should also be a multiple of 4. +* This driver currently only supports DMA RX and no IO RX. +* +* Initialization: +* This driver uses the GQSPI controller with RX DMA. It supports both +* interrupt and polled transfers. Manual start of GENFIFO is used. +* XQspiPsu_CfgInitialize() initializes the instance variables. +* Additional setting can be done using SetOptions/ClearOptions functions +* and SelectSlave function. +* +* Transfer: +* Polled or Interrupt transfers can be done. The transfer function needs the +* message(s) to be transmitted in the form of an array of type XQspiPsu_Msg. +* This is supposed to contain the byte count and any TX/RX buffers as required. +* Flags can be used indicate further information such as whether the message +* should be striped. The transfer functions form and write GENFIFO entries, +* check the status of the transfer and report back to the application +* when done. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who Date     Changes
+* ----- --- -------- -----------------------------------------------.
+* 1.0   hk  08/21/14 First release
+*
+* 
+* +******************************************************************************/ +#ifndef _XQSPIPSU_H_ /* prevent circular inclusions */ +#define _XQSPIPSU_H_ /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xstatus.h" +#include "xqspipsu_hw.h" + +/**************************** Type Definitions *******************************/ +/** + * The handler data type allows the user to define a callback function to + * handle the asynchronous processing for the QSPIPSU device. The application + * using this driver is expected to define a handler of this type to support + * interrupt driven mode. The handler executes in an interrupt context, so + * only minimal processing should be performed. + * + * @param CallBackRef is the callback reference passed in by the upper + * layer when setting the callback functions, and passed back to + * the upper layer when the callback is invoked. Its type is + * not important to the driver, so it is a void pointer. + * @param StatusEvent holds one or more status events that have occurred. + * See the XQspiPsu_SetStatusHandler() for details on the status + * events that can be passed in the callback. + * @param ByteCount indicates how many bytes of data were successfully + * transferred. This may be less than the number of bytes + * requested if the status event indicates an error. + */ +typedef void (*XQspiPsu_StatusHandler) (void *CallBackRef, u32 StatusEvent, + unsigned ByteCount); + +/** + * This typedef contains configuration information for a flash message. + */ +typedef struct { + u8 *TxBfrPtr; + u8 *RxBfrPtr; + u32 ByteCount; + u32 BusWidth; + u32 Flags; +} XQspiPsu_Msg; + +/** + * This typedef contains configuration information for the device. + */ +typedef struct { + u16 DeviceId; /**< Unique ID of device */ + u32 BaseAddress; /**< Base address of the device */ + u32 InputClockHz; /**< Input clock frequency */ + u8 ConnectionMode; /**< Single, Stacked and Parallel mode */ + u8 BusWidth; /**< Bus width available on board */ +} XQspiPsu_Config; + +/** + * The XQspiPsu driver instance data. The user is required to allocate a + * variable of this type for every QSPIPSU device in the system. A pointer + * to a variable of this type is then passed to the driver API functions. + */ +typedef struct { + XQspiPsu_Config Config; /**< Configuration structure */ + u32 IsReady; /**< Device is initialized and ready */ + + u8 *SendBufferPtr; /**< Buffer to send (state) */ + u8 *RecvBufferPtr; /**< Buffer to receive (state) */ + u8 *GenFifoBufferPtr; /**< Gen FIFO entries */ + int TxBytes; /**< Number of bytes to transfer (state) */ + int RxBytes; /**< Number of bytes left to transfer(state) */ + int GenFifoEntries; /**< Number of Gen FIFO entries remaining */ + u32 IsBusy; /**< A transfer is in progress (state) */ + u32 ReadMode; /**< DMA or IO mode */ + u32 GenFifoCS; + u32 GenFifoBus; + int NumMsg; + int MsgCnt; + XQspiPsu_Msg *Msg; + XQspiPsu_StatusHandler StatusHandler; + void *StatusRef; /**< Callback reference for status handler */ +} XQspiPsu; + +/***************** Macros (Inline Functions) Definitions *********************/ + +#define XQSPIPSU_READMODE_DMA 0x0 +#define XQSPIPSU_READMODE_IO 0x1 + +#define XQSPIPSU_SELECT_FLASH_CS_LOWER 0x1 +#define XQSPIPSU_SELECT_FLASH_CS_UPPER 0x2 +#define XQSPIPSU_SELECT_FLASH_CS_BOTH 0x3 + +#define XQSPIPSU_SELECT_FLASH_BUS_LOWER 0x1 +#define XQSPIPSU_SELECT_FLASH_BUS_UPPER 0x2 +#define XQSPIPSU_SELECT_FLASH_BUS_BOTH 0x3 + +#define XQSPIPSU_SELECT_MODE_SPI 0x1 +#define XQSPIPSU_SELECT_MODE_DUALSPI 0x2 +#define XQSPIPSU_SELECT_MODE_QUADSPI 0x4 + +#define XQSPIPSU_GENFIFO_CS_SETUP 0x04 +#define XQSPIPSU_GENFIFO_CS_HOLD 0x03 + +#define XQSPIPSU_CLK_ACTIVE_LOW_OPTION 0x2 +#define XQSPIPSU_CLK_PHASE_1_OPTION 0x4 +#define XQSPIPSU_MANUAL_START_OPTION 0x8 + +#define XQSPIPSU_GENFIFO_EXP_START 0x100 + +#define XQSPIPSU_DMA_BYTES_MAX 0x10000000 + +#define XQSPIPSU_CLK_PRESCALE_2 0x00 +#define XQSPIPSU_CLK_PRESCALE_4 0x01 +#define XQSPIPSU_CLK_PRESCALE_8 0x02 +#define XQSPIPSU_CLK_PRESCALE_16 0x03 +#define XQSPIPSU_CLK_PRESCALE_32 0x04 +#define XQSPIPSU_CLK_PRESCALE_64 0x05 +#define XQSPIPSU_CLK_PRESCALE_128 0x06 +#define XQSPIPSU_CLK_PRESCALE_256 0x07 +#define XQSPIPSU_CR_PRESC_MAXIMUM 7 + +#define XQSPIPSU_CONNECTION_MODE_SINGLE 0 +#define XQSPIPSU_CONNECTION_MODE_STACKED 1 +#define XQSPIPSU_CONNECTION_MODE_PARALLEL 2 + +/* Add more flags as required */ +#define XQSPIPSU_MSG_FLAG_STRIPE 0x1 + +#define XQspiPsu_Select(InstancePtr) XQspiPsu_Out32((InstancePtr->Config.BaseAddress) + XQSPIPSU_SEL_OFFSET, XQSPIPSU_SEL_MASK) + +#define XQspiPsu_Enable(InstancePtr) XQspiPsu_Out32((InstancePtr->Config.BaseAddress) + XQSPIPSU_EN_OFFSET, XQSPIPSU_EN_MASK) + +#define XQspiPsu_Disable(InstancePtr) XQspiPsu_Out32((InstancePtr->Config.BaseAddress) + XQSPIPSU_EN_OFFSET, 0x0) + +#define XQspiPsu_IsManualStart(InstancePtr) ((XQspiPsu_GetOptions(InstancePtr) & XQSPIPSU_MANUAL_START_OPTION) ? TRUE : FALSE) + +/************************** Function Prototypes ******************************/ + +/* Initialization and reset */ +XQspiPsu_Config *XQspiPsu_LookupConfig(u16 DeviceId); +int XQspiPsu_CfgInitialize(XQspiPsu *InstancePtr, XQspiPsu_Config *ConfigPtr, + u32 EffectiveAddr); +void XQspiPsu_Reset(XQspiPsu *InstancePtr); +void XQspiPsu_Abort(XQspiPsu *InstancePtr); + +/* Transfer functions and handlers */ +int XQspiPsu_PolledTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + unsigned NumMsg); +int XQspiPsu_InterruptTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + unsigned NumMsg); +int XQspiPsu_InterruptHandler(XQspiPsu *InstancePtr); +void XQspiPsu_SetStatusHandler(XQspiPsu *InstancePtr, void *CallBackRef, + XQspiPsu_StatusHandler FuncPtr); + +/* Configuration functions */ +int XQspiPsu_SetClkPrescaler(XQspiPsu *InstancePtr, u8 Prescaler); +void XQspiPsu_SelectFlash(XQspiPsu *InstancePtr, u8 FlashCS, u8 FlashBus); +int XQspiPsu_SetOptions(XQspiPsu *InstancePtr, u32 Options); +int XQspiPsu_ClearOptions(XQspiPsu *InstancePtr, u32 Options); +u32 XQspiPsu_GetOptions(XQspiPsu *InstancePtr); + +#ifdef __cplusplus +} +#endif + + +#endif /* _XQSPIPSU_H_ */ diff --git a/XilinxProcessorIPLib/drivers/qspipsu/src/xqspipsu_g.c b/XilinxProcessorIPLib/drivers/qspipsu/src/xqspipsu_g.c new file mode 100755 index 00000000..7fce7cc7 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/qspipsu/src/xqspipsu_g.c @@ -0,0 +1,80 @@ +/****************************************************************************** +* +* Copyright (C) 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 xqspipsu_g.c +* +* This file contains a configuration table that specifies the configuration of +* QSPIPSU devices in the system. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who Date     Changes
+* ----- --- -------- -----------------------------------------------
+* 1.0   hk  08/21/14 First release
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xqspipsu.h" +#include "xparameters.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Prototypes ******************************/ + +/** + * This table contains configuration information for each QSPIPSU device + * in the system. + */ +XQspiPsu_Config XQspiPsu_ConfigTable[XPAR_XQSPIPSU_NUM_INSTANCES] = { + { + XPAR_XQSPIPSU_0_DEVICE_ID, /* Device ID for instance */ + XPAR_XQSPIPSU_0_BASEADDR, /* Device base address */ + XPAR_XQSPIPSU_0_QSPI_CLK_FREQ_HZ, + XPAR_XQSPIPSU_0_QSPI_MODE + }, +}; diff --git a/XilinxProcessorIPLib/drivers/qspipsu/src/xqspipsu_hw.h b/XilinxProcessorIPLib/drivers/qspipsu/src/xqspipsu_hw.h new file mode 100755 index 00000000..086ada50 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/qspipsu/src/xqspipsu_hw.h @@ -0,0 +1,833 @@ +/****************************************************************************** +* +* Copyright (C) 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 xqspipsu_hw.h +* +* This file contains low level access funcitons using the base address +* directly without an instance. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who Date     Changes
+* ----- --- -------- -----------------------------------------------.
+* 1.0   hk  08/21/14 First release
+*
+* 
+* +******************************************************************************/ +#ifndef _XQSPIPSU_HW_H_ /* prevent circular inclusions */ +#define _XQSPIPSU_HW_H_ /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_assert.h" +#include "xil_io.h" +#include "xparameters.h" + +/************************** Constant Definitions *****************************/ + +/** + * QSPI Base Address + */ +#define XQSPIPS_BASEADDR 0XFF0F0000 + +/** + * GQSPI Base Address + */ +#define XQSPIPSU_BASEADDR 0xFF0F0100 +#define XQSPIPSU_OFFSET 0x100 + +/** + * Register: XQSPIPS_EN_REG + */ +#define XQSPIPS_EN_REG ( ( XQSPIPS_BASEADDR ) + 0X00000014 ) + +#define XQSPIPS_EN_SHIFT 0 +#define XQSPIPS_EN_WIDTH 1 +#define XQSPIPS_EN_MASK 0X00000001 + +/** + * Register: XQSPIPSU_CFG + */ +#define XQSPIPSU_CFG_OFFSET 0X00000000 + +#define XQSPIPSU_CFG_MODE_EN_SHIFT 30 +#define XQSPIPSU_CFG_MODE_EN_WIDTH 2 +#define XQSPIPSU_CFG_MODE_EN_MASK 0XC0000000 +#define XQSPIPSU_CFG_MODE_EN_DMA_MASK 0X80000000 + +#define XQSPIPSU_CFG_GEN_FIFO_START_MODE_SHIFT 29 +#define XQSPIPSU_CFG_GEN_FIFO_START_MODE_WIDTH 1 +#define XQSPIPSU_CFG_GEN_FIFO_START_MODE_MASK 0X20000000 + +#define XQSPIPSU_CFG_START_GEN_FIFO_SHIFT 28 +#define XQSPIPSU_CFG_START_GEN_FIFO_WIDTH 1 +#define XQSPIPSU_CFG_START_GEN_FIFO_MASK 0X10000000 + +#define XQSPIPSU_CFG_ENDIAN_SHIFT 26 +#define XQSPIPSU_CFG_ENDIAN_WIDTH 1 +#define XQSPIPSU_CFG_ENDIAN_MASK 0X04000000 + +#define XQSPIPSU_CFG_EN_POLL_TO_SHIFT 20 +#define XQSPIPSU_CFG_EN_POLL_TO_WIDTH 1 +#define XQSPIPSU_CFG_EN_POLL_TO_MASK 0X00100000 + +#define XQSPIPSU_CFG_WP_HOLD_SHIFT 19 +#define XQSPIPSU_CFG_WP_HOLD_WIDTH 1 +#define XQSPIPSU_CFG_WP_HOLD_MASK 0X00080000 + +#define XQSPIPSU_CFG_BAUD_RATE_DIV_SHIFT 3 +#define XQSPIPSU_CFG_BAUD_RATE_DIV_WIDTH 3 +#define XQSPIPSU_CFG_BAUD_RATE_DIV_MASK 0X00000038 + +#define XQSPIPSU_CFG_CLK_PHA_SHIFT 2 +#define XQSPIPSU_CFG_CLK_PHA_WIDTH 1 +#define XQSPIPSU_CFG_CLK_PHA_MASK 0X00000004 + +#define XQSPIPSU_CFG_CLK_POL_SHIFT 1 +#define XQSPIPSU_CFG_CLK_POL_WIDTH 1 +#define XQSPIPSU_CFG_CLK_POL_MASK 0X00000002 + +/** + * Register: XQSPIPSU_ISR + */ +#define XQSPIPSU_ISR_OFFSET 0X00000004 + +#define XQSPIPSU_ISR_RXEMPTY_SHIFT 11 +#define XQSPIPSU_ISR_RXEMPTY_WIDTH 1 +#define XQSPIPSU_ISR_RXEMPTY_MASK 0X00000800 + +#define XQSPIPSU_ISR_GENFIFOFULL_SHIFT 10 +#define XQSPIPSU_ISR_GENFIFOFULL_WIDTH 1 +#define XQSPIPSU_ISR_GENFIFOFULL_MASK 0X00000400 + +#define XQSPIPSU_ISR_GENFIFONOT_FULL_SHIFT 9 +#define XQSPIPSU_ISR_GENFIFONOT_FULL_WIDTH 1 +#define XQSPIPSU_ISR_GENFIFONOT_FULL_MASK 0X00000200 + +#define XQSPIPSU_ISR_TXEMPTY_SHIFT 8 +#define XQSPIPSU_ISR_TXEMPTY_WIDTH 1 +#define XQSPIPSU_ISR_TXEMPTY_MASK 0X00000100 + +#define XQSPIPSU_ISR_GENFIFOEMPTY_SHIFT 7 +#define XQSPIPSU_ISR_GENFIFOEMPTY_WIDTH 1 +#define XQSPIPSU_ISR_GENFIFOEMPTY_MASK 0X00000080 + +#define XQSPIPSU_ISR_RXFULL_SHIFT 5 +#define XQSPIPSU_ISR_RXFULL_WIDTH 1 +#define XQSPIPSU_ISR_RXFULL_MASK 0X00000020 + +#define XQSPIPSU_ISR_RXNEMPTY_SHIFT 4 +#define XQSPIPSU_ISR_RXNEMPTY_WIDTH 1 +#define XQSPIPSU_ISR_RXNEMPTY_MASK 0X00000010 + +#define XQSPIPSU_ISR_TXFULL_SHIFT 3 +#define XQSPIPSU_ISR_TXFULL_WIDTH 1 +#define XQSPIPSU_ISR_TXFULL_MASK 0X00000008 + +#define XQSPIPSU_ISR_TXNOT_FULL_SHIFT 2 +#define XQSPIPSU_ISR_TXNOT_FULL_WIDTH 1 +#define XQSPIPSU_ISR_TXNOT_FULL_MASK 0X00000004 + +#define XQSPIPSU_ISR_POLL_TIME_EXPIRE_SHIFT 1 +#define XQSPIPSU_ISR_POLL_TIME_EXPIRE_WIDTH 1 +#define XQSPIPSU_ISR_POLL_TIME_EXPIRE_MASK 0X00000002 + +#define XQSPIPSU_ISR_WR_TO_CLR_MASK 0X00000002 + +/** + * Register: XQSPIPSU_IER + */ +#define XQSPIPSU_IER_OFFSET 0X00000008 + +#define XQSPIPSU_IER_RXEMPTY_SHIFT 11 +#define XQSPIPSU_IER_RXEMPTY_WIDTH 1 +#define XQSPIPSU_IER_RXEMPTY_MASK 0X00000800 + +#define XQSPIPSU_IER_GENFIFOFULL_SHIFT 10 +#define XQSPIPSU_IER_GENFIFOFULL_WIDTH 1 +#define XQSPIPSU_IER_GENFIFOFULL_MASK 0X00000400 + +#define XQSPIPSU_IER_GENFIFONOT_FULL_SHIFT 9 +#define XQSPIPSU_IER_GENFIFONOT_FULL_WIDTH 1 +#define XQSPIPSU_IER_GENFIFONOT_FULL_MASK 0X00000200 + +#define XQSPIPSU_IER_TXEMPTY_SHIFT 8 +#define XQSPIPSU_IER_TXEMPTY_WIDTH 1 +#define XQSPIPSU_IER_TXEMPTY_MASK 0X00000100 + +#define XQSPIPSU_IER_GENFIFOEMPTY_SHIFT 7 +#define XQSPIPSU_IER_GENFIFOEMPTY_WIDTH 1 +#define XQSPIPSU_IER_GENFIFOEMPTY_MASK 0X00000080 + +#define XQSPIPSU_IER_RXFULL_SHIFT 5 +#define XQSPIPSU_IER_RXFULL_WIDTH 1 +#define XQSPIPSU_IER_RXFULL_MASK 0X00000020 + +#define XQSPIPSU_IER_RXNEMPTY_SHIFT 4 +#define XQSPIPSU_IER_RXNEMPTY_WIDTH 1 +#define XQSPIPSU_IER_RXNEMPTY_MASK 0X00000010 + +#define XQSPIPSU_IER_TXFULL_SHIFT 3 +#define XQSPIPSU_IER_TXFULL_WIDTH 1 +#define XQSPIPSU_IER_TXFULL_MASK 0X00000008 + +#define XQSPIPSU_IER_TXNOT_FULL_SHIFT 2 +#define XQSPIPSU_IER_TXNOT_FULL_WIDTH 1 +#define XQSPIPSU_IER_TXNOT_FULL_MASK 0X00000004 + +#define XQSPIPSU_IER_POLL_TIME_EXPIRE_SHIFT 1 +#define XQSPIPSU_IER_POLL_TIME_EXPIRE_WIDTH 1 +#define XQSPIPSU_IER_POLL_TIME_EXPIRE_MASK 0X00000002 + +/** + * Register: XQSPIPSU_IDR + */ +#define XQSPIPSU_IDR_OFFSET 0X0000000C + +#define XQSPIPSU_IDR_RXEMPTY_SHIFT 11 +#define XQSPIPSU_IDR_RXEMPTY_WIDTH 1 +#define XQSPIPSU_IDR_RXEMPTY_MASK 0X00000800 + +#define XQSPIPSU_IDR_GENFIFOFULL_SHIFT 10 +#define XQSPIPSU_IDR_GENFIFOFULL_WIDTH 1 +#define XQSPIPSU_IDR_GENFIFOFULL_MASK 0X00000400 + +#define XQSPIPSU_IDR_GENFIFONOT_FULL_SHIFT 9 +#define XQSPIPSU_IDR_GENFIFONOT_FULL_WIDTH 1 +#define XQSPIPSU_IDR_GENFIFONOT_FULL_MASK 0X00000200 + +#define XQSPIPSU_IDR_TXEMPTY_SHIFT 8 +#define XQSPIPSU_IDR_TXEMPTY_WIDTH 1 +#define XQSPIPSU_IDR_TXEMPTY_MASK 0X00000100 + +#define XQSPIPSU_IDR_GENFIFOEMPTY_SHIFT 7 +#define XQSPIPSU_IDR_GENFIFOEMPTY_WIDTH 1 +#define XQSPIPSU_IDR_GENFIFOEMPTY_MASK 0X00000080 + +#define XQSPIPSU_IDR_RXFULL_SHIFT 5 +#define XQSPIPSU_IDR_RXFULL_WIDTH 1 +#define XQSPIPSU_IDR_RXFULL_MASK 0X00000020 + +#define XQSPIPSU_IDR_RXNEMPTY_SHIFT 4 +#define XQSPIPSU_IDR_RXNEMPTY_WIDTH 1 +#define XQSPIPSU_IDR_RXNEMPTY_MASK 0X00000010 + +#define XQSPIPSU_IDR_TXFULL_SHIFT 3 +#define XQSPIPSU_IDR_TXFULL_WIDTH 1 +#define XQSPIPSU_IDR_TXFULL_MASK 0X00000008 + +#define XQSPIPSU_IDR_TXNOT_FULL_SHIFT 2 +#define XQSPIPSU_IDR_TXNOT_FULL_WIDTH 1 +#define XQSPIPSU_IDR_TXNOT_FULL_MASK 0X00000004 + +#define XQSPIPSU_IDR_POLL_TIME_EXPIRE_SHIFT 1 +#define XQSPIPSU_IDR_POLL_TIME_EXPIRE_WIDTH 1 +#define XQSPIPSU_IDR_POLL_TIME_EXPIRE_MASK 0X00000002 + +#define XQSPIPSU_IDR_ALL_MASK 0X0FBE + +/** + * Register: XQSPIPSU_IMR + */ +#define XQSPIPSU_IMR_OFFSET 0X00000010 + +#define XQSPIPSU_IMR_RXEMPTY_SHIFT 11 +#define XQSPIPSU_IMR_RXEMPTY_WIDTH 1 +#define XQSPIPSU_IMR_RXEMPTY_MASK 0X00000800 + +#define XQSPIPSU_IMR_GENFIFOFULL_SHIFT 10 +#define XQSPIPSU_IMR_GENFIFOFULL_WIDTH 1 +#define XQSPIPSU_IMR_GENFIFOFULL_MASK 0X00000400 + +#define XQSPIPSU_IMR_GENFIFONOT_FULL_SHIFT 9 +#define XQSPIPSU_IMR_GENFIFONOT_FULL_WIDTH 1 +#define XQSPIPSU_IMR_GENFIFONOT_FULL_MASK 0X00000200 + +#define XQSPIPSU_IMR_TXEMPTY_SHIFT 8 +#define XQSPIPSU_IMR_TXEMPTY_WIDTH 1 +#define XQSPIPSU_IMR_TXEMPTY_MASK 0X00000100 + +#define XQSPIPSU_IMR_GENFIFOEMPTY_SHIFT 7 +#define XQSPIPSU_IMR_GENFIFOEMPTY_WIDTH 1 +#define XQSPIPSU_IMR_GENFIFOEMPTY_MASK 0X00000080 + +#define XQSPIPSU_IMR_RXFULL_SHIFT 5 +#define XQSPIPSU_IMR_RXFULL_WIDTH 1 +#define XQSPIPSU_IMR_RXFULL_MASK 0X00000020 + +#define XQSPIPSU_IMR_RXNEMPTY_SHIFT 4 +#define XQSPIPSU_IMR_RXNEMPTY_WIDTH 1 +#define XQSPIPSU_IMR_RXNEMPTY_MASK 0X00000010 + +#define XQSPIPSU_IMR_TXFULL_SHIFT 3 +#define XQSPIPSU_IMR_TXFULL_WIDTH 1 +#define XQSPIPSU_IMR_TXFULL_MASK 0X00000008 + +#define XQSPIPSU_IMR_TXNOT_FULL_SHIFT 2 +#define XQSPIPSU_IMR_TXNOT_FULL_WIDTH 1 +#define XQSPIPSU_IMR_TXNOT_FULL_MASK 0X00000004 + +#define XQSPIPSU_IMR_POLL_TIME_EXPIRE_SHIFT 1 +#define XQSPIPSU_IMR_POLL_TIME_EXPIRE_WIDTH 1 +#define XQSPIPSU_IMR_POLL_TIME_EXPIRE_MASK 0X00000002 + +/** + * Register: XQSPIPSU_EN_REG + */ +#define XQSPIPSU_EN_OFFSET 0X00000014 + +#define XQSPIPSU_EN_SHIFT 0 +#define XQSPIPSU_EN_WIDTH 1 +#define XQSPIPSU_EN_MASK 0X00000001 + +/** + * Register: XQSPIPSU_TXD + */ +#define XQSPIPSU_TXD_OFFSET 0X0000001C + +#define XQSPIPSU_TXD_SHIFT 0 +#define XQSPIPSU_TXD_WIDTH 32 +#define XQSPIPSU_TXD_MASK 0XFFFFFFFF + +#define XQSPIPSU_TXD_DEPTH 32 + +/** + * Register: XQSPIPSU_RXD + */ +#define XQSPIPSU_RXD_OFFSET 0X00000020 + +#define XQSPIPSU_RXD_SHIFT 0 +#define XQSPIPSU_RXD_WIDTH 32 +#define XQSPIPSU_RXD_MASK 0XFFFFFFFF + +/** + * Register: XQSPIPSU_TX_THRESHOLD + */ +#define XQSPIPSU_TX_THRESHOLD_OFFSET 0X00000028 + +#define XQSPIPSU_TX_FIFO_THRESHOLD_SHIFT 0 +#define XQSPIPSU_TX_FIFO_THRESHOLD_WIDTH 6 +#define XQSPIPSU_TX_FIFO_THRESHOLD_MASK 0X0000003F +#define XQSPIPSU_TX_FIFO_THRESHOLD_RESET_VAL 0X01 + +/** + * Register: XQSPIPSU_RX_THRESHOLD + */ +#define XQSPIPSU_RX_THRESHOLD_OFFSET 0X0000002C + +#define XQSPIPSU_RX_FIFO_THRESHOLD_SHIFT 0 +#define XQSPIPSU_RX_FIFO_THRESHOLD_WIDTH 6 +#define XQSPIPSU_RX_FIFO_THRESHOLD_MASK 0X0000003F +#define XQSPIPSU_RX_FIFO_THRESHOLD_RESET_VAL 0X01 + +#define XQSPIPSU_RXFIFO_THRESHOLD_OPT 32 + +/** + * Register: XQSPIPSU_GPIO + */ +#define XQSPIPSU_GPIO_OFFSET 0X00000030 + +#define XQSPIPSU_GPIO_WP_N_SHIFT 0 +#define XQSPIPSU_GPIO_WP_N_WIDTH 1 +#define XQSPIPSU_GPIO_WP_N_MASK 0X00000001 + +/** + * Register: XQSPIPSU_LPBK_DLY_ADJ + */ +#define XQSPIPSU_LPBK_DLY_ADJ_OFFSET 0X00000038 + +#define XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_SHIFT 5 +#define XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_WIDTH 1 +#define XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_MASK 0X00000020 + +#define XQSPIPSU_LPBK_DLY_ADJ_DLY1_SHIFT 3 +#define XQSPIPSU_LPBK_DLY_ADJ_DLY1_WIDTH 2 +#define XQSPIPSU_LPBK_DLY_ADJ_DLY1_MASK 0X00000018 + +#define XQSPIPSU_LPBK_DLY_ADJ_DLY0_SHIFT 0 +#define XQSPIPSU_LPBK_DLY_ADJ_DLY0_WIDTH 3 +#define XQSPIPSU_LPBK_DLY_ADJ_DLY0_MASK 0X00000007 + +/** + * Register: XQSPIPSU_GEN_FIFO + */ +#define XQSPIPSU_GEN_FIFO_OFFSET 0X00000040 + +#define XQSPIPSU_GEN_FIFO_DATA_SHIFT 0 +#define XQSPIPSU_GEN_FIFO_DATA_WIDTH 20 +#define XQSPIPSU_GEN_FIFO_DATA_MASK 0X000FFFFF + +/** + * Register: XQSPIPSU_SEL + */ +#define XQSPIPSU_SEL_OFFSET 0X00000044 + +#define XQSPIPSU_SEL_SHIFT 0 +#define XQSPIPSU_SEL_WIDTH 1 +#define XQSPIPSU_SEL_MASK 0X00000001 + +/** + * Register: XQSPIPSU_FIFO_CTRL + */ +#define XQSPIPSU_FIFO_CTRL_OFFSET 0X0000004C + +#define XQSPIPSU_FIFO_CTRL_RST_RX_FIFO_SHIFT 2 +#define XQSPIPSU_FIFO_CTRL_RST_RX_FIFO_WIDTH 1 +#define XQSPIPSU_FIFO_CTRL_RST_RX_FIFO_MASK 0X00000004 + +#define XQSPIPSU_FIFO_CTRL_RST_TX_FIFO_SHIFT 1 +#define XQSPIPSU_FIFO_CTRL_RST_TX_FIFO_WIDTH 1 +#define XQSPIPSU_FIFO_CTRL_RST_TX_FIFO_MASK 0X00000002 + +#define XQSPIPSU_FIFO_CTRL_RST_GEN_FIFO_SHIFT 0 +#define XQSPIPSU_FIFO_CTRL_RST_GEN_FIFO_WIDTH 1 +#define XQSPIPSU_FIFO_CTRL_RST_GEN_FIFO_MASK 0X00000001 + +/** + * Register: XQSPIPSU_GF_THRESHOLD + */ +#define XQSPIPSU_GF_THRESHOLD_OFFSET 0X00000050 + +#define XQSPIPSU_GEN_FIFO_THRESHOLD_SHIFT 0 +#define XQSPIPSU_GEN_FIFO_THRESHOLD_WIDTH 5 +#define XQSPIPSU_GEN_FIFO_THRESHOLD_MASK 0X0000001F +#define XQSPIPSU_GEN_FIFO_THRESHOLD_RESET_VAL 0X10 + +/** + * Register: XQSPIPSU_POLL_CFG + */ +#define XQSPIPSU_POLL_CFG_OFFSET 0X00000054 + +#define XQSPIPSU_POLL_CFG_EN_MASK_UPPER_SHIFT 31 +#define XQSPIPSU_POLL_CFG_EN_MASK_UPPER_WIDTH 1 +#define XQSPIPSU_POLL_CFG_EN_MASK_UPPER_MASK 0X80000000 + +#define XQSPIPSU_POLL_CFG_EN_MASK_LOWER_SHIFT 30 +#define XQSPIPSU_POLL_CFG_EN_MASK_LOWER_WIDTH 1 +#define XQSPIPSU_POLL_CFG_EN_MASK_LOWER_MASK 0X40000000 + +#define XQSPIPSU_POLL_CFG_MASK_EN_SHIFT 8 +#define XQSPIPSU_POLL_CFG_MASK_EN_WIDTH 8 +#define XQSPIPSU_POLL_CFG_MASK_EN_MASK 0X0000FF00 + +#define XQSPIPSU_POLL_CFG_DATA_VALUE_SHIFT 0 +#define XQSPIPSU_POLL_CFG_DATA_VALUE_WIDTH 8 +#define XQSPIPSU_POLL_CFG_DATA_VALUE_MASK 0X000000FF + +/** + * Register: XQSPIPSU_P_TIMEOUT + */ +#define XQSPIPSU_P_TO_OFFSET 0X00000058 + +#define XQSPIPSU_P_TO_VALUE_SHIFT 0 +#define XQSPIPSU_P_TO_VALUE_WIDTH 32 +#define XQSPIPSU_P_TO_VALUE_MASK 0XFFFFFFFF + +/** + * Register: XQSPIPSU_XFER_STS + */ +#define XQSPIPSU_XFER_STS_OFFSET 0X0000005C + +#define XQSPIPSU_XFER_STS_PEND_BYTES_SHIFT 0 +#define XQSPIPSU_XFER_STS_PEND_BYTES_WIDTH 32 +#define XQSPIPSU_XFER_STS_PEND_BYTES_MASK 0XFFFFFFFF + +/** + * Register: XQSPIPSU_GF_SNAPSHOT + */ +#define XQSPIPSU_GF_SNAPSHOT_OFFSET 0X00000060 + +#define XQSPIPSU_GF_SNAPSHOT_SHIFT 0 +#define XQSPIPSU_GF_SNAPSHOT_WIDTH 20 +#define XQSPIPSU_GF_SNAPSHOT_MASK 0X000FFFFF + +/** + * Register: XQSPIPSU_RX_COPY + */ +#define XQSPIPSU_RX_COPY_OFFSET 0X00000064 + +#define XQSPIPSU_RX_COPY_UPPER_SHIFT 8 +#define XQSPIPSU_RX_COPY_UPPER_WIDTH 8 +#define XQSPIPSU_RX_COPY_UPPER_MASK 0X0000FF00 + +#define XQSPIPSU_RX_COPY_LOWER_SHIFT 0 +#define XQSPIPSU_RX_COPY_LOWER_WIDTH 8 +#define XQSPIPSU_RX_COPY_LOWER_MASK 0X000000FF + +/** + * Register: XQSPIPSU_MOD_ID + */ +#define XQSPIPSU_MOD_ID_OFFSET 0X000000FC + +#define XQSPIPSU_MOD_ID_SHIFT 0 +#define XQSPIPSU_MOD_ID_WIDTH 32 +#define XQSPIPSU_MOD_ID_MASK 0XFFFFFFFF + +/** + * Register: XQSPIPSU_QSPIDMA_DST_ADDR + */ +#define XQSPIPSU_QSPIDMA_DST_ADDR_OFFSET 0X00000700 + +#define XQSPIPSU_QSPIDMA_DST_ADDR_SHIFT 2 +#define XQSPIPSU_QSPIDMA_DST_ADDR_WIDTH 30 +#define XQSPIPSU_QSPIDMA_DST_ADDR_MASK 0XFFFFFFFC + +/** + * Register: XQSPIPSU_QSPIDMA_DST_SIZE + */ +#define XQSPIPSU_QSPIDMA_DST_SIZE_OFFSET 0X00000704 + +#define XQSPIPSU_QSPIDMA_DST_SIZE_SHIFT 2 +#define XQSPIPSU_QSPIDMA_DST_SIZE_WIDTH 27 +#define XQSPIPSU_QSPIDMA_DST_SIZE_MASK 0X1FFFFFFC + +/** + * Register: XQSPIPSU_QSPIDMA_DST_STS + */ +#define XQSPIPSU_QSPIDMA_DST_STS_OFFSET 0X00000708 + +#define XQSPIPSU_QSPIDMA_DST_STS_DONE_CNT_SHIFT 13 +#define XQSPIPSU_QSPIDMA_DST_STS_DONE_CNT_WIDTH 3 +#define XQSPIPSU_QSPIDMA_DST_STS_DONE_CNT_MASK 0X0000E000 + +#define XQSPIPSU_QSPIDMA_DST_STS_DST_FIFO_LEVEL_SHIFT 5 +#define XQSPIPSU_QSPIDMA_DST_STS_DST_FIFO_LEVEL_WIDTH 8 +#define XQSPIPSU_QSPIDMA_DST_STS_DST_FIFO_LEVEL_MASK 0X00001FE0 + +#define XQSPIPSU_QSPIDMA_DST_STS_WR_OUTSTANDING_SHIFT 1 +#define XQSPIPSU_QSPIDMA_DST_STS_WR_OUTSTANDING_WIDTH 4 +#define XQSPIPSU_QSPIDMA_DST_STS_WR_OUTSTANDING_MASK 0X0000001E + +#define XQSPIPSU_QSPIDMA_DST_STS_BUSY_SHIFT 0 +#define XQSPIPSU_QSPIDMA_DST_STS_BUSY_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_STS_BUSY_MASK 0X00000001 + +/** + * Register: XQSPIPSU_QSPIDMA_DST_CTRL + */ +#define XQSPIPSU_QSPIDMA_DST_CTRL_OFFSET 0X0000070C + +#define XQSPIPSU_QSPIDMA_DST_CTRL_FIFO_LVL_HIT_THRESHOLD_SHIFT 25 +#define XQSPIPSU_QSPIDMA_DST_CTRL_FIFO_LVL_HIT_THRESHOLD_WIDTH 7 +#define XQSPIPSU_QSPIDMA_DST_CTRL_FIFO_LVL_HIT_THRESHOLD_MASK 0XFE000000 + +#define XQSPIPSU_QSPIDMA_DST_CTRL_APB_ERR_RESP_SHIFT 24 +#define XQSPIPSU_QSPIDMA_DST_CTRL_APB_ERR_RESP_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_CTRL_APB_ERR_RESP_MASK 0X01000000 + +#define XQSPIPSU_QSPIDMA_DST_CTRL_ENDIAN_SHIFT 23 +#define XQSPIPSU_QSPIDMA_DST_CTRL_ENDIAN_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_CTRL_ENDIAN_MASK 0X00800000 + +#define XQSPIPSU_QSPIDMA_DST_CTRL_AXI_BRST_TYPE_SHIFT 22 +#define XQSPIPSU_QSPIDMA_DST_CTRL_AXI_BRST_TYPE_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_CTRL_AXI_BRST_TYPE_MASK 0X00400000 + +#define XQSPIPSU_QSPIDMA_DST_CTRL_TO_VAL_SHIFT 10 +#define XQSPIPSU_QSPIDMA_DST_CTRL_TO_VAL_WIDTH 12 +#define XQSPIPSU_QSPIDMA_DST_CTRL_TO_VAL_MASK 0X003FFC00 + +#define XQSPIPSU_QSPIDMA_DST_CTRL_FIFO_THRESHOLD_SHIFT 2 +#define XQSPIPSU_QSPIDMA_DST_CTRL_FIFO_THRESHOLD_WIDTH 8 +#define XQSPIPSU_QSPIDMA_DST_CTRL_FIFO_THRESHOLD_MASK 0X000003FC + +#define XQSPIPSU_QSPIDMA_DST_CTRL_PAUSE_STRM_SHIFT 1 +#define XQSPIPSU_QSPIDMA_DST_CTRL_PAUSE_STRM_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_CTRL_PAUSE_STRM_MASK 0X00000002 + +#define XQSPIPSU_QSPIDMA_DST_CTRL_PAUSE_MEM_SHIFT 0 +#define XQSPIPSU_QSPIDMA_DST_CTRL_PAUSE_MEM_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_CTRL_PAUSE_MEM_MASK 0X00000001 + +#define XQSPIPSU_QSPIDMA_DST_CTRL_RESET_VAL 0x403FFA00 + +/** + * Register: XQSPIPSU_QSPIDMA_DST_I_STS + */ +#define XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET 0X00000714 + +#define XQSPIPSU_QSPIDMA_DST_I_STS_FIFO_OF_SHIFT 7 +#define XQSPIPSU_QSPIDMA_DST_I_STS_FIFO_OF_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_STS_FIFO_OF_MASK 0X00000080 + +#define XQSPIPSU_QSPIDMA_DST_I_STS_INVALID_APB_SHIFT 6 +#define XQSPIPSU_QSPIDMA_DST_I_STS_INVALID_APB_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_STS_INVALID_APB_MASK 0X00000040 + +#define XQSPIPSU_QSPIDMA_DST_I_STS_THRESHOLD_HIT_SHIFT 5 +#define XQSPIPSU_QSPIDMA_DST_I_STS_THRESHOLD_HIT_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_STS_THRESHOLD_HIT_MASK 0X00000020 + +#define XQSPIPSU_QSPIDMA_DST_I_STS_TO_MEM_SHIFT 4 +#define XQSPIPSU_QSPIDMA_DST_I_STS_TO_MEM_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_STS_TO_MEM_MASK 0X00000010 + +#define XQSPIPSU_QSPIDMA_DST_I_STS_TO_STRM_SHIFT 3 +#define XQSPIPSU_QSPIDMA_DST_I_STS_TO_STRM_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_STS_TO_STRM_MASK 0X00000008 + +#define XQSPIPSU_QSPIDMA_DST_I_STS_AXI_BRESP_ERR_SHIFT 2 +#define XQSPIPSU_QSPIDMA_DST_I_STS_AXI_BRESP_ERR_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_STS_AXI_BRESP_ERR_MASK 0X00000004 + +#define XQSPIPSU_QSPIDMA_DST_I_STS_DONE_SHIFT 1 +#define XQSPIPSU_QSPIDMA_DST_I_STS_DONE_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK 0X00000002 + +#define XQSPIPSU_QSPIDMA_DST_INTR_ERR_MASK 0X000000FC + +/** + * Register: XQSPIPSU_QSPIDMA_DST_I_EN + */ +#define XQSPIPSU_QSPIDMA_DST_I_EN_OFFSET 0X00000718 + +#define XQSPIPSU_QSPIDMA_DST_I_EN_FIFO_OF_SHIFT 7 +#define XQSPIPSU_QSPIDMA_DST_I_EN_FIFO_OF_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_EN_FIFO_OF_MASK 0X00000080 + +#define XQSPIPSU_QSPIDMA_DST_I_EN_INVALID_APB_SHIFT 6 +#define XQSPIPSU_QSPIDMA_DST_I_EN_INVALID_APB_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_EN_INVALID_APB_MASK 0X00000040 + +#define XQSPIPSU_QSPIDMA_DST_I_EN_THRESHOLD_HIT_SHIFT 5 +#define XQSPIPSU_QSPIDMA_DST_I_EN_THRESHOLD_HIT_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_EN_THRESHOLD_HIT_MASK 0X00000020 + +#define XQSPIPSU_QSPIDMA_DST_I_EN_TO_MEM_SHIFT 4 +#define XQSPIPSU_QSPIDMA_DST_I_EN_TO_MEM_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_EN_TO_MEM_MASK 0X00000010 + +#define XQSPIPSU_QSPIDMA_DST_I_EN_TO_STRM_SHIFT 3 +#define XQSPIPSU_QSPIDMA_DST_I_EN_TO_STRM_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_EN_TO_STRM_MASK 0X00000008 + +#define XQSPIPSU_QSPIDMA_DST_I_EN_AXI_BRESP_ERR_SHIFT 2 +#define XQSPIPSU_QSPIDMA_DST_I_EN_AXI_BRESP_ERR_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_EN_AXI_BRESP_ERR_MASK 0X00000004 + +#define XQSPIPSU_QSPIDMA_DST_I_EN_DONE_SHIFT 1 +#define XQSPIPSU_QSPIDMA_DST_I_EN_DONE_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_EN_DONE_MASK 0X00000002 + +/** + * Register: XQSPIPSU_QSPIDMA_DST_I_DIS + */ +#define XQSPIPSU_QSPIDMA_DST_I_DIS_OFFSET 0X0000071C + +#define XQSPIPSU_QSPIDMA_DST_I_DIS_FIFO_OF_SHIFT 7 +#define XQSPIPSU_QSPIDMA_DST_I_DIS_FIFO_OF_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_DIS_FIFO_OF_MASK 0X00000080 + +#define XQSPIPSU_QSPIDMA_DST_I_DIS_INVALID_APB_SHIFT 6 +#define XQSPIPSU_QSPIDMA_DST_I_DIS_INVALID_APB_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_DIS_INVALID_APB_MASK 0X00000040 + +#define XQSPIPSU_QSPIDMA_DST_I_DIS_THRESHOLD_HIT_SHIFT 5 +#define XQSPIPSU_QSPIDMA_DST_I_DIS_THRESHOLD_HIT_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_DIS_THRESHOLD_HIT_MASK 0X00000020 + +#define XQSPIPSU_QSPIDMA_DST_I_DIS_TO_MEM_SHIFT 4 +#define XQSPIPSU_QSPIDMA_DST_I_DIS_TO_MEM_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_DIS_TO_MEM_MASK 0X00000010 + +#define XQSPIPSU_QSPIDMA_DST_I_DIS_TO_STRM_SHIFT 3 +#define XQSPIPSU_QSPIDMA_DST_I_DIS_TO_STRM_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_DIS_TO_STRM_MASK 0X00000008 + +#define XQSPIPSU_QSPIDMA_DST_I_DIS_AXI_BRESP_ERR_SHIFT 2 +#define XQSPIPSU_QSPIDMA_DST_I_DIS_AXI_BRESP_ERR_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_DIS_AXI_BRESP_ERR_MASK 0X00000004 + +#define XQSPIPSU_QSPIDMA_DST_I_DIS_DONE_SHIFT 1 +#define XQSPIPSU_QSPIDMA_DST_I_DIS_DONE_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_I_DIS_DONE_MASK 0X00000002 + +/** + * Register: XQSPIPSU_QSPIDMA_DST_IMR + */ +#define XQSPIPSU_QSPIDMA_DST_IMR_OFFSET 0X00000720 + +#define XQSPIPSU_QSPIDMA_DST_IMR_FIFO_OF_SHIFT 7 +#define XQSPIPSU_QSPIDMA_DST_IMR_FIFO_OF_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_IMR_FIFO_OF_MASK 0X00000080 + +#define XQSPIPSU_QSPIDMA_DST_IMR_INVALID_APB_SHIFT 6 +#define XQSPIPSU_QSPIDMA_DST_IMR_INVALID_APB_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_IMR_INVALID_APB_MASK 0X00000040 + +#define XQSPIPSU_QSPIDMA_DST_IMR_THRESHOLD_HIT_SHIFT 5 +#define XQSPIPSU_QSPIDMA_DST_IMR_THRESHOLD_HIT_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_IMR_THRESHOLD_HIT_MASK 0X00000020 + +#define XQSPIPSU_QSPIDMA_DST_IMR_TO_MEM_SHIFT 4 +#define XQSPIPSU_QSPIDMA_DST_IMR_TO_MEM_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_IMR_TO_MEM_MASK 0X00000010 + +#define XQSPIPSU_QSPIDMA_DST_IMR_TO_STRM_SHIFT 3 +#define XQSPIPSU_QSPIDMA_DST_IMR_TO_STRM_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_IMR_TO_STRM_MASK 0X00000008 + +#define XQSPIPSU_QSPIDMA_DST_IMR_AXI_BRESP_ERR_SHIFT 2 +#define XQSPIPSU_QSPIDMA_DST_IMR_AXI_BRESP_ERR_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_IMR_AXI_BRESP_ERR_MASK 0X00000004 + +#define XQSPIPSU_QSPIDMA_DST_IMR_DONE_SHIFT 1 +#define XQSPIPSU_QSPIDMA_DST_IMR_DONE_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_IMR_DONE_MASK 0X00000002 + +/** + * Register: XQSPIPSU_QSPIDMA_DST_CTRL2 + */ +#define XQSPIPSU_QSPIDMA_DST_CTRL2_OFFSET 0X00000724 + +#define XQSPIPSU_QSPIDMA_DST_CTRL2_RAM_EMASA_SHIFT 27 +#define XQSPIPSU_QSPIDMA_DST_CTRL2_RAM_EMASA_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_CTRL2_RAM_EMASA_MASK 0X08000000 + +#define XQSPIPSU_QSPIDMA_DST_CTRL2_AWCACHE_SHIFT 24 +#define XQSPIPSU_QSPIDMA_DST_CTRL2_AWCACHE_WIDTH 3 +#define XQSPIPSU_QSPIDMA_DST_CTRL2_AWCACHE_MASK 0X07000000 + +#define XQSPIPSU_QSPIDMA_DST_CTRL2_TO_EN_SHIFT 22 +#define XQSPIPSU_QSPIDMA_DST_CTRL2_TO_EN_WIDTH 1 +#define XQSPIPSU_QSPIDMA_DST_CTRL2_TO_EN_MASK 0X00400000 + +#define XQSPIPSU_QSPIDMA_DST_CTRL2_RAM_EMAB_SHIFT 19 +#define XQSPIPSU_QSPIDMA_DST_CTRL2_RAM_EMAB_WIDTH 3 +#define XQSPIPSU_QSPIDMA_DST_CTRL2_RAM_EMAB_MASK 0X00380000 + +#define XQSPIPSU_QSPIDMA_DST_CTRL2_RAM_EMAA_SHIFT 16 +#define XQSPIPSU_QSPIDMA_DST_CTRL2_RAM_EMAA_WIDTH 3 +#define XQSPIPSU_QSPIDMA_DST_CTRL2_RAM_EMAA_MASK 0X00070000 + +#define XQSPIPSU_QSPIDMA_DST_CTRL2_TO_PRE_SHIFT 4 +#define XQSPIPSU_QSPIDMA_DST_CTRL2_TO_PRE_WIDTH 12 +#define XQSPIPSU_QSPIDMA_DST_CTRL2_TO_PRE_MASK 0X0000FFF0 + +#define XQSPIPSU_QSPIDMA_DST_CTRL2_MAX_OUTS_CMDS_SHIFT 0 +#define XQSPIPSU_QSPIDMA_DST_CTRL2_MAX_OUTS_CMDS_WIDTH 4 +#define XQSPIPSU_QSPIDMA_DST_CTRL2_MAX_OUTS_CMDS_MASK 0X0000000F + +/** + * Register: XQSPIPSU_QSPIDMA_DST_ADDR_MSB + */ +#define XQSPIPSU_QSPIDMA_DST_ADDR_MSB_OFFSET 0X00000728 + +#define XQSPIPSU_QSPIDMA_DST_ADDR_MSB_SHIFT 0 +#define XQSPIPSU_QSPIDMA_DST_ADDR_MSB_WIDTH 12 +#define XQSPIPSU_QSPIDMA_DST_ADDR_MSB_MASK 0X00000FFF + +/** + * Register: XQSPIPSU_QSPIDMA_FUTURE_ECO + */ +#define XQSPIPSU_QSPIDMA_FUTURE_ECO_OFFSET 0X00000EFC + +#define XQSPIPSU_QSPIDMA_FUTURE_ECO_VAL_SHIFT 0 +#define XQSPIPSU_QSPIDMA_FUTURE_ECO_VAL_WIDTH 32 +#define XQSPIPSU_QSPIDMA_FUTURE_ECO_VAL_MASK 0XFFFFFFFF + +/* + * Generic FIFO masks + */ +#define XQSPIPSU_GENFIFO_IMM_DATA_MASK 0xFF +#define XQSPIPSU_GENFIFO_DATA_XFER 0x100 +#define XQSPIPSU_GENFIFO_EXP 0x200 +#define XQSPIPSU_GENFIFO_MODE_SPI 0x400 +#define XQSPIPSU_GENFIFO_MODE_DUALSPI 0x800 +#define XQSPIPSU_GENFIFO_MODE_QUADSPI 0xC00 +#define XQSPIPSU_GENFIFO_MODE_MASK 0xC00 /* And with ~MASK first */ +#define XQSPIPSU_GENFIFO_CS_LOWER 0x1000 +#define XQSPIPSU_GENFIFO_CS_UPPER 0x2000 +#define XQSPIPSU_GENFIFO_BUS_LOWER 0x4000 +#define XQSPIPSU_GENFIFO_BUS_UPPER 0x8000 +#define XQSPIPSU_GENFIFO_BUS_BOTH 0xC000 /* inverse is no bus */ +#define XQSPIPSU_GENFIFO_BUS_MASK 0xC000 /* And with ~MASK first */ +#define XQSPIPSU_GENFIFO_TX 0x10000 /* inverse is zero pump */ +#define XQSPIPSU_GENFIFO_RX 0x20000 /* inverse is RX discard */ +#define XQSPIPSU_GENFIFO_STRIPE 0x40000 +#define XQSPIPSU_GENFIFO_POLL 0x80000 + +/***************** Macros (Inline Functions) Definitions *********************/ + +#define XQspiPsu_In32 Xil_In32 +#define XQspiPsu_Out32 Xil_Out32 + +/****************************************************************************/ +/** +* Read a register. +* +* @param BaseAddress contains the base address of the device. +* @param RegOffset contains the offset from the 1st register of the +* device to the target register. +* +* @return The value read from the register. +* +* @note C-Style signature: +* u32 XQspiPsu_ReadReg(u32 BaseAddress. int RegOffset) +* +******************************************************************************/ +#define XQspiPsu_ReadReg(BaseAddress, RegOffset) XQspiPsu_In32((BaseAddress) + (RegOffset)) + +/***************************************************************************/ +/** +* Write to a register. +* +* @param BaseAddress contains the base address of the device. +* @param RegOffset contains the offset from the 1st register of the +* device to target register. +* @param RegisterValue is the value to be written to the register. +* +* @return None. +* +* @note C-Style signature: +* void XQspiPsu_WriteReg(u32 BaseAddress, int RegOffset, +* u32 RegisterValue) +* +******************************************************************************/ +#define XQspiPsu_WriteReg(BaseAddress, RegOffset, RegisterValue) XQspiPsu_Out32((BaseAddress) + (RegOffset), (RegisterValue)) + + +#ifdef __cplusplus +} +#endif + + +#endif /* _XQSPIPSU_H_ */ diff --git a/XilinxProcessorIPLib/drivers/qspipsu/src/xqspipsu_options.c b/XilinxProcessorIPLib/drivers/qspipsu/src/xqspipsu_options.c new file mode 100755 index 00000000..bd7e4b0a --- /dev/null +++ b/XilinxProcessorIPLib/drivers/qspipsu/src/xqspipsu_options.c @@ -0,0 +1,363 @@ +/****************************************************************************** +* +* Copyright (C) 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 xqspipsu_options.c +* +* This file implements funcitons to configure the QSPIPSU component, +* specifically some optional settings, clock and flash related information. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who Date     Changes
+* ----- --- -------- -----------------------------------------------
+* 1.0   hk  08/21/14 First release
+*
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xqspipsu.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +/* + * Create the table of options which are processed to get/set the device + * options. These options are table driven to allow easy maintenance and + * expansion of the options. + */ +typedef struct { + u32 Option; + u32 Mask; +} OptionsMap; + +static OptionsMap OptionsTable[] = { + {XQSPIPSU_CLK_ACTIVE_LOW_OPTION, XQSPIPSU_CFG_CLK_POL_MASK}, + {XQSPIPSU_CLK_PHASE_1_OPTION, XQSPIPSU_CFG_CLK_PHA_MASK}, + {XQSPIPSU_MANUAL_START_OPTION, XQSPIPSU_CFG_GEN_FIFO_START_MODE_MASK}, +}; + +#define XQSPIPSU_NUM_OPTIONS (sizeof(OptionsTable) / sizeof(OptionsMap)) + +/*****************************************************************************/ +/** +* +* This function sets the options for the QSPIPSU device driver.The options +* control how the device behaves relative to the QSPIPSU bus. The device must be +* idle rather than busy transferring data before setting these device options. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Options contains the specified options to be set. This is a bit +* mask where a 1 indicates the option should be turned ON and +* a 0 indicates no action. One or more bit values may be +* contained in the mask. See the bit definitions named +* XQSPIPSU_*_OPTIONS in the file xqspipsu.h. +* +* @return +* - XST_SUCCESS if options are successfully set. +* - XST_DEVICE_BUSY if the device is currently transferring data. +* The transfer must complete or be aborted before setting options. +* +* @note +* This function is not thread-safe. +* +******************************************************************************/ +int XQspiPsu_SetOptions(XQspiPsu *InstancePtr, u32 Options) +{ + u32 ConfigReg; + unsigned int Index; + u32 QspiPsuOptions; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Do not allow to modify the Control Register while a transfer is in + * progress. Not thread-safe. + */ + if (InstancePtr->IsBusy) { + return XST_DEVICE_BUSY; + } + + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + + /* + * Loop through the options table, turning the option on + * depending on whether the bit is set in the incoming options flag. + */ + for (Index = 0; Index < XQSPIPSU_NUM_OPTIONS; Index++) { + if (Options & OptionsTable[Index].Option) { + /* Turn it on */ + ConfigReg |= OptionsTable[Index].Mask; + } + } + + /* + * Now write the control register. Leave it to the upper layers + * to restart the device. + */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + ConfigReg); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function resets the options for the QSPIPSU device driver.The options +* control how the device behaves relative to the QSPIPSU bus. The device must be +* idle rather than busy transferring data before setting these device options. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Options contains the specified options to be set. This is a bit +* mask where a 1 indicates the option should be turned OFF and +* a 0 indicates no action. One or more bit values may be +* contained in the mask. See the bit definitions named +* XQSPIPSU_*_OPTIONS in the file xqspipsu.h. +* +* @return +* - XST_SUCCESS if options are successfully set. +* - XST_DEVICE_BUSY if the device is currently transferring data. +* The transfer must complete or be aborted before setting options. +* +* @note +* This function is not thread-safe. +* +******************************************************************************/ +int XQspiPsu_ClearOptions(XQspiPsu *InstancePtr, u32 Options) +{ + u32 ConfigReg; + unsigned int Index; + u32 QspiPsuOptions; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Do not allow to modify the Control Register while a transfer is in + * progress. Not thread-safe. + */ + if (InstancePtr->IsBusy) { + return XST_DEVICE_BUSY; + } + + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + + /* + * Loop through the options table, turning the option on + * depending on whether the bit is set in the incoming options flag. + */ + for (Index = 0; Index < XQSPIPSU_NUM_OPTIONS; Index++) { + if (Options & OptionsTable[Index].Option) { + /* Turn it off */ + ConfigReg &= ~OptionsTable[Index].Mask; + } + } + + /* + * Now write the control register. Leave it to the upper layers + * to restart the device. + */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + ConfigReg); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function gets the options for the QSPIPSU device. The options control how +* the device behaves relative to the QSPIPSU bus. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* +* @return +* +* Options contains the specified options currently set. This is a bit value +* where a 1 means the option is on, and a 0 means the option is off. +* See the bit definitions named XQSPIPSU_*_OPTIONS in file xqspipsu.h. +* +* @note None. +* +******************************************************************************/ +u32 XQspiPsu_GetOptions(XQspiPsu *InstancePtr) +{ + u32 OptionsFlag = 0; + u32 ConfigReg; + unsigned int Index; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Get the current options from QSPIPSU configuration register. + */ + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + + /* + * Loop through the options table to grab options + */ + for (Index = 0; Index < XQSPIPSU_NUM_OPTIONS; Index++) { + if (ConfigReg & OptionsTable[Index].Mask) { + OptionsFlag |= OptionsTable[Index].Option; + } + } + + return OptionsFlag; +} + +/*****************************************************************************/ +/** +* +* Configures the clock according to the prescaler passed. +* +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Prescaler - clock prescaler to be set. +* +* @return +* - XST_SUCCESS if successful. +* - XST_DEVICE_IS_STARTED if the device is already started. +* It must be stopped to re-initialize. +* +* @note None. +* +******************************************************************************/ +int XQspiPsu_SetClkPrescaler(XQspiPsu *InstancePtr, u8 Prescaler) +{ + u32 ConfigReg; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(Prescaler <= XQSPIPSU_CR_PRESC_MAXIMUM); + + /* + * Do not allow the slave select to change while a transfer is in + * progress. Not thread-safe. + */ + if (InstancePtr->IsBusy) { + return XST_DEVICE_BUSY; + } + + /* + * Read the configuration register, mask out the relevant bits, and set + * them with the shifted value passed into the function. Write the + * results back to the configuration register. + */ + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + + ConfigReg &= ~XQSPIPSU_CFG_BAUD_RATE_DIV_MASK; + ConfigReg |= (u32) (Prescaler & XQSPIPSU_CR_PRESC_MAXIMUM) << + XQSPIPSU_CFG_BAUD_RATE_DIV_SHIFT; + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET, ConfigReg); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This funciton should be used to tell the QSPIPSU driver the HW flash +* configuration being used. This API should be called atleast once in the +* application. If desired, it can be called multiple times when switching +* between communicating to different flahs devices/using different configs. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Prescaler - clock prescaler to be set. +* +* @return +* - XST_SUCCESS if successful. +* - XST_DEVICE_IS_STARTED if the device is already started. +* It must be stopped to re-initialize. +* +* @note If this funciton is not called atleast once in the application, +* the driver assumes there is a single flash connected to the +* lower bus and CS line. +* +******************************************************************************/ +void XQspiPsu_SelectFlash(XQspiPsu *InstancePtr, u8 FlashCS, u8 FlashBus) +{ + Xil_AssertVoid(InstancePtr != NULL); + + /* + * Bus and CS lines selected here will be updated in the instance and + * used for subsequent GENFIFO entries during transfer. + */ + + /* Choose slave select line */ + switch(FlashCS) { + case XQSPIPSU_SELECT_FLASH_CS_BOTH: + InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_LOWER | + XQSPIPSU_GENFIFO_CS_UPPER; + break; + case XQSPIPSU_SELECT_FLASH_CS_UPPER: + InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_UPPER; + break; + case XQSPIPSU_SELECT_FLASH_CS_LOWER: + default: + InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_LOWER; + } + + /* Choose bus */ + switch(FlashBus) { + case XQSPIPSU_SELECT_FLASH_BUS_BOTH: + InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_LOWER | + XQSPIPSU_GENFIFO_BUS_UPPER; + break; + case XQSPIPSU_SELECT_FLASH_BUS_UPPER: + InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_UPPER; + break; + case XQSPIPSU_SELECT_FLASH_BUS_LOWER: + default: + InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_LOWER; + } +} diff --git a/XilinxProcessorIPLib/drivers/qspipsu/src/xqspipsu_sinit.c b/XilinxProcessorIPLib/drivers/qspipsu/src/xqspipsu_sinit.c new file mode 100755 index 00000000..014ba05b --- /dev/null +++ b/XilinxProcessorIPLib/drivers/qspipsu/src/xqspipsu_sinit.c @@ -0,0 +1,97 @@ +/****************************************************************************** +* +* Copyright (C) 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 xqspipsu_sinit.c +* +* The implementation of the XQspiPsu component's static initialization +* functionality. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who Date     Changes
+* ----- --- -------- -----------------------------------------------
+* 1.0   hk  08/21/14 First release
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xstatus.h" +#include "xqspipsu.h" +#include "xparameters.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +extern XQspiPsu_Config XQspiPsu_ConfigTable[]; + +/*****************************************************************************/ +/** +* +* Looks up the device configuration based on the unique device ID. A table +* contains the configuration info for each device in the system. +* +* @param DeviceId contains the ID of the device to look up the +* configuration for. +* +* @return +* +* A pointer to the configuration found or NULL if the specified device ID was +* not found. See xqspipsu.h for the definition of XQspiPsu_Config. +* +* @note None. +* +******************************************************************************/ +XQspiPsu_Config *XQspiPsu_LookupConfig(u16 DeviceId) +{ + XQspiPsu_Config *CfgPtr = NULL; + int Index; + + for (Index = 0; Index < XPAR_XQSPIPSU_NUM_INSTANCES; Index++) { + if (XQspiPsu_ConfigTable[Index].DeviceId == DeviceId) { + CfgPtr = &XQspiPsu_ConfigTable[Index]; + break; + } + } + return CfgPtr; +}