diff options
-rw-r--r-- | bsps/include/dev/spi/xqspipsu.h | 567 | ||||
-rw-r--r-- | bsps/include/dev/spi/xqspipsu_control.h | 102 | ||||
-rw-r--r-- | bsps/include/dev/spi/xqspipsu_flash_config.h | 355 | ||||
-rw-r--r-- | bsps/include/dev/spi/xqspipsu_hw.h | 1006 | ||||
-rw-r--r-- | bsps/shared/dev/spi/VERSION | 29 | ||||
-rw-r--r-- | bsps/shared/dev/spi/xqspipsu.c | 1048 | ||||
-rw-r--r-- | bsps/shared/dev/spi/xqspipsu_control.c | 282 | ||||
-rw-r--r-- | bsps/shared/dev/spi/xqspipsu_hw.c | 768 | ||||
-rw-r--r-- | bsps/shared/dev/spi/xqspipsu_options.c | 532 |
9 files changed, 4689 insertions, 0 deletions
diff --git a/bsps/include/dev/spi/xqspipsu.h b/bsps/include/dev/spi/xqspipsu.h new file mode 100644 index 0000000000..7d9b662464 --- /dev/null +++ b/bsps/include/dev/spi/xqspipsu.h @@ -0,0 +1,567 @@ +/****************************************************************************** +* Copyright (C) 2014 - 2022 Xilinx, Inc. All rights reserved. +* SPDX-License-Identifier: MIT +******************************************************************************/ + + +/*****************************************************************************/ +/** + * + * @file xqspipsu.h + * @addtogroup Overview + * @{ + * @details + * + * This section explains the implementation the functions required to use the + * QSPIPSU hardware to perform a transfer. These are accessible to the user + * via xqspipsu.h. + * + * 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 different 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 supports DMA RX and IO RX. + * + * <b>Initialization & Configuration</b> + * + * 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. + * + * <b>Transfer</b> + * + * 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. + * + * <pre> + * MODIFICATION HISTORY: + * + * Ver Who Date Changes + * ----- --- -------- -----------------------------------------------. + * 1.0 hk 08/21/14 First release + * sk 03/13/15 Added IO mode support. + * hk 03/18/15 Switch to I/O mode before clearing RX FIFO. + * Clear and disable DMA interrupts/status in abort. + * Use DMA DONE bit instead of BUSY as recommended. + * sk 04/24/15 Modified the code according to MISRAC-2012. + * sk 06/17/15 Removed NULL checks for Rx/Tx buffers. As + * writing/reading from 0x0 location is permitted. + * 1.1 sk 04/12/16 Added debug message prints. + * 1.2 nsk 07/01/16 Added LQSPI support + * Modified XQspiPsu_Select() macro in xqspipsu.h + * Added XQspiPsu_GetLqspiConfigReg() in xqspipsu.h + * Added required macros in xqspipsu_hw.h + * Modified XQspiPsu_SetOptions() to support + * LQSPI options and updated OptionsTable in + * xqspipsu_options.c + * rk 07/15/16 Added support for TapDelays at different frequencies. + * nsk 08/05/16 Added example support PollData and PollTimeout + * Added XQSPIPSU_MSG_FLAG_POLL macro in xqspipsu.h + * Added XQspiPsu_Create_PollConfigData and + * XQspiPsu_PollData() functions in xqspipsu.c + * 1.3 nsk 09/16/16 Update PollData and Polltimeout support for dual parallel + * configuration. Updated XQspiPsu_PollData() and + * XQspiPsu_Create_PollConfigData() functions in xqspipsu.c + * and also modified the polldata example + * ms 03/17/17 Added readme.txt file in examples folder for doxygen + * generation. + * ms 04/05/17 Modified Comment lines in functions of qspipsu + * examples to recognize it as documentation block + * and modified filename tag to include them in + * doxygen examples. + * 1.4 tjs 05/26/17 Added support for accessing upper DDR (0x800000000) + * while booting images from QSPI + * 1.5 tjs 08/08/17 Added index.html file for importing examples + * from system.mss + * 1.5 nsk 08/14/17 Added CCI support + * 1.5 tjs 09/14/17 Modified the checks for 4 byte addressing and commands. + * 1.6 tjs 10/16/17 Flow for accessing flash is made similar to u-boot + * and linux For CR-984966 + * 1.6 tjs 11/02/17 Resolved the compilation errors for ICCARM. CR-988625 + * 1.7 tjs 11/16/17 Removed the unsupported 4 Byte write and sector erase + * commands. + * 1.7 tjs 12/01/17 Added support for MT25QL02G Flash from Micron. CR-990642 + * 1.7 tjs 12/19/17 Added support for S25FL064L from Spansion. CR-990724 + * 1.7 tjs 01/11/18 Added support for MX66L1G45G flash from Macronix CR-992367 + * 1.7 tjs 01/16/18 Removed the check for DMA MSB to be written. (CR#992560) + * 1.7 tjs 01/17/18 Added support to toggle the WP pin of flash. (PR#2448) + * Added XQspiPsu_SetWP() in xqspipsu_options.c + * Added XQspiPsu_WriteProtectToggle() in xqspipsu.c and + * also added write protect example. + * 1.7 tjs 03/14/18 Added support in EL1 NS mode (CR#974882) + * 1.7 tjs 26/03/18 In dual parallel mode enable both CS when issuing Write + * enable command. CR-998478 + * 1.8 tjs 05/02/18 Added support for IS25LP064 and IS25WP064. + * 1.8 tjs 06/26/18 Added an example for accessing 64bit dma within + * 32 bit application. CR#1004701 + * 1.8 tjs 06/26/18 Removed checkpatch warnings + * 1.8 tjs 07/09/19 Fixed cppcheck, doxygen and gcc warnings. + * 1.8 tjs 07/18/18 Setup64BRxDma() should be called only if the RxAddress is + * greater than 32 bit address space. (CR#1006862) + * 1.8 tjs 07/18/18 Added support for the low density ISSI flash parts. + * 1.8 tjs 09/06/18 Fixed the code in XQspiPsu_GenFifoEntryData() for data + * transfer length up to 255 for reducing the extra loop. + * 1.9 tjs 11/22/17 Added the check for A72 and R5 processors (CR-987075) + * 1.9 tjs 04/17/18 Updated register addresses as per the latest revision + * of versal (CR#999610) + * 1.9 aru 01/17/19 Fixed the violations for MISRAC-2012 + * in safety mode .Done changes such as added U suffix, + * Declared pointer param as const. + * 1.9 nsk 02/01/19 Clear DMA_DST_ADDR_MSB register on 32bit machine, if the + * address is of only 32bit (CR#1020031) + * 1.9 nsk 02/01/19 Added QSPI idling support + * + * 1.9 akm 03/08/19 Set recommended clock and data tap delay values for 40MHZ, + * 100MHZ and 150MHZ frequencies(CR#1023187) + * 1.9 nsk 03/27/19 Update 64bit dma support + * (CR#1018102). + * 1.9 akm 04/03/19 Fixed data alignment warnings on IAR compiler. + * 1.9 akm 04/03/19 Fixed compilation error in XQspiPsu_LqspiRead() + * function on IAR compiler. + * 1.10 sk 08/20/19 Fixed issues in poll timeout feature. + * 1.10 akm 08/22/19 Set recommended tap delay values for 37.5MHZ, 100MHZ and + * 150MHZ frequencies in Versal. + * 1.10 akm 09/05/19 Added Multi Die Erase and Muti Die Read support. + * 1.11 akm 11/07/19 Removed LQSPI register access in Versal. + * 1.11 akm 11/15/19 Fixed Coverity deadcode warning in + * XQspipsu_Calculate_Tapdelay(). + * 1.11 akm 02/19/20 Added XQspiPsu_StartDmaTransfer() and XQspiPsu_CheckDmaDone() + * APIs for non-blocking transfer. + * 1.11 sd 01/02/20 Added clocking support + * 1.11 akm 03/09/20 Reorganize the source code, enable qspi controller and + * interrupts in XQspiPsu_CfgInitialize() API. + * 1.11 akm 03/26/20 Fixed issue by updating XQspiPsu_CfgInitialize to return + * XST_DEVICE_IS_STARTED instead of asserting, when the + * instance is already configured(CR#1058525). + * 1.12 akm 09/02/20 Updated the Makefile to support parallel make execution. + * 1.13 akm 01/04/21 Fix MISRA-C violations. + * 1.13 sne 04/23/21 Fixed doxygen warnings. + * 1.14 akm 06/24/21 Allow enough time for the controller to reset the FIFOs. + * 1.14 akm 08/12/21 Perform Dcache invalidate at the end of the DMA transfer. + * + * </pre> + * + ******************************************************************************/ + +#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" +#include "xil_cache.h" +#include "xil_mem.h" +#if defined (XCLOCKING) +#include "xil_clocking.h" +#endif + +/**************************** 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) (const void *CallBackRef, u32 StatusEvent, + u32 ByteCount); + +/** + * This typedef contains configuration information for a flash message. + */ +typedef struct { + u8 *TxBfrPtr; /**< Tx Buffer pointer */ + u8 *RxBfrPtr; /**< Rx Buffer pointer */ + u32 ByteCount; /**< Byte Count */ + u32 BusWidth; /**< Bus Width */ + u32 Flags; /**< Flags */ + u8 PollData; /**< Poll Data */ + u32 PollTimeout;/**< Poll Timeout */ + u8 PollStatusCmd; /**< Poll Status command */ + u8 PollBusMask; /**< Poll Bus mask */ + u64 RxAddr64bit; /**< 64 bit Rx address */ + u8 Xfer64bit; /**< 64 bit Tx address */ +} XQspiPsu_Msg; + +/** + * This typedef contains configuration information for the device. + */ +typedef struct { + u16 DeviceId; /**< Unique ID of device */ + UINTPTR 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 */ + u8 IsCacheCoherent; /**< Describes whether Cache Coherent or not */ +#if defined (XCLOCKING) + u32 RefClk; /**< Input clocks */ +#endif +} 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) */ + u64 RecvBuffer; /**< Buffer Address to receive (state) */ + u8 *GenFifoBufferPtr; /**< Gen FIFO entries */ + s32 TxBytes; /**< Number of bytes to transfer (state) */ + s32 RxBytes; /**< Number of bytes left to transfer(state) */ + s32 GenFifoEntries; /**< Number of Gen FIFO entries remaining */ + u32 IsBusy; /**< A transfer is in progress (state) */ + u32 ReadMode; /**< DMA or IO mode */ + u32 GenFifoCS; /**< Gen FIFO chip selection */ + u32 GenFifoBus; /**< Gen FIFO bus */ + s32 NumMsg; /**< Number of messages */ + s32 MsgCnt; /**< Message Count */ + s32 IsUnaligned; /**< Unaligned information */ + u8 IsManualstart; /**< Manual start information */ + XQspiPsu_Msg *Msg; /**< Message */ + XQspiPsu_StatusHandler StatusHandler; /**< Status Handler */ + void *StatusRef; /**< Callback reference for status handler */ +} XQspiPsu; + +/***************** Macros (Inline Functions) Definitions *********************/ + +/** + * Definitions for Intel, STM, Winbond and Spansion Serial Flash Device + * geometry. + */ +#define BYTES256_PER_PAGE 256U /**< 256 Bytes per Page */ +#define BYTES512_PER_PAGE 512U /**< 512 Bytes per Page */ +#define BYTES1024_PER_PAGE 1024U /**< 1024 Bytes per Page */ +#define PAGES16_PER_SECTOR 16U /**< 16 Pages per Sector */ +#define PAGES128_PER_SECTOR 128U /**< 128 Pages per Sector */ +#define PAGES256_PER_SECTOR 256U /**< 256 Pages per Sector */ +#define PAGES512_PER_SECTOR 512U /**< 512 Pages per Sector */ +#define PAGES1024_PER_SECTOR 1024U /**< 1024 Pages per Sector */ +#define NUM_OF_SECTORS2 2U /**< 2 Sectors */ +#define NUM_OF_SECTORS4 4U /**< 4 Sectors */ +#define NUM_OF_SECTORS8 8U /**< 8 Sector */ +#define NUM_OF_SECTORS16 16U /**< 16 Sectors */ +#define NUM_OF_SECTORS32 32U /**< 32 Sectors */ +#define NUM_OF_SECTORS64 64U /**< 64 Sectors */ +#define NUM_OF_SECTORS128 128U /**< 128 Sectors */ +#define NUM_OF_SECTORS256 256U /**< 256 Sectors */ +#define NUM_OF_SECTORS512 512U /**< 512 Sectors */ +#define NUM_OF_SECTORS1024 1024U /**< 1024 Sectors */ +#define NUM_OF_SECTORS2048 2048U /**< 2048 Sectors */ +#define NUM_OF_SECTORS4096 4096U /**< 4096 Sectors */ +#define NUM_OF_SECTORS8192 8192U /**< 8192 Sectors */ +#define SECTOR_SIZE_64K 0X10000U /**< 64K Sector */ +#define SECTOR_SIZE_128K 0X20000U /**< 128K Sector */ +#define SECTOR_SIZE_256K 0X40000U /**< 256K Sector */ +#define SECTOR_SIZE_512K 0X80000U /**< 512K Sector */ + + +#define XQSPIPSU_READMODE_DMA 0x0U /**< DMA read mode */ +#define XQSPIPSU_READMODE_IO 0x1U /**< IO read mode */ + +#define XQSPIPSU_SELECT_FLASH_CS_LOWER 0x1U /**< Select lower flash */ +#define XQSPIPSU_SELECT_FLASH_CS_UPPER 0x2U /**< Select upper flash */ +#define XQSPIPSU_SELECT_FLASH_CS_BOTH 0x3U /**< Select both flash */ + +#define XQSPIPSU_SELECT_FLASH_BUS_LOWER 0x1U /**< Select lower bus flash */ +#define XQSPIPSU_SELECT_FLASH_BUS_UPPER 0x2U /**< Select upper bus flash */ +#define XQSPIPSU_SELECT_FLASH_BUS_BOTH 0x3U /**< Select both bus flash */ + +#define XQSPIPSU_SELECT_MODE_SPI 0x1U /**< Select SPI mode */ +#define XQSPIPSU_SELECT_MODE_DUALSPI 0x2U /**< Select dual SPI mode */ +#define XQSPIPSU_SELECT_MODE_QUADSPI 0x4U /**< Select quad SPI mode */ + +#define XQSPIPSU_GENFIFO_CS_SETUP 0x05U /**< Chip select setup in GENFIO */ +#define XQSPIPSU_GENFIFO_CS_HOLD 0x04U /**< Chip select hold in GENFIFO */ + +#define XQSPIPSU_CLK_ACTIVE_LOW_OPTION 0x2U /**< Clk Active low option */ +#define XQSPIPSU_CLK_PHASE_1_OPTION 0x4U /**< Clk phase 1 option */ +#define XQSPIPSU_MANUAL_START_OPTION 0x8U /**< Manual start option */ +#if !defined (versal) +#define XQSPIPSU_LQSPI_MODE_OPTION 0x20U /**< LQSPI mode option */ + +#define XQSPIPSU_LQSPI_LESS_THEN_SIXTEENMB 1U /**< LQSPI less Than 16 MB */ +#endif + +#define XQSPIPSU_GENFIFO_EXP_START 0x100U /**< Genfifo start */ + +#define XQSPIPSU_DMA_BYTES_MAX 0x10000000U /**< DMA bytes max */ + +#define XQSPIPSU_CLK_PRESCALE_2 0x00U /**< Clock prescale 2 */ +#define XQSPIPSU_CLK_PRESCALE_4 0x01U /**< Clock prescale 4 */ +#define XQSPIPSU_CLK_PRESCALE_8 0x02U /**< Clock prescale 8 */ +#define XQSPIPSU_CLK_PRESCALE_16 0x03U /**< Clock prescale 16 */ +#define XQSPIPSU_CLK_PRESCALE_32 0x04U /**< Clock prescale 32 */ +#define XQSPIPSU_CLK_PRESCALE_64 0x05U /**< Clock prescale 64 */ +#define XQSPIPSU_CLK_PRESCALE_128 0x06U /**< Clock prescale 128 */ +#define XQSPIPSU_CLK_PRESCALE_256 0x07U /**< Clock prescale 256 */ +#define XQSPIPSU_CR_PRESC_MAXIMUM 7U /**< Prescale max */ + +#define XQSPIPSU_CONNECTION_MODE_SINGLE 0U /**< Single mode connection */ +#define XQSPIPSU_CONNECTION_MODE_STACKED 1U /**< Stacked mode connection */ +#define XQSPIPSU_CONNECTION_MODE_PARALLEL 2U /**< Parallel mode connection */ + +/*QSPI Frequencies*/ +#define XQSPIPSU_FREQ_37_5MHZ 37500000U /**< Frequency 375 Mhz */ +#define XQSPIPSU_FREQ_40MHZ 40000000U /**< Frequency 40 Mhz */ +#define XQSPIPSU_FREQ_100MHZ 100000000U /**< Frequency 100 Mhz */ +#define XQSPIPSU_FREQ_150MHZ 150000000U /**< Frequency 150 Mhz */ + +/* Add more flags as required */ +#define XQSPIPSU_MSG_FLAG_STRIPE 0x1U /**< Stripe Msg flag */ +#define XQSPIPSU_MSG_FLAG_RX 0x2U /**< Rx Msg flag */ +#define XQSPIPSU_MSG_FLAG_TX 0x4U /**< Tx Msg flag */ +#define XQSPIPSU_MSG_FLAG_POLL 0x8U /**< POLL Msg flag */ + +#define XQSPIPSU_RXADDR_OVER_32BIT 0x100000000U /**< Rx address over 32 bit */ + +#define XQSPIPSU_SET_WP 1 /**< GQSPI configuration to toggle WP of flash */ + +/** + * select QSPI controller + */ +#define XQspiPsu_Select(InstancePtr, Mask) \ + XQspiPsu_Out32(((InstancePtr)->Config.BaseAddress) + \ + XQSPIPSU_SEL_OFFSET, (Mask)) + +/** + * Enable QSPI Controller + */ +#define XQspiPsu_Enable(InstancePtr) \ + XQspiPsu_Out32(((InstancePtr)->Config.BaseAddress) + \ + XQSPIPSU_EN_OFFSET, XQSPIPSU_EN_MASK) + +/** + * Disable QSPI controller */ +#define XQspiPsu_Disable(InstancePtr) \ + XQspiPsu_Out32(((InstancePtr)->Config.BaseAddress) + \ + XQSPIPSU_EN_OFFSET, 0x0U) + +/** + * Read Configuration register of LQSPI Controller + */ +#if !defined (versal) +#define XQspiPsu_GetLqspiConfigReg(InstancePtr) \ + XQspiPsu_In32((XQSPIPS_BASEADDR) + \ + XQSPIPSU_LQSPI_CR_OFFSET) +#endif + +/*****************************************************************************/ +/** + * + * This function enables the manual start option + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * + * @return None + * + * @note None. + * + ******************************************************************************/ +static inline void XQspiPsu_ManualStartEnable(XQspiPsu *InstancePtr) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_ManualStartEnable\r\n"); +#endif + + if (InstancePtr->IsManualstart == (u8)TRUE) { +#ifdef DEBUG + xil_printf("\nManual Start\r\n"); +#endif + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET) | + XQSPIPSU_CFG_START_GEN_FIFO_MASK); + } +} +/*****************************************************************************/ +/** + * + * 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(const XQspiPsu *InstancePtr) +{ + u32 GenFifoEntry; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_GenFifoEntryCSAssert\r\n"); +#endif + + GenFifoEntry = 0x0U; + GenFifoEntry |= (XQSPIPSU_GENFIFO_MODE_SPI | InstancePtr->GenFifoCS | + InstancePtr->GenFifoBus | XQSPIPSU_GENFIFO_CS_SETUP); +#ifdef DEBUG + xil_printf("\nFifoEntry=%08x\r\n", GenFifoEntry); +#endif + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry); +} + +/*****************************************************************************/ +/** + * + * 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(const XQspiPsu *InstancePtr) +{ + u32 GenFifoEntry; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_GenFifoEntryCSDeAssert\r\n"); +#endif + + GenFifoEntry = 0x0U; + GenFifoEntry |= (XQSPIPSU_GENFIFO_MODE_SPI | InstancePtr->GenFifoBus | + XQSPIPSU_GENFIFO_CS_HOLD); +#ifdef DEBUG + xil_printf("\nFifoEntry=%08x\r\n", GenFifoEntry); +#endif + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry); +} + +/*****************************************************************************/ +/** + * + * 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 inline void StubStatusHandler(const void *CallBackRef, u32 StatusEvent, + u32 ByteCount) +{ + (const void) CallBackRef; + (void) StatusEvent; + (void) ByteCount; + + Xil_AssertVoidAlways(); +} +/************************** Function Prototypes ******************************/ + +/* Initialization and reset */ +XQspiPsu_Config *XQspiPsu_LookupConfig(u16 DeviceId); +s32 XQspiPsu_CfgInitialize(XQspiPsu *InstancePtr, + const XQspiPsu_Config *ConfigPtr, + UINTPTR EffectiveAddr); +void XQspiPsu_Reset(XQspiPsu *InstancePtr); +void XQspiPsu_Abort(XQspiPsu *InstancePtr); + +/* Transfer functions and handlers */ +s32 XQspiPsu_PolledTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 NumMsg); +s32 XQspiPsu_InterruptTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 NumMsg); +s32 XQspiPsu_InterruptHandler(XQspiPsu *InstancePtr); +void XQspiPsu_SetStatusHandler(XQspiPsu *InstancePtr, void *CallBackRef, + XQspiPsu_StatusHandler FuncPointer); + +/* Non blocking Transfer functions */ +s32 XQspiPsu_StartDmaTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 NumMsg); +s32 XQspiPsu_CheckDmaDone(XQspiPsu *InstancePtr); + +/* Configuration functions */ +s32 XQspiPsu_SetClkPrescaler(const XQspiPsu *InstancePtr, u8 Prescaler); +void XQspiPsu_SelectFlash(XQspiPsu *InstancePtr, u8 FlashCS, u8 FlashBus); +s32 XQspiPsu_SetOptions(XQspiPsu *InstancePtr, u32 Options); +s32 XQspiPsu_ClearOptions(XQspiPsu *InstancePtr, u32 Options); +u32 XQspiPsu_GetOptions(const XQspiPsu *InstancePtr); +s32 XQspiPsu_SetReadMode(XQspiPsu *InstancePtr, u32 Mode); +void XQspiPsu_SetWP(const XQspiPsu *InstancePtr, u8 Value); +void XQspiPsu_WriteProtectToggle(const XQspiPsu *InstancePtr, u32 Toggle); +void XQspiPsu_Idle(const XQspiPsu *InstancePtr); + +/************************** Variable Prototypes ******************************/ + +/** + * This table contains configuration information for each QSPIPSU device + * in the system. + */ +#ifndef __rtems__ +extern XQspiPsu_Config XQspiPsu_ConfigTable[XPAR_XQSPIPSU_NUM_INSTANCES]; +#endif /* __rtems__ */ + +#ifdef __cplusplus +} +#endif + + +#endif /* XQSPIPSU_H_ */ +/** @} */ diff --git a/bsps/include/dev/spi/xqspipsu_control.h b/bsps/include/dev/spi/xqspipsu_control.h new file mode 100644 index 0000000000..76b0a8ce7c --- /dev/null +++ b/bsps/include/dev/spi/xqspipsu_control.h @@ -0,0 +1,102 @@ +/****************************************************************************** +* Copyright (C) 2020 - 2022 Xilinx, Inc. All rights reserved. +* SPDX-License-Identifier: MIT +******************************************************************************/ + + +/*****************************************************************************/ +/** + * + * @file xqspipsu_control.h + * @addtogroup Overview + * @{ + * + * 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 + * + * + * <pre> + * MODIFICATION HISTORY: + * + * Ver Who Date Changes + * ----- --- -------- -----------------------------------------------. + * 1.11 akm 03/09/20 First release + * 1.13 akm 01/04/21 Fix MISRA-C violations. + * 1.15 akm 03/03/22 Enable tapdelay settings for applications on + * Microblaze platform. + * + * </pre> + * + ******************************************************************************/ + +/** @cond INTERNAL */ +#ifndef XQSPIPSU_CONTROL_H_ /**< prevent circular inclusions */ +#define XQSPIPSU_CONTROL_H_ /**< by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xqspipsu.h" + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +#if defined (ARMR5) || defined (__aarch64__) || defined (__MICROBLAZE__) +#define TAPDLY_BYPASS_VALVE_40MHZ 0x01U +#define TAPDLY_BYPASS_VALVE_100MHZ 0x01U +#define USE_DLY_LPBK 0x01U +#define USE_DATA_DLY_ADJ 0x01U +#define DATA_DLY_ADJ_DLY 0X02U +#define LPBK_DLY_ADJ_DLY0 0X02U +#define LPBK_DLY_ADJ_DLY1 0X02U +#endif + +#ifdef __MICROBLAZE__ +#define XPS_SYS_CTRL_BASEADDR 0xFF180000U /**< System controller Baseaddress */ +#endif +/************************** Function Prototypes ******************************/ +void XQspiPsu_GenFifoEntryData(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg); +u32 XQspiPsu_SetIOMode(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg); +void XQspiPsu_IORead(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 StatusReg); +void XQspiPsu_PollDataConfig(XQspiPsu *InstancePtr, XQspiPsu_Msg *FlashMsg); +void XQspiPsu_TXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg); +void XQspiPsu_SetupRxDma(const XQspiPsu *InstancePtr, + XQspiPsu_Msg *Msg); +void XQspiPsu_Setup64BRxDma(const XQspiPsu *InstancePtr, + XQspiPsu_Msg *Msg); +void XQspiPsu_RXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg); +void XQspiPsu_TXRXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 *GenFifoEntry); +void XQspiPsu_GenFifoEntryDataLen(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 *GenFifoEntry); +u32 XQspiPsu_CreatePollDataConfig(const XQspiPsu *InstancePtr, + const XQspiPsu_Msg *FlashMsg); +void XQspiPsu_PollDataHandler(XQspiPsu *InstancePtr, u32 StatusReg); +u32 XQspiPsu_SelectSpiMode(u8 SpiMode); +void XQspiPsu_SetDefaultConfig(XQspiPsu *InstancePtr); +void XQspiPsu_FillTxFifo(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, u32 Size); +void XQspiPsu_ReadRxFifo(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, s32 Size); + +#if defined (ARMR5) || defined (__aarch64__) || defined (__MICROBLAZE__) +s32 XQspipsu_Set_TapDelay(const XQspiPsu *InstancePtr, u32 TapdelayBypass, + u32 LPBKDelay, u32 Datadelay); +s32 XQspipsu_Calculate_Tapdelay(const XQspiPsu *InstancePtr, u8 Prescaler); +#endif + +#ifdef __cplusplus +} +#endif + + +#endif /* XQSPIPSU_CONTROL_H_ */ +/** @endcond */ +/** @} */ diff --git a/bsps/include/dev/spi/xqspipsu_flash_config.h b/bsps/include/dev/spi/xqspipsu_flash_config.h new file mode 100644 index 0000000000..323b223ee3 --- /dev/null +++ b/bsps/include/dev/spi/xqspipsu_flash_config.h @@ -0,0 +1,355 @@ +/****************************************************************************** +* Copyright (C) 2020 - 2022 Xilinx, Inc. All rights reserved. +* SPDX-License-Identifier: MIT +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xqspipsu_flash_config.h +* +* +* This file contains flash configuration table and flash related defines. +* This file should be included in the example files and compiled along with +* the examples (*.c). +* +* @note +* +* None. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- -------- ----------------------------------------------- +* 1.12 akm 07/07/20 First release +* 1.12 akm 07/07/20 Add support for Macronix flash(MX66U2G45G, MX66L2G45G) +* and ISSI flash(IS25LP01G, IS25WP01G) parts. +* 1.13 akm 12/10/20 Set Read command as per the qspi bus width. +* 1.14 akm 07/16/21 Enable Quad Mode for Winbond flashes. +* 1.15 akm 11/19/21 Fix read/write failures on Spansion flash parts. +* +*</pre> +* + ******************************************************************************/ + +#ifndef XQSPIPSU_FLASH_CONFIG_H_ /* prevent circular inclusions */ +#define XQSPIPSU_FLASH_CONFIG_H_ /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xparameters.h" /* SDK generated parameters */ +#include "xqspipsu.h" /* QSPIPSU device driver */ + +/************************** 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 VOLATILE_WRITE_ENABLE_CMD 0x50 +#define QUAD_MODE_ENABLE_BIT 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 ENTER_4B_ADDR_MODE 0xB7 +#define EXIT_4B_ADDR_MODE 0xE9 +#define EXIT_4B_ADDR_MODE_ISSI 0x29 +/* 4-byte address opcodes */ +#define READ_CMD_4B 0x13 +#define FAST_READ_CMD_4B 0x0C +#define DUAL_READ_CMD_4B 0x3C +#define QUAD_READ_CMD_4B 0x6C +#define WRITE_CMD_4B 0x12 +#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 + +#define WRITE_STATUS_REG_2_CMD 0x31 +#define READ_STATUS_REG_2_CMD 0x35 +#define WB_QUAD_MODE_ENABLE_BIT 0x01 + +/* + * 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 + +/* + * Bus width + */ +#define BUSWIDTH_SINGLE 0 +#define BUSWIDTH_DOUBLE 1 + +/* + * 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 SPANSION_ID_BYTE0 0x01 +#define WINBOND_ID_BYTE0 0xEF +#define MACRONIX_ID_BYTE0 0xC2 +#define ISSI_ID_BYTE0 0x9D + +/**************************** Type Definitions *******************************/ + +typedef struct{ + u32 jedec_id; /* JEDEC ID */ + + 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 + */ + u32 SectMask; /* Mask to get sector start address */ + u8 NumDie; /* No. of die forming a single flash */ +} FlashInfo; + +/************************** Variable Definitions *****************************/ +FlashInfo Flash_Config_Table[] = { + /* Spansion */ + /*s25fl064l*/ + {0x016017, SECTOR_SIZE_64K, NUM_OF_SECTORS128, BYTES256_PER_PAGE, + 0x8000, 0x800000, 0xFFFF0000, 1}, + /*s25fl128l*/ + {0x016018, SECTOR_SIZE_64K, NUM_OF_SECTORS256, BYTES256_PER_PAGE, + 0x10000, 0x1000000, 0xFFFF0000, 1}, + /*s25fl256l*/ + {0x016019, SECTOR_SIZE_64K, NUM_OF_SECTORS512, BYTES256_PER_PAGE, + 0x20000, 0x2000000, 0xFFFF0000, 1}, + /*s25fl512s*/ + {0x010220, SECTOR_SIZE_64K, NUM_OF_SECTORS1024, BYTES256_PER_PAGE, + 0x40000, 0x4000000, 0xFFFF0000, 1}, + /* Spansion 1Gbit is handled as 512Mbit stacked */ + /* Micron */ + /*n25q128a11*/ + {0x20bb18, SECTOR_SIZE_64K, NUM_OF_SECTORS256, BYTES256_PER_PAGE, + 0x10000, 0x1000000, 0xFFFF0000, 1}, + /*n25q128a13*/ + {0x20ba18, SECTOR_SIZE_64K, NUM_OF_SECTORS256, BYTES256_PER_PAGE, + 0x10000, 0x1000000, 0xFFFF0000, 1}, + /*n25q256ax1*/ + {0x20bb19, SECTOR_SIZE_64K, NUM_OF_SECTORS512, BYTES256_PER_PAGE, + 0x20000, 0x2000000, 0xFFFF0000, 1}, + /*n25q256a*/ + {0x20ba19, SECTOR_SIZE_64K, NUM_OF_SECTORS512, BYTES256_PER_PAGE, + 0x20000, 0x2000000, 0xFFFF0000, 1}, + /*mt25qu512a*/ + {0x20bb20, SECTOR_SIZE_64K, NUM_OF_SECTORS1024, BYTES256_PER_PAGE, + 0x40000, 0x4000000, 0xFFFF0000, 2}, + /*n25q512ax3*/ + {0x20ba20, SECTOR_SIZE_64K, NUM_OF_SECTORS1024, BYTES256_PER_PAGE, + 0x40000, 0x4000000, 0xFFFF0000, 2}, + /*n25q00a*/ + {0x20bb21, SECTOR_SIZE_64K, NUM_OF_SECTORS2048, BYTES256_PER_PAGE, + 0x80000, 0x8000000, 0xFFFF0000, 4}, + /*n25q00*/ + {0x20ba21, SECTOR_SIZE_64K, NUM_OF_SECTORS2048, BYTES256_PER_PAGE, + 0x80000, 0x8000000, 0xFFFF0000, 4}, + /*mt25qu02g*/ + {0x20bb22, SECTOR_SIZE_64K, NUM_OF_SECTORS4096, BYTES256_PER_PAGE, + 0x100000, 0x10000000, 0xFFFF0000, 4}, + /*mt25ql02g*/ + {0x20ba22, SECTOR_SIZE_64K, NUM_OF_SECTORS4096, BYTES256_PER_PAGE, + 0x100000, 0x10000000, 0xFFFF0000, 4}, + /* Winbond */ + /*w25q128fw*/ + {0xef6018, SECTOR_SIZE_64K, NUM_OF_SECTORS256, BYTES256_PER_PAGE, + 0x10000, 0x1000000, 0xFFFF0000, 1}, + /*w25q128jv*/ + {0xef7018, SECTOR_SIZE_64K, NUM_OF_SECTORS256, BYTES256_PER_PAGE, + 0x10000, 0x1000000, 0xFFFF0000, 1}, + /*w25h02jv*/ + {0xef9022, SECTOR_SIZE_64K, NUM_OF_SECTORS4096, BYTES256_PER_PAGE, + 0x100000, 0x10000000, 0xFFFF0000, 4}, + /* Macronix */ + /*mx66l1g45g*/ + {0xc2201b, SECTOR_SIZE_64K, NUM_OF_SECTORS2048, BYTES256_PER_PAGE, + 0x80000, 0x8000000, 0xFFFF0000, 4}, + /*mx66l1g55g*/ + {0xc2261b, SECTOR_SIZE_64K, NUM_OF_SECTORS2048, BYTES256_PER_PAGE, + 0x80000, 0x8000000, 0xFFFF0000, 4}, + /*mx66u1g45g*/ + {0xc2253b, SECTOR_SIZE_64K, NUM_OF_SECTORS2048, BYTES256_PER_PAGE, + 0x80000, 0x8000000, 0xFFFF0000, 4}, + /*mx66l2g45g*/ + {0xc2201c, SECTOR_SIZE_64K, NUM_OF_SECTORS4096, BYTES256_PER_PAGE, + 0x100000, 0x10000000, 0xFFFF0000, 1}, + /*mx66u2g45g*/ + {0xc2253c, SECTOR_SIZE_64K, NUM_OF_SECTORS4096, BYTES256_PER_PAGE, + 0x100000, 0x10000000, 0xFFFF0000, 1}, + /* ISSI */ + /*is25wp080d*/ + {0x9d7014, SECTOR_SIZE_64K, NUM_OF_SECTORS16, BYTES256_PER_PAGE, + 0x1000, 0x100000, 0xFFFF0000, 1}, + /*is25lp080d*/ + {0x9d6014, SECTOR_SIZE_64K, NUM_OF_SECTORS16, BYTES256_PER_PAGE, + 0x1000, 0x100000, 0xFFFF0000, 1}, + /*is25wp016d*/ + {0x9d7015, SECTOR_SIZE_64K, NUM_OF_SECTORS32, BYTES256_PER_PAGE, + 0x2000, 0x200000, 0xFFFF0000, 1}, + /*is25lp016d*/ + {0x9d6015, SECTOR_SIZE_64K, NUM_OF_SECTORS32, BYTES256_PER_PAGE, + 0x2000, 0x200000, 0xFFFF0000, 1}, + /*is25wp032*/ + {0x9d7016, SECTOR_SIZE_64K, NUM_OF_SECTORS64, BYTES256_PER_PAGE, + 0x4000, 0x400000, 0xFFFF0000, 1}, + /*is25lp032*/ + {0x9d6016, SECTOR_SIZE_64K, NUM_OF_SECTORS64, BYTES256_PER_PAGE, + 0x4000, 0x400000, 0xFFFF0000, 1}, + /*is25wp064*/ + {0x9d7017, SECTOR_SIZE_64K, NUM_OF_SECTORS128, BYTES256_PER_PAGE, + 0x8000, 0x800000, 0xFFFF0000, 1}, + /*is25lp064*/ + {0x9d6017, SECTOR_SIZE_64K, NUM_OF_SECTORS128, BYTES256_PER_PAGE, + 0x8000, 0x800000, 0xFFFF0000, 1}, + /*is25wp128*/ + {0x9d7018, SECTOR_SIZE_64K, NUM_OF_SECTORS256, BYTES256_PER_PAGE, + 0x10000, 0x1000000, 0xFFFF0000, 1}, + /*is25lp128*/ + {0x9d6018, SECTOR_SIZE_64K, NUM_OF_SECTORS256, BYTES256_PER_PAGE, + 0x10000, 0x1000000, 0xFFFF0000, 1}, + /*is25lp256d*/ + {0x9d6019, SECTOR_SIZE_64K, NUM_OF_SECTORS512, BYTES256_PER_PAGE, + 0x20000, 0x2000000, 0xFFFF0000, 1}, + /*is25wp256d*/ + {0x9d7019, SECTOR_SIZE_64K, NUM_OF_SECTORS512, BYTES256_PER_PAGE, + 0x20000, 0x2000000, 0xFFFF0000, 1}, + /*is25lp512m*/ + {0x9d601a, SECTOR_SIZE_64K, NUM_OF_SECTORS1024, BYTES256_PER_PAGE, + 0x40000, 0x4000000, 0xFFFF0000, 2}, + /*is25wp512m*/ + {0x9d701a, SECTOR_SIZE_64K, NUM_OF_SECTORS1024, BYTES256_PER_PAGE, + 0x40000, 0x4000000, 0xFFFF0000, 2}, + /*is25lp01g*/ + {0x9d601b, SECTOR_SIZE_64K, NUM_OF_SECTORS2048, BYTES256_PER_PAGE, + 0x80000, 0x8000000, 0xFFFF0000, 1}, + /*is25wp01g*/ + {0x9d701b, SECTOR_SIZE_64K, NUM_OF_SECTORS2048, BYTES256_PER_PAGE, + 0x80000, 0x8000000, 0xFFFF0000, 1} +}; + +static INLINE u32 CalculateFCTIndex(u32 ReadId, u32 *FCTIndex) +{ + u32 Index; + + for (Index = 0; Index < sizeof(Flash_Config_Table)/sizeof(Flash_Config_Table[0]); + Index++) { + if (ReadId == Flash_Config_Table[Index].jedec_id) { + *FCTIndex = Index; + return XST_SUCCESS; + } + } + + return XST_FAILURE; +} + +#ifdef __cplusplus +} +#endif + +#endif /* XQSPIPSU_FLASH_CONFIG_H_ */ +/** @} */ diff --git a/bsps/include/dev/spi/xqspipsu_hw.h b/bsps/include/dev/spi/xqspipsu_hw.h new file mode 100644 index 0000000000..a798f9bb89 --- /dev/null +++ b/bsps/include/dev/spi/xqspipsu_hw.h @@ -0,0 +1,1006 @@ +/****************************************************************************** +* Copyright (C) 2014 - 2022 Xilinx, Inc. All rights reserved. +* SPDX-License-Identifier: MIT +******************************************************************************/ + +/*****************************************************************************/ +/** +* +* @file xqspipsu_hw.h +* @addtogroup Overview +* @{ +* +* This file contains low level access functions using the base address +* directly without an instance. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- -------- -----------------------------------------------. +* 1.0 hk 08/21/14 First release +* hk 03/18/15 Add DMA status register masks required. +* sk 04/24/15 Modified the code according to MISRAC-2012. +* 1.2 nsk 07/01/16 Added LQSPI supported Masks +* rk 07/15/16 Added support for TapDelays at different frequencies. +* 1.7 tjs 03/14/18 Added support in EL1 NS mode. +* 1.9 tjs 04/17/18 Updated register addresses as per the latest revision +* of versal (CR#999610) +* 1.9 aru 01/17/19 Fixed the violations for MISRAC-2012 +* in safety mode .Done changes such as added U suffix +* 1.11 akm 11/07/19 Removed LQSPI register access in Versal. +* 1.15 akm 12/02/21 Fix Doxygen warnings. +* +* </pre> +* +******************************************************************************/ +#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 *****************************/ +/** + * @name Device Base Address + * Below macros gives QSPI, QSPIPSU base address. + * @{ + */ +/** + * QSPI Base Address + */ +#if defined (versal) +#define XQSPIPS_BASEADDR 0XF1030000U +#else +#define XQSPIPS_BASEADDR 0XFF0F0000U +#endif + +#if defined (versal) +#define XQSPIPSU_BASEADDR 0XF1030100U +#else +#define XQSPIPSU_BASEADDR 0xFF0F0100U +#endif +#define XQSPIPSU_OFFSET 0x100U +/** @} */ + +/** + * @name XQSPIPS Enable Register information + * QSPIPSU Enable Register + * @{ + */ +/** + * Register: XQSPIPS_EN_REG + */ +#define XQSPIPS_EN_REG ( ( XQSPIPS_BASEADDR ) + 0X00000014U ) +#define XQSPIPS_EN_SHIFT 0U +#define XQSPIPS_EN_WIDTH 1U +#define XQSPIPS_EN_MASK 0X00000001U +/** @} */ + +/** + * @name XQSPIPSU configuration Register information + * This register contains bits for configuring GQSPI controller + * @{ + */ +/** + * Register: XQSPIPSU_CFG + */ +#define XQSPIPSU_CFG_OFFSET 0X00000000U + +#define XQSPIPSU_CFG_MODE_EN_SHIFT 30U +#define XQSPIPSU_CFG_MODE_EN_WIDTH 2U +#define XQSPIPSU_CFG_MODE_EN_MASK 0XC0000000U +#define XQSPIPSU_CFG_MODE_EN_DMA_MASK 0X80000000U + +#define XQSPIPSU_CFG_GEN_FIFO_START_MODE_SHIFT 29U +#define XQSPIPSU_CFG_GEN_FIFO_START_MODE_WIDTH 1U +#define XQSPIPSU_CFG_GEN_FIFO_START_MODE_MASK 0X20000000U + +#define XQSPIPSU_CFG_START_GEN_FIFO_SHIFT 28U +#define XQSPIPSU_CFG_START_GEN_FIFO_WIDTH 1U +#define XQSPIPSU_CFG_START_GEN_FIFO_MASK 0X10000000U + +#define XQSPIPSU_CFG_ENDIAN_SHIFT 26U +#define XQSPIPSU_CFG_ENDIAN_WIDTH 1U +#define XQSPIPSU_CFG_ENDIAN_MASK 0X04000000U + +#define XQSPIPSU_CFG_EN_POLL_TO_SHIFT 20U +#define XQSPIPSU_CFG_EN_POLL_TO_WIDTH 1U +#define XQSPIPSU_CFG_EN_POLL_TO_MASK 0X00100000U + +#define XQSPIPSU_CFG_WP_HOLD_SHIFT 19U +#define XQSPIPSU_CFG_WP_HOLD_WIDTH 1U +#define XQSPIPSU_CFG_WP_HOLD_MASK 0X00080000U + +#define XQSPIPSU_CFG_BAUD_RATE_DIV_SHIFT 3U +#define XQSPIPSU_CFG_BAUD_RATE_DIV_WIDTH 3U +#define XQSPIPSU_CFG_BAUD_RATE_DIV_MASK 0X00000038U + +#define XQSPIPSU_CFG_CLK_PHA_SHIFT 2U +#define XQSPIPSU_CFG_CLK_PHA_WIDTH 1U +#define XQSPIPSU_CFG_CLK_PHA_MASK 0X00000004U + +#define XQSPIPSU_CFG_CLK_POL_SHIFT 1U +#define XQSPIPSU_CFG_CLK_POL_WIDTH 1U +#define XQSPIPSU_CFG_CLK_POL_MASK 0X00000002U +/** @} */ + +/** + * @name XQSPIPSU LQSPI Register information + * This register contains bits for configuring LQSPI + * @{ + */ +/** + * Register: XQSPIPSU_LQSPI + */ +#if !defined (versal) +#define XQSPIPSU_LQSPI_CR_OFFSET 0X000000A0U +#define XQSPIPSU_LQSPI_CR_LINEAR_MASK 0x80000000U /**< LQSPI mode enable */ +#define XQSPIPSU_LQSPI_CR_TWO_MEM_MASK 0x40000000U /**< Both memories or one */ +#define XQSPIPSU_LQSPI_CR_SEP_BUS_MASK 0x20000000U /**< Separate memory bus */ +#define XQSPIPSU_LQSPI_CR_U_PAGE_MASK 0x10000000U /**< Upper memory page */ +#define XQSPIPSU_LQSPI_CR_ADDR_32BIT_MASK 0x01000000U /**< Upper memory page */ +#define XQSPIPSU_LQSPI_CR_MODE_EN_MASK 0x02000000U /**< Enable mode bits */ +#define XQSPIPSU_LQSPI_CR_MODE_ON_MASK 0x01000000U /**< Mode on */ +#define XQSPIPSU_LQSPI_CR_MODE_BITS_MASK 0x00FF0000U /**< Mode value for dual I/O + or quad I/O */ +#define XQSPIPS_LQSPI_CR_INST_MASK 0x000000FFU /**< Read instr code */ +#define XQSPIPS_LQSPI_CR_RST_STATE 0x80000003U /**< Default LQSPI CR value */ +#define XQSPIPS_LQSPI_CR_4_BYTE_STATE 0x88000013U /**< Default 4 Byte LQSPI CR value */ +#define XQSPIPS_LQSPI_CFG_RST_STATE 0x800238C1U /**< Default LQSPI CFG value */ +#endif +/** @} */ + +/** + * @name XQSPIPSU Interrupt Status Register information + * QSPIPSU Interrupt Status Register + * @{ + */ +/** + * Register: XQSPIPSU_ISR + */ +#define XQSPIPSU_ISR_OFFSET 0X00000004U + +#define XQSPIPSU_ISR_RXEMPTY_SHIFT 11U +#define XQSPIPSU_ISR_RXEMPTY_WIDTH 1U +#define XQSPIPSU_ISR_RXEMPTY_MASK 0X00000800U + +#define XQSPIPSU_ISR_GENFIFOFULL_SHIFT 10U +#define XQSPIPSU_ISR_GENFIFOFULL_WIDTH 1U +#define XQSPIPSU_ISR_GENFIFOFULL_MASK 0X00000400U + +#define XQSPIPSU_ISR_GENFIFONOT_FULL_SHIFT 9U +#define XQSPIPSU_ISR_GENFIFONOT_FULL_WIDTH 1U +#define XQSPIPSU_ISR_GENFIFONOT_FULL_MASK 0X00000200U + +#define XQSPIPSU_ISR_TXEMPTY_SHIFT 8U +#define XQSPIPSU_ISR_TXEMPTY_WIDTH 1U +#define XQSPIPSU_ISR_TXEMPTY_MASK 0X00000100U + +#define XQSPIPSU_ISR_GENFIFOEMPTY_SHIFT 7U +#define XQSPIPSU_ISR_GENFIFOEMPTY_WIDTH 1U +#define XQSPIPSU_ISR_GENFIFOEMPTY_MASK 0X00000080U + +#define XQSPIPSU_ISR_RXFULL_SHIFT 5U +#define XQSPIPSU_ISR_RXFULL_WIDTH 1U +#define XQSPIPSU_ISR_RXFULL_MASK 0X00000020U + +#define XQSPIPSU_ISR_RXNEMPTY_SHIFT 4U +#define XQSPIPSU_ISR_RXNEMPTY_WIDTH 1U +#define XQSPIPSU_ISR_RXNEMPTY_MASK 0X00000010U + +#define XQSPIPSU_ISR_TXFULL_SHIFT 3U +#define XQSPIPSU_ISR_TXFULL_WIDTH 1U +#define XQSPIPSU_ISR_TXFULL_MASK 0X00000008U + +#define XQSPIPSU_ISR_TXNOT_FULL_SHIFT 2U +#define XQSPIPSU_ISR_TXNOT_FULL_WIDTH 1U +#define XQSPIPSU_ISR_TXNOT_FULL_MASK 0X00000004U + +#define XQSPIPSU_ISR_POLL_TIME_EXPIRE_SHIFT 1U +#define XQSPIPSU_ISR_POLL_TIME_EXPIRE_WIDTH 1U +#define XQSPIPSU_ISR_POLL_TIME_EXPIRE_MASK 0X00000002U + +#define XQSPIPSU_ISR_WR_TO_CLR_MASK 0X00000002U +/** @} */ + +/** + * @name XQSPIPSU Interrupt Enable Register information + * This register bits for enabling interrupts + * @{ + */ +/** + * Register: XQSPIPSU_IER + */ +#define XQSPIPSU_IER_OFFSET 0X00000008U + +#define XQSPIPSU_IER_RXEMPTY_SHIFT 11U +#define XQSPIPSU_IER_RXEMPTY_WIDTH 1U +#define XQSPIPSU_IER_RXEMPTY_MASK 0X00000800U + +#define XQSPIPSU_IER_GENFIFOFULL_SHIFT 10U +#define XQSPIPSU_IER_GENFIFOFULL_WIDTH 1U +#define XQSPIPSU_IER_GENFIFOFULL_MASK 0X00000400U + +#define XQSPIPSU_IER_GENFIFONOT_FULL_SHIFT 9U +#define XQSPIPSU_IER_GENFIFONOT_FULL_WIDTH 1U +#define XQSPIPSU_IER_GENFIFONOT_FULL_MASK 0X00000200U + +#define XQSPIPSU_IER_TXEMPTY_SHIFT 8U +#define XQSPIPSU_IER_TXEMPTY_WIDTH 1U +#define XQSPIPSU_IER_TXEMPTY_MASK 0X00000100U + +#define XQSPIPSU_IER_GENFIFOEMPTY_SHIFT 7U +#define XQSPIPSU_IER_GENFIFOEMPTY_WIDTH 1U +#define XQSPIPSU_IER_GENFIFOEMPTY_MASK 0X00000080U + +#define XQSPIPSU_IER_RXFULL_SHIFT 5U +#define XQSPIPSU_IER_RXFULL_WIDTH 1U +#define XQSPIPSU_IER_RXFULL_MASK 0X00000020U + +#define XQSPIPSU_IER_RXNEMPTY_SHIFT 4U +#define XQSPIPSU_IER_RXNEMPTY_WIDTH 1U +#define XQSPIPSU_IER_RXNEMPTY_MASK 0X00000010U + +#define XQSPIPSU_IER_TXFULL_SHIFT 3U +#define XQSPIPSU_IER_TXFULL_WIDTH 1U +#define XQSPIPSU_IER_TXFULL_MASK 0X00000008U + +#define XQSPIPSU_IER_TXNOT_FULL_SHIFT 2U +#define XQSPIPSU_IER_TXNOT_FULL_WIDTH 1U +#define XQSPIPSU_IER_TXNOT_FULL_MASK 0X00000004U + +#define XQSPIPSU_IER_POLL_TIME_EXPIRE_SHIFT 1U +#define XQSPIPSU_IER_POLL_TIME_EXPIRE_WIDTH 1U +#define XQSPIPSU_IER_POLL_TIME_EXPIRE_MASK 0X00000002U +/** @} */ + +/** + * @name XQSPIPSU Interrupt Disable Register information + * This register bits for disabling interrupts + * @{ + */ +/** + * Register: XQSPIPSU_IDR + */ +#define XQSPIPSU_IDR_OFFSET 0X0000000CU + +#define XQSPIPSU_IDR_RXEMPTY_SHIFT 11U +#define XQSPIPSU_IDR_RXEMPTY_WIDTH 1U +#define XQSPIPSU_IDR_RXEMPTY_MASK 0X00000800U + +#define XQSPIPSU_IDR_GENFIFOFULL_SHIFT 10U +#define XQSPIPSU_IDR_GENFIFOFULL_WIDTH 1U +#define XQSPIPSU_IDR_GENFIFOFULL_MASK 0X00000400U + +#define XQSPIPSU_IDR_GENFIFONOT_FULL_SHIFT 9U +#define XQSPIPSU_IDR_GENFIFONOT_FULL_WIDTH 1U +#define XQSPIPSU_IDR_GENFIFONOT_FULL_MASK 0X00000200U + +#define XQSPIPSU_IDR_TXEMPTY_SHIFT 8U +#define XQSPIPSU_IDR_TXEMPTY_WIDTH 1U +#define XQSPIPSU_IDR_TXEMPTY_MASK 0X00000100U + +#define XQSPIPSU_IDR_GENFIFOEMPTY_SHIFT 7U +#define XQSPIPSU_IDR_GENFIFOEMPTY_WIDTH 1U +#define XQSPIPSU_IDR_GENFIFOEMPTY_MASK 0X00000080U + +#define XQSPIPSU_IDR_RXFULL_SHIFT 5U +#define XQSPIPSU_IDR_RXFULL_WIDTH 1U +#define XQSPIPSU_IDR_RXFULL_MASK 0X00000020U + +#define XQSPIPSU_IDR_RXNEMPTY_SHIFT 4U +#define XQSPIPSU_IDR_RXNEMPTY_WIDTH 1U +#define XQSPIPSU_IDR_RXNEMPTY_MASK 0X00000010U + +#define XQSPIPSU_IDR_TXFULL_SHIFT 3U +#define XQSPIPSU_IDR_TXFULL_WIDTH 1U +#define XQSPIPSU_IDR_TXFULL_MASK 0X00000008U + +#define XQSPIPSU_IDR_TXNOT_FULL_SHIFT 2U +#define XQSPIPSU_IDR_TXNOT_FULL_WIDTH 1U +#define XQSPIPSU_IDR_TXNOT_FULL_MASK 0X00000004U + +#define XQSPIPSU_IDR_POLL_TIME_EXPIRE_SHIFT 1U +#define XQSPIPSU_IDR_POLL_TIME_EXPIRE_WIDTH 1U +#define XQSPIPSU_IDR_POLL_TIME_EXPIRE_MASK 0X00000002U + +#define XQSPIPSU_IDR_ALL_MASK 0X0FBEU +/** @} */ + +/** + * @name XQSPIPSU Interrupt Mask Register information + * This register bits for masking interrupts + * @{ + */ +/** + * Register: XQSPIPSU_IMR + */ +#define XQSPIPSU_IMR_OFFSET 0X00000010U + +#define XQSPIPSU_IMR_RXEMPTY_SHIFT 11U +#define XQSPIPSU_IMR_RXEMPTY_WIDTH 1U +#define XQSPIPSU_IMR_RXEMPTY_MASK 0X00000800U + +#define XQSPIPSU_IMR_GENFIFOFULL_SHIFT 10U +#define XQSPIPSU_IMR_GENFIFOFULL_WIDTH 1U +#define XQSPIPSU_IMR_GENFIFOFULL_MASK 0X00000400U + +#define XQSPIPSU_IMR_GENFIFONOT_FULL_SHIFT 9U +#define XQSPIPSU_IMR_GENFIFONOT_FULL_WIDTH 1U +#define XQSPIPSU_IMR_GENFIFONOT_FULL_MASK 0X00000200U + +#define XQSPIPSU_IMR_TXEMPTY_SHIFT 8U +#define XQSPIPSU_IMR_TXEMPTY_WIDTH 1U +#define XQSPIPSU_IMR_TXEMPTY_MASK 0X00000100U + +#define XQSPIPSU_IMR_GENFIFOEMPTY_SHIFT 7U +#define XQSPIPSU_IMR_GENFIFOEMPTY_WIDTH 1U +#define XQSPIPSU_IMR_GENFIFOEMPTY_MASK 0X00000080U + +#define XQSPIPSU_IMR_RXFULL_SHIFT 5U +#define XQSPIPSU_IMR_RXFULL_WIDTH 1U +#define XQSPIPSU_IMR_RXFULL_MASK 0X00000020U + +#define XQSPIPSU_IMR_RXNEMPTY_SHIFT 4U +#define XQSPIPSU_IMR_RXNEMPTY_WIDTH 1U +#define XQSPIPSU_IMR_RXNEMPTY_MASK 0X00000010U + +#define XQSPIPSU_IMR_TXFULL_SHIFT 3U +#define XQSPIPSU_IMR_TXFULL_WIDTH 1U +#define XQSPIPSU_IMR_TXFULL_MASK 0X00000008U + +#define XQSPIPSU_IMR_TXNOT_FULL_SHIFT 2U +#define XQSPIPSU_IMR_TXNOT_FULL_WIDTH 1U +#define XQSPIPSU_IMR_TXNOT_FULL_MASK 0X00000004U + +#define XQSPIPSU_IMR_POLL_TIME_EXPIRE_SHIFT 1U +#define XQSPIPSU_IMR_POLL_TIME_EXPIRE_WIDTH 1U +#define XQSPIPSU_IMR_POLL_TIME_EXPIRE_MASK 0X00000002U +/** @} */ + +/** + * @name XQSPIPSU Enable Register information + * This register bits for enabling QSPI controller + * @{ + */ +/** + * Register: XQSPIPSU_EN_REG + */ +#define XQSPIPSU_EN_OFFSET 0X00000014U + +#define XQSPIPSU_EN_SHIFT 0U +#define XQSPIPSU_EN_WIDTH 1U +#define XQSPIPSU_EN_MASK 0X00000001U +/** @} */ + +/** + * @name XQSPIPSU TX Data Register information + * This register bits for configuring TXFIFO + * @{ + */ +/** + * Register: XQSPIPSU_TXD + */ +#define XQSPIPSU_TXD_OFFSET 0X0000001CU + +#define XQSPIPSU_TXD_SHIFT 0U +#define XQSPIPSU_TXD_WIDTH 32U +#define XQSPIPSU_TXD_MASK 0XFFFFFFFFU + +#define XQSPIPSU_TXD_DEPTH 64 +/** @} */ + +/** + * @name XQSPIPSU RX Data Register information + * This register bits for configuring RXFIFO + * @{ + */ +/** + * Register: XQSPIPSU_RXD + */ +#define XQSPIPSU_RXD_OFFSET 0X00000020U + +#define XQSPIPSU_RXD_SHIFT 0U +#define XQSPIPSU_RXD_WIDTH 32U +#define XQSPIPSU_RXD_MASK 0XFFFFFFFFU +/** @} */ + +/** + * @name XQSPIPSU TX/RX Threshold Register information + * This register bits for configuring TX/RX Threshold + * @{ + */ +/** + * Register: XQSPIPSU_TX_THRESHOLD + */ +#define XQSPIPSU_TX_THRESHOLD_OFFSET 0X00000028U + +#define XQSPIPSU_TX_FIFO_THRESHOLD_SHIFT 0U +#define XQSPIPSU_TX_FIFO_THRESHOLD_WIDTH 6U +#define XQSPIPSU_TX_FIFO_THRESHOLD_MASK 0X0000003FU +#define XQSPIPSU_TX_FIFO_THRESHOLD_RESET_VAL 0X01U + +#define XQSPIPSU_RX_THRESHOLD_OFFSET 0X0000002CU + +#define XQSPIPSU_RX_FIFO_THRESHOLD_SHIFT 0U +#define XQSPIPSU_RX_FIFO_THRESHOLD_WIDTH 6U +#define XQSPIPSU_RX_FIFO_THRESHOLD_MASK 0X0000003FU +#define XQSPIPSU_RX_FIFO_THRESHOLD_RESET_VAL 0X01U + +#define XQSPIPSU_RXFIFO_THRESHOLD_OPT 32U +/** @} */ + +/** + * @name XQSPIPSU GPIO Register information + * @{ + */ +/** + * Register: XQSPIPSU_GPIO + */ +#define XQSPIPSU_GPIO_OFFSET 0X00000030U + +#define XQSPIPSU_GPIO_WP_N_SHIFT 0U +#define XQSPIPSU_GPIO_WP_N_WIDTH 1U +#define XQSPIPSU_GPIO_WP_N_MASK 0X00000001U +/** @} */ + +/** + * @name XQSPIPSU Loopback Master Clock Delay Adjustment Register information + * This register contains bits for configuring loopback + * @{ + */ +/** + * Register: XQSPIPSU_LPBK_DLY_ADJ + */ +#define XQSPIPSU_LPBK_DLY_ADJ_OFFSET 0X00000038U + +#define XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_SHIFT 5U +#define XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_WIDTH 1U +#define XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_MASK 0X00000020U + +#define XQSPIPSU_LPBK_DLY_ADJ_DLY1_SHIFT 3U +#define XQSPIPSU_LPBK_DLY_ADJ_DLY1_WIDTH 2U +#define XQSPIPSU_LPBK_DLY_ADJ_DLY1_MASK 0X00000018U + +#define XQSPIPSU_LPBK_DLY_ADJ_DLY0_SHIFT 0U +#define XQSPIPSU_LPBK_DLY_ADJ_DLY0_WIDTH 3U +#define XQSPIPSU_LPBK_DLY_ADJ_DLY0_MASK 0X00000007U +/** @} */ + +/** + * @name XQSPIPSU GEN_FIFO Register information + * This register contains bits for configuring GENFIFO + * @{ + */ +/** + * Register: XQSPIPSU_GEN_FIFO + */ +#define XQSPIPSU_GEN_FIFO_OFFSET 0X00000040U + +#define XQSPIPSU_GEN_FIFO_DATA_SHIFT 0U +#define XQSPIPSU_GEN_FIFO_DATA_WIDTH 20U +#define XQSPIPSU_GEN_FIFO_DATA_MASK 0X000FFFFFU +/** @} */ + +/** + * @name XQSPIPSU Select Register information + * This register contains bits for selection GQSPI/LQSPI controller + * @{ + */ +/** + * Register: XQSPIPSU_SEL + */ +#define XQSPIPSU_SEL_OFFSET 0X00000044U + +#define XQSPIPSU_SEL_SHIFT 0U +#define XQSPIPSU_SEL_WIDTH 1U +#if !defined (versal) +#define XQSPIPSU_SEL_LQSPI_MASK 0X0U +#endif +#define XQSPIPSU_SEL_GQSPI_MASK 0X00000001U +/** @} */ + +/** + * @name XQSPIPSU FIFO Control Register information + * This register contains bits for controlling TXFIFO and RXFIFO + * @{ + */ +/** + * Register: XQSPIPSU_FIFO_CTRL + */ +#define XQSPIPSU_FIFO_CTRL_OFFSET 0X0000004CU + +#define XQSPIPSU_FIFO_CTRL_RST_RX_FIFO_SHIFT 2U +#define XQSPIPSU_FIFO_CTRL_RST_RX_FIFO_WIDTH 1U +#define XQSPIPSU_FIFO_CTRL_RST_RX_FIFO_MASK 0X00000004U + +#define XQSPIPSU_FIFO_CTRL_RST_TX_FIFO_SHIFT 1U +#define XQSPIPSU_FIFO_CTRL_RST_TX_FIFO_WIDTH 1U +#define XQSPIPSU_FIFO_CTRL_RST_TX_FIFO_MASK 0X00000002U + +#define XQSPIPSU_FIFO_CTRL_RST_GEN_FIFO_SHIFT 0U +#define XQSPIPSU_FIFO_CTRL_RST_GEN_FIFO_WIDTH 1U +#define XQSPIPSU_FIFO_CTRL_RST_GEN_FIFO_MASK 0X00000001U +/** @} */ + +/** + * @name XQSPIPSU GENFIFO Threshold Register information + * This register contains bits for configuring GENFIFO threshold + * @{ + */ +/** + * Register: XQSPIPSU_GF_THRESHOLD + */ +#define XQSPIPSU_GF_THRESHOLD_OFFSET 0X00000050U + +#define XQSPIPSU_GEN_FIFO_THRESHOLD_SHIFT 0U +#define XQSPIPSU_GEN_FIFO_THRESHOLD_WIDTH 5U +#define XQSPIPSU_GEN_FIFO_THRESHOLD_MASK 0X0000001FU +#define XQSPIPSU_GEN_FIFO_THRESHOLD_RESET_VAL 0X10U +/** @} */ + +/** + * @name XQSPIPSU Poll configuration Register information + * This register contains bits for configuring Poll feature + * @{ + */ +/** + * Register: XQSPIPSU_POLL_CFG + */ +#define XQSPIPSU_POLL_CFG_OFFSET 0X00000054U + +#define XQSPIPSU_POLL_CFG_EN_MASK_UPPER_SHIFT 31U +#define XQSPIPSU_POLL_CFG_EN_MASK_UPPER_WIDTH 1U +#define XQSPIPSU_POLL_CFG_EN_MASK_UPPER_MASK 0X80000000U + +#define XQSPIPSU_POLL_CFG_EN_MASK_LOWER_SHIFT 30U +#define XQSPIPSU_POLL_CFG_EN_MASK_LOWER_WIDTH 1U +#define XQSPIPSU_POLL_CFG_EN_MASK_LOWER_MASK 0X40000000U + +#define XQSPIPSU_POLL_CFG_MASK_EN_SHIFT 8U +#define XQSPIPSU_POLL_CFG_MASK_EN_WIDTH 8U +#define XQSPIPSU_POLL_CFG_MASK_EN_MASK 0X0000FF00U + +#define XQSPIPSU_POLL_CFG_DATA_VALUE_SHIFT 0U +#define XQSPIPSU_POLL_CFG_DATA_VALUE_WIDTH 8U +#define XQSPIPSU_POLL_CFG_DATA_VALUE_MASK 0X000000FFU + +#define XQSPIPSU_P_TO_OFFSET 0X00000058U + +#define XQSPIPSU_P_TO_VALUE_SHIFT 0U +#define XQSPIPSU_P_TO_VALUE_WIDTH 32U +#define XQSPIPSU_P_TO_VALUE_MASK 0XFFFFFFFFU +/** @} */ + +/** + * @name XQSPIPSU Transfer Status Register information + * This register contains bits for transfer status + * @{ + */ +/** + * Register: XQSPIPSU_XFER_STS + */ +#define XQSPIPSU_XFER_STS_OFFSET 0X0000005CU + +#define XQSPIPSU_XFER_STS_PEND_BYTES_SHIFT 0U +#define XQSPIPSU_XFER_STS_PEND_BYTES_WIDTH 32U +#define XQSPIPSU_XFER_STS_PEND_BYTES_MASK 0XFFFFFFFFU +/** @} */ + +/** + * @name XQSPIPSU GEN_FIFO Snapshot Register information + * This register contains bits for configuring GENFIFO + * @{ + */ +/** + * Register: XQSPIPSU_GF_SNAPSHOT + */ +#define XQSPIPSU_GF_SNAPSHOT_OFFSET 0X00000060U + +#define XQSPIPSU_GF_SNAPSHOT_SHIFT 0U +#define XQSPIPSU_GF_SNAPSHOT_WIDTH 20U +#define XQSPIPSU_GF_SNAPSHOT_MASK 0X000FFFFFU +/** @} */ + +/** + * @name XQSPIPSU Receive Data Copy Register information + * @{ + */ +/** + * Register: XQSPIPSU_RX_COPY + */ +#define XQSPIPSU_RX_COPY_OFFSET 0X00000064U + +#define XQSPIPSU_RX_COPY_UPPER_SHIFT 8U +#define XQSPIPSU_RX_COPY_UPPER_WIDTH 8U +#define XQSPIPSU_RX_COPY_UPPER_MASK 0X0000FF00U + +#define XQSPIPSU_RX_COPY_LOWER_SHIFT 0U +#define XQSPIPSU_RX_COPY_LOWER_WIDTH 8U +#define XQSPIPSU_RX_COPY_LOWER_MASK 0X000000FFU +/** @} */ + +/** + * @name XQSPIPSU Module Identification Register information + * @{ + */ +/** + * Register: XQSPIPSU_MOD_ID + */ +#define XQSPIPSU_MOD_ID_OFFSET 0X000000FCU + +#define XQSPIPSU_MOD_ID_SHIFT 0U +#define XQSPIPSU_MOD_ID_WIDTH 32U +#define XQSPIPSU_MOD_ID_MASK 0XFFFFFFFFU +/** @} */ + +/** + * @name XQSPIPSU DMA Transfer Register information + * This register contains bits for configuring DMA + * @{ + */ +/** + * Register: XQSPIPSU_QSPIDMA_DST_ADDR + */ +#define XQSPIPSU_QSPIDMA_DST_ADDR_OFFSET 0X00000700U + +#define XQSPIPSU_QSPIDMA_DST_ADDR_SHIFT 2U +#define XQSPIPSU_QSPIDMA_DST_ADDR_WIDTH 30U +#define XQSPIPSU_QSPIDMA_DST_ADDR_MASK 0XFFFFFFFCU + +#define XQSPIPSU_QSPIDMA_DST_SIZE_OFFSET 0X00000704U + +#define XQSPIPSU_QSPIDMA_DST_SIZE_SHIFT 2U +#define XQSPIPSU_QSPIDMA_DST_SIZE_WIDTH 27U +#define XQSPIPSU_QSPIDMA_DST_SIZE_MASK 0X1FFFFFFCU + +#define XQSPIPSU_QSPIDMA_DST_STS_OFFSET 0X00000708U + +#define XQSPIPSU_QSPIDMA_DST_STS_DONE_CNT_SHIFT 13U +#define XQSPIPSU_QSPIDMA_DST_STS_DONE_CNT_WIDTH 3U +#define XQSPIPSU_QSPIDMA_DST_STS_DONE_CNT_MASK 0X0000E000U + +#define XQSPIPSU_QSPIDMA_DST_STS_DST_FIFO_LEVEL_SHIFT 5U +#define XQSPIPSU_QSPIDMA_DST_STS_DST_FIFO_LEVEL_WIDTH 8U +#define XQSPIPSU_QSPIDMA_DST_STS_DST_FIFO_LEVEL_MASK 0X00001FE0U + +#define XQSPIPSU_QSPIDMA_DST_STS_WR_OUTSTANDING_SHIFT 1U +#define XQSPIPSU_QSPIDMA_DST_STS_WR_OUTSTANDING_WIDTH 4U +#define XQSPIPSU_QSPIDMA_DST_STS_WR_OUTSTANDING_MASK 0X0000001EU + +#define XQSPIPSU_QSPIDMA_DST_STS_BUSY_SHIFT 0U +#define XQSPIPSU_QSPIDMA_DST_STS_BUSY_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_STS_BUSY_MASK 0X00000001U + +#define XQSPIPSU_QSPIDMA_DST_STS_WTC 0xE000U + +#define XQSPIPSU_QSPIDMA_DST_CTRL_OFFSET 0X0000070CU + +#define XQSPIPSU_QSPIDMA_DST_CTRL_FIFO_LVL_HIT_THRESHOLD_SHIFT 25U +#define XQSPIPSU_QSPIDMA_DST_CTRL_FIFO_LVL_HIT_THRESHOLD_WIDTH 7U +#define XQSPIPSU_QSPIDMA_DST_CTRL_FIFO_LVL_HIT_THRESHOLD_MASK 0XFE000000U + +#define XQSPIPSU_QSPIDMA_DST_CTRL_APB_ERR_RESP_SHIFT 24U +#define XQSPIPSU_QSPIDMA_DST_CTRL_APB_ERR_RESP_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_CTRL_APB_ERR_RESP_MASK 0X01000000U + +#define XQSPIPSU_QSPIDMA_DST_CTRL_ENDIAN_SHIFT 23U +#define XQSPIPSU_QSPIDMA_DST_CTRL_ENDIAN_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_CTRL_ENDIAN_MASK 0X00800000U + +#define XQSPIPSU_QSPIDMA_DST_CTRL_AXI_BRST_TYPE_SHIFT 22U +#define XQSPIPSU_QSPIDMA_DST_CTRL_AXI_BRST_TYPE_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_CTRL_AXI_BRST_TYPE_MASK 0X00400000U + +#define XQSPIPSU_QSPIDMA_DST_CTRL_TO_VAL_SHIFT 10U +#define XQSPIPSU_QSPIDMA_DST_CTRL_TO_VAL_WIDTH 12U +#define XQSPIPSU_QSPIDMA_DST_CTRL_TO_VAL_MASK 0X003FFC00U + +#define XQSPIPSU_QSPIDMA_DST_CTRL_FIFO_THRESHOLD_SHIFT 2U +#define XQSPIPSU_QSPIDMA_DST_CTRL_FIFO_THRESHOLD_WIDTH 8U +#define XQSPIPSU_QSPIDMA_DST_CTRL_FIFO_THRESHOLD_MASK 0X000003FCU + +#define XQSPIPSU_QSPIDMA_DST_CTRL_PAUSE_STRM_SHIFT 1U +#define XQSPIPSU_QSPIDMA_DST_CTRL_PAUSE_STRM_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_CTRL_PAUSE_STRM_MASK 0X00000002U + +#define XQSPIPSU_QSPIDMA_DST_CTRL_PAUSE_MEM_SHIFT 0U +#define XQSPIPSU_QSPIDMA_DST_CTRL_PAUSE_MEM_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_CTRL_PAUSE_MEM_MASK 0X00000001U + +#define XQSPIPSU_QSPIDMA_DST_CTRL_RESET_VAL 0x403FFA00U + +#define XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET 0X00000714U + +#define XQSPIPSU_QSPIDMA_DST_I_STS_FIFO_OF_SHIFT 7U +#define XQSPIPSU_QSPIDMA_DST_I_STS_FIFO_OF_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_STS_FIFO_OF_MASK 0X00000080U + +#define XQSPIPSU_QSPIDMA_DST_I_STS_INVALID_APB_SHIFT 6U +#define XQSPIPSU_QSPIDMA_DST_I_STS_INVALID_APB_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_STS_INVALID_APB_MASK 0X00000040U + +#define XQSPIPSU_QSPIDMA_DST_I_STS_THRESHOLD_HIT_SHIFT 5U +#define XQSPIPSU_QSPIDMA_DST_I_STS_THRESHOLD_HIT_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_STS_THRESHOLD_HIT_MASK 0X00000020U + +#define XQSPIPSU_QSPIDMA_DST_I_STS_TO_MEM_SHIFT 4U +#define XQSPIPSU_QSPIDMA_DST_I_STS_TO_MEM_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_STS_TO_MEM_MASK 0X00000010U + +#define XQSPIPSU_QSPIDMA_DST_I_STS_TO_STRM_SHIFT 3U +#define XQSPIPSU_QSPIDMA_DST_I_STS_TO_STRM_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_STS_TO_STRM_MASK 0X00000008U + +#define XQSPIPSU_QSPIDMA_DST_I_STS_AXI_BRESP_ERR_SHIFT 2U +#define XQSPIPSU_QSPIDMA_DST_I_STS_AXI_BRESP_ERR_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_STS_AXI_BRESP_ERR_MASK 0X00000004U + +#define XQSPIPSU_QSPIDMA_DST_I_STS_DONE_SHIFT 1U +#define XQSPIPSU_QSPIDMA_DST_I_STS_DONE_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK 0X00000002U + +#define XQSPIPSU_QSPIDMA_DST_INTR_ERR_MASK 0X000000FCU +#define XQSPIPSU_QSPIDMA_DST_INTR_ALL_MASK 0X000000FEU + +#define XQSPIPSU_QSPIDMA_DST_I_EN_OFFSET 0X00000718U + +#define XQSPIPSU_QSPIDMA_DST_I_EN_FIFO_OF_SHIFT 7U +#define XQSPIPSU_QSPIDMA_DST_I_EN_FIFO_OF_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_EN_FIFO_OF_MASK 0X00000080U + +#define XQSPIPSU_QSPIDMA_DST_I_EN_INVALID_APB_SHIFT 6U +#define XQSPIPSU_QSPIDMA_DST_I_EN_INVALID_APB_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_EN_INVALID_APB_MASK 0X00000040U + +#define XQSPIPSU_QSPIDMA_DST_I_EN_THRESHOLD_HIT_SHIFT 5U +#define XQSPIPSU_QSPIDMA_DST_I_EN_THRESHOLD_HIT_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_EN_THRESHOLD_HIT_MASK 0X00000020U + +#define XQSPIPSU_QSPIDMA_DST_I_EN_TO_MEM_SHIFT 4U +#define XQSPIPSU_QSPIDMA_DST_I_EN_TO_MEM_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_EN_TO_MEM_MASK 0X00000010U + +#define XQSPIPSU_QSPIDMA_DST_I_EN_TO_STRM_SHIFT 3U +#define XQSPIPSU_QSPIDMA_DST_I_EN_TO_STRM_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_EN_TO_STRM_MASK 0X00000008U + +#define XQSPIPSU_QSPIDMA_DST_I_EN_AXI_BRESP_ERR_SHIFT 2U +#define XQSPIPSU_QSPIDMA_DST_I_EN_AXI_BRESP_ERR_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_EN_AXI_BRESP_ERR_MASK 0X00000004U + +#define XQSPIPSU_QSPIDMA_DST_I_EN_DONE_SHIFT 1U +#define XQSPIPSU_QSPIDMA_DST_I_EN_DONE_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_EN_DONE_MASK 0X00000002U + +#define XQSPIPSU_QSPIDMA_DST_I_DIS_OFFSET 0X0000071CU + +#define XQSPIPSU_QSPIDMA_DST_I_DIS_FIFO_OF_SHIFT 7U +#define XQSPIPSU_QSPIDMA_DST_I_DIS_FIFO_OF_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_DIS_FIFO_OF_MASK 0X00000080U + +#define XQSPIPSU_QSPIDMA_DST_I_DIS_INVALID_APB_SHIFT 6U +#define XQSPIPSU_QSPIDMA_DST_I_DIS_INVALID_APB_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_DIS_INVALID_APB_MASK 0X00000040U + +#define XQSPIPSU_QSPIDMA_DST_I_DIS_THRESHOLD_HIT_SHIFT 5U +#define XQSPIPSU_QSPIDMA_DST_I_DIS_THRESHOLD_HIT_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_DIS_THRESHOLD_HIT_MASK 0X00000020U + +#define XQSPIPSU_QSPIDMA_DST_I_DIS_TO_MEM_SHIFT 4U +#define XQSPIPSU_QSPIDMA_DST_I_DIS_TO_MEM_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_DIS_TO_MEM_MASK 0X00000010U + +#define XQSPIPSU_QSPIDMA_DST_I_DIS_TO_STRM_SHIFT 3U +#define XQSPIPSU_QSPIDMA_DST_I_DIS_TO_STRM_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_DIS_TO_STRM_MASK 0X00000008U + +#define XQSPIPSU_QSPIDMA_DST_I_DIS_AXI_BRESP_ERR_SHIFT 2U +#define XQSPIPSU_QSPIDMA_DST_I_DIS_AXI_BRESP_ERR_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_DIS_AXI_BRESP_ERR_MASK 0X00000004U + +#define XQSPIPSU_QSPIDMA_DST_I_DIS_DONE_SHIFT 1U +#define XQSPIPSU_QSPIDMA_DST_I_DIS_DONE_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_I_DIS_DONE_MASK 0X00000002U + +#define XQSPIPSU_QSPIDMA_DST_IMR_OFFSET 0X00000720U + +#define XQSPIPSU_QSPIDMA_DST_IMR_FIFO_OF_SHIFT 7U +#define XQSPIPSU_QSPIDMA_DST_IMR_FIFO_OF_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_IMR_FIFO_OF_MASK 0X00000080U + +#define XQSPIPSU_QSPIDMA_DST_IMR_INVALID_APB_SHIFT 6U +#define XQSPIPSU_QSPIDMA_DST_IMR_INVALID_APB_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_IMR_INVALID_APB_MASK 0X00000040U + +#define XQSPIPSU_QSPIDMA_DST_IMR_THRESHOLD_HIT_SHIFT 5U +#define XQSPIPSU_QSPIDMA_DST_IMR_THRESHOLD_HIT_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_IMR_THRESHOLD_HIT_MASK 0X00000020U + +#define XQSPIPSU_QSPIDMA_DST_IMR_TO_MEM_SHIFT 4U +#define XQSPIPSU_QSPIDMA_DST_IMR_TO_MEM_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_IMR_TO_MEM_MASK 0X00000010U + +#define XQSPIPSU_QSPIDMA_DST_IMR_TO_STRM_SHIFT 3U +#define XQSPIPSU_QSPIDMA_DST_IMR_TO_STRM_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_IMR_TO_STRM_MASK 0X00000008U + +#define XQSPIPSU_QSPIDMA_DST_IMR_AXI_BRESP_ERR_SHIFT 2U +#define XQSPIPSU_QSPIDMA_DST_IMR_AXI_BRESP_ERR_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_IMR_AXI_BRESP_ERR_MASK 0X00000004U + +#define XQSPIPSU_QSPIDMA_DST_IMR_DONE_SHIFT 1U +#define XQSPIPSU_QSPIDMA_DST_IMR_DONE_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_IMR_DONE_MASK 0X00000002U + +#define XQSPIPSU_QSPIDMA_DST_CTRL2_OFFSET 0X00000724U + +#define XQSPIPSU_QSPIDMA_DST_CTRL2_RAM_EMASA_SHIFT 27U +#define XQSPIPSU_QSPIDMA_DST_CTRL2_RAM_EMASA_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_CTRL2_RAM_EMASA_MASK 0X08000000U + +#define XQSPIPSU_QSPIDMA_DST_CTRL2_AWCACHE_SHIFT 24U +#define XQSPIPSU_QSPIDMA_DST_CTRL2_AWCACHE_WIDTH 3U +#define XQSPIPSU_QSPIDMA_DST_CTRL2_AWCACHE_MASK 0X07000000U + +#define XQSPIPSU_QSPIDMA_DST_CTRL2_TO_EN_SHIFT 22U +#define XQSPIPSU_QSPIDMA_DST_CTRL2_TO_EN_WIDTH 1U +#define XQSPIPSU_QSPIDMA_DST_CTRL2_TO_EN_MASK 0X00400000U + +#define XQSPIPSU_QSPIDMA_DST_CTRL2_RAM_EMAB_SHIFT 19U +#define XQSPIPSU_QSPIDMA_DST_CTRL2_RAM_EMAB_WIDTH 3U +#define XQSPIPSU_QSPIDMA_DST_CTRL2_RAM_EMAB_MASK 0X00380000U + +#define XQSPIPSU_QSPIDMA_DST_CTRL2_RAM_EMAA_SHIFT 16U +#define XQSPIPSU_QSPIDMA_DST_CTRL2_RAM_EMAA_WIDTH 3U +#define XQSPIPSU_QSPIDMA_DST_CTRL2_RAM_EMAA_MASK 0X00070000U + +#define XQSPIPSU_QSPIDMA_DST_CTRL2_TO_PRE_SHIFT 4U +#define XQSPIPSU_QSPIDMA_DST_CTRL2_TO_PRE_WIDTH 12U +#define XQSPIPSU_QSPIDMA_DST_CTRL2_TO_PRE_MASK 0X0000FFF0U + +#define XQSPIPSU_QSPIDMA_DST_CTRL2_MAX_OUTS_CMDS_SHIFT 0U +#define XQSPIPSU_QSPIDMA_DST_CTRL2_MAX_OUTS_CMDS_WIDTH 4U +#define XQSPIPSU_QSPIDMA_DST_CTRL2_MAX_OUTS_CMDS_MASK 0X0000000FU + +#define XQSPIPSU_QSPIDMA_DST_ADDR_MSB_OFFSET 0X00000728U + +#define XQSPIPSU_QSPIDMA_DST_ADDR_MSB_SHIFT 0U +#define XQSPIPSU_QSPIDMA_DST_ADDR_MSB_WIDTH 12U +#define XQSPIPSU_QSPIDMA_DST_ADDR_MSB_MASK 0X00000FFFU + +#define XQSPIPSU_QSPIDMA_FUTURE_ECO_OFFSET 0X00000EFCU + +#define XQSPIPSU_QSPIDMA_FUTURE_ECO_VAL_SHIFT 0U +#define XQSPIPSU_QSPIDMA_FUTURE_ECO_VAL_WIDTH 32U +#define XQSPIPSU_QSPIDMA_FUTURE_ECO_VAL_MASK 0XFFFFFFFFU +/** @} */ + +/** + * @name XQSPIPSU Generic FIFO masks information + * Generic FIFO masks information + * @{ + */ +/** + * Generic FIFO masks + */ +#define XQSPIPSU_GENFIFO_IMM_DATA_MASK 0xFFU +#define XQSPIPSU_GENFIFO_DATA_XFER 0x100U +#define XQSPIPSU_GENFIFO_EXP 0x200U +#define XQSPIPSU_GENFIFO_MODE_SPI 0x400U +#define XQSPIPSU_GENFIFO_MODE_DUALSPI 0x800U +#define XQSPIPSU_GENFIFO_MODE_QUADSPI 0xC00U +#define XQSPIPSU_GENFIFO_MODE_MASK 0xC00U /* And with ~MASK first */ +#define XQSPIPSU_GENFIFO_CS_LOWER 0x1000U +#define XQSPIPSU_GENFIFO_CS_UPPER 0x2000U +#define XQSPIPSU_GENFIFO_BUS_LOWER 0x4000U +#define XQSPIPSU_GENFIFO_BUS_UPPER 0x8000U +#define XQSPIPSU_GENFIFO_BUS_BOTH 0xC000U /* inverse is no bus */ +#define XQSPIPSU_GENFIFO_BUS_MASK 0xC000U /* And with ~MASK first */ +#define XQSPIPSU_GENFIFO_TX 0x10000U /* inverse is zero pump */ +#define XQSPIPSU_GENFIFO_RX 0x20000U /* inverse is RX discard */ +#define XQSPIPSU_GENFIFO_STRIPE 0x40000U +#define XQSPIPSU_GENFIFO_POLL 0x80000U +/** @} */ + +/** + * @name XQSPIPSU RX Data Delay Register information + * @{ + */ +/** + * QSPI Data delay register + */ +#define XQSPIPSU_DATA_DLY_ADJ_OFFSET 0X000000F8U + +#define XQSPIPSU_DATA_DLY_ADJ_USE_DATA_DLY_SHIFT 31U +#define XQSPIPSU_DATA_DLY_ADJ_USE_DATA_DLY_WIDTH 1U +#define XQSPIPSU_DATA_DLY_ADJ_USE_DATA_DLY_MASK 0X80000000U + +#define XQSPIPSU_DATA_DLY_ADJ_DLY_SHIFT 28U +#define XQSPIPSU_DATA_DLY_ADJ_DLY_WIDTH 3U +#define XQSPIPSU_DATA_DLY_ADJ_DLY_MASK 0X70000000U +/** @} */ + +/** + * @name TAPDLY Bypass register information + * @{ + */ +/** + * Tapdelay Bypass register + */ + +#if defined versal +#define IOU_TAPDLY_BYPASS_OFFSET 0X0000003CU +#else +#define IOU_TAPDLY_BYPASS_OFFSET 0X00000390U +#endif + +#define IOU_TAPDLY_BYPASS_LQSPI_RX_SHIFT 0X02U +#if !defined (versal) +#define IOU_TAPDLY_BYPASS_LQSPI_RX_WIDTH 0X01U +#define IOU_TAPDLY_BYPASS_LQSPI_RX_MASK 0x00000004U +#endif + +#if defined versal +#define IOU_TAPDLY_RESET_STATE 0x4U +#else +#define IOU_TAPDLY_RESET_STATE 0x7U +#endif +/** @} */ + +/***************** Macros (Inline Functions) Definitions *********************/ + +#define XQspiPsu_In32 Xil_In32 /**< Read the 32 bit register value */ +#define XQspiPsu_Out32 Xil_Out32 /**< Write the 32 bit register value */ + +/****************************************************************************/ +/** +* 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. s32 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, s32 RegOffset, +* u32 RegisterValue) +* +******************************************************************************/ +#define XQspiPsu_WriteReg(BaseAddress, RegOffset, RegisterValue) XQspiPsu_Out32((BaseAddress) + (RegOffset), (RegisterValue)) + + +#ifdef __cplusplus +} +#endif + + +#endif /**< XQSPIPSU_H */ +/** @} */ diff --git a/bsps/shared/dev/spi/VERSION b/bsps/shared/dev/spi/VERSION new file mode 100644 index 0000000000..a0acb181b6 --- /dev/null +++ b/bsps/shared/dev/spi/VERSION @@ -0,0 +1,29 @@ +The information in this file describes the source of the following files in +bsps/shared/dev/spi/ and bsps/include/dev/spi/: + +- xqspipsu_control.c +- xqspipsu_control.h +- xqspipsu_flash_config.h +- xqspipsu_hw.c +- xqspipsu_hw.h +- xqspipsu_options.c +- xqspipsu.c +- xqspipsu.h + +Import from: + +https://github.com/Xilinx/embeddedsw.git + +commit 8a89579489c88ea5acd23d7d439ac928659c26cf +Author: msreeram <manikanta.sreeram@xilinx.com> +AuthorDate: Wed Apr 6 23:24:38 2022 -0600 +Commit: Siva Addepalli <sivaprasad.addepalli@xilinx.com> +CommitDate: Fri Apr 8 16:47:15 2022 +0530 + + update license file for EmbeddedSW 2022.1 release + + Update license file for EmbeddedSW 2022.1 release + + Signed-off-by: Manikanta Sreeram <msreeram@xilinx.com> + + Acked-by : Meena Paleti <meena.paleti@xilinx.com> diff --git a/bsps/shared/dev/spi/xqspipsu.c b/bsps/shared/dev/spi/xqspipsu.c new file mode 100644 index 0000000000..1286efd359 --- /dev/null +++ b/bsps/shared/dev/spi/xqspipsu.c @@ -0,0 +1,1048 @@ +/****************************************************************************** +* Copyright (C) 2014 - 2022 Xilinx, Inc. All rights reserved. +* SPDX-License-Identifier: MIT +******************************************************************************/ + + +/*****************************************************************************/ +/** + * + * @file xqspipsu.c + * @addtogroup Overview + * @{ + * + * This file implements the functions required to use the QSPIPSU hardware to + * perform a transfer. These are accessible to the user via xqspipsu.h. + * + * <pre> + * MODIFICATION HISTORY: + * + * Ver Who Date Changes + * ----- --- -------- ----------------------------------------------- + * 1.0 hk 08/21/14 First release + * sk 03/13/15 Added IO mode support. + * hk 03/18/15 Switch to I/O mode before clearing RX FIFO. + * Clear and disable DMA interrupts/status in abort. + * Use DMA DONE bit instead of BUSY as recommended. + * sk 04/24/15 Modified the code according to MISRAC-2012. + * sk 06/17/15 Removed NULL checks for Rx/Tx buffers. As + * writing/reading from 0x0 location is permitted. + * 1.1 sk 04/12/16 Added debug message prints. + * 1.2 nsk 07/01/16 Changed XQspiPsu_Select to support GQSPI and LQSPI + * selection. + * rk 07/15/16 Added support for TapDelays at different frequencies. + * nsk 08/05/16 Added example support PollData and PollTimeout + * 1.3 nsk 09/16/16 Update PollData and PollTimeout support for dual + * parallel configurations, modified XQspiPsu_PollData() + * and XQspiPsu_Create_PollConfigData() + * 1,5 nsk 08/14/17 Added CCI support + * 1.7 tjs 01/16/18 Removed the check for DMA MSB to be written. (CR#992560) + * 1.7 tjs 01/17/18 Added a support to toggle WP pin of the flash. + * 1.7 tjs 03/14/18 Added support in EL1 NS mode (CR#974882) + * 1.8 tjs 06/26/18 Added an example for accessing 64bit dma within + * 32 bit application. CR#1004701 + * 1.8 tjs 06/26/18 Removed checkpatch warnings. + * 1.8 tjs 07/09/18 Fixed cppcheck and doxygen warnings. (CR#1006336) + * 1.8 tjs 07/18/18 Setup64BRxDma() should be called only if the RxAddress is + * greater than 32 bit address space. (CR#1006862) + * 1.8 tjs 09/06/18 Fixed the code in XQspiPsu_GenFifoEntryData() for data + * transfer length up to 255 for reducing the extra loop. + * 1.8 mus 11/05/18 Support 64 bit DMA addresses for Microblaze-X platform. + * 1.9 tjs 11/22/17 Added the check for A72 and R5 processors (CR-987075) + * 1.9 tjs 04/17/18 Updated register addresses as per the latest revision + * of versal (CR#999610) + * 1.9 aru 01/17/19 Fixes violations according to MISRAC-2012 + * in safety mode and modified the code such as + * Added UNITPTR inplace of INTPTR,Declared the pointer param + * as Pointer to const . + * 1.9 nsk 02/01/19 Clear DMA_DST_ADDR_MSB register on 32bit machine, if the + * address is of only 32bit (CR#1020031) + * 1.9 nsk 02/01/19 Added QSPI idling support. + * 1.9 rama 03/13/19 Fixed MISRA violations related to UR data anamoly, + * expression is not a boolean + * 1.9 nsk 03/27/19 Update 64bit dma support + * 1.10 sk 08/20/19 Fixed issues in poll timeout feature. + * 1.11 akm 02/19/20 Added XQspiPsu_StartDmaTransfer() and XQspiPsu_CheckDmaDone() + * APIs for non-blocking transfer. + * 1.11 sd 01/02/20 Added clocking support + * 1.11 akm 03/09/20 Reorganize the source code, enable qspi controller and + * interrupts in XQspiPsu_CfgInitialize() API. + * 1.11 akm 03/26/20 Fixed issue by updating XQspiPsu_CfgInitialize to return + * XST_DEVICE_IS_STARTED instead of asserting, when the + * instance is already configured. + * 1.13 akm 01/04/21 Fix MISRA-C violations. + * 1.14 akm 06/24/21 Allow enough time for the controller to reset the FIFOs. + * 1.14 akm 08/12/21 Perform Dcache invalidate at the end of the DMA transfer. + * 1.15 akm 10/21/21 Fix MISRA-C violations. + * + * </pre> + * + ******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xqspipsu.h" +#include "xqspipsu_control.h" +#include "sleep.h" + +/************************** Constant Definitions *****************************/ +#define MAX_DELAY_CNT 10000000U /**< Max delay count */ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +/*****************************************************************************/ +/** + * + * Initializes a specific XQspiPsu instance as such 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. + * + ******************************************************************************/ +s32 XQspiPsu_CfgInitialize(XQspiPsu *InstancePtr, + const XQspiPsu_Config *ConfigPtr, + UINTPTR EffectiveAddr) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(ConfigPtr != NULL); + s32 Status; + + /* + * 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 == (u32)TRUE) || + (InstancePtr->IsReady == XIL_COMPONENT_IS_READY)) { + Status = (s32)XST_DEVICE_IS_STARTED; + } else { + /* Set some default values. */ + InstancePtr->IsBusy = (u32)FALSE; + InstancePtr->Config.BaseAddress = + EffectiveAddr + XQSPIPSU_OFFSET; + InstancePtr->Config.ConnectionMode = ConfigPtr->ConnectionMode; + InstancePtr->StatusHandler = StubStatusHandler; + InstancePtr->Config.BusWidth = ConfigPtr->BusWidth; + InstancePtr->Config.InputClockHz = ConfigPtr->InputClockHz; +#if defined (XCLOCKING) + InstancePtr->Config.RefClk = ConfigPtr->RefClk; +#endif + InstancePtr->Config.IsCacheCoherent = + ConfigPtr->IsCacheCoherent; + /* 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; + InstancePtr->IsUnaligned = 0; + InstancePtr->IsManualstart = (u8)TRUE; + + /* Select QSPIPSU */ + XQspiPsu_Select(InstancePtr, XQSPIPSU_SEL_GQSPI_MASK); + /* + * 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); + /* Enable */ + XQspiPsu_Enable(InstancePtr); + + InstancePtr->IsReady = XIL_COMPONENT_IS_READY; + + Status = (s32)XST_SUCCESS; + } + + return Status; +} + +/*****************************************************************************/ +/** + * + * Stops the transfer of data to internal DST FIFO from stream interface and + * also stops the issuing of new write commands to memory. + * + * By calling this API, any ongoing Dma transfers will be paused and DMA will + * not issue AXI write commands to memory + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * + * @return None. + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_Idle(const XQspiPsu *InstancePtr) +{ + u32 RegEn; + u32 DmaStatus; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* Check for QSPI enable */ + RegEn = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_EN_OFFSET); + if ((RegEn & XQSPIPSU_EN_MASK) != 0U) { + DmaStatus = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_CTRL_OFFSET); + DmaStatus |= XQSPIPSU_QSPIDMA_DST_CTRL_PAUSE_STRM_MASK; + DmaStatus |= XQSPIPSU_QSPIDMA_DST_CTRL_PAUSE_MEM_MASK; + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_CTRL_OFFSET, DmaStatus); + } +#if defined (XCLOCKING) + Xil_ClockDisable(InstancePtr->Config.RefClk); +#endif +} + +/*****************************************************************************/ +/** + * + * 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) +{ + Xil_AssertVoid(InstancePtr != NULL); +#ifdef DEBUG + xil_printf("\nXQspiPsu_Reset\r\n"); +#endif + + /* Abort any transfer that is in progress */ + XQspiPsu_Abort(InstancePtr); + + /* Default value to config register */ + XQspiPsu_SetDefaultConfig(InstancePtr); + +} + +/*****************************************************************************/ +/** + * + * Aborts a transfer in progress. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * + * @return None. + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_Abort(XQspiPsu *InstancePtr) +{ + u32 IntrStatus, ConfigReg, FifoStatus; + u32 DelayCount = 0U; + + Xil_AssertVoid(InstancePtr != NULL); +#ifdef DEBUG + xil_printf("\nXQspiPsu_Abort\r\n"); +#endif + IntrStatus = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_ISR_OFFSET); + + /* Clear and disable interrupts */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_ISR_OFFSET, IntrStatus | XQSPIPSU_ISR_WR_TO_CLR_MASK); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET, + XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET)); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_STS_OFFSET, + XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_STS_OFFSET) | + XQSPIPSU_QSPIDMA_DST_STS_WTC); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_IDR_OFFSET, XQSPIPSU_IDR_ALL_MASK); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_I_DIS_OFFSET, + XQSPIPSU_QSPIDMA_DST_INTR_ALL_MASK); + + /* + * Clear GEN FIFO, TX FIFO & RX FIFO. Switch to IO mode to Clear + * RX FIFO. This is because of DMA behaviour where it waits on + * RX empty and goes busy assuming there is data to be transferred + * even if there is no request. + */ + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK; + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET, ConfigReg); + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_FIFO_CTRL_OFFSET, + XQSPIPSU_FIFO_CTRL_RST_TX_FIFO_MASK | + XQSPIPSU_FIFO_CTRL_RST_GEN_FIFO_MASK | + XQSPIPSU_FIFO_CTRL_RST_RX_FIFO_MASK); + /* + * QSPI Controller takes few clock cycles to update the RX_FIFO_Empty, + * TX_FIFO_Empty and GEN_FIFO_Empty status bit. Checking the GQSPI FIFO + * Control register bits gives enough time for the QSPI controller to + * update the status bit. The opeartion timesout, if the status bit are + * not updated after 10secs. + */ + + FifoStatus = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_FIFO_CTRL_OFFSET); + while(FifoStatus != 0U) { + if (DelayCount == MAX_DELAY_CNT) { +#ifdef DEBUG + xil_printf("Timeout error, FIFO reset failed.\r\n"); +#endif + } else { + /* Wait for 1 usec */ + usleep(1); + DelayCount++; + FifoStatus = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_FIFO_CTRL_OFFSET); + } + } + + if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { + ConfigReg |= XQSPIPSU_CFG_MODE_EN_DMA_MASK; + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET, ConfigReg); + } + + + InstancePtr->TxBytes = 0; + InstancePtr->RxBytes = 0; + InstancePtr->GenFifoEntries = 0; + InstancePtr->IsBusy = (u32)FALSE; +} + +/*****************************************************************************/ +/** + * This is the handler for polling functionality of controller. It reads data + * from RXFIFO, since when data from the flash device (status data) matched + * with configured value in poll_cfg, then controller writes the matched data + * into RXFIFO. + * + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param StatusReg is the Interrupt status Register value. + * + * @return None. + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_PollDataHandler(XQspiPsu *InstancePtr, u32 StatusReg) +{ + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_PollDataHandler\r\n"); +#endif + + if ((StatusReg & XQSPIPSU_ISR_RXNEMPTY_MASK) != (u32)FALSE) { + /* + * Read data from RXFIFO, since when data from the + * flash device (status data) matched with configured + * value in poll_cfg, then controller writes the + * matched data into RXFIFO. + */ + (void)XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_RXD_OFFSET); + + InstancePtr->StatusHandler(InstancePtr->StatusRef, + XST_SPI_POLL_DONE, 0); + } + if ((StatusReg & XQSPIPSU_ISR_POLL_TIME_EXPIRE_MASK) != (u32)FALSE) { + InstancePtr->StatusHandler(InstancePtr->StatusRef, + XST_FLASH_TIMEOUT_ERROR, 0); + } + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_IDR_OFFSET, + (u32)XQSPIPSU_IER_RXNEMPTY_MASK | + (u32)XQSPIPSU_IER_POLL_TIME_EXPIRE_MASK); + InstancePtr->IsBusy = (u32)FALSE; + if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { + XQspiPsu_SetReadMode(InstancePtr, XQSPIPSU_READMODE_DMA); + } + /* De-select slave */ + XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr); + XQspiPsu_ManualStartEnable(InstancePtr); +} + +/*****************************************************************************/ +/** + * + * 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. + * + ******************************************************************************/ +s32 XQspiPsu_PolledTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 NumMsg) +{ + s32 Index; + u32 QspiPsuStatusReg; + u32 IOPending = (u32)FALSE; + u32 DmaIntrSts; + s32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(Msg != NULL); + Xil_AssertNonvoid(NumMsg > 0U); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + for (Index = 0; Index < (s32)NumMsg; Index++) { + Xil_AssertNonvoid(Msg[Index].ByteCount > 0U); + } + /* + * Check whether there is another transfer in progress. + * Not thread-safe + */ + if (InstancePtr->IsBusy == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + goto END; + } + /* Check for ByteCount upper limit - 2^28 for DMA */ + for (Index = 0; Index < (s32)NumMsg; Index++) { + if ((Msg[Index].ByteCount > XQSPIPSU_DMA_BYTES_MAX) && + ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) { + Status = (s32)XST_FAILURE; + goto END; + } + } + /* + * Set the busy flag, which will be cleared when the transfer is + * entirely done. + */ + InstancePtr->IsBusy = (u32)TRUE; + +#if defined (XCLOCKING) + Xil_ClockEnable(InstancePtr->Config.RefClk); +#endif + /* Select slave */ + XQspiPsu_GenFifoEntryCSAssert(InstancePtr); + + /* list */ + Index = 0; + while (Index < (s32)NumMsg) { + XQspiPsu_GenFifoEntryData(InstancePtr, &Msg[Index]); + XQspiPsu_ManualStartEnable(InstancePtr); + /* Use thresholds here */ + /* If there is more data to be transmitted */ + do { + QspiPsuStatusReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_ISR_OFFSET); + /* Transmit more data if left */ + if (((QspiPsuStatusReg & XQSPIPSU_ISR_TXNOT_FULL_MASK) != (u32)FALSE) && + ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_TX) != (u32)FALSE) && + (InstancePtr->TxBytes > 0)) { + XQspiPsu_FillTxFifo(InstancePtr, &Msg[Index], + (u32)XQSPIPSU_TXD_DEPTH); + } + + if ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE) { + if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { + /* Check if DMA RX is complete and update RxBytes */ + DmaIntrSts = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET); + if ((DmaIntrSts & + XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK) != (u32)FALSE) { + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET, DmaIntrSts); + /* DMA transfer done, Invalidate Data Cache */ + if (!((Msg[Index].RxAddr64bit >= XQSPIPSU_RXADDR_OVER_32BIT) || + (Msg[Index].Xfer64bit != (u8)0U)) && + (InstancePtr->Config.IsCacheCoherent == 0U)) { + Xil_DCacheInvalidateRange((INTPTR)Msg[Index].RxBfrPtr, + (INTPTR)Msg[Index].ByteCount); + } + IOPending = XQspiPsu_SetIOMode(InstancePtr, &Msg[Index]); + InstancePtr->RxBytes = 0; + if (IOPending == (u32)TRUE) { + break; + } + } + } else { + XQspiPsu_IORead(InstancePtr, &Msg[Index], QspiPsuStatusReg); + } + } + } while (((QspiPsuStatusReg & + XQSPIPSU_ISR_GENFIFOEMPTY_MASK) == (u32)FALSE) || + (InstancePtr->TxBytes != 0) || + ((QspiPsuStatusReg & XQSPIPSU_ISR_TXEMPTY_MASK) == (u32)FALSE) || + (InstancePtr->RxBytes != 0)); + + if ((InstancePtr->IsUnaligned != 0) && (IOPending == (u32)FALSE)) { + InstancePtr->IsUnaligned = 0; + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + (XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET) | + XQSPIPSU_CFG_MODE_EN_DMA_MASK)); + InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA; + } + if (IOPending == (u32)TRUE) { + IOPending = (u32)FALSE; + } else { + Index++; + } + } + /* De-select slave */ + XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr); + XQspiPsu_ManualStartEnable(InstancePtr); + do { + QspiPsuStatusReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_ISR_OFFSET); + } while ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) == (u32)FALSE); + + /* Clear the busy flag. */ + InstancePtr->IsBusy = (u32)FALSE; + + Status = (s32)XST_SUCCESS; + +#if defined (XCLOCKING) + Xil_ClockDisable(InstancePtr->Config.RefClk); +#endif + END: + return Status; +} + +/*****************************************************************************/ +/** + * + * 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. + * + ******************************************************************************/ +s32 XQspiPsu_InterruptTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 NumMsg) +{ + s32 Index; + s32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + for (Index = 0; Index < (s32)NumMsg; Index++) + Xil_AssertNonvoid(Msg[Index].ByteCount > 0U); + /* + * Check whether there is another transfer in progress. + * Not thread-safe + */ + if (InstancePtr->IsBusy == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + goto END; + } +#if defined (XCLOCKING) + Xil_ClockEnable(InstancePtr->Config.RefClk); +#endif + + if ((Msg[0].Flags & XQSPIPSU_MSG_FLAG_POLL) != (u32)FALSE) { + InstancePtr->IsBusy = (u32)TRUE; + XQspiPsu_PollDataConfig(InstancePtr, Msg); + } else { + /* Check for ByteCount upper limit - 2^28 for DMA */ + for (Index = 0; Index < (s32)NumMsg; Index++) { + if ((Msg[Index].ByteCount > XQSPIPSU_DMA_BYTES_MAX) && + ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) { + Status = (s32)XST_FAILURE; + goto END; + } + } + /* + * Set the busy flag, which will be cleared when the transfer is + * entirely done. + */ + InstancePtr->IsBusy = (u32)TRUE; + + InstancePtr->Msg = Msg; + InstancePtr->NumMsg = (s32)NumMsg; + InstancePtr->MsgCnt = 0; + + /* Select slave */ + XQspiPsu_GenFifoEntryCSAssert(InstancePtr); + /* This might not work if not manual start */ + /* Put first message in FIFO along with the above slave select */ + XQspiPsu_GenFifoEntryData(InstancePtr, &Msg[0]); + XQspiPsu_ManualStartEnable(InstancePtr); + + /* Enable interrupts */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_IER_OFFSET, + (u32)XQSPIPSU_IER_TXNOT_FULL_MASK | + (u32)XQSPIPSU_IER_TXEMPTY_MASK | + (u32)XQSPIPSU_IER_RXNEMPTY_MASK | + (u32)XQSPIPSU_IER_GENFIFOEMPTY_MASK | + (u32)XQSPIPSU_IER_RXEMPTY_MASK); + + if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_QSPIDMA_DST_I_EN_OFFSET, + XQSPIPSU_QSPIDMA_DST_I_EN_DONE_MASK); + } + } + Status = (s32)XST_SUCCESS; + + END: + return Status; +} + +/*****************************************************************************/ +/** + * + * 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. + * + ******************************************************************************/ +s32 XQspiPsu_InterruptHandler(XQspiPsu *InstancePtr) +{ + u32 QspiPsuStatusReg, DmaIntrStatusReg = 0; + XQspiPsu_Msg *Msg; + s32 NumMsg; + s32 MsgCnt; + u8 DeltaMsgCnt = 0; + u32 TxRxFlag; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(InstancePtr->NumMsg > 0); + Xil_AssertNonvoid(InstancePtr->Msg != NULL); + + Msg = InstancePtr->Msg; + NumMsg = InstancePtr->NumMsg; + MsgCnt = InstancePtr->MsgCnt; + TxRxFlag = Msg[MsgCnt].Flags; + + /* QSPIPSU Intr cleared on read */ + QspiPsuStatusReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_ISR_OFFSET); + if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { + /* DMA Intr write to clear */ + DmaIntrStatusReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET, + DmaIntrStatusReg); + } + if (((DmaIntrStatusReg & XQSPIPSU_QSPIDMA_DST_INTR_ERR_MASK) != (u32)FALSE)) { + /* 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) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_TX) != (u32)FALSE) && + ((QspiPsuStatusReg & XQSPIPSU_ISR_TXNOT_FULL_MASK) != (u32)FALSE) && + (InstancePtr->TxBytes > 0)) { + XQspiPsu_FillTxFifo(InstancePtr, &Msg[MsgCnt], (u32)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) && ((TxRxFlag & XQSPIPSU_MSG_FLAG_TX) != (u32)FALSE) && + ((QspiPsuStatusReg & XQSPIPSU_ISR_TXEMPTY_MASK) != (u32)FALSE) && + ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != (u32)FALSE) && + (InstancePtr->TxBytes == 0) && + ((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) == (u32)FALSE)) { + MsgCnt += 1; + DeltaMsgCnt = 1U; + } + + if ((MsgCnt < NumMsg) && + ((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) { + if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { + if ((DmaIntrStatusReg & + XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK) != (u32)FALSE) { + /* DMA transfer done, Invalidate Data Cache */ + if (!((Msg[MsgCnt].RxAddr64bit >= XQSPIPSU_RXADDR_OVER_32BIT) || + (Msg[MsgCnt].Xfer64bit != (u8)0U)) && + (InstancePtr->Config.IsCacheCoherent == 0U)) { + Xil_DCacheInvalidateRange((INTPTR)Msg[MsgCnt].RxBfrPtr, (INTPTR)Msg[MsgCnt].ByteCount); + } + if (XQspiPsu_SetIOMode(InstancePtr, &Msg[MsgCnt]) == (u32)TRUE) { + XQspiPsu_GenFifoEntryData(InstancePtr, &Msg[MsgCnt]); + XQspiPsu_ManualStartEnable(InstancePtr); + } else { + InstancePtr->RxBytes = 0; + MsgCnt += 1; + DeltaMsgCnt = 1U; + } + } + } else { + if (InstancePtr->RxBytes != 0) { + XQspiPsu_IORead(InstancePtr, &Msg[MsgCnt], QspiPsuStatusReg); + if (InstancePtr->RxBytes == 0) { + MsgCnt += 1; + DeltaMsgCnt = 1U; + } + } + } + } + + /* + * 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 == (u8)FALSE) && + ((TxRxFlag & XQSPIPSU_MSG_FLAG_RX) == (u32)FALSE) && + ((TxRxFlag & XQSPIPSU_MSG_FLAG_TX) == (u32)FALSE) && + ((TxRxFlag & XQSPIPSU_MSG_FLAG_POLL) == (u32)FALSE) && + ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != (u32)FALSE)) { + MsgCnt += 1; + DeltaMsgCnt = 1U; + } + 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) != (u32)FALSE) && + ((DeltaMsgCnt != (u8)FALSE) || (MsgCnt > NumMsg))) { + if (MsgCnt < NumMsg) { + if (InstancePtr->IsUnaligned != 0) { + InstancePtr->IsUnaligned = 0; + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET, (XQspiPsu_ReadReg( + InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET) | + XQSPIPSU_CFG_MODE_EN_DMA_MASK)); + InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA; + } + /* This might not work if not manual start */ + XQspiPsu_GenFifoEntryData(InstancePtr, &Msg[MsgCnt]); + XQspiPsu_ManualStartEnable(InstancePtr); + } 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); + XQspiPsu_ManualStartEnable(InstancePtr); + } else { + /* Disable interrupts */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_IDR_OFFSET, + (u32)XQSPIPSU_IER_TXNOT_FULL_MASK | + (u32)XQSPIPSU_IER_TXEMPTY_MASK | + (u32)XQSPIPSU_IER_RXNEMPTY_MASK | + (u32)XQSPIPSU_IER_GENFIFOEMPTY_MASK | + (u32)XQSPIPSU_IER_RXEMPTY_MASK); + if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_I_DIS_OFFSET, + XQSPIPSU_QSPIDMA_DST_I_EN_DONE_MASK); + } + /* Clear the busy flag. */ + InstancePtr->IsBusy = (u32)FALSE; +#if defined (XCLOCKING) + Xil_ClockDisable(InstancePtr->Config.RefClk); +#endif + /* Call status handler to indicate completion */ + InstancePtr->StatusHandler(InstancePtr->StatusRef, + XST_SPI_TRANSFER_DONE, 0); + } + } + if ((TxRxFlag & XQSPIPSU_MSG_FLAG_POLL) != (u32)FALSE) { + XQspiPsu_PollDataHandler(InstancePtr, QspiPsuStatusReg); + } + return (s32)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. + * + * <pre> + * + * 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. + * + * </pre> + * @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 FuncPointer 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 FuncPointer) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(FuncPointer != NULL); + Xil_AssertVoid(CallBackRef != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + InstancePtr->StatusHandler = FuncPointer; + InstancePtr->StatusRef = CallBackRef; +} + +/*****************************************************************************/ +/** + * @brief + * This API enables/ disables Write Protect pin on the flash parts. + * + * @param InstancePtr is a pointer to the QSPIPSU driver component to use. + * + * @param Toggle is a value of the GPIO pin + * + * @return None + * + * @note By default WP pin as per the QSPI controller is driven High + * which means no write protection. Calling this function once + * will enable the protection. + * + ******************************************************************************/ +void XQspiPsu_WriteProtectToggle(const XQspiPsu *InstancePtr, u32 Toggle) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + /* For Single and Stacked flash configuration with x1 or x2 mode*/ + if (InstancePtr->Config.ConnectionMode == + XQSPIPSU_CONNECTION_MODE_SINGLE) { + /* Select slave */ + XQspiPsu_GenFifoEntryCSAssert(InstancePtr); + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_GPIO_OFFSET, Toggle); + + } else { +#ifdef DEBUG + xil_printf("Dual Parallel/Stacked configuration "); + xil_printf("is not supported by this API\r\n"); +#endif + } +} + +/*****************************************************************************/ +/** +* +* This function start a DMA transfer. +* + * @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 ByteCount is greater than + * XQSPIPSU_DMA_BYTES_MAX. + * - XST_DEVICE_BUSY if a transfer is already in progress. + * + * @note None. + * +* +******************************************************************************/ +s32 XQspiPsu_StartDmaTransfer(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 NumMsg) +{ + s32 Index; + u32 QspiPsuStatusReg = 0; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(Msg != NULL); + Xil_AssertNonvoid(NumMsg > 0U); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + for (Index = 0; Index < (s32)NumMsg; Index++) { + Xil_AssertNonvoid(Msg[Index].ByteCount > 0U); + } + + /* + * Check whether there is another transfer in progress. + * Not thread-safe + */ + if (InstancePtr->IsBusy == (u32)TRUE) { + return (s32)XST_DEVICE_BUSY; + } + + /* Check for ByteCount upper limit - 2^28 for DMA */ + for (Index = 0; Index < (s32)NumMsg; Index++) { + if ((Msg[Index].ByteCount > XQSPIPSU_DMA_BYTES_MAX) && + ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) { + return (s32)XST_FAILURE; + } + } + + /* + * Set the busy flag, which will be cleared when the transfer is + * entirely done. + */ + InstancePtr->IsBusy = (u32)TRUE; + + /* Select slave */ + XQspiPsu_GenFifoEntryCSAssert(InstancePtr); + /* list */ + Index = 0; + while (Index < (s32)NumMsg) { + InstancePtr->Msg = &Msg[Index]; + XQspiPsu_GenFifoEntryData(InstancePtr, &Msg[Index]); + if (InstancePtr->IsManualstart == (u32)TRUE) { +#ifdef DEBUG + xil_printf("\nManual Start\r\n"); +#endif + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET) | + XQSPIPSU_CFG_START_GEN_FIFO_MASK); + } + do { + if((InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) && + ((Msg[Index].Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) { + break; + } + QspiPsuStatusReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_ISR_OFFSET); + + } while (((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) == (u32)FALSE) || + (InstancePtr->TxBytes != 0) || + ((QspiPsuStatusReg & XQSPIPSU_ISR_TXEMPTY_MASK) == (u32)FALSE)); + + if(InstancePtr->ReadMode == XQSPIPSU_READMODE_IO) { + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET, (XQspiPsu_ReadReg( + InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET) | + XQSPIPSU_CFG_MODE_EN_DMA_MASK)); + InstancePtr->ReadMode = XQSPIPSU_READMODE_DMA; + } + Index++; + } + return (s32)XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function check for DMA transfer complete. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* +* @return +* - XST_SUCCESS if DMA transfer complete. +* - XST_FAILURE if DMA transfer is not completed. +* +* @note None. +* +******************************************************************************/ +s32 XQspiPsu_CheckDmaDone(XQspiPsu *InstancePtr) +{ + u32 QspiPsuStatusReg; + u32 DmaIntrSts; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + DmaIntrSts = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET); + if ((DmaIntrSts & XQSPIPSU_QSPIDMA_DST_I_STS_DONE_MASK) != (u32)FALSE) { + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_QSPIDMA_DST_I_STS_OFFSET, DmaIntrSts); + /* DMA transfer done, Invalidate Data Cache */ + if (!((InstancePtr->Msg->RxAddr64bit >= XQSPIPSU_RXADDR_OVER_32BIT) || + (InstancePtr->Msg->Xfer64bit != (u8)0U)) && + (InstancePtr->Config.IsCacheCoherent == 0U)) { + Xil_DCacheInvalidateRange((INTPTR)InstancePtr->Msg->RxBfrPtr, (INTPTR)InstancePtr->RxBytes); + } + /* De-select slave */ + XQspiPsu_GenFifoEntryCSDeAssert(InstancePtr); + if (InstancePtr->IsManualstart == (u8)TRUE) { +#ifdef DEBUG + xil_printf("\nManual Start\r\n"); +#endif + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET) | + XQSPIPSU_CFG_START_GEN_FIFO_MASK); + } + do { + QspiPsuStatusReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_ISR_OFFSET); + } while ((QspiPsuStatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) == (u32)FALSE); + + /* Clear the busy flag. */ + InstancePtr->IsBusy = (u32)FALSE; + + return (s32)XST_SUCCESS; + } + else { + return (s32)XST_FAILURE; + } + +} +/** @} */ diff --git a/bsps/shared/dev/spi/xqspipsu_control.c b/bsps/shared/dev/spi/xqspipsu_control.c new file mode 100644 index 0000000000..af2400bf4c --- /dev/null +++ b/bsps/shared/dev/spi/xqspipsu_control.c @@ -0,0 +1,282 @@ +/****************************************************************************** +* Copyright (C) 2020 - 2022 Xilinx, Inc. All rights reserved. +* SPDX-License-Identifier: MIT +******************************************************************************/ + + +/*****************************************************************************/ +/** + * + * @file xqspipsu_control.c + * @addtogroup Overview + * @{ + * + * This file contains intermediate control functions used by functions + * in xqspipsu.c and xqspipsu_options.c files. + * + * <pre> + * MODIFICATION HISTORY: + * + * Ver Who Date Changes + * ----- --- -------- ----------------------------------------------- + * 1.11 akm 03/09/20 First release + * 1.13 akm 01/04/21 Fix MISRA-C violations. + * 1.15 akm 10/21/21 Fix MISRA-C violations. + * 1.15 akm 03/03/22 Enable tapdelay settings for applications on + * Microblaze platform. + * </pre> + * + ******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xqspipsu_control.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +/*****************************************************************************/ + +/*****************************************************************************/ +/** + * + * 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. + * + * @return + * - XST_SUCCESS if successful. + * - XST_FAILURE if transfer fails. + * - XST_DEVICE_BUSY if a transfer is already in progress. + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_GenFifoEntryData(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg) +{ + u32 GenFifoEntry; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_GenFifoEntryData\r\n"); +#endif + + GenFifoEntry = 0x0U; + /* Bus width */ + GenFifoEntry &= ~(u32)XQSPIPSU_GENFIFO_MODE_MASK; + GenFifoEntry |= XQspiPsu_SelectSpiMode((u8)Msg->BusWidth); + + GenFifoEntry |= InstancePtr->GenFifoCS; + GenFifoEntry &= ~(u32)XQSPIPSU_GENFIFO_BUS_MASK; + GenFifoEntry |= InstancePtr->GenFifoBus; + + /* Data */ + if (((Msg->Flags) & XQSPIPSU_MSG_FLAG_STRIPE) != (u32)FALSE) { + GenFifoEntry |= XQSPIPSU_GENFIFO_STRIPE; + } else { + GenFifoEntry &= ~XQSPIPSU_GENFIFO_STRIPE; + } + /* If Byte Count is less than 8 bytes do the transfer in IO mode */ + if ((Msg->ByteCount < 8U) && + (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA)) { + InstancePtr->ReadMode = XQSPIPSU_READMODE_IO; + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + (XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET) & + ~XQSPIPSU_CFG_MODE_EN_MASK)); + InstancePtr->IsUnaligned = 1; + } + + XQspiPsu_TXRXSetup(InstancePtr, Msg, &GenFifoEntry); + + XQspiPsu_GenFifoEntryDataLen(InstancePtr, Msg, &GenFifoEntry); + + /* One dummy GenFifo entry in case of IO mode */ + if ((InstancePtr->ReadMode == XQSPIPSU_READMODE_IO) && + ((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) { + GenFifoEntry = 0x0U; +#ifdef DEBUG + xil_printf("\nDummy FifoEntry=%08x\r\n", GenFifoEntry); +#endif + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry); + } +} + +/*****************************************************************************/ +/** + * + * This function enables the polling functionality of controller + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * + * + * @param FlashMsg is a pointer to the structure containing transfer data + * + * @return None + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_PollDataConfig(XQspiPsu *InstancePtr, XQspiPsu_Msg *FlashMsg) +{ + + u32 GenFifoEntry; + u32 Value; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(FlashMsg != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_PollDataConfig\r\n"); +#endif + + Value = XQspiPsu_CreatePollDataConfig(InstancePtr, FlashMsg); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_POLL_CFG_OFFSET, Value); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_P_TO_OFFSET, FlashMsg->PollTimeout); + + XQspiPsu_GenFifoEntryCSAssert(InstancePtr); + + GenFifoEntry = (u32)0; + GenFifoEntry |= (u32)XQSPIPSU_GENFIFO_TX; + GenFifoEntry |= InstancePtr->GenFifoBus; + GenFifoEntry |= InstancePtr->GenFifoCS; + GenFifoEntry |= (u32)XQSPIPSU_GENFIFO_MODE_SPI; + GenFifoEntry |= (u32)FlashMsg->PollStatusCmd; + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry); + + GenFifoEntry = (u32)0; + GenFifoEntry |= (u32)XQSPIPSU_GENFIFO_POLL; + GenFifoEntry |= (u32)XQSPIPSU_GENFIFO_RX; + GenFifoEntry |= InstancePtr->GenFifoBus; + GenFifoEntry |= InstancePtr->GenFifoCS; + GenFifoEntry |= (u32)XQSPIPSU_GENFIFO_MODE_SPI; + if (((FlashMsg->Flags) & XQSPIPSU_MSG_FLAG_STRIPE) != (u32)FALSE) { + GenFifoEntry |= XQSPIPSU_GENFIFO_STRIPE; + } else { + GenFifoEntry &= ~XQSPIPSU_GENFIFO_STRIPE; + } + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET, + GenFifoEntry); + + /* One Dummy entry required for IO mode */ + GenFifoEntry = 0x0U; + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET, + GenFifoEntry); + + InstancePtr->Msg = FlashMsg; + InstancePtr->NumMsg = (s32)1; + InstancePtr->MsgCnt = 0; + + Value = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + Value &= ~XQSPIPSU_CFG_MODE_EN_MASK; + Value |= (XQSPIPSU_CFG_START_GEN_FIFO_MASK | + XQSPIPSU_CFG_GEN_FIFO_START_MODE_MASK | + XQSPIPSU_CFG_EN_POLL_TO_MASK); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + Value); + + /* Enable interrupts */ + Value = ((u32)XQSPIPSU_IER_RXNEMPTY_MASK | + (u32)XQSPIPSU_IER_POLL_TIME_EXPIRE_MASK); + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_IER_OFFSET, + Value); + +} + +#if defined (ARMR5) || defined (__aarch64__) || defined (__MICROBLAZE__) +/*****************************************************************************/ +/** +* +* Configures the clock according to the prescaler passed. +* +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Prescaler - clock prescaler. +* +* @return +* - XST_SUCCESS if successful. +* - XST_DEVICE_BUSY if the device is currently transferring data. +* The transfer must complete or be aborted before setting Tapdelay. +* +* @note None. +* +******************************************************************************/ +s32 XQspipsu_Calculate_Tapdelay(const XQspiPsu *InstancePtr, u8 Prescaler) +{ + u32 FreqDiv, Divider; + u32 Tapdelay = 0; + u32 LBkModeReg = 0; + u32 delayReg = 0; + s32 Status; + + 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 == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + goto END; + } else { + + Divider = (u32)1U << (Prescaler+1U); + + FreqDiv = (InstancePtr->Config.InputClockHz)/Divider; + +#if defined (versal) + if (FreqDiv <= XQSPIPSU_FREQ_37_5MHZ) { +#else + if (FreqDiv <= XQSPIPSU_FREQ_40MHZ) { +#endif + Tapdelay |= (TAPDLY_BYPASS_VALVE_40MHZ << + IOU_TAPDLY_BYPASS_LQSPI_RX_SHIFT); + } else if (FreqDiv <= XQSPIPSU_FREQ_100MHZ) { + Tapdelay |= (TAPDLY_BYPASS_VALVE_100MHZ << + IOU_TAPDLY_BYPASS_LQSPI_RX_SHIFT); + LBkModeReg |= (USE_DLY_LPBK << XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_SHIFT); +#if defined (versal) + delayReg |= (u32)USE_DATA_DLY_ADJ << + XQSPIPSU_DATA_DLY_ADJ_USE_DATA_DLY_SHIFT; +#else + delayReg |= ((u32)USE_DATA_DLY_ADJ << + XQSPIPSU_DATA_DLY_ADJ_USE_DATA_DLY_SHIFT) | + ((u32)DATA_DLY_ADJ_DLY << XQSPIPSU_DATA_DLY_ADJ_DLY_SHIFT); +#endif + } else if (FreqDiv <= XQSPIPSU_FREQ_150MHZ) { +#if defined (versal) + LBkModeReg |= (USE_DLY_LPBK << XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_SHIFT) | + (LPBK_DLY_ADJ_DLY1 << XQSPIPSU_LPBK_DLY_ADJ_DLY1_SHIFT); +#else + LBkModeReg |= USE_DLY_LPBK << XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_SHIFT; +#endif + } else { + Status = (s32)XST_FAILURE; + goto END; + } + + Status = XQspipsu_Set_TapDelay(InstancePtr, Tapdelay, LBkModeReg, delayReg); + } + + END: + return Status; +} +#endif +/** @} */ diff --git a/bsps/shared/dev/spi/xqspipsu_hw.c b/bsps/shared/dev/spi/xqspipsu_hw.c new file mode 100644 index 0000000000..6f7708893f --- /dev/null +++ b/bsps/shared/dev/spi/xqspipsu_hw.c @@ -0,0 +1,768 @@ +/****************************************************************************** +* Copyright (C) 2020 - 2022 Xilinx, Inc. All rights reserved. +* SPDX-License-Identifier: MIT +******************************************************************************/ + + +/*****************************************************************************/ +/** + * + * @file xqspipsu_hw.c + * @addtogroup Overview + * @{ + * + * This file contains functions to reads RXFifo, writes TXFifo and setup + * RX DMA operation, used by xqspipsu_control.c and xqspipsu_lowlevel.c files. + * + * <pre> + * MODIFICATION HISTORY: + * + * Ver Who Date Changes + * ----- --- -------- ----------------------------------------------- + * 1.11 akm 03/09/20 First release + * mn 03/30/20 Add xil_smc.h include for Xil_Smc calls + * 1.13 akm 01/04/21 Fix MISRA-C violations. + * 1.15 akm 10/21/21 Fix MISRA-C violations. + * 1.15 akm 11/16/21 Typecast function parameter with appropriate + * data type. + * 1.15 akm 11/30/21 Fix compilation warnings reported with -Wundef flag + * 1.15 akm 03/03/22 Enable tapdelay settings for applications on + * Microblaze platform. + * + * </pre> + ******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xqspipsu.h" +#include "xqspipsu_control.h" +#if defined (__aarch64__) +#include "xil_smc.h" +#endif +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +/*****************************************************************************/ + +/*****************************************************************************/ +/** + * + * 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. + * + ******************************************************************************/ +void XQspiPsu_FillTxFifo(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, u32 Size) +{ + u32 Count = 0; + u32 Data = 0U; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(Size != 0U); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_FillTxFifo\r\n"); +#endif + while ((InstancePtr->TxBytes > 0) && (Count < Size)) { + if (InstancePtr->TxBytes >= 4) { + (void)Xil_MemCpy((u8 *)&Data, Msg->TxBfrPtr, 4); + Msg->TxBfrPtr += 4; + InstancePtr->TxBytes -= 4; + Count += 4U; + } else { + (void)Xil_MemCpy((u8 *)&Data, Msg->TxBfrPtr, + (u32)InstancePtr->TxBytes); + Msg->TxBfrPtr += InstancePtr->TxBytes; + Count += (u32)InstancePtr->TxBytes; + InstancePtr->TxBytes = 0; + } + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_TXD_OFFSET, Data); +#ifdef DEBUG + xil_printf("\nData is %08x\r\n", Data); +#endif + + } + if (InstancePtr->TxBytes < 0) { + InstancePtr->TxBytes = 0; + } +} + +/*****************************************************************************/ +/** + * + * This function checks the TX buffer in the message and setup the + * TX FIFO as required. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * + * @return None + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_TXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_TXSetup\r\n"); +#endif + InstancePtr->TxBytes = (s32)Msg->ByteCount; + InstancePtr->SendBufferPtr = Msg->TxBfrPtr; + + XQspiPsu_FillTxFifo(InstancePtr, Msg, (u32)XQSPIPSU_TXD_DEPTH); +} + +/*****************************************************************************/ +/** + * + * 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. + * + ******************************************************************************/ +void XQspiPsu_SetupRxDma(const XQspiPsu *InstancePtr, + XQspiPsu_Msg *Msg) +{ + s32 Remainder; + s32 DmaRxBytes; + UINTPTR AddrTemp; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_SetupRxDma\r\n"); +#endif + + AddrTemp = ((UINTPTR)(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); + +#if defined(__aarch64__) || defined(__arch64__) + AddrTemp = ((UINTPTR)(Msg->RxBfrPtr) >> 32U); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_ADDR_MSB_OFFSET, (u32)AddrTemp & + XQSPIPSU_QSPIDMA_DST_ADDR_MSB_MASK); +#else + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_ADDR_MSB_OFFSET, 0U); +#endif + + Remainder = InstancePtr->RxBytes % 4; + DmaRxBytes = InstancePtr->RxBytes; + if (Remainder != 0) { + /* This is done to make Dma bytes aligned */ + DmaRxBytes = InstancePtr->RxBytes - Remainder; + Msg->ByteCount = (u32)DmaRxBytes; + } + if (InstancePtr->Config.IsCacheCoherent == 0U) { + Xil_DCacheInvalidateRange((INTPTR)Msg->RxBfrPtr, (INTPTR)Msg->ByteCount); + } + /* Write no. of words to DMA DST SIZE */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_SIZE_OFFSET, (u32)DmaRxBytes); +} + +/*****************************************************************************/ +/** + * + * This function sets up the RX DMA operation on a 32bit Machine + * For 64bit Dma transfers. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * + * @return None + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_Setup64BRxDma(const XQspiPsu *InstancePtr, + XQspiPsu_Msg *Msg) +{ + s32 Remainder; + s32 DmaRxBytes; + u64 AddrTemp; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_Setup64BRxDma\r\n"); +#endif + AddrTemp = Msg->RxAddr64bit & XQSPIPSU_QSPIDMA_DST_ADDR_MASK; + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_ADDR_OFFSET, (u32)AddrTemp); + + AddrTemp = (Msg->RxAddr64bit >> 32); + 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 - Remainder; + Msg->ByteCount = (u32)DmaRxBytes; + } + + /* Write no. of words to DMA DST SIZE */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_QSPIDMA_DST_SIZE_OFFSET, (u32)DmaRxBytes); + +} + +/*****************************************************************************/ +/** + * + * This function reads remaining bytes, after the completion of a DMA transfer, + * using IO mode + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * + * @return + * - XST_SUCCESS if successful. + * - XST_FAILURE if transfer fails. + * - XST_DEVICE_BUSY if a transfer is already in progress. + * + * @note None. + * + ******************************************************************************/ +u32 XQspiPsu_SetIOMode(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(Msg != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_DMARXComplete\r\n"); +#endif + + /* Read remaining bytes using IO mode */ + if ((InstancePtr->RxBytes % 4) != 0) { + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + (XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET) & + ~XQSPIPSU_CFG_MODE_EN_MASK)); + InstancePtr->ReadMode = XQSPIPSU_READMODE_IO; + Msg->ByteCount = (u32)InstancePtr->RxBytes % 4U; + Msg->RxBfrPtr += (InstancePtr->RxBytes - (InstancePtr->RxBytes % 4)); + InstancePtr->IsUnaligned = 1; + return (u32) TRUE; + } + return (u32) FALSE; +} + +/*****************************************************************************/ +/** + * + * This function checks the RX buffers in the message and setup the + * RX DMA as required. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * + * @return None + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_RXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_RXSetup\r\n"); +#endif + InstancePtr->RxBytes = (s32)Msg->ByteCount; + + if (InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA) { + if ((Msg->RxAddr64bit >= XQSPIPSU_RXADDR_OVER_32BIT) || + (Msg->Xfer64bit != (u8)0U)) { + XQspiPsu_Setup64BRxDma(InstancePtr, Msg); + } else { + XQspiPsu_SetupRxDma(InstancePtr, Msg); + } + } +} + +/*****************************************************************************/ +/** + * + * 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. + * + ******************************************************************************/ +void XQspiPsu_TXRXSetup(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 *GenFifoEntry) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(GenFifoEntry != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_TXRXSetup\r\n"); +#endif + /* Transmit */ + if (((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) != (u32)FALSE) && + ((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) == (u32)FALSE)) { + + *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER; + *GenFifoEntry |= XQSPIPSU_GENFIFO_TX; + /* Discard RX data */ + *GenFifoEntry &= ~XQSPIPSU_GENFIFO_RX; + + /* Setup data to be TXed */ + XQspiPsu_TXSetup(InstancePtr, Msg); + + InstancePtr->RecvBufferPtr = NULL; + InstancePtr->RxBytes = 0; + } + /*Receive*/ + if (((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE) && + ((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) == (u32)FALSE)) { + + /* TX auto fill */ + *GenFifoEntry &= ~XQSPIPSU_GENFIFO_TX; + /* Setup RX */ + *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER; + *GenFifoEntry |= XQSPIPSU_GENFIFO_RX; + + /* Setup DMA for data to be RXed */ + XQspiPsu_RXSetup(InstancePtr, Msg); + + InstancePtr->SendBufferPtr = NULL; + InstancePtr->TxBytes = 0; + } + /* If only dummy is requested as a separate entry */ + if (((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) == (u32)FALSE) && + ((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) == (u32)FALSE)) { + + *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER; + *GenFifoEntry &= ~(XQSPIPSU_GENFIFO_TX | XQSPIPSU_GENFIFO_RX); + InstancePtr->TxBytes = 0; + InstancePtr->RxBytes = 0; + InstancePtr->SendBufferPtr = NULL; + InstancePtr->RecvBufferPtr = NULL; + } + /* Dummy and cmd sent by upper layer to received data */ + if (((Msg->Flags & XQSPIPSU_MSG_FLAG_TX) != (u32)FALSE) && + ((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) { + *GenFifoEntry |= XQSPIPSU_GENFIFO_DATA_XFER; + *GenFifoEntry |= (XQSPIPSU_GENFIFO_TX | XQSPIPSU_GENFIFO_RX); + + /* Setup data to be TXed */ + XQspiPsu_TXSetup(InstancePtr, Msg); + /* Setup DMA for data to be RXed */ + XQspiPsu_RXSetup(InstancePtr, Msg); + } +} +/*****************************************************************************/ +/** + * + * This function writes the Data length to GENFIFO entries that need to be + * transmitted or received. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * @param GenFifoEntry is 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. + * + ******************************************************************************/ +void XQspiPsu_GenFifoEntryDataLen(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 *GenFifoEntry) +{ + u32 TempCount; + u32 ImmData; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(GenFifoEntry != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_GenFifoEntryDataLen\r\n"); +#endif + + if (Msg->ByteCount <= XQSPIPSU_GENFIFO_IMM_DATA_MASK) { + *GenFifoEntry &= ~(u32)XQSPIPSU_GENFIFO_IMM_DATA_MASK; + *GenFifoEntry |= Msg->ByteCount; + #ifdef DEBUG + xil_printf("\nFifoEntry=%08x\r\n", *GenFifoEntry); + #endif + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET, + *GenFifoEntry); + } else { + TempCount = Msg->ByteCount; + u32 Exponent = 8; /* 2^8 = 256 */ + ImmData = TempCount & 0xFFU; + /* Exponent entries */ + *GenFifoEntry |= XQSPIPSU_GENFIFO_EXP; + while (TempCount != 0U) { + if ((TempCount & XQSPIPSU_GENFIFO_EXP_START) != (u32)FALSE) { + *GenFifoEntry &= ~(u32)XQSPIPSU_GENFIFO_IMM_DATA_MASK; + *GenFifoEntry |= Exponent; + #ifdef DEBUG + xil_printf("\nFifoEntry=%08x\r\n", + *GenFifoEntry); + #endif + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET, + *GenFifoEntry); + } + TempCount = TempCount >> 1; + Exponent++; + } + /* Immediate entry */ + *GenFifoEntry &= ~(u32)XQSPIPSU_GENFIFO_EXP; + if ((ImmData & 0xFFU) != (u32)FALSE) { + *GenFifoEntry &= ~(u32)XQSPIPSU_GENFIFO_IMM_DATA_MASK; + *GenFifoEntry |= ImmData & 0xFFU; + #ifdef DEBUG + xil_printf("\nFifoEntry=%08x\r\n", *GenFifoEntry); + #endif + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET, + *GenFifoEntry); + } + } +} + +/*****************************************************************************/ +/** + * + * This function creates Poll config register data to write + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * + * @param FlashMsg is a pointer to the structure containing transfer data. + * + * @return None + * + * @note None. + * + ******************************************************************************/ +u32 XQspiPsu_CreatePollDataConfig(const XQspiPsu *InstancePtr, + const XQspiPsu_Msg *FlashMsg) +{ + u32 ConfigData = 0; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(FlashMsg != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_CreatePollDataConfig\r\n"); +#endif + + if ((InstancePtr->GenFifoBus & XQSPIPSU_GENFIFO_BUS_UPPER) != (u32)FALSE) { + ConfigData = (u32)XQSPIPSU_SELECT_FLASH_BUS_LOWER << + XQSPIPSU_POLL_CFG_EN_MASK_UPPER_SHIFT; + } + if ((InstancePtr->GenFifoBus & XQSPIPSU_GENFIFO_BUS_LOWER) != (u32)FALSE) { + ConfigData |= (u32)XQSPIPSU_SELECT_FLASH_BUS_LOWER << + XQSPIPSU_POLL_CFG_EN_MASK_LOWER_SHIFT; + } + ConfigData |= (u32)(((u32)FlashMsg->PollBusMask << + XQSPIPSU_POLL_CFG_MASK_EN_SHIFT) & XQSPIPSU_POLL_CFG_MASK_EN_MASK); + ConfigData |= (u32)(((u32)FlashMsg->PollData << + XQSPIPSU_POLL_CFG_DATA_VALUE_SHIFT) + & XQSPIPSU_POLL_CFG_DATA_VALUE_MASK); + return ConfigData; +} + +/*****************************************************************************/ +/** + * + * 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. + * + ******************************************************************************/ +u32 XQspiPsu_SelectSpiMode(u8 SpiMode) +{ + u32 Mask; + + Xil_AssertNonvoid(SpiMode > 0U); +#ifdef DEBUG + xil_printf("\nXQspiPsu_SelectSpiMode\r\n"); +#endif + + 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: + Mask = XQSPIPSU_GENFIFO_MODE_SPI; + break; + default: + Mask = XQSPIPSU_GENFIFO_MODE_SPI; + break; + } +#ifdef DEBUG + xil_printf("\nSPIMode is %08x\r\n", SpiMode); +#endif + return Mask; +} + +/*****************************************************************************/ +/** + * + * Enable and initialize DMA Mode, set little endain, disable poll timeout, + * clear prescalar bits and reset thresholds + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * + * @return None. + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_SetDefaultConfig(XQspiPsu *InstancePtr) +{ + u32 ConfigReg; + + Xil_AssertVoid(InstancePtr != NULL); +#ifdef DEBUG + xil_printf("\nXQspiPsu_SetDefaultConfig\r\n"); +#endif + + /* 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 &= ~(u32)XQSPIPSU_CFG_BAUD_RATE_DIV_MASK; + /* CPOL CPHA 00 */ + ConfigReg &= ~(u32)XQSPIPSU_CFG_CLK_PHA_MASK; + ConfigReg &= ~(u32)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); +} + +/*****************************************************************************/ +/** + * + * Read the specified number of bytes from RX FIFO + * + * @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 read. + * + * @return None + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_ReadRxFifo(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, s32 Size) +{ + s32 Count = 0; + u32 Data; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(Size > 0); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_ReadRxFifo\r\n"); +#endif + while ((InstancePtr->RxBytes != 0) && (Count < Size)) { + Data = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_RXD_OFFSET); +#ifdef DEBUG + xil_printf("\nData is %08x\r\n", Data); +#endif + if (InstancePtr->RxBytes >= 4) { + (void)Xil_MemCpy(Msg->RxBfrPtr, (u8 *)&Data, 4); + InstancePtr->RxBytes -= 4; + Msg->RxBfrPtr += 4; + Count += 4; + } else { + /* Read unaligned bytes (< 4 bytes) */ + (void)Xil_MemCpy(Msg->RxBfrPtr, (u8 *)&Data, + (u32)InstancePtr->RxBytes); + Msg->RxBfrPtr += InstancePtr->RxBytes; + Count += InstancePtr->RxBytes; + InstancePtr->RxBytes = 0; + } + } +} + +/*****************************************************************************/ +/** + * + * This function reads data from RXFifo in IO mode. + * + * @param InstancePtr is a pointer to the XQspiPsu instance. + * @param Msg is a pointer to the structure containing transfer data. + * @param StatusReg is the Interrupt status Register value. + * + * @return None. + * + * @note None. + * + ******************************************************************************/ +void XQspiPsu_IORead(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, + u32 StatusReg) +{ + s32 RxThr; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(Msg != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); +#ifdef DEBUG + xil_printf("\nXQspiPsu_IORXComplete\r\n"); +#endif + + if ((StatusReg & XQSPIPSU_ISR_RXNEMPTY_MASK) != 0U) { + /* + * Check if PIO RX is complete and + * update RxBytes + */ + RxThr = (s32)XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_RX_THRESHOLD_OFFSET); + RxThr = RxThr*4; + XQspiPsu_ReadRxFifo(InstancePtr, Msg, RxThr); + + return; + } + + if ((StatusReg & XQSPIPSU_ISR_GENFIFOEMPTY_MASK) != 0U) { + XQspiPsu_ReadRxFifo(InstancePtr, Msg, InstancePtr->RxBytes); + } +} + +#if defined (ARMR5) || defined (__aarch64__) || defined (__MICROBLAZE__) +/*****************************************************************************/ +/** +* +* This function sets the Tapdelay values for the QSPIPSU device driver.The device +* must be idle rather than busy transferring data before setting Tapdelay. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param TapdelayBypss contains the IOU_TAPDLY_BYPASS register value. +* @param LPBKDelay contains the GQSPI_LPBK_DLY_ADJ register value. +* @param Datadelay contains the QSPI_DATA_DLY_ADJ register value. +* +* @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 TapDelay. +* +* @note +* This function is not thread-safe. +* +******************************************************************************/ +s32 XQspipsu_Set_TapDelay(const XQspiPsu *InstancePtr, u32 TapdelayBypass, + u32 LPBKDelay, u32 Datadelay) +{ + s32 Status; + + 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 == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + } else { +#if defined (__aarch64__) && (EL1_NONSECURE == 1) && !defined (versal) + Xil_Smc(MMIO_WRITE_SMC_FID, (u64)(XPS_SYS_CTRL_BASEADDR + + IOU_TAPDLY_BYPASS_OFFSET) | ((u64)(0x4) << 32), + (u64)TapdelayBypass, 0, 0, 0, 0, 0); +#elif defined (versal) + XQspiPsu_WriteReg(XQSPIPS_BASEADDR, IOU_TAPDLY_BYPASS_OFFSET, + TapdelayBypass); +#else + XQspiPsu_WriteReg(XPS_SYS_CTRL_BASEADDR, IOU_TAPDLY_BYPASS_OFFSET, + TapdelayBypass); +#endif + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_LPBK_DLY_ADJ_OFFSET, LPBKDelay); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_DATA_DLY_ADJ_OFFSET, Datadelay); + + Status = (s32)XST_SUCCESS; + } + return Status; +} +#endif +/** @} */ diff --git a/bsps/shared/dev/spi/xqspipsu_options.c b/bsps/shared/dev/spi/xqspipsu_options.c new file mode 100644 index 0000000000..c889d64abb --- /dev/null +++ b/bsps/shared/dev/spi/xqspipsu_options.c @@ -0,0 +1,532 @@ +/****************************************************************************** +* Copyright (C) 2014 - 2022 Xilinx, Inc. All rights reserved. +* SPDX-License-Identifier: MIT +******************************************************************************/ + +/*****************************************************************************/ +/** +* +* @file xqspipsu_options.c +* @addtogroup Overview +* @{ +* +* This file implements functions to configure the QSPIPSU component, +* specifically some optional settings, clock and flash related information. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- -------- ----------------------------------------------- +* 1.0 hk 08/21/14 First release +* sk 03/13/15 Added IO mode support. +* sk 04/24/15 Modified the code according to MISRAC-2012. +* 1.1 sk 04/12/16 Added debug message prints. +* 1.2 nsk 07/01/16 Modified XQspiPsu_SetOptions() to support +* LQSPI options and updated OptionsTable +* rk 07/15/16 Added support for TapDelays at different frequencies. +* 1.7 tjs 01/17/18 Added support to toggle the WP pin of flash. (PR#2448) +* 1.7 tjs 03/14/18 Added support in EL1 NS mode. (CR#974882) +* 1.8 tjs 05/02/18 Added support for IS25LP064 and IS25WP064. +* 1.8 tjs 07/26/18 Resolved cppcheck errors. (CR#1006336) +* 1.9 tjs 04/17/18 Updated register addresses as per the latest revision +* of versal (CR#999610) +* 1.9 aru 01/17/19 Fixes violations according to MISRAC-2012 +* in safety mode and modified the code such as +* Added Xil_MemCpy inplace of memcpy,Declared the pointer param +* as Pointer to const, declared XQspi_Set_TapDelay() as static. +* 1.9 akm 03/08/19 Set recommended clock and data tap delay values for 40MHZ, +* 100MHZ and 150MHZ frequencies(CR#1023187) +* 1.10 akm 08/22/19 Set recommended tap delay values for 37.5MHZ, 100MHZ and +* 150MHZ frequencies in Versal. +* 1.11 akm 11/07/19 Removed LQSPI register access in Versal. +* 1.11 akm 11/15/19 Fixed Coverity deadcode warning in +* XQspipsu_Calculate_Tapdelay(). +* 1.11 akm 03/09/20 Reorganize the source code, enable qspi controller and +* interrupts in XQspiPsu_CfgInitialize() API. +* 1.13 akm 01/04/21 Fix MISRA-C violations. +* 1.15 akm 03/03/22 Enable tapdelay settings for applications on Microblaze +* platform. +* +* </pre> +* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xqspipsu_control.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; /**< Get/Set the device option */ + u32 Mask; /**< 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}, +#if !defined (versal) + {XQSPIPSU_LQSPI_MODE_OPTION, XQSPIPSU_CFG_WP_HOLD_MASK}, +#endif +}; + +/** + * Number of options in option table + */ +#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. +* +******************************************************************************/ +s32 XQspiPsu_SetOptions(XQspiPsu *InstancePtr, u32 Options) +{ + u32 ConfigReg; + u32 Index; +#if !defined (versal) + u32 QspiPsuOptions; +#endif + s32 Status; + u32 OptionsVal; + OptionsVal = Options; + + 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 == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + } else { + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); +#if !defined (versal) + QspiPsuOptions = OptionsVal & XQSPIPSU_LQSPI_MODE_OPTION; + OptionsVal &= (~XQSPIPSU_LQSPI_MODE_OPTION); +#endif + /* + * Loop through the options table, turning the option on + * depending on whether the bit is set in the incoming options flag. + */ + for (Index = 0U; Index < XQSPIPSU_NUM_OPTIONS; Index++) { + if ((OptionsVal & OptionsTable[Index].Option) == + OptionsTable[Index].Option) { + /* Turn it on */ + ConfigReg |= OptionsTable[Index].Mask; + } else { + /* 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); + + if ((OptionsVal & XQSPIPSU_MANUAL_START_OPTION) != (u32)FALSE) { + InstancePtr->IsManualstart = (u8)TRUE; + } +#if !defined (versal) + if ((QspiPsuOptions & XQSPIPSU_LQSPI_MODE_OPTION) != (u32)FALSE) { + if ((Options & XQSPIPSU_LQSPI_LESS_THEN_SIXTEENMB) != (u32)FALSE) { + XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_LQSPI_CR_OFFSET,XQSPIPS_LQSPI_CR_RST_STATE); + } else { + XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_LQSPI_CR_OFFSET,XQSPIPS_LQSPI_CR_4_BYTE_STATE); + } + XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_CFG_OFFSET,XQSPIPS_LQSPI_CFG_RST_STATE); + /* Enable the QSPI controller */ + XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_EN_OFFSET,XQSPIPSU_EN_MASK); + } else { + /* + * Check for the LQSPI configuration options. + */ + ConfigReg = XQspiPsu_ReadReg(XQSPIPS_BASEADDR,XQSPIPSU_LQSPI_CR_OFFSET); + ConfigReg &= ~(XQSPIPSU_LQSPI_CR_LINEAR_MASK); + XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_LQSPI_CR_OFFSET, ConfigReg); + } +#endif + Status = (s32)XST_SUCCESS; + } + return Status; +} + +/*****************************************************************************/ +/** +* +* 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. +* +******************************************************************************/ +s32 XQspiPsu_ClearOptions(XQspiPsu *InstancePtr, u32 Options) +{ + u32 ConfigReg; + u32 Index; + s32 Status; + + 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 == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + } else { + + 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 = 0U; Index < XQSPIPSU_NUM_OPTIONS; Index++) { + if ((Options & OptionsTable[Index].Option) != (u32)FALSE) { + /* 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); + + if ((Options & XQSPIPSU_MANUAL_START_OPTION) != (u32)FALSE) { + InstancePtr->IsManualstart = (u8)FALSE; + } + + Status = (s32)XST_SUCCESS; + } + + return Status; +} + +/*****************************************************************************/ +/** +* +* 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(const XQspiPsu *InstancePtr) +{ + u32 OptionsFlag = 0; + u32 ConfigReg; + u32 Index; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* Loop through the options table to grab options */ + for (Index = 0U; Index < XQSPIPSU_NUM_OPTIONS; Index++) { + /* + * Get the current options from QSPIPSU configuration register. + */ + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + if ((ConfigReg & OptionsTable[Index].Mask) != (u32)FALSE) { + 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. +* - XST_DEVICE_BUSY if the device is currently transferring data. +* It must be stopped to re-initialize. +* +* @note None. +* +******************************************************************************/ +s32 XQspiPsu_SetClkPrescaler(const XQspiPsu *InstancePtr, u8 Prescaler) +{ + u32 ConfigReg; + s32 Status; + + 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 == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + } else { + /* + * 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 &= ~(u32)XQSPIPSU_CFG_BAUD_RATE_DIV_MASK; + ConfigReg |= (u32) ((u32)Prescaler & (u32)XQSPIPSU_CR_PRESC_MAXIMUM) << + XQSPIPSU_CFG_BAUD_RATE_DIV_SHIFT; + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + ConfigReg); + +#if defined (ARMR5) || defined (__aarch64__) || defined (__MICROBLAZE__) + Status = XQspipsu_Calculate_Tapdelay(InstancePtr,Prescaler); +#else + Status = (s32)XST_SUCCESS; +#endif + } + return Status; +} + +/*****************************************************************************/ +/** +* +* This function should be used to tell the QSPIPSU driver the HW flash +* configuration being used. This API should be called at least 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 FlashCS - Flash Chip Select. +* @param FlashBus - Flash Bus (Upper, Lower or Both). +* +* @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 function is not called at least 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); + Xil_AssertVoid(FlashCS > 0U); + Xil_AssertVoid(FlashBus > 0U); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + +#ifdef DEBUG + xil_printf("\nXQspiPsu_SelectFlash\r\n"); +#endif + + /* + * 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 = (u32)XQSPIPSU_GENFIFO_CS_LOWER | + (u32)XQSPIPSU_GENFIFO_CS_UPPER; + break; + case XQSPIPSU_SELECT_FLASH_CS_UPPER: + InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_UPPER; + break; + case XQSPIPSU_SELECT_FLASH_CS_LOWER: + InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_LOWER; + break; + default: + InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_LOWER; + break; + } + + /* Choose bus */ + switch (FlashBus) { + case XQSPIPSU_SELECT_FLASH_BUS_BOTH: + InstancePtr->GenFifoBus = (u32)XQSPIPSU_GENFIFO_BUS_LOWER | + (u32)XQSPIPSU_GENFIFO_BUS_UPPER; + break; + case XQSPIPSU_SELECT_FLASH_BUS_UPPER: + InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_UPPER; + break; + case XQSPIPSU_SELECT_FLASH_BUS_LOWER: + InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_LOWER; + break; + default: + InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_LOWER; + break; + } +#ifdef DEBUG + xil_printf("\nGenFifoCS is %08x and GenFifoBus is %08x\r\n", + InstancePtr->GenFifoCS, InstancePtr->GenFifoBus); +#endif + +} + +/*****************************************************************************/ +/** +* +* This function sets the Read mode for the QSPIPSU device driver.The device +* must be idle rather than busy transferring data before setting Read mode +* options. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Mode contains the specified Mode to be set. See the +* bit definitions named XQSPIPSU_READMODE_* 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 Mode. +* +* @note +* This function is not thread-safe. +* +******************************************************************************/ +s32 XQspiPsu_SetReadMode(XQspiPsu *InstancePtr, u32 Mode) +{ + u32 ConfigReg; + s32 Status; + +#ifdef DEBUG + xil_printf("\nXQspiPsu_SetReadMode\r\n"); +#endif + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid((Mode == XQSPIPSU_READMODE_DMA) || (Mode == XQSPIPSU_READMODE_IO)); + + /* + * Do not allow to modify the Control Register while a transfer is in + * progress. Not thread-safe. + */ + if (InstancePtr->IsBusy == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + } else { + + InstancePtr->ReadMode = Mode; + + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + + if (Mode == XQSPIPSU_READMODE_DMA) { + ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK; + ConfigReg |= XQSPIPSU_CFG_MODE_EN_DMA_MASK; + } else { + ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK; + } + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + ConfigReg); + + Status = (s32)XST_SUCCESS; + } +#ifdef DEBUG + xil_printf("\nRead Mode is %08x\r\n", InstancePtr->ReadMode); +#endif + return Status; +} + +/*****************************************************************************/ +/** +* +* This function sets the Write Protect and Hold options for the QSPIPSU device +* driver.The device must be idle rather than busy transferring data before +* setting Write Protect and Hold options. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Value of the WP_HOLD bit in configuration register +* +* @return None +* +* @note +* This function is not thread-safe. This function can only be used with single +* flash configuration and x1/x2 data mode. This function cannot be used with +* x4 data mode and dual parallel and stacked flash configuration. +* +******************************************************************************/ +void XQspiPsu_SetWP(const XQspiPsu *InstancePtr, u8 Value) +{ + u32 ConfigReg; + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertVoid(InstancePtr->IsBusy != TRUE); + + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + ConfigReg |= (u32)((u32)Value << XQSPIPSU_CFG_WP_HOLD_SHIFT); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + ConfigReg); +} +/** @} */ |