[rtems commit] bsps: Add Xilinx GQSPI flash helper

Joel Sherrill joel at rtems.org
Fri Jan 27 20:34:03 UTC 2023


Module:    rtems
Branch:    master
Commit:    d55c1319651e1787364ad00471657e49b8315986
Changeset: http://git.rtems.org/rtems/commit/?id=d55c1319651e1787364ad00471657e49b8315986

Author:    Alex White <alex.white at oarcorp.com>
Date:      Sun Jan  8 14:24:25 2023 -0600

bsps: Add Xilinx GQSPI flash helper

This adds helper functions for working with NOR flash connected to the
Xilinx GQSPI controller. The helper functions are based on Xilinx's
QSPIPSU flash interrupt example.

---

 bsps/include/dev/spi/xqspipsu-flash-helper.h |   81 ++
 bsps/shared/dev/spi/xqspipsu-flash-helper.c  | 2005 ++++++++++++++++++++++++++
 spec/build/bsps/objqspipsu.yml               |   32 +
 spec/build/bsps/optxpssysctrlbaseaddress.yml |   18 +
 4 files changed, 2136 insertions(+)

diff --git a/bsps/include/dev/spi/xqspipsu-flash-helper.h b/bsps/include/dev/spi/xqspipsu-flash-helper.h
new file mode 100644
index 0000000000..075f7f826d
--- /dev/null
+++ b/bsps/include/dev/spi/xqspipsu-flash-helper.h
@@ -0,0 +1,81 @@
+/******************************************************************************
+* Copyright (C) 2018 - 2022 Xilinx, Inc.  All rights reserved.
+* SPDX-License-Identifier: MIT
+******************************************************************************/
+
+#include "xqspipsu.h"
+
+int QspiPsu_NOR_Initialize(
+  XQspiPsu *QspiPsuInstancePtr,
+  u16 QspiPsuIntrId
+);
+
+/*****************************************************************************/
+/**
+ *
+ * This function erases the sectors in the  serial Flash connected to the
+ * QSPIPSU interface.
+ *
+ * @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.
+ *
+ * @return	XST_SUCCESS if successful, else XST_FAILURE.
+ *
+ * @note	None.
+ *
+ ******************************************************************************/
+int QspiPsu_NOR_Erase(
+  XQspiPsu *QspiPsuPtr,
+  u32 Address,
+  u32 ByteCount
+);
+
+/*****************************************************************************/
+/**
+ *
+ * This function writes to the  serial Flash connected to the QSPIPSU interface.
+ * All the data put into the buffer must be in the same page of the device with
+ * page boundaries being on 256 byte boundaries.
+ *
+ * @param	QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
+ * @param	Address contains the address to write data to in the Flash.
+ * @param	ByteCount contains the number of bytes to write.
+ * @param	WriteBfrPtr is pointer to the write buffer (which is to be transmitted)
+ *
+ * @return	XST_SUCCESS if successful, else XST_FAILURE.
+ *
+ * @note	None.
+ *
+ ******************************************************************************/
+int QspiPsu_NOR_Write(
+  XQspiPsu *QspiPsuPtr,
+  u32 Address,
+  u32 ByteCount,
+	u8 *WriteBfrPtr
+);
+
+/*****************************************************************************/
+/**
+ *
+ * This function performs a read. 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	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.
+ *
+ ******************************************************************************/
+int QspiPsu_NOR_Read(
+  XQspiPsu *QspiPsuPtr,
+  u32 Address,
+  u32 ByteCount,
+  u8 **ReadBfrPtr
+);
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..7fa04efdde
--- /dev/null
+++ b/bsps/shared/dev/spi/xqspipsu-flash-helper.c
@@ -0,0 +1,2005 @@
+/******************************************************************************
+* 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++;
+  }
+}
+
+/*****************************************************************************/
+/**
+ *
+ * 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)
+{
+  int Status;
+  u32 ReadId = 0;
+
+  /*
+   * 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 = 3;
+  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);
+
+  /* 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(
+  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_Erase(
+  XQspiPsu *QspiPsuPtr,
+  u32 Address,
+  u32 ByteCount
+)
+{
+  u8 WriteEnableCmd;
+  u8 ReadStatusCmd;
+  u8 FlashStatus[2];
+  int Sector;
+  u32 RealAddr;
+  u32 NumSect;
+  int Status;
+  u32 SectSize;
+  u32 SectMask;
+
+  WriteEnableCmd = WRITE_ENABLE_CMD;
+
+  if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) {
+    SectMask = (Flash_Config_Table[FCTIndex]).SectMask - (Flash_Config_Table[FCTIndex]).SectSize;
+    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;
+    SectMask = (Flash_Config_Table[FCTIndex]).SectMask;
+    SectSize = (Flash_Config_Table[FCTIndex]).SectSize;
+  } else {
+    SectSize = (Flash_Config_Table[FCTIndex]).SectSize;
+    NumSect = (Flash_Config_Table[FCTIndex]).NumSect;
+    SectMask = (Flash_Config_Table[FCTIndex]).SectMask;
+  }
+
+  /*
+   * 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
+   */
+  NumSect = (ByteCount / SectSize) + 1;
+
+  /*
+   * If ByteCount to k sectors,
+   * but the address range spans from N to N+k+1 sectors, then
+   * increment no. of sectors to be erased
+   */
+
+  if (((Address + ByteCount) & SectMask) ==
+    ((Address + (NumSect * SectSize)) & SectMask)) {
+    NumSect++;
+  }
+
+  for (Sector = 0; Sector < NumSect; Sector++) {
+
+    /*
+     * Translate address based on type of connection
+     * If stacked assert the slave select based on address
+     */
+    RealAddr = GetRealAddr(QspiPsuPtr, Address);
+
+    /*
+     * Send the write enable command to the Flash so that it can be
+     * written to, this needs to be sent as a separate
+     * transfer before the write
+     */
+    FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
+    FlashMsg[0].RxBfrPtr = NULL;
+    FlashMsg[0].ByteCount = 1;
+    FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
+    FlashMsg[0].Flags = 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);
+
+  }
+  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;
+  }
+  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;
+}
diff --git a/spec/build/bsps/objqspipsu.yml b/spec/build/bsps/objqspipsu.yml
new file mode 100644
index 0000000000..5f8679c83c
--- /dev/null
+++ b/spec/build/bsps/objqspipsu.yml
@@ -0,0 +1,32 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+build-type: objects
+cflags: []
+copyrights:
+- Copyright (C) 2022 On-Line Applications Research (OAR)
+cppflags: []
+cxxflags: []
+enabled-by: true
+includes:
+- bsps/include/dev/spi/
+- bsps/include/xil/
+- bsps/include/xil/${XIL_SUPPORT_PATH}/
+install:
+- destination: ${BSP_INCLUDEDIR}/dev/spi
+  source:
+  - bsps/include/dev/spi/xqspipsu_control.h
+  - bsps/include/dev/spi/xqspipsu_flash_config.h
+  - bsps/include/dev/spi/xqspipsu_hw.h
+  - bsps/include/dev/spi/xqspipsu-flash-helper.h
+  - bsps/include/dev/spi/xqspipsu.h
+links:
+- role: build-dependency
+  uid: objxilinxsupport
+- role: build-dependency
+  uid: optxpssysctrlbaseaddress
+source:
+- bsps/shared/dev/spi/xqspipsu_control.c
+- bsps/shared/dev/spi/xqspipsu_hw.c
+- bsps/shared/dev/spi/xqspipsu_options.c
+- bsps/shared/dev/spi/xqspipsu-flash-helper.c
+- bsps/shared/dev/spi/xqspipsu.c
+type: build
diff --git a/spec/build/bsps/optxpssysctrlbaseaddress.yml b/spec/build/bsps/optxpssysctrlbaseaddress.yml
new file mode 100644
index 0000000000..644cbccc58
--- /dev/null
+++ b/spec/build/bsps/optxpssysctrlbaseaddress.yml
@@ -0,0 +1,18 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+actions:
+- get-integer: null
+- assert-uint32: null
+- env-assign: null
+- format-and-define: null
+build-type: option
+copyrights:
+- Copyright (C) 2022 On-Line Applications Research Corporation (OAR)
+default: 0xFF180000
+default-by-variant: []
+description: |
+  base address of XPS
+enabled-by: true
+format: '{:#010x}'
+links: []
+name: XPS_SYS_CTRL_BASEADDR
+type: build



More information about the vc mailing list