summaryrefslogtreecommitdiffstats
path: root/bsps/shared
diff options
context:
space:
mode:
authorAlex White <alex.white@oarcorp.com>2022-12-14 14:10:33 -0600
committerJoel Sherrill <joel@rtems.org>2023-01-27 14:49:27 -0600
commitfd2f9d40b5c48d08ad997bbab894855d3017f362 (patch)
tree23464e5d982564c3bf526d990b8ea95007c140d2 /bsps/shared
parentspec: Install NandPsu headers correctly (diff)
downloadrtems-fd2f9d40b5c48d08ad997bbab894855d3017f362.tar.bz2
bsps: Import Xilinx GQSPI driver
This adds Xilinx's driver for the Xilinx GQSPI controller embedded in the ZynqMP SoC. Within that device alone, it is possible to access this peripheral from MicroBlaze, ARMv7, and ARMv8 cores. The imported files are and should be able to remain unmodified. Import information is kept in bsps/shared/dev/spi/VERSION.
Diffstat (limited to 'bsps/shared')
-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);
+}
+/** @} */