summaryrefslogtreecommitdiffstats
path: root/bsps/shared/dev
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/shared/dev')
-rw-r--r--bsps/shared/dev/spi/VERSION29
-rw-r--r--bsps/shared/dev/spi/xqspipsu.c1048
-rw-r--r--bsps/shared/dev/spi/xqspipsu_control.c282
-rw-r--r--bsps/shared/dev/spi/xqspipsu_hw.c768
-rw-r--r--bsps/shared/dev/spi/xqspipsu_options.c532
5 files changed, 2659 insertions, 0 deletions
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);
+}
+/** @} */