summaryrefslogtreecommitdiffstats
path: root/bsps/shared/dev/spi
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/shared/dev/spi')
-rw-r--r--bsps/shared/dev/spi/VERSION29
-rw-r--r--bsps/shared/dev/spi/xqspipsu-flash-helper.c2341
-rw-r--r--bsps/shared/dev/spi/xqspipsu.c1086
-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
6 files changed, 5038 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-flash-helper.c b/bsps/shared/dev/spi/xqspipsu-flash-helper.c
new file mode 100644
index 0000000000..10e1066173
--- /dev/null
+++ b/bsps/shared/dev/spi/xqspipsu-flash-helper.c
@@ -0,0 +1,2341 @@
+/******************************************************************************
+* Copyright (C) 2018 - 2022 Xilinx, Inc. All rights reserved.
+* SPDX-License-Identifier: MIT
+******************************************************************************/
+
+/**
+ * @file xqspipsu_flash_helper.c
+ *
+ * This file contains flash helper functions for the QSPIPSU driver. It
+ * consists of modified functions from Xilinx's flash example in
+ * examples/xqspipsu_generic_flash_interrupt_example.c of the qspipsu driver.
+ *
+ */
+
+#include "xqspipsu_flash_config.h"
+#include "xqspipsu-flash-helper.h"
+
+#include <rtems.h>
+
+/*
+ * Number of flash pages to be written.
+ */
+#define PAGE_COUNT 32
+
+/*
+ * Max page size to initialize write and read buffer
+ */
+#define MAX_PAGE_SIZE 1024
+
+#define TEST_ADDRESS 0x000000
+
+#define ENTER_4B 1
+#define EXIT_4B 0
+
+u8 ReadCmd;
+u8 WriteCmd;
+u8 StatusCmd;
+u8 SectorEraseCmd;
+u8 FSRFlag;
+
+static int FlashReadID(XQspiPsu *QspiPsuPtr);
+
+static int MultiDieRead(
+ XQspiPsu *QspiPsuPtr,
+ u32 Address,
+ u32 ByteCount,
+ u8 Command,
+ u8 *WriteBfrPtr,
+ u8 *ReadBfrPtr
+);
+
+static u32 GetRealAddr(
+ XQspiPsu *QspiPsuPtr,
+ u32 Address
+);
+
+static int BulkErase(
+ XQspiPsu *QspiPsuPtr,
+ u8 *WriteBfrPtr
+);
+
+static int DieErase(
+ XQspiPsu *QspiPsuPtr,
+ u8 *WriteBfrPtr
+);
+
+static int QspiPsuSetupIntrSystem(
+ XQspiPsu *QspiPsuInstancePtr,
+ u16 QspiPsuIntrId
+);
+
+static void QspiPsuHandler(
+ void *CallBackRef,
+ u32 StatusEvent,
+ unsigned int ByteCount
+);
+
+static int FlashEnterExit4BAddMode(
+ XQspiPsu *QspiPsuPtr,
+ unsigned int Enable
+);
+
+static int FlashEnableQuadMode(XQspiPsu *QspiPsuPtr);
+
+u8 TxBfrPtr;
+u8 ReadBfrPtr[3];
+u32 FlashMake;
+u32 FCTIndex; /* Flash configuration table index */
+
+static XQspiPsu_Msg FlashMsg[5];
+
+/*
+ * The following variables are shared between non-interrupt processing and
+ * interrupt processing such that they must be global.
+ */
+volatile int TransferInProgress;
+
+/*
+ * The following variable tracks any errors that occur during interrupt
+ * processing
+ */
+int Error;
+
+/*
+ * The following variable allows a test value to be added to the values that
+ * are written to the Flash such that unique values can be generated to
+ * guarantee the writes to the Flash were successful
+ */
+int Test = 1;
+
+/*
+ * The following variables are used to read and write to the flash and they
+ * are global to avoid having large buffers on the stack
+ * The buffer size accounts for maximum page size and maximum banks -
+ * for each bank separate read will be performed leading to that many
+ * (overhead+dummy) bytes
+ */
+#ifdef __ICCARM__
+#pragma data_alignment = 32
+u8 ReadBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + (DATA_OFFSET + DUMMY_SIZE)*8];
+#else
+u8 ReadBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + (DATA_OFFSET + DUMMY_SIZE)*8] __attribute__ ((aligned(64)));
+#endif
+u8 WriteBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + DATA_OFFSET];
+u8 CmdBfr[8];
+
+/*
+ * The following constants specify the max amount of data and the size of the
+ * the buffer required to hold the data and overhead to transfer the data to
+ * and from the Flash. Initialized to single flash page size.
+ */
+u32 MaxData = PAGE_COUNT*256;
+
+int QspiPsu_NOR_Initialize(
+ XQspiPsu *QspiPsuInstancePtr,
+ u16 QspiPsuIntrId
+)
+{
+ int Status;
+
+ if (QspiPsuInstancePtr == NULL) {
+ return XST_FAILURE;
+ }
+
+ /*
+ * Connect the QspiPsu device to the interrupt subsystem such that
+ * interrupts can occur. This function is application specific
+ */
+ Status = QspiPsuSetupIntrSystem(QspiPsuInstancePtr, QspiPsuIntrId);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+
+ /*
+ * Setup the handler for the QSPIPSU that will be called from the
+ * interrupt context when an QSPIPSU status occurs, specify a pointer to
+ * the QSPIPSU driver instance as the callback reference
+ * so the handler is able to access the instance data
+ */
+ XQspiPsu_SetStatusHandler(QspiPsuInstancePtr, QspiPsuInstancePtr,
+ (XQspiPsu_StatusHandler) QspiPsuHandler);
+
+ /*
+ * Set Manual Start
+ */
+ XQspiPsu_SetOptions(QspiPsuInstancePtr, XQSPIPSU_MANUAL_START_OPTION);
+
+ /*
+ * Set the prescaler for QSPIPSU clock
+ */
+ XQspiPsu_SetClkPrescaler(QspiPsuInstancePtr, XQSPIPSU_CLK_PRESCALE_8);
+
+ XQspiPsu_SelectFlash(QspiPsuInstancePtr,
+ XQSPIPSU_SELECT_FLASH_CS_LOWER,
+ XQSPIPSU_SELECT_FLASH_BUS_LOWER);
+
+ /*
+ * Read flash ID and obtain all flash related information
+ * It is important to call the read id function before
+ * performing proceeding to any operation, including
+ * preparing the WriteBuffer
+ */
+
+ Status = FlashReadID(QspiPsuInstancePtr);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+
+ /*
+ * Some flash needs to enable Quad mode before using
+ * quad commands.
+ */
+ Status = FlashEnableQuadMode(QspiPsuInstancePtr);
+ if (Status != XST_SUCCESS)
+ return XST_FAILURE;
+
+ /*
+ * Address size and read command selection
+ * Micron flash on REMUS doesn't support these 4B write/erase commands
+ */
+ if(QspiPsuInstancePtr->Config.BusWidth == BUSWIDTH_SINGLE)
+ ReadCmd = FAST_READ_CMD;
+ else if(QspiPsuInstancePtr->Config.BusWidth == BUSWIDTH_DOUBLE)
+ ReadCmd = DUAL_READ_CMD;
+ else
+ ReadCmd = QUAD_READ_CMD;
+
+ WriteCmd = WRITE_CMD;
+ SectorEraseCmd = SEC_ERASE_CMD;
+
+ if ((Flash_Config_Table[FCTIndex].NumDie > 1) &&
+ (FlashMake == MICRON_ID_BYTE0)) {
+ StatusCmd = READ_FLAG_STATUS_CMD;
+ FSRFlag = 1;
+ } else {
+ StatusCmd = READ_STATUS_CMD;
+ FSRFlag = 0;
+ }
+
+ if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) {
+ Status = FlashEnterExit4BAddMode(QspiPsuInstancePtr, ENTER_4B);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ if (FlashMake == SPANSION_ID_BYTE0) {
+ if(QspiPsuInstancePtr->Config.BusWidth == BUSWIDTH_SINGLE)
+ ReadCmd = FAST_READ_CMD_4B;
+ else if(QspiPsuInstancePtr->Config.BusWidth == BUSWIDTH_DOUBLE)
+ ReadCmd = DUAL_READ_CMD_4B;
+ else
+ ReadCmd = QUAD_READ_CMD_4B;
+
+ WriteCmd = WRITE_CMD_4B;
+ SectorEraseCmd = SEC_ERASE_CMD_4B;
+ }
+ }
+
+ return XST_SUCCESS;
+}
+
+/*****************************************************************************/
+/**
+ *
+ * Callback handler.
+ *
+ * @param CallBackRef is the upper layer callback reference passed back
+ * when the callback function is invoked.
+ * @param StatusEvent is the event that just occurred.
+ * @param ByteCount is the number of bytes transferred up until the event
+ * occurred.
+ *
+ * @return None
+ *
+ * @note None.
+ *
+ *****************************************************************************/
+static void QspiPsuHandler(
+ void *CallBackRef,
+ u32 StatusEvent,
+ unsigned int ByteCount
+)
+{
+ /*
+ * Indicate the transfer on the QSPIPSU bus is no longer in progress
+ * regardless of the status event
+ */
+ TransferInProgress = FALSE;
+
+ /*
+ * If the event was not transfer done, then track it as an error
+ */
+ if (StatusEvent != XST_SPI_TRANSFER_DONE) {
+ Error++;
+ }
+}
+
+int QspiPsu_NOR_RDSFDP(
+ XQspiPsu *QspiPsuPtr,
+ u32 Address,
+ u32 ByteCount,
+ u8 **ReadBfrPtr
+)
+{
+ int Status;
+
+ *ReadBfrPtr = ReadBuffer;
+
+ CmdBfr[COMMAND_OFFSET] = READ_SFDP;
+ CmdBfr[ADDRESS_1_OFFSET] =
+ (u8)((Address & 0xFF0000) >> 16);
+ CmdBfr[ADDRESS_2_OFFSET] =
+ (u8)((Address & 0xFF00) >> 8);
+ CmdBfr[ADDRESS_3_OFFSET] =
+ (u8)(Address & 0xFF);
+
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].TxBfrPtr = CmdBfr;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 4;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[1].TxBfrPtr = NULL;
+ FlashMsg[1].RxBfrPtr = NULL;
+ FlashMsg[1].ByteCount = DUMMY_CLOCKS;
+ FlashMsg[1].Flags = 0;
+
+ FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[2].TxBfrPtr = NULL;
+ FlashMsg[2].RxBfrPtr = *ReadBfrPtr;
+ FlashMsg[2].ByteCount = ByteCount;
+ FlashMsg[2].Flags = XQSPIPSU_MSG_FLAG_RX;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 3);
+ if (Status != XST_SUCCESS)
+ return XST_FAILURE;
+
+ while (TransferInProgress);
+
+ rtems_cache_invalidate_multiple_data_lines(ReadBuffer, ByteCount);
+ return 0;
+}
+
+int QspiPsu_NOR_RDID(XQspiPsu *QspiPsuPtr, u8 *ReadBfrPtr, u32 ReadLen)
+{
+ int Status;
+
+ /*
+ * Read ID
+ */
+ TxBfrPtr = READ_ID;
+ FlashMsg[0].TxBfrPtr = &TxBfrPtr;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ FlashMsg[1].TxBfrPtr = NULL;
+ FlashMsg[1].RxBfrPtr = ReadBfrPtr;
+ FlashMsg[1].ByteCount = ReadLen;
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ rtems_cache_invalidate_multiple_data_lines(ReadBfrPtr, ReadLen);
+ return XST_SUCCESS;
+}
+
+/*****************************************************************************/
+/**
+ *
+ * Reads the flash ID and identifies the flash in FCT table.
+ *
+ * @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
+ *
+ * @return XST_SUCCESS if successful, else XST_FAILURE.
+ *
+ * @note None.
+ *
+ *****************************************************************************/
+static int FlashReadID(XQspiPsu *QspiPsuPtr)
+{
+ u32 ReadId = 0;
+ u32 ReadLen = 3;
+ int Status;
+
+ Status = QspiPsu_NOR_RDID(QspiPsuPtr, ReadBfrPtr, ReadLen);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+
+ /* In case of dual, read both and ensure they are same make/size */
+
+ /*
+ * Deduce flash make
+ */
+ FlashMake = ReadBfrPtr[0];
+
+ ReadId = ((ReadBfrPtr[0] << 16) | (ReadBfrPtr[1] << 8) | ReadBfrPtr[2]);
+ /*
+ * Assign corresponding index in the Flash configuration table
+ */
+ Status = CalculateFCTIndex(ReadId, &FCTIndex);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+
+ return XST_SUCCESS;
+}
+
+int QspiPsu_NOR_Write_Page(
+ XQspiPsu *QspiPsuPtr,
+ u32 Address,
+ u32 ByteCount,
+ u8 *WriteBfrPtr
+)
+{
+ u8 WriteEnableCmd;
+ u8 ReadStatusCmd;
+ u8 FlashStatus[2];
+ u8 WriteCmdBfr[5];
+ u32 RealAddr;
+ u32 CmdByteCount;
+ int Status;
+
+ WriteEnableCmd = WRITE_ENABLE_CMD;
+ /*
+ * Translate address based on type of connection
+ * If stacked assert the slave select based on address
+ */
+ RealAddr = GetRealAddr(QspiPsuPtr, Address);
+
+ /*
+ * Send the write enable command to the Flash so that it can be
+ * written to, this needs to be sent as a separate transfer before
+ * the write
+ */
+ FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ TransferInProgress = TRUE;
+
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+
+ while (TransferInProgress);
+
+ WriteCmdBfr[COMMAND_OFFSET] = WriteCmd;
+
+ /* To be used only if 4B address program cmd is supported by flash */
+ if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) {
+ WriteCmdBfr[ADDRESS_1_OFFSET] =
+ (u8)((RealAddr & 0xFF000000) >> 24);
+ WriteCmdBfr[ADDRESS_2_OFFSET] =
+ (u8)((RealAddr & 0xFF0000) >> 16);
+ WriteCmdBfr[ADDRESS_3_OFFSET] =
+ (u8)((RealAddr & 0xFF00) >> 8);
+ WriteCmdBfr[ADDRESS_4_OFFSET] =
+ (u8)(RealAddr & 0xFF);
+ CmdByteCount = 5;
+ } else {
+ WriteCmdBfr[ADDRESS_1_OFFSET] =
+ (u8)((RealAddr & 0xFF0000) >> 16);
+ WriteCmdBfr[ADDRESS_2_OFFSET] =
+ (u8)((RealAddr & 0xFF00) >> 8);
+ WriteCmdBfr[ADDRESS_3_OFFSET] =
+ (u8)(RealAddr & 0xFF);
+ CmdByteCount = 4;
+ }
+
+ FlashMsg[0].TxBfrPtr = WriteCmdBfr;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = CmdByteCount;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ FlashMsg[1].TxBfrPtr = WriteBfrPtr;
+ FlashMsg[1].RxBfrPtr = NULL;
+ FlashMsg[1].ByteCount = ByteCount;
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_TX;
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
+ }
+
+ TransferInProgress = TRUE;
+
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+
+ while (TransferInProgress);
+
+ /*
+ * Wait for the write command to the Flash to be completed, it takes
+ * some time for the data to be written
+ */
+ while (1) {
+ ReadStatusCmd = StatusCmd;
+ FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ FlashMsg[1].TxBfrPtr = NULL;
+ FlashMsg[1].RxBfrPtr = FlashStatus;
+ FlashMsg[1].ByteCount = 2;
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
+ }
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ if (FSRFlag) {
+ FlashStatus[1] &= FlashStatus[0];
+ } else {
+ FlashStatus[1] |= FlashStatus[0];
+ }
+ }
+
+ if (FSRFlag) {
+ if ((FlashStatus[1] & 0x80) != 0) {
+ break;
+ }
+ } else {
+ if ((FlashStatus[1] & 0x01) == 0) {
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int QspiPsu_NOR_Write(
+ XQspiPsu *QspiPsuPtr,
+ u32 Address,
+ u32 ByteCount,
+ u8 *WriteBfrPtr
+)
+{
+ int Status;
+ size_t ByteCountRemaining = ByteCount;
+ unsigned char *WriteBfrPartial = WriteBfrPtr;
+ uint32_t AddressPartial = Address;
+ uint32_t PageSize = Flash_Config_Table[FCTIndex].PageSize;
+ if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ PageSize *= 2;
+ }
+
+ while (ByteCountRemaining > 0) {
+ /* Get write boundary */
+ size_t WriteChunkLen = RTEMS_ALIGN_UP(AddressPartial + 1, PageSize);
+
+ /* Get offset to write boundary */
+ WriteChunkLen -= (size_t)AddressPartial;
+
+ /* Cap short writes */
+ if (WriteChunkLen > ByteCountRemaining) {
+ WriteChunkLen = ByteCountRemaining;
+ }
+
+ Status = QspiPsu_NOR_Write_Page(
+ QspiPsuPtr,
+ AddressPartial,
+ WriteChunkLen,
+ WriteBfrPartial
+ );
+ if ( Status != XST_SUCCESS ) {
+ return Status;
+ }
+
+ ByteCountRemaining -= WriteChunkLen;
+ AddressPartial += WriteChunkLen;
+ WriteBfrPartial += WriteChunkLen;
+ }
+ return Status;
+}
+
+int QspiPsu_NOR_Erase(
+ XQspiPsu *QspiPsuPtr,
+ u32 Address,
+ u32 ByteCount
+)
+{
+ u8 WriteEnableCmd;
+ u8 ReadStatusCmd;
+ u8 FlashStatus[2];
+ int Sector;
+ u32 RealAddr;
+ u32 NumSect;
+ int Status;
+ u32 SectSize;
+
+ WriteEnableCmd = WRITE_ENABLE_CMD;
+
+ if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ SectSize = (Flash_Config_Table[FCTIndex]).SectSize * 2;
+ NumSect = (Flash_Config_Table[FCTIndex]).NumSect;
+ } else if (QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED) {
+ NumSect = (Flash_Config_Table[FCTIndex]).NumSect * 2;
+ SectSize = (Flash_Config_Table[FCTIndex]).SectSize;
+ } else {
+ SectSize = (Flash_Config_Table[FCTIndex]).SectSize;
+ NumSect = (Flash_Config_Table[FCTIndex]).NumSect;
+ }
+
+ /*
+ * If erase size is same as the total size of the flash, use bulk erase
+ * command or die erase command multiple times as required
+ */
+ if (ByteCount == NumSect * SectSize) {
+
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_STACKED) {
+ XQspiPsu_SelectFlash(QspiPsuPtr,
+ XQSPIPSU_SELECT_FLASH_CS_LOWER,
+ XQSPIPSU_SELECT_FLASH_BUS_LOWER);
+ }
+
+ if (Flash_Config_Table[FCTIndex].NumDie == 1) {
+ /*
+ * Call Bulk erase
+ */
+ BulkErase(QspiPsuPtr, CmdBfr);
+ }
+
+ if (Flash_Config_Table[FCTIndex].NumDie > 1) {
+ /*
+ * Call Die erase
+ */
+ DieErase(QspiPsuPtr, CmdBfr);
+ }
+ /*
+ * If stacked mode, bulk erase second flash
+ */
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_STACKED) {
+
+ XQspiPsu_SelectFlash(QspiPsuPtr,
+ XQSPIPSU_SELECT_FLASH_CS_UPPER,
+ XQSPIPSU_SELECT_FLASH_BUS_LOWER);
+
+ if (Flash_Config_Table[FCTIndex].NumDie == 1) {
+ /*
+ * Call Bulk erase
+ */
+ BulkErase(QspiPsuPtr, CmdBfr);
+ }
+
+ if (Flash_Config_Table[FCTIndex].NumDie > 1) {
+ /*
+ * Call Die erase
+ */
+ DieErase(QspiPsuPtr, CmdBfr);
+ }
+ }
+
+ return 0;
+ }
+
+ /*
+ * If the erase size is less than the total size of the flash, use
+ * sector erase command
+ */
+
+ /*
+ * Calculate no. of sectors to erase based on byte count
+ */
+ u32 SectorStartBase = RTEMS_ALIGN_DOWN(Address, SectSize);
+ u32 SectorEndTop = RTEMS_ALIGN_UP(Address + ByteCount, SectSize);
+ NumSect = (SectorEndTop - SectorStartBase)/SectSize;
+
+ for (Sector = 0; Sector < NumSect; Sector++) {
+
+ /*
+ * Translate address based on type of connection
+ * If stacked assert the slave select based on address
+ */
+ RealAddr = GetRealAddr(QspiPsuPtr, Address);
+
+ /*
+ * Send the write enable command to the Flash so that it can be
+ * written to, this needs to be sent as a separate
+ * transfer before the write
+ */
+ FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ CmdBfr[COMMAND_OFFSET] = SectorEraseCmd;
+
+ /*
+ * To be used only if 4B address sector erase cmd is
+ * supported by flash
+ */
+ if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) {
+ CmdBfr[ADDRESS_1_OFFSET] =
+ (u8)((RealAddr & 0xFF000000) >> 24);
+ CmdBfr[ADDRESS_2_OFFSET] =
+ (u8)((RealAddr & 0xFF0000) >> 16);
+ CmdBfr[ADDRESS_3_OFFSET] =
+ (u8)((RealAddr & 0xFF00) >> 8);
+ CmdBfr[ADDRESS_4_OFFSET] =
+ (u8)(RealAddr & 0xFF);
+ FlashMsg[0].ByteCount = 5;
+ } else {
+ CmdBfr[ADDRESS_1_OFFSET] =
+ (u8)((RealAddr & 0xFF0000) >> 16);
+ CmdBfr[ADDRESS_2_OFFSET] =
+ (u8)((RealAddr & 0xFF00) >> 8);
+ CmdBfr[ADDRESS_3_OFFSET] =
+ (u8)(RealAddr & 0xFF);
+ FlashMsg[0].ByteCount = 4;
+ }
+
+ FlashMsg[0].TxBfrPtr = CmdBfr;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ /*
+ * Wait for the erase command to be completed
+ */
+ while (1) {
+ ReadStatusCmd = StatusCmd;
+ FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ FlashMsg[1].TxBfrPtr = NULL;
+ FlashMsg[1].RxBfrPtr = FlashStatus;
+ FlashMsg[1].ByteCount = 2;
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
+ }
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr,
+ FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ if (FSRFlag) {
+ FlashStatus[1] &= FlashStatus[0];
+ } else {
+ FlashStatus[1] |= FlashStatus[0];
+ }
+ }
+
+ if (FSRFlag) {
+ if ((FlashStatus[1] & 0x80) != 0) {
+ break;
+ }
+ } else {
+ if ((FlashStatus[1] & 0x01) == 0) {
+ break;
+ }
+ }
+ }
+ Address += SectSize;
+ }
+
+ return 0;
+}
+
+int QspiPsu_NOR_Read(
+ XQspiPsu *QspiPsuPtr,
+ u32 Address,
+ u32 ByteCount,
+ u8 **ReadBfrPtr
+)
+{
+ u32 RealAddr;
+ u32 DiscardByteCnt;
+ u32 FlashMsgCnt;
+ int Status;
+
+ *ReadBfrPtr = ReadBuffer;
+
+ /* Check die boundary conditions if required for any flash */
+ if (Flash_Config_Table[FCTIndex].NumDie > 1) {
+
+ Status = MultiDieRead(QspiPsuPtr, Address, ByteCount, ReadCmd,
+ CmdBfr, *ReadBfrPtr);
+ if (Status != XST_SUCCESS)
+ return XST_FAILURE;
+ } else {
+ /* For Dual Stacked, split and read for boundary crossing */
+ /*
+ * Translate address based on type of connection
+ * If stacked assert the slave select based on address
+ */
+ RealAddr = GetRealAddr(QspiPsuPtr, Address);
+
+ CmdBfr[COMMAND_OFFSET] = ReadCmd;
+ if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) {
+ CmdBfr[ADDRESS_1_OFFSET] =
+ (u8)((RealAddr & 0xFF000000) >> 24);
+ CmdBfr[ADDRESS_2_OFFSET] =
+ (u8)((RealAddr & 0xFF0000) >> 16);
+ CmdBfr[ADDRESS_3_OFFSET] =
+ (u8)((RealAddr & 0xFF00) >> 8);
+ CmdBfr[ADDRESS_4_OFFSET] =
+ (u8)(RealAddr & 0xFF);
+ DiscardByteCnt = 5;
+ } else {
+ CmdBfr[ADDRESS_1_OFFSET] =
+ (u8)((RealAddr & 0xFF0000) >> 16);
+ CmdBfr[ADDRESS_2_OFFSET] =
+ (u8)((RealAddr & 0xFF00) >> 8);
+ CmdBfr[ADDRESS_3_OFFSET] =
+ (u8)(RealAddr & 0xFF);
+ DiscardByteCnt = 4;
+ }
+
+ FlashMsg[0].TxBfrPtr = CmdBfr;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = DiscardByteCnt;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ FlashMsgCnt = 1;
+
+ /* It is recommended to have a separate entry for dummy */
+ if (ReadCmd == FAST_READ_CMD || ReadCmd == DUAL_READ_CMD ||
+ ReadCmd == QUAD_READ_CMD || ReadCmd == FAST_READ_CMD_4B ||
+ ReadCmd == DUAL_READ_CMD_4B ||
+ ReadCmd == QUAD_READ_CMD_4B) {
+ /* Update Dummy cycles as per flash specs for QUAD IO */
+
+ /*
+ * It is recommended that Bus width value during dummy
+ * phase should be same as data phase
+ */
+ if (ReadCmd == FAST_READ_CMD ||
+ ReadCmd == FAST_READ_CMD_4B) {
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ }
+
+ if (ReadCmd == DUAL_READ_CMD ||
+ ReadCmd == DUAL_READ_CMD_4B) {
+ FlashMsg[1].BusWidth =
+ XQSPIPSU_SELECT_MODE_DUALSPI;
+ }
+
+ if (ReadCmd == QUAD_READ_CMD ||
+ ReadCmd == QUAD_READ_CMD_4B) {
+ FlashMsg[1].BusWidth =
+ XQSPIPSU_SELECT_MODE_QUADSPI;
+ }
+
+ FlashMsg[1].TxBfrPtr = NULL;
+ FlashMsg[1].RxBfrPtr = NULL;
+ FlashMsg[1].ByteCount = DUMMY_CLOCKS;
+ FlashMsg[1].Flags = 0;
+
+ FlashMsgCnt++;
+ }
+
+ /* Dummy cycles need to be changed as per flash specs
+ * for QUAD IO
+ */
+ if (ReadCmd == FAST_READ_CMD || ReadCmd == FAST_READ_CMD_4B)
+ FlashMsg[FlashMsgCnt].BusWidth =
+ XQSPIPSU_SELECT_MODE_SPI;
+
+ if (ReadCmd == DUAL_READ_CMD || ReadCmd == DUAL_READ_CMD_4B)
+ FlashMsg[FlashMsgCnt].BusWidth =
+ XQSPIPSU_SELECT_MODE_DUALSPI;
+
+ if (ReadCmd == QUAD_READ_CMD || ReadCmd == QUAD_READ_CMD_4B)
+ FlashMsg[FlashMsgCnt].BusWidth =
+ XQSPIPSU_SELECT_MODE_QUADSPI;
+
+ FlashMsg[FlashMsgCnt].TxBfrPtr = NULL;
+ FlashMsg[FlashMsgCnt].RxBfrPtr = *ReadBfrPtr;
+ FlashMsg[FlashMsgCnt].ByteCount = ByteCount;
+ FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_RX;
+
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ FlashMsg[FlashMsgCnt].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
+ }
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg,
+ FlashMsgCnt + 1);
+ if (Status != XST_SUCCESS)
+ return XST_FAILURE;
+
+ while (TransferInProgress);
+
+ }
+ rtems_cache_invalidate_multiple_data_lines(ReadBuffer, ByteCount);
+ return 0;
+}
+
+/*****************************************************************************/
+/**
+ *
+ * This function performs a read operation for multi die flash devices.
+ * Default setting is in DMA mode.
+ *
+ * @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
+ * @param Address contains the address of the first sector which needs to
+ * be erased.
+ * @param ByteCount contains the total size to be erased.
+ * @param Command is the command used to read data from the flash.
+ * Supports normal, fast, dual and quad read commands.
+ * @param WriteBfrPtr is pointer to the write buffer which contains data to be
+ * transmitted
+ * @param ReadBfrPtr is pointer to the read buffer to which valid received data
+ * should be written
+ *
+ * @return XST_SUCCESS if successful, else XST_FAILURE.
+ *
+ * @note None.
+ *
+ ******************************************************************************/
+static int MultiDieRead(
+ XQspiPsu *QspiPsuPtr,
+ u32 Address,
+ u32 ByteCount,
+ u8 Command,
+ u8 *WriteBfrPtr,
+ u8 *ReadBfrPtr
+)
+{
+ u32 RealAddr;
+ u32 DiscardByteCnt;
+ u32 FlashMsgCnt;
+ int Status;
+ u32 cur_bank = 0;
+ u32 nxt_bank = 0;
+ u32 bank_size;
+ u32 remain_len = ByteCount;
+ u32 data_len;
+ u32 transfer_len;
+ u8 *ReadBuffer = ReadBfrPtr;
+
+ /*
+ * Some flash devices like N25Q512 have multiple dies
+ * in it. Read operation in these devices is bounded
+ * by its die segment. In a continuous read, across
+ * multiple dies, when the last byte of the selected
+ * die segment is read, the next byte read is the
+ * first byte of the same die segment. This is Die
+ * cross over issue. So to handle this issue, split
+ * a read transaction, that spans across multiple
+ * banks, into one read per bank. Bank size is 16MB
+ * for single and dual stacked mode and 32MB for dual
+ * parallel mode.
+ */
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL)
+ bank_size = SIXTEENMB << 1;
+ else
+ bank_size = SIXTEENMB;
+
+ while (remain_len) {
+ cur_bank = Address / bank_size;
+ nxt_bank = (Address + remain_len) / bank_size;
+
+ if (cur_bank != nxt_bank) {
+ transfer_len = (bank_size * (cur_bank + 1)) - Address;
+ if (remain_len < transfer_len)
+ data_len = remain_len;
+ else
+ data_len = transfer_len;
+ } else {
+ data_len = remain_len;
+ }
+ /*
+ * Translate address based on type of connection
+ * If stacked assert the slave select based on address
+ */
+ RealAddr = GetRealAddr(QspiPsuPtr, Address);
+
+ WriteBfrPtr[COMMAND_OFFSET] = Command;
+ if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) {
+ WriteBfrPtr[ADDRESS_1_OFFSET] =
+ (u8)((RealAddr & 0xFF000000) >> 24);
+ WriteBfrPtr[ADDRESS_2_OFFSET] =
+ (u8)((RealAddr & 0xFF0000) >> 16);
+ WriteBfrPtr[ADDRESS_3_OFFSET] =
+ (u8)((RealAddr & 0xFF00) >> 8);
+ WriteBfrPtr[ADDRESS_4_OFFSET] =
+ (u8)(RealAddr & 0xFF);
+ DiscardByteCnt = 5;
+ } else {
+ WriteBfrPtr[ADDRESS_1_OFFSET] =
+ (u8)((RealAddr & 0xFF0000) >> 16);
+ WriteBfrPtr[ADDRESS_2_OFFSET] =
+ (u8)((RealAddr & 0xFF00) >> 8);
+ WriteBfrPtr[ADDRESS_3_OFFSET] =
+ (u8)(RealAddr & 0xFF);
+ DiscardByteCnt = 4;
+ }
+
+ FlashMsg[0].TxBfrPtr = WriteBfrPtr;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = DiscardByteCnt;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ FlashMsgCnt = 1;
+
+ /* It is recommended to have a separate entry for dummy */
+ if (Command == FAST_READ_CMD || Command == DUAL_READ_CMD ||
+ Command == QUAD_READ_CMD || Command == FAST_READ_CMD_4B ||
+ Command == DUAL_READ_CMD_4B ||
+ Command == QUAD_READ_CMD_4B) {
+ /* Update Dummy cycles as per flash specs for QUAD IO */
+
+ /*
+ * It is recommended that Bus width value during dummy
+ * phase should be same as data phase
+ */
+ if (Command == FAST_READ_CMD ||
+ Command == FAST_READ_CMD_4B) {
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ }
+
+ if (Command == DUAL_READ_CMD ||
+ Command == DUAL_READ_CMD_4B) {
+ FlashMsg[1].BusWidth =
+ XQSPIPSU_SELECT_MODE_DUALSPI;
+ }
+
+ if (Command == QUAD_READ_CMD ||
+ Command == QUAD_READ_CMD_4B) {
+ FlashMsg[1].BusWidth =
+ XQSPIPSU_SELECT_MODE_QUADSPI;
+ }
+
+ FlashMsg[1].TxBfrPtr = NULL;
+ FlashMsg[1].RxBfrPtr = NULL;
+ FlashMsg[1].ByteCount = DUMMY_CLOCKS;
+ FlashMsg[1].Flags = 0;
+
+ FlashMsgCnt++;
+ }
+
+ /* Dummy cycles need to be changed as per flash
+ * specs for QUAD IO
+ */
+ if (Command == FAST_READ_CMD || Command == FAST_READ_CMD_4B)
+ FlashMsg[FlashMsgCnt].BusWidth =
+ XQSPIPSU_SELECT_MODE_SPI;
+
+ if (Command == DUAL_READ_CMD || Command == DUAL_READ_CMD_4B)
+ FlashMsg[FlashMsgCnt].BusWidth =
+ XQSPIPSU_SELECT_MODE_DUALSPI;
+
+ if (Command == QUAD_READ_CMD || Command == QUAD_READ_CMD_4B)
+ FlashMsg[FlashMsgCnt].BusWidth =
+ XQSPIPSU_SELECT_MODE_QUADSPI;
+
+ FlashMsg[FlashMsgCnt].TxBfrPtr = NULL;
+ FlashMsg[FlashMsgCnt].RxBfrPtr = ReadBuffer;
+ FlashMsg[FlashMsgCnt].ByteCount = data_len;
+ FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_RX;
+
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL)
+ FlashMsg[FlashMsgCnt].Flags |=
+ XQSPIPSU_MSG_FLAG_STRIPE;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg,
+ FlashMsgCnt + 1);
+ if (Status != XST_SUCCESS)
+ return XST_FAILURE;
+
+ while (TransferInProgress);
+
+
+ ReadBuffer += data_len;
+ Address += data_len;
+ remain_len -= data_len;
+ }
+ rtems_cache_invalidate_multiple_data_lines(ReadBfrPtr, ByteCount);
+ return 0;
+}
+
+/*****************************************************************************/
+/**
+ *
+ * This functions performs a bulk erase operation when the
+ * flash device has a single die. Works for both Spansion and Micron
+ *
+ * @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
+ * @param WriteBfrPtr is the pointer to command+address to be sent
+ *
+ * @return XST_SUCCESS if successful, else XST_FAILURE.
+ *
+ * @note None.
+ *
+ ******************************************************************************/
+static int BulkErase(
+ XQspiPsu *QspiPsuPtr,
+ u8 *WriteBfrPtr
+)
+{
+ u8 WriteEnableCmd;
+ u8 ReadStatusCmd;
+ u8 FlashStatus[2];
+ int Status;
+
+ WriteEnableCmd = WRITE_ENABLE_CMD;
+ /*
+ * Send the write enable command to the Flash so that it can be
+ * written to, this needs to be sent as a separate transfer before
+ * the write
+ */
+ FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ WriteBfrPtr[COMMAND_OFFSET] = BULK_ERASE_CMD;
+ FlashMsg[0].TxBfrPtr = WriteBfrPtr;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ /*
+ * Wait for the write command to the Flash to be completed, it takes
+ * some time for the data to be written
+ */
+ while (1) {
+ ReadStatusCmd = StatusCmd;
+ FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ FlashMsg[1].TxBfrPtr = NULL;
+ FlashMsg[1].RxBfrPtr = FlashStatus;
+ FlashMsg[1].ByteCount = 2;
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
+ }
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ if (FSRFlag) {
+ FlashStatus[1] &= FlashStatus[0];
+ } else {
+ FlashStatus[1] |= FlashStatus[0];
+ }
+ }
+
+ if (FSRFlag) {
+ if ((FlashStatus[1] & 0x80) != 0) {
+ break;
+ }
+ } else {
+ if ((FlashStatus[1] & 0x01) == 0) {
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+/**
+ *
+ * This functions performs a die erase operation on all the die in
+ * the flash device. This function uses the die erase command for
+ * Micron 512Mbit and 1Gbit
+ *
+ * @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
+ * @param WriteBfrPtr is the pointer to command+address to be sent
+ *
+ * @return XST_SUCCESS if successful, else XST_FAILURE.
+ *
+ * @note None.
+ *
+ ******************************************************************************/
+static int DieErase(
+ XQspiPsu *QspiPsuPtr,
+ u8 *WriteBfrPtr
+)
+{
+ u8 WriteEnableCmd;
+ u8 DieCnt;
+ u8 ReadStatusCmd;
+ u8 FlashStatus[2];
+ int Status;
+ u32 DieSize = 0;
+ u32 Address;
+ u32 RealAddr;
+ u32 SectSize = 0;
+ u32 NumSect = 0;
+
+ WriteEnableCmd = WRITE_ENABLE_CMD;
+
+ if (QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ SectSize = (Flash_Config_Table[FCTIndex]).SectSize * 2;
+ } else if (QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED) {
+ NumSect = (Flash_Config_Table[FCTIndex]).NumSect * 2;
+ } else {
+ SectSize = (Flash_Config_Table[FCTIndex]).SectSize;
+ NumSect = (Flash_Config_Table[FCTIndex]).NumSect;
+ }
+ DieSize = (NumSect * SectSize) / Flash_Config_Table[FCTIndex].NumDie;
+
+ for (DieCnt = 0;
+ DieCnt < Flash_Config_Table[FCTIndex].NumDie;
+ DieCnt++) {
+ /*
+ * Send the write enable command to the Flash so that it can be
+ * written to, this needs to be sent as a separate transfer
+ * before the write
+ */
+ FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ WriteBfrPtr[COMMAND_OFFSET] = DIE_ERASE_CMD;
+
+ Address = DieSize * DieCnt;
+ RealAddr = GetRealAddr(QspiPsuPtr, Address);
+ /*
+ * To be used only if 4B address sector erase cmd is
+ * supported by flash
+ */
+ if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) {
+ WriteBfrPtr[ADDRESS_1_OFFSET] =
+ (u8)((RealAddr & 0xFF000000) >> 24);
+ WriteBfrPtr[ADDRESS_2_OFFSET] =
+ (u8)((RealAddr & 0xFF0000) >> 16);
+ WriteBfrPtr[ADDRESS_3_OFFSET] =
+ (u8)((RealAddr & 0xFF00) >> 8);
+ WriteBfrPtr[ADDRESS_4_OFFSET] =
+ (u8)(RealAddr & 0xFF);
+ FlashMsg[0].ByteCount = 5;
+ } else {
+ WriteBfrPtr[ADDRESS_1_OFFSET] =
+ (u8)((RealAddr & 0xFF0000) >> 16);
+ WriteBfrPtr[ADDRESS_2_OFFSET] =
+ (u8)((RealAddr & 0xFF00) >> 8);
+ WriteBfrPtr[ADDRESS_3_OFFSET] =
+ (u8)(RealAddr & 0xFF);
+ FlashMsg[0].ByteCount = 4;
+ }
+ FlashMsg[0].TxBfrPtr = WriteBfrPtr;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ /*
+ * Wait for the write command to the Flash to be completed,
+ * it takes some time for the data to be written
+ */
+ while (1) {
+ ReadStatusCmd = StatusCmd;
+ FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ FlashMsg[1].TxBfrPtr = NULL;
+ FlashMsg[1].RxBfrPtr = FlashStatus;
+ FlashMsg[1].ByteCount = 2;
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
+ }
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr,
+ FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ if (FSRFlag) {
+ FlashStatus[1] &= FlashStatus[0];
+ } else {
+ FlashStatus[1] |= FlashStatus[0];
+ }
+ }
+
+ if (FSRFlag) {
+ if ((FlashStatus[1] & 0x80) != 0) {
+ break;
+ }
+ } else {
+ if ((FlashStatus[1] & 0x01) == 0) {
+ break;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+/**
+ *
+ * This functions translates the address based on the type of interconnection.
+ * In case of stacked, this function asserts the corresponding slave select.
+ *
+ * @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
+ * @param Address which is to be accessed (for erase, write or read)
+ *
+ * @return RealAddr is the translated address - for single it is unchanged;
+ * for stacked, the lower flash size is subtracted;
+ * for parallel the address is divided by 2.
+ *
+ * @note In addition to get the actual address to work on flash this
+ * function also selects the CS and BUS based on the configuration
+ * detected.
+ *
+ ******************************************************************************/
+static u32 GetRealAddr(
+ XQspiPsu *QspiPsuPtr,
+ u32 Address
+)
+{
+ u32 RealAddr = 0;
+
+ switch (QspiPsuPtr->Config.ConnectionMode) {
+ case XQSPIPSU_CONNECTION_MODE_SINGLE:
+ XQspiPsu_SelectFlash(QspiPsuPtr,
+ XQSPIPSU_SELECT_FLASH_CS_LOWER,
+ XQSPIPSU_SELECT_FLASH_BUS_LOWER);
+ RealAddr = Address;
+ break;
+ case XQSPIPSU_CONNECTION_MODE_STACKED:
+ /* Select lower or upper Flash based on sector address */
+ if (Address & Flash_Config_Table[FCTIndex].FlashDeviceSize) {
+
+ XQspiPsu_SelectFlash(QspiPsuPtr,
+ XQSPIPSU_SELECT_FLASH_CS_UPPER,
+ XQSPIPSU_SELECT_FLASH_BUS_LOWER);
+ /*
+ * Subtract first flash size when accessing second flash
+ */
+ RealAddr = Address &
+ (~Flash_Config_Table[FCTIndex].FlashDeviceSize);
+ }else{
+ /*
+ * Set selection to L_PAGE
+ */
+ XQspiPsu_SelectFlash(QspiPsuPtr,
+ XQSPIPSU_SELECT_FLASH_CS_LOWER,
+ XQSPIPSU_SELECT_FLASH_BUS_LOWER);
+
+ RealAddr = Address;
+
+ }
+ break;
+ case XQSPIPSU_CONNECTION_MODE_PARALLEL:
+ /*
+ * The effective address in each flash is the actual
+ * address / 2
+ */
+ XQspiPsu_SelectFlash(QspiPsuPtr,
+ XQSPIPSU_SELECT_FLASH_CS_BOTH,
+ XQSPIPSU_SELECT_FLASH_BUS_BOTH);
+ RealAddr = Address / 2;
+ break;
+ default:
+ /* RealAddr wont be assigned in this case; */
+ break;
+
+ }
+
+ return(RealAddr);
+}
+
+/*****************************************************************************/
+/**
+ *
+ * This function setups the interrupt system for a QspiPsu device.
+ *
+ * @param QspiPsuInstancePtr is a pointer to the instance of the
+ * QspiPsu device.
+ * @param QspiPsuIntrId is the interrupt Id for an QSPIPSU device.
+ *
+ * @return XST_SUCCESS if successful, otherwise XST_FAILURE.
+ *
+ * @note None.
+ *
+ ******************************************************************************/
+static int QspiPsuSetupIntrSystem(
+ XQspiPsu *QspiPsuInstancePtr,
+ u16 QspiPsuIntrId
+)
+{
+ return rtems_interrupt_handler_install(
+ QspiPsuIntrId,
+ NULL,
+ RTEMS_INTERRUPT_UNIQUE,
+ (rtems_interrupt_handler) XQspiPsu_InterruptHandler,
+ QspiPsuInstancePtr
+ );
+}
+
+/*****************************************************************************/
+/**
+ * @brief
+ * This API enters the flash device into 4 bytes addressing mode.
+ * As per the Micron and ISSI spec, before issuing the command
+ * to enter into 4 byte addr mode, a write enable command is issued.
+ * For Macronix and Winbond flash parts write
+ * enable is not required.
+ *
+ * @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
+ * @param Enable is a either 1 or 0 if 1 then enters 4 byte if 0 exits.
+ *
+ * @return
+ * - XST_SUCCESS if successful.
+ * - XST_FAILURE if it fails.
+ *
+ *
+ ******************************************************************************/
+static int FlashEnterExit4BAddMode(
+ XQspiPsu *QspiPsuPtr,
+ unsigned int Enable
+)
+{
+ int Status;
+ u8 WriteEnableCmd;
+ u8 Cmd;
+ u8 WriteDisableCmd;
+ u8 ReadStatusCmd;
+ u8 WriteBuffer[2] = {0};
+ u8 FlashStatus[2] = {0};
+
+ if (Enable) {
+ Cmd = ENTER_4B_ADDR_MODE;
+ } else {
+ if (FlashMake == ISSI_ID_BYTE0)
+ Cmd = EXIT_4B_ADDR_MODE_ISSI;
+ else
+ Cmd = EXIT_4B_ADDR_MODE;
+ }
+
+ switch (FlashMake) {
+ case ISSI_ID_BYTE0:
+ case MICRON_ID_BYTE0:
+ WriteEnableCmd = WRITE_ENABLE_CMD;
+ GetRealAddr(QspiPsuPtr, TEST_ADDRESS);
+ /*
+ * Send the write enable command to the Flash so that it can be
+ * written to, this needs to be sent as a separate transfer
+ * before the write
+ */
+ FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ break;
+
+ case SPANSION_ID_BYTE0:
+
+ /* Read Extended Addres Register */
+ WriteBuffer[0] = BANK_REG_RD;
+ FlashMsg[0].TxBfrPtr = &WriteBuffer[0];
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ FlashMsg[1].TxBfrPtr = NULL;
+ FlashMsg[1].RxBfrPtr = &WriteBuffer[1];
+ FlashMsg[1].ByteCount = 1;
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+ if (Enable) {
+ WriteBuffer[0] = BANK_REG_WR;
+ WriteBuffer[1] |= 1 << 7;
+ } else {
+ WriteBuffer[0] = BANK_REG_WR;
+ WriteBuffer[1] &= ~(0x01 << 7);
+ }
+
+ FlashMsg[0].TxBfrPtr = &WriteBuffer[0];
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[1].TxBfrPtr = &WriteBuffer[1];
+ FlashMsg[2].RxBfrPtr = NULL;
+ FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[2].Flags = XQSPIPSU_MSG_FLAG_TX;
+ FlashMsg[2].ByteCount = 1;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+ WriteBuffer[0] = BANK_REG_RD;
+ FlashMsg[0].TxBfrPtr = &WriteBuffer[0];
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ FlashMsg[1].TxBfrPtr = NULL;
+ FlashMsg[1].RxBfrPtr = &FlashStatus[0];
+ FlashMsg[1].ByteCount = 1;
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ return Status;
+
+ default:
+ /*
+ * For Macronix and Winbond flash parts
+ * Write enable command is not required.
+ */
+ break;
+ }
+
+ GetRealAddr(QspiPsuPtr, TEST_ADDRESS);
+
+ FlashMsg[0].TxBfrPtr = &Cmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ while (1) {
+ ReadStatusCmd = StatusCmd;
+
+ FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ FlashMsg[1].TxBfrPtr = NULL;
+ FlashMsg[1].RxBfrPtr = FlashStatus;
+ FlashMsg[1].ByteCount = 2;
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
+
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
+ }
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ if (FSRFlag) {
+ FlashStatus[1] &= FlashStatus[0];
+ } else {
+ FlashStatus[1] |= FlashStatus[0];
+ }
+ }
+
+ if (FSRFlag) {
+ if ((FlashStatus[1] & 0x80) != 0) {
+ break;
+ }
+ } else {
+ if ((FlashStatus[1] & 0x01) == 0) {
+ break;
+ }
+ }
+ }
+
+ switch (FlashMake) {
+ case ISSI_ID_BYTE0:
+ case MICRON_ID_BYTE0:
+ WriteDisableCmd = WRITE_DISABLE_CMD;
+ GetRealAddr(QspiPsuPtr, TEST_ADDRESS);
+ /*
+ * Send the write enable command to the Flash so that it can be
+ * written to, this needs to be sent as a separate transfer
+ * before the write
+ */
+ FlashMsg[0].TxBfrPtr = &WriteDisableCmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ break;
+
+ default:
+ /*
+ * For Macronix and Winbond flash parts
+ * Write disable command is not required.
+ */
+ break;
+ }
+ return Status;
+}
+
+/*****************************************************************************/
+/**
+ * @brief
+ * This API enables Quad mode for the flash parts which require to enable quad
+ * mode before using Quad commands.
+ * For S25FL-L series flash parts this is required as the default configuration
+ * is x1/x2 mode.
+ *
+ * @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
+ *
+ * @return
+ * - XST_SUCCESS if successful.
+ * - XST_FAILURE if it fails.
+ *
+ *
+ ******************************************************************************/
+static int FlashEnableQuadMode(XQspiPsu *QspiPsuPtr)
+{
+ int Status;
+ u8 WriteEnableCmd;
+ u8 ReadStatusCmd;
+ u8 FlashStatus[2];
+ u8 StatusRegVal;
+ u8 WriteBuffer[3] = {0};
+
+ switch (FlashMake) {
+ case SPANSION_ID_BYTE0:
+ TxBfrPtr = READ_CONFIG_CMD;
+ FlashMsg[0].TxBfrPtr = &TxBfrPtr;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ FlashMsg[1].TxBfrPtr = NULL;
+ FlashMsg[1].RxBfrPtr = &WriteBuffer[2];
+ FlashMsg[1].ByteCount = 1;
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr,
+ FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ WriteEnableCmd = WRITE_ENABLE_CMD;
+ /*
+ * Send the write enable command to the Flash
+ * so that it can be written to, this needs
+ * to be sent as a separate transfer before
+ * the write
+ */
+ FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr,
+ FlashMsg, 1);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ GetRealAddr(QspiPsuPtr, TEST_ADDRESS);
+
+ WriteBuffer[0] = WRITE_CONFIG_CMD;
+ WriteBuffer[1] |= 0x02;
+ WriteBuffer[2] |= 0x01 << 1;
+
+ FlashMsg[0].TxBfrPtr = &WriteBuffer[0];
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[1].TxBfrPtr = &WriteBuffer[1];
+ FlashMsg[1].RxBfrPtr = NULL;
+ FlashMsg[1].ByteCount = 2;
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr,
+ FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ while (1) {
+ TxBfrPtr = READ_STATUS_CMD;
+ FlashMsg[0].TxBfrPtr = &TxBfrPtr;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ FlashMsg[1].TxBfrPtr = NULL;
+ FlashMsg[1].RxBfrPtr = FlashStatus;
+ FlashMsg[1].ByteCount = 2;
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr,
+ FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ if (FSRFlag) {
+ FlashStatus[1] &= FlashStatus[0];
+ }else {
+ FlashStatus[1] |= FlashStatus[0];
+ }
+ }
+
+ if ((FlashStatus[1] & 0x01) == 0x00)
+ break;
+ }
+ TxBfrPtr = READ_CONFIG_CMD;
+ FlashMsg[0].TxBfrPtr = &TxBfrPtr;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ FlashMsg[1].TxBfrPtr = NULL;
+ FlashMsg[1].RxBfrPtr = ReadBfrPtr;
+ FlashMsg[1].ByteCount = 1;
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+ break;
+ case ISSI_ID_BYTE0:
+ /*
+ * Read Status Register to a buffer
+ */
+ ReadStatusCmd = READ_STATUS_CMD;
+ FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+ FlashMsg[1].TxBfrPtr = NULL;
+ FlashMsg[1].RxBfrPtr = FlashStatus;
+ FlashMsg[1].ByteCount = 2;
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
+ }
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ if (FSRFlag) {
+ FlashStatus[1] &= FlashStatus[0];
+ } else {
+ FlashStatus[1] |= FlashStatus[0];
+ }
+ }
+ /*
+ * Set Quad Enable Bit in the buffer
+ */
+ StatusRegVal = FlashStatus[1];
+ StatusRegVal |= 0x1 << QUAD_MODE_ENABLE_BIT;
+
+ /*
+ * Write enable
+ */
+ WriteEnableCmd = WRITE_ENABLE_CMD;
+ /*
+ * Send the write enable command to the Flash so that it can be
+ * written to, this needs to be sent as a separate transfer
+ * before the write
+ */
+ FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ /*
+ * Write Status register
+ */
+ WriteBuffer[COMMAND_OFFSET] = WRITE_STATUS_CMD;
+ FlashMsg[0].TxBfrPtr = WriteBuffer;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ FlashMsg[1].TxBfrPtr = &StatusRegVal;
+ FlashMsg[1].RxBfrPtr = NULL;
+ FlashMsg[1].ByteCount = 1;
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_TX;
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
+ }
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ /*
+ * Write Disable
+ */
+ WriteEnableCmd = WRITE_DISABLE_CMD;
+ FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+ break;
+
+ case WINBOND_ID_BYTE0:
+ ReadStatusCmd = READ_STATUS_REG_2_CMD;
+ FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+ FlashMsg[1].TxBfrPtr = NULL;
+ FlashMsg[1].RxBfrPtr = FlashStatus;
+ FlashMsg[1].ByteCount = 2;
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ if (FSRFlag) {
+ FlashStatus[1] &= FlashStatus[0];
+ } else {
+ FlashStatus[1] |= FlashStatus[0];
+ }
+ }
+ /*
+ * Set Quad Enable Bit in the buffer
+ */
+ StatusRegVal = FlashStatus[1];
+ StatusRegVal |= 0x1 << WB_QUAD_MODE_ENABLE_BIT;
+ /*
+ * Write Enable
+ */
+ WriteEnableCmd = WRITE_ENABLE_CMD;
+ FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 1);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+ /*
+ * Write Status register
+ */
+ WriteBuffer[COMMAND_OFFSET] = WRITE_STATUS_REG_2_CMD;
+ FlashMsg[0].TxBfrPtr = WriteBuffer;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ FlashMsg[1].TxBfrPtr = &StatusRegVal;
+ FlashMsg[1].RxBfrPtr = NULL;
+ FlashMsg[1].ByteCount = 1;
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_TX;
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ while (1) {
+ ReadStatusCmd = READ_STATUS_CMD;
+ FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+ FlashMsg[1].TxBfrPtr = NULL;
+ FlashMsg[1].RxBfrPtr = FlashStatus;
+ FlashMsg[1].ByteCount = 2;
+ FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ if (FSRFlag) {
+ FlashStatus[1] &= FlashStatus[0];
+ } else {
+ FlashStatus[1] |= FlashStatus[0];
+ }
+ }
+ if ((FlashStatus[1] & 0x01) == 0x00) {
+ break;
+ }
+ }
+ /*
+ * Write Disable
+ */
+ WriteEnableCmd = WRITE_DISABLE_CMD;
+ FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
+ FlashMsg[0].RxBfrPtr = NULL;
+ FlashMsg[0].ByteCount = 1;
+ FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg, 2);
+ if (Status != XST_SUCCESS) {
+ return XST_FAILURE;
+ }
+ while (TransferInProgress);
+ break;
+
+ default:
+ /*
+ * Currently only S25FL-L series requires the
+ * Quad enable bit to be set to 1.
+ */
+ Status = XST_SUCCESS;
+ break;
+ }
+
+ return Status;
+}
+
+static int MultiDieReadEcc(
+ XQspiPsu *QspiPsuPtr,
+ u32 Address,
+ u32 ByteCount,
+ u8 *WriteBfrPtr,
+ u8 *ReadBfrPtr
+);
+
+int QspiPsu_NOR_Read_Ecc(
+ XQspiPsu *QspiPsuPtr,
+ u32 Address,
+ u8 *ReadBfrPtr
+)
+{
+ u32 RealAddr;
+ u32 DiscardByteCnt;
+ u32 FlashMsgCnt;
+ u8 EccBuffer[16];
+ int ByteCount = sizeof(EccBuffer);
+ int Status;
+
+ /* Check die boundary conditions if required for any flash */
+ if (Flash_Config_Table[FCTIndex].NumDie > 1) {
+
+ Status = MultiDieReadEcc(QspiPsuPtr, Address, ByteCount,
+ CmdBfr, EccBuffer);
+ if (Status == XST_SUCCESS) {
+ /* All bytes are the same, so copy one return byte into the output buffer */
+ *ReadBfrPtr = EccBuffer[0];
+ }
+ return Status;
+ }
+
+ /* For Dual Stacked, split and read for boundary crossing */
+ /*
+ * Translate address based on type of connection
+ * If stacked assert the slave select based on address
+ */
+ RealAddr = GetRealAddr(QspiPsuPtr, Address);
+
+ CmdBfr[COMMAND_OFFSET] = READ_ECCSR;
+ CmdBfr[ADDRESS_1_OFFSET] =
+ (u8)((RealAddr & 0xFF000000) >> 24);
+ CmdBfr[ADDRESS_2_OFFSET] =
+ (u8)((RealAddr & 0xFF0000) >> 16);
+ CmdBfr[ADDRESS_3_OFFSET] =
+ (u8)((RealAddr & 0xFF00) >> 8);
+ CmdBfr[ADDRESS_4_OFFSET] =
+ (u8)(RealAddr & 0xF0);
+ DiscardByteCnt = 5;
+
+ FlashMsgCnt = 0;
+
+ FlashMsg[FlashMsgCnt].TxBfrPtr = CmdBfr;
+ FlashMsg[FlashMsgCnt].RxBfrPtr = NULL;
+ FlashMsg[FlashMsgCnt].ByteCount = DiscardByteCnt;
+ FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ FlashMsgCnt++;
+
+ FlashMsg[FlashMsgCnt].TxBfrPtr = NULL;
+ FlashMsg[FlashMsgCnt].RxBfrPtr = NULL;
+ FlashMsg[FlashMsgCnt].ByteCount = DUMMY_CLOCKS;
+ FlashMsg[FlashMsgCnt].Flags = 0;
+
+ FlashMsgCnt++;
+
+ FlashMsg[FlashMsgCnt].TxBfrPtr = NULL;
+ FlashMsg[FlashMsgCnt].RxBfrPtr = EccBuffer;
+ FlashMsg[FlashMsgCnt].ByteCount = ByteCount;
+ FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_RX;
+
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ FlashMsg[FlashMsgCnt].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
+ }
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg,
+ FlashMsgCnt + 1);
+ if (Status == XST_SUCCESS) {
+ while (TransferInProgress);
+
+ /* All bytes are the same, so copy one return byte into the output buffer */
+ *ReadBfrPtr = EccBuffer[0];
+ }
+
+ return Status;
+}
+
+/*****************************************************************************/
+/**
+ *
+ * This function performs an ECC read operation for multi die flash devices.
+ * Default setting is in DMA mode.
+ *
+ * @param QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
+ * @param Address contains the address of the first sector which needs to
+ * be erased.
+ * @param ByteCount contains the total size to be erased.
+ * @param WriteBfrPtr is pointer to the write buffer which contains data to be
+ * transmitted
+ * @param ReadBfrPtr is pointer to the read buffer to which valid received data
+ * should be written
+ *
+ * @return XST_SUCCESS if successful, else XST_FAILURE.
+ *
+ * @note None.
+ *
+ ******************************************************************************/
+static int MultiDieReadEcc(
+ XQspiPsu *QspiPsuPtr,
+ u32 Address,
+ u32 ByteCount,
+ u8 *WriteBfrPtr,
+ u8 *ReadBuffer
+)
+{
+ u32 RealAddr;
+ u32 DiscardByteCnt;
+ u32 FlashMsgCnt;
+ int Status;
+ u32 cur_bank = 0;
+ u32 nxt_bank = 0;
+ u32 bank_size;
+ u32 remain_len = ByteCount;
+ u32 data_len;
+ u32 transfer_len;
+
+ /*
+ * Some flash devices like N25Q512 have multiple dies
+ * in it. Read operation in these devices is bounded
+ * by its die segment. In a continuous read, across
+ * multiple dies, when the last byte of the selected
+ * die segment is read, the next byte read is the
+ * first byte of the same die segment. This is Die
+ * cross over issue. So to handle this issue, split
+ * a read transaction, that spans across multiple
+ * banks, into one read per bank. Bank size is 16MB
+ * for single and dual stacked mode and 32MB for dual
+ * parallel mode.
+ */
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL)
+ bank_size = SIXTEENMB << 1;
+ else
+ bank_size = SIXTEENMB;
+
+ while (remain_len) {
+ cur_bank = Address / bank_size;
+ nxt_bank = (Address + remain_len) / bank_size;
+
+ if (cur_bank != nxt_bank) {
+ transfer_len = (bank_size * (cur_bank + 1)) - Address;
+ if (remain_len < transfer_len)
+ data_len = remain_len;
+ else
+ data_len = transfer_len;
+ } else {
+ data_len = remain_len;
+ }
+ /*
+ * Translate address based on type of connection
+ * If stacked assert the slave select based on address
+ */
+ RealAddr = GetRealAddr(QspiPsuPtr, Address);
+
+ WriteBfrPtr[COMMAND_OFFSET] = READ_ECCSR;
+ WriteBfrPtr[ADDRESS_1_OFFSET] =
+ (u8)((RealAddr & 0xFF000000) >> 24);
+ WriteBfrPtr[ADDRESS_2_OFFSET] =
+ (u8)((RealAddr & 0xFF0000) >> 16);
+ WriteBfrPtr[ADDRESS_3_OFFSET] =
+ (u8)((RealAddr & 0xFF00) >> 8);
+ WriteBfrPtr[ADDRESS_4_OFFSET] =
+ (u8)(RealAddr & 0xF0);
+ DiscardByteCnt = 5;
+
+ FlashMsgCnt = 0;
+
+ FlashMsg[FlashMsgCnt].TxBfrPtr = WriteBfrPtr;
+ FlashMsg[FlashMsgCnt].RxBfrPtr = NULL;
+ FlashMsg[FlashMsgCnt].ByteCount = DiscardByteCnt;
+ FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_TX;
+
+ FlashMsgCnt++;
+
+ FlashMsg[FlashMsgCnt].TxBfrPtr = NULL;
+ FlashMsg[FlashMsgCnt].RxBfrPtr = NULL;
+ FlashMsg[FlashMsgCnt].ByteCount = DUMMY_CLOCKS;
+ FlashMsg[FlashMsgCnt].Flags = 0;
+
+ FlashMsgCnt++;
+
+ FlashMsg[FlashMsgCnt].TxBfrPtr = NULL;
+ FlashMsg[FlashMsgCnt].RxBfrPtr = ReadBuffer;
+ FlashMsg[FlashMsgCnt].ByteCount = data_len;
+ FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+ FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_RX;
+
+ if (QspiPsuPtr->Config.ConnectionMode ==
+ XQSPIPSU_CONNECTION_MODE_PARALLEL)
+ FlashMsg[FlashMsgCnt].Flags |=
+ XQSPIPSU_MSG_FLAG_STRIPE;
+
+ TransferInProgress = TRUE;
+ Status = XQspiPsu_InterruptTransfer(QspiPsuPtr, FlashMsg,
+ FlashMsgCnt + 1);
+ if (Status != XST_SUCCESS)
+ return XST_FAILURE;
+
+ while (TransferInProgress);
+
+ ReadBuffer += data_len;
+ Address += data_len;
+ remain_len -= data_len;
+ }
+ return 0;
+}
+
+u32 QspiPsu_NOR_Get_Sector_Size(XQspiPsu *QspiPsuPtr)
+{
+ if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ return Flash_Config_Table[FCTIndex].SectSize * 2;
+ }
+ return Flash_Config_Table[FCTIndex].SectSize;
+}
+
+u32 QspiPsu_NOR_Get_Device_Size(XQspiPsu *QspiPsuPtr)
+{
+ if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED
+ || QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+ return Flash_Config_Table[FCTIndex].FlashDeviceSize * 2;
+ }
+ return Flash_Config_Table[FCTIndex].FlashDeviceSize;
+}
diff --git a/bsps/shared/dev/spi/xqspipsu.c b/bsps/shared/dev/spi/xqspipsu.c
new file mode 100644
index 0000000000..93d3fa4c98
--- /dev/null
+++ b/bsps/shared/dev/spi/xqspipsu.c
@@ -0,0 +1,1086 @@
+/******************************************************************************
+* 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"
+#ifdef __rtems__
+#include <rtems/rtems/cache.h>
+#endif
+
+/************************** 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;
+
+#ifdef __rtems__
+ u32 FifoStatusMask = XQSPIPSU_ISR_RXEMPTY_MASK;
+ FifoStatusMask |= XQSPIPSU_ISR_TXEMPTY_MASK;
+ FifoStatusMask |= XQSPIPSU_ISR_GENFIFOEMPTY_MASK;
+#endif
+
+ 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,
+#ifdef __rtems__
+ XQSPIPSU_ISR_OFFSET) & FifoStatusMask;
+ while(FifoStatus != FifoStatusMask) {
+#else
+ XQSPIPSU_FIFO_CTRL_OFFSET);
+ while(FifoStatus != 0U) {
+#endif
+ 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,
+#ifdef __rtems__
+ XQSPIPSU_ISR_OFFSET) & FifoStatusMask;
+#else
+ XQSPIPSU_FIFO_CTRL_OFFSET);
+#endif
+ }
+ }
+
+ 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);
+#ifdef __rtems__
+ if (Msg[Index].TxBfrPtr != NULL) {
+ rtems_cache_flush_multiple_data_lines(Msg[Index].TxBfrPtr, Msg[Index].ByteCount);
+ }
+#endif
+ }
+#ifdef __rtems__
+ rtems_cache_flush_multiple_data_lines(Msg, NumMsg * sizeof(*Msg));
+#endif
+
+ /*
+ * 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++)
+#ifdef __rtems__
+ {
+#endif
+ Xil_AssertNonvoid(Msg[Index].ByteCount > 0U);
+#ifdef __rtems__
+ if (Msg[Index].TxBfrPtr != NULL) {
+ rtems_cache_flush_multiple_data_lines(Msg[Index].TxBfrPtr, Msg[Index].ByteCount);
+ }
+ }
+ rtems_cache_flush_multiple_data_lines(Msg, NumMsg * sizeof(*Msg));
+#endif
+
+ /*
+ * 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);
+}
+/** @} */