[PATCH 2/3] bsps: Add Xilinx GQSPI flash helper

Alex White alex.white at oarcorp.com
Mon Jan 23 19:52:06 UTC 2023


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(+)
 create mode 100644 bsps/include/dev/spi/xqspipsu-flash-helper.h
 create mode 100644 bsps/shared/dev/spi/xqspipsu-flash-helper.c
 create mode 100644 spec/build/bsps/objqspipsu.yml
 create mode 100644 spec/build/bsps/optxpssysctrlbaseaddress.yml

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..ae9223bef6
--- /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
-- 
2.34.1



More information about the devel mailing list