Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:05

0001 /******************************************************************************
0002 * Copyright (C) 2018 - 2022 Xilinx, Inc.  All rights reserved.
0003 * SPDX-License-Identifier: MIT
0004 ******************************************************************************/
0005 
0006 /**
0007  * @file xqspipsu_flash_helper.c
0008  *
0009  * This file contains flash helper functions for the QSPIPSU driver. It
0010  * consists of modified functions from Xilinx's flash example in
0011  * examples/xqspipsu_generic_flash_interrupt_example.c of the qspipsu driver.
0012  *
0013  */
0014 
0015 #include "xqspipsu_flash_config.h"
0016 #include "xqspipsu-flash-helper.h"
0017 
0018 #include <rtems.h>
0019 #include <string.h>
0020 
0021 /*
0022  * Number of flash pages to be written.
0023  */
0024 #define PAGE_COUNT      32
0025 
0026 /*
0027  * Max page size to initialize write and read buffer
0028  */
0029 #define MAX_PAGE_SIZE 1024
0030 
0031 #define TEST_ADDRESS        0x000000
0032 
0033 #define XQSPI_FLASH_MAX_READ_SIZE ((size_t)0x8000)
0034 
0035 #define ENTER_4B    1
0036 #define EXIT_4B     0
0037 
0038 #define NOR_TIMEOUT_US   5000000U
0039 #define NOR_TIMEOUT_TICKS (NOR_TIMEOUT_US / rtems_configuration_get_microseconds_per_tick())
0040 
0041 u8 ReadCmd;
0042 u8 WriteCmd;
0043 u8 StatusCmd;
0044 u8 SectorEraseCmd;
0045 u8 FSRFlag;
0046 
0047 static int FlashReadID(XQspiPsu *QspiPsuPtr);
0048 
0049 static int MultiDieRead(
0050   XQspiPsu *QspiPsuPtr,
0051   u32 Address,
0052   u32 ByteCount,
0053   u8 Command,
0054   u8 *WriteBfrPtr,
0055   u8 *ReadBfrPtr
0056 );
0057 
0058 static u32 GetRealAddr(
0059   XQspiPsu *QspiPsuPtr,
0060   u32 Address
0061 );
0062 
0063 static int BulkErase(
0064   XQspiPsu *QspiPsuPtr,
0065   u8 *WriteBfrPtr
0066 );
0067 
0068 static int DieErase(
0069   XQspiPsu *QspiPsuPtr,
0070   u8 *WriteBfrPtr
0071 );
0072 
0073 static int QspiPsuSetupIntrSystem(
0074   XQspiPsu *QspiPsuInstancePtr,
0075   u16 QspiPsuIntrId
0076 );
0077 
0078 static void QspiPsuHandler(
0079   void *CallBackRef,
0080   u32 StatusEvent,
0081   unsigned int ByteCount
0082 );
0083 
0084 static int FlashEnterExit4BAddMode(
0085   XQspiPsu *QspiPsuPtr,
0086   unsigned int Enable
0087 );
0088 
0089 static int FlashEnableQuadMode(XQspiPsu *QspiPsuPtr);
0090 
0091 u8 TxBfrPtr;
0092 u8 ReadBfrPtr[3];
0093 u32 FlashMake;
0094 u32 FCTIndex;   /* Flash configuration table index */
0095 
0096 static XQspiPsu_Msg FlashMsg[5];
0097 
0098 /*
0099  * The following variables are shared between non-interrupt processing and
0100  * interrupt processing such that they must be global.
0101  */
0102 rtems_id TransferTask;
0103 
0104 static s32 transfer_and_wait(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg, u32 NumMsg)
0105 {
0106   rtems_status_code sc;
0107   TransferTask = rtems_task_self();
0108   s32 Status = XQspiPsu_InterruptTransfer(InstancePtr, Msg, NumMsg);
0109   if (Status != XST_SUCCESS) {
0110     return Status;
0111   }
0112 
0113   sc = rtems_event_transient_receive(RTEMS_WAIT, NOR_TIMEOUT_TICKS);
0114   if (sc != RTEMS_SUCCESSFUL) {
0115     rtems_event_transient_clear();
0116     XQspiPsu_Abort(InstancePtr);
0117     return XST_FAILURE;
0118   }
0119 
0120   return XST_SUCCESS;
0121 }
0122 
0123 /*
0124  * The following variables are used to read and write to the flash and they
0125  * are global to avoid having large buffers on the stack
0126  * The buffer size accounts for maximum page size and maximum banks -
0127  * for each bank separate read will be performed leading to that many
0128  * (overhead+dummy) bytes
0129  */
0130 #ifdef __ICCARM__
0131 #pragma data_alignment = 32
0132 u8 ReadBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + (DATA_OFFSET + DUMMY_SIZE)*8];
0133 #else
0134 u8 ReadBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + (DATA_OFFSET + DUMMY_SIZE)*8] __attribute__ ((aligned(64)));
0135 #endif
0136 u8 WriteBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + DATA_OFFSET];
0137 u8 CmdBfr[8];
0138 
0139 /*
0140  * The following constants specify the max amount of data and the size of the
0141  * the buffer required to hold the data and overhead to transfer the data to
0142  * and from the Flash. Initialized to single flash page size.
0143  */
0144 u32 MaxData = PAGE_COUNT*256;
0145 
0146 int QspiPsu_NOR_Initialize(
0147   XQspiPsu *QspiPsuInstancePtr,
0148   u16 QspiPsuIntrId
0149 )
0150 {
0151   int Status;
0152 
0153   if (QspiPsuInstancePtr == NULL) {
0154     return XST_FAILURE;
0155   }
0156 
0157   /*
0158    * Connect the QspiPsu device to the interrupt subsystem such that
0159    * interrupts can occur. This function is application specific
0160    */
0161   Status = QspiPsuSetupIntrSystem(QspiPsuInstancePtr, QspiPsuIntrId);
0162   if (Status != XST_SUCCESS) {
0163     return XST_FAILURE;
0164   }
0165 
0166     /*
0167    * Setup the handler for the QSPIPSU that will be called from the
0168    * interrupt context when an QSPIPSU status occurs, specify a pointer to
0169    * the QSPIPSU driver instance as the callback reference
0170    * so the handler is able to access the instance data
0171    */
0172   XQspiPsu_SetStatusHandler(QspiPsuInstancePtr, QspiPsuInstancePtr,
0173          (XQspiPsu_StatusHandler) QspiPsuHandler);
0174 
0175   /*
0176    * Set Manual Start
0177    */
0178   XQspiPsu_SetOptions(QspiPsuInstancePtr, XQSPIPSU_MANUAL_START_OPTION);
0179 
0180   /*
0181    * Set the prescaler for QSPIPSU clock
0182    */
0183   XQspiPsu_SetClkPrescaler(QspiPsuInstancePtr, XQSPIPSU_CLK_PRESCALE_8);
0184 
0185   XQspiPsu_SelectFlash(QspiPsuInstancePtr,
0186     XQSPIPSU_SELECT_FLASH_CS_LOWER,
0187     XQSPIPSU_SELECT_FLASH_BUS_LOWER);
0188 
0189   /*
0190    * Read flash ID and obtain all flash related information
0191    * It is important to call the read id function before
0192    * performing proceeding to any operation, including
0193    * preparing the WriteBuffer
0194    */
0195 
0196   Status = FlashReadID(QspiPsuInstancePtr);
0197   if (Status != XST_SUCCESS) {
0198     return XST_FAILURE;
0199   }
0200 
0201   /*
0202    * Some flash needs to enable Quad mode before using
0203    * quad commands.
0204    */
0205   Status = FlashEnableQuadMode(QspiPsuInstancePtr);
0206   if (Status != XST_SUCCESS)
0207     return XST_FAILURE;
0208 
0209   /*
0210    * Address size and read command selection
0211    * Micron flash on REMUS doesn't support these 4B write/erase commands
0212    */
0213   if(QspiPsuInstancePtr->Config.BusWidth == BUSWIDTH_SINGLE)
0214     ReadCmd = FAST_READ_CMD;
0215   else if(QspiPsuInstancePtr->Config.BusWidth == BUSWIDTH_DOUBLE)
0216     ReadCmd = DUAL_READ_CMD;
0217   else
0218     ReadCmd = QUAD_READ_CMD;
0219 
0220   WriteCmd = WRITE_CMD;
0221   SectorEraseCmd = SEC_ERASE_CMD;
0222 
0223   if ((Flash_Config_Table[FCTIndex].NumDie > 1) &&
0224       (FlashMake == MICRON_ID_BYTE0)) {
0225     StatusCmd = READ_FLAG_STATUS_CMD;
0226     FSRFlag = 1;
0227   } else {
0228     StatusCmd = READ_STATUS_CMD;
0229     FSRFlag = 0;
0230   }
0231 
0232   if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) {
0233     Status = FlashEnterExit4BAddMode(QspiPsuInstancePtr, ENTER_4B);
0234     if (Status != XST_SUCCESS) {
0235       return XST_FAILURE;
0236     }
0237     if (FlashMake == SPANSION_ID_BYTE0) {
0238       if(QspiPsuInstancePtr->Config.BusWidth == BUSWIDTH_SINGLE)
0239         ReadCmd = FAST_READ_CMD_4B;
0240       else if(QspiPsuInstancePtr->Config.BusWidth == BUSWIDTH_DOUBLE)
0241         ReadCmd = DUAL_READ_CMD_4B;
0242       else
0243         ReadCmd = QUAD_READ_CMD_4B;
0244 
0245       WriteCmd = WRITE_CMD_4B;
0246       SectorEraseCmd = SEC_ERASE_CMD_4B;
0247     }
0248   }
0249 
0250   return XST_SUCCESS;
0251 }
0252 
0253 /*****************************************************************************/
0254 /**
0255  *
0256  * Callback handler.
0257  *
0258  * @param   CallBackRef is the upper layer callback reference passed back
0259  *      when the callback function is invoked.
0260  * @param   StatusEvent is the event that just occurred.
0261  * @param   ByteCount is the number of bytes transferred up until the event
0262  *      occurred.
0263  *
0264  * @return  None
0265  *
0266  * @note    None.
0267  *
0268  *****************************************************************************/
0269 static void QspiPsuHandler(
0270   void *CallBackRef,
0271   u32 StatusEvent,
0272   unsigned int ByteCount
0273 )
0274 {
0275   /* Indicate the transfer on the QSPIPSU bus is no longer in progress */
0276   if (StatusEvent == XST_SPI_TRANSFER_DONE) {
0277     (void) rtems_event_transient_send(TransferTask);
0278   }
0279 }
0280 
0281 int QspiPsu_NOR_RDSFDP(
0282   XQspiPsu *QspiPsuPtr,
0283   u32 Address,
0284   u32 ByteCount,
0285   u8 **ReadBfrPtr
0286 )
0287 {
0288   int Status;
0289 
0290   *ReadBfrPtr = ReadBuffer;
0291 
0292   CmdBfr[COMMAND_OFFSET]   = READ_SFDP;
0293   CmdBfr[ADDRESS_1_OFFSET] =
0294       (u8)((Address & 0xFF0000) >> 16);
0295   CmdBfr[ADDRESS_2_OFFSET] =
0296       (u8)((Address & 0xFF00) >> 8);
0297   CmdBfr[ADDRESS_3_OFFSET] =
0298       (u8)(Address & 0xFF);
0299 
0300   FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
0301   FlashMsg[0].TxBfrPtr = CmdBfr;
0302   FlashMsg[0].RxBfrPtr = NULL;
0303   FlashMsg[0].ByteCount = 4;
0304   FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
0305 
0306   FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
0307   FlashMsg[1].TxBfrPtr = NULL;
0308   FlashMsg[1].RxBfrPtr = NULL;
0309   FlashMsg[1].ByteCount = DUMMY_CLOCKS;
0310   FlashMsg[1].Flags = 0;
0311 
0312   FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
0313   FlashMsg[2].TxBfrPtr = NULL;
0314   FlashMsg[2].RxBfrPtr = *ReadBfrPtr;
0315   FlashMsg[2].ByteCount = ByteCount;
0316   FlashMsg[2].Flags = XQSPIPSU_MSG_FLAG_RX;
0317 
0318   Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 3);
0319   if (Status != XST_SUCCESS)
0320     return XST_FAILURE;
0321 
0322   rtems_cache_invalidate_multiple_data_lines(ReadBuffer, ByteCount);
0323   return 0;
0324 }
0325 
0326 int QspiPsu_NOR_RDID(XQspiPsu *QspiPsuPtr, u8 *ReadBfrPtr, u32 ReadLen)
0327 {
0328   int Status;
0329 
0330   /*
0331    * Read ID
0332    */
0333   TxBfrPtr = READ_ID;
0334   FlashMsg[0].TxBfrPtr = &TxBfrPtr;
0335   FlashMsg[0].RxBfrPtr = NULL;
0336   FlashMsg[0].ByteCount = 1;
0337   FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
0338   FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
0339 
0340   FlashMsg[1].TxBfrPtr = NULL;
0341   FlashMsg[1].RxBfrPtr = ReadBfrPtr;
0342   FlashMsg[1].ByteCount = ReadLen;
0343   FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
0344   FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
0345 
0346   Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 2);
0347   if (Status != XST_SUCCESS) {
0348     return XST_FAILURE;
0349   }
0350 
0351   rtems_cache_invalidate_multiple_data_lines(ReadBfrPtr, ReadLen);
0352   return XST_SUCCESS;
0353 }
0354 
0355 /*****************************************************************************/
0356 /**
0357  *
0358  * Reads the flash ID and identifies the flash in FCT table.
0359  *
0360  * @param   QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
0361  *
0362  * @return  XST_SUCCESS if successful, else XST_FAILURE.
0363  *
0364  * @note    None.
0365  *
0366  *****************************************************************************/
0367 static int FlashReadID(XQspiPsu *QspiPsuPtr)
0368 {
0369   u32 ReadId = 0;
0370   u32 ReadLen = 3;
0371   int Status;
0372 
0373   Status = QspiPsu_NOR_RDID(QspiPsuPtr, ReadBfrPtr, ReadLen);
0374   if (Status != XST_SUCCESS) {
0375     return XST_FAILURE;
0376   }
0377 
0378   /* In case of dual, read both and ensure they are same make/size */
0379 
0380   /*
0381    * Deduce flash make
0382    */
0383   FlashMake = ReadBfrPtr[0];
0384 
0385   ReadId = ((ReadBfrPtr[0] << 16) | (ReadBfrPtr[1] << 8) | ReadBfrPtr[2]);
0386   /*
0387    * Assign corresponding index in the Flash configuration table
0388    */
0389   Status = CalculateFCTIndex(ReadId, &FCTIndex);
0390   if (Status != XST_SUCCESS) {
0391     return XST_FAILURE;
0392   }
0393 
0394   return XST_SUCCESS;
0395 }
0396 
0397 int QspiPsu_NOR_Write_Page(
0398   XQspiPsu *QspiPsuPtr,
0399   u32 Address,
0400   u32 ByteCount,
0401   u8 *WriteBfrPtr
0402 )
0403 {
0404   u8 WriteEnableCmd;
0405   u8 ReadStatusCmd;
0406   u8 FlashStatus[2];
0407   u8 WriteCmdBfr[5];
0408   u32 RealAddr;
0409   u32 CmdByteCount;
0410   int Status;
0411 
0412   WriteEnableCmd = WRITE_ENABLE_CMD;
0413   /*
0414    * Translate address based on type of connection
0415    * If stacked assert the slave select based on address
0416    */
0417   RealAddr = GetRealAddr(QspiPsuPtr, Address);
0418 
0419   /*
0420    * Send the write enable command to the Flash so that it can be
0421    * written to, this needs to be sent as a separate transfer before
0422    * the write
0423    */
0424   FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
0425   FlashMsg[0].RxBfrPtr = NULL;
0426   FlashMsg[0].ByteCount = 1;
0427   FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
0428   FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
0429 
0430   Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 1);
0431   if (Status != XST_SUCCESS) {
0432     return XST_FAILURE;
0433   }
0434 
0435   WriteCmdBfr[COMMAND_OFFSET]   = WriteCmd;
0436 
0437   /* To be used only if 4B address program cmd is supported by flash */
0438   if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) {
0439     WriteCmdBfr[ADDRESS_1_OFFSET] =
0440         (u8)((RealAddr & 0xFF000000) >> 24);
0441     WriteCmdBfr[ADDRESS_2_OFFSET] =
0442         (u8)((RealAddr & 0xFF0000) >> 16);
0443     WriteCmdBfr[ADDRESS_3_OFFSET] =
0444         (u8)((RealAddr & 0xFF00) >> 8);
0445     WriteCmdBfr[ADDRESS_4_OFFSET] =
0446         (u8)(RealAddr & 0xFF);
0447     CmdByteCount = 5;
0448   } else {
0449     WriteCmdBfr[ADDRESS_1_OFFSET] =
0450         (u8)((RealAddr & 0xFF0000) >> 16);
0451     WriteCmdBfr[ADDRESS_2_OFFSET] =
0452         (u8)((RealAddr & 0xFF00) >> 8);
0453     WriteCmdBfr[ADDRESS_3_OFFSET] =
0454         (u8)(RealAddr & 0xFF);
0455     CmdByteCount = 4;
0456   }
0457 
0458   FlashMsg[0].TxBfrPtr = WriteCmdBfr;
0459   FlashMsg[0].RxBfrPtr = NULL;
0460   FlashMsg[0].ByteCount = CmdByteCount;
0461   FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
0462   FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
0463 
0464   FlashMsg[1].TxBfrPtr = WriteBfrPtr;
0465   FlashMsg[1].RxBfrPtr = NULL;
0466   FlashMsg[1].ByteCount = ByteCount;
0467   FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
0468   FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_TX;
0469   if (QspiPsuPtr->Config.ConnectionMode ==
0470       XQSPIPSU_CONNECTION_MODE_PARALLEL) {
0471     FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
0472   }
0473 
0474   Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 2);
0475   if (Status != XST_SUCCESS) {
0476     return XST_FAILURE;
0477   }
0478 
0479   /*
0480    * Wait for the write command to the Flash to be completed, it takes
0481    * some time for the data to be written
0482    */
0483   while (1) {
0484     ReadStatusCmd = StatusCmd;
0485     FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
0486     FlashMsg[0].RxBfrPtr = NULL;
0487     FlashMsg[0].ByteCount = 1;
0488     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
0489     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
0490 
0491     FlashMsg[1].TxBfrPtr = NULL;
0492     FlashMsg[1].RxBfrPtr = FlashStatus;
0493     FlashMsg[1].ByteCount = 2;
0494     FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
0495     FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
0496     if (QspiPsuPtr->Config.ConnectionMode ==
0497         XQSPIPSU_CONNECTION_MODE_PARALLEL) {
0498       FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
0499     }
0500 
0501     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 2);
0502     if (Status != XST_SUCCESS) {
0503       return XST_FAILURE;
0504     }
0505 
0506     if (QspiPsuPtr->Config.ConnectionMode ==
0507         XQSPIPSU_CONNECTION_MODE_PARALLEL) {
0508       if (FSRFlag) {
0509         FlashStatus[1] &= FlashStatus[0];
0510       } else {
0511         FlashStatus[1] |= FlashStatus[0];
0512       }
0513     }
0514 
0515     if (FSRFlag) {
0516       if ((FlashStatus[1] & 0x80) != 0) {
0517         break;
0518       }
0519     } else {
0520       if ((FlashStatus[1] & 0x01) == 0) {
0521         break;
0522       }
0523     }
0524   }
0525 
0526   return 0;
0527 }
0528 
0529 int QspiPsu_NOR_Write(
0530   XQspiPsu *QspiPsuPtr,
0531   u32 Address,
0532   u32 ByteCount,
0533   u8 *WriteBfrPtr
0534 )
0535 {
0536   int Status;
0537   size_t ByteCountRemaining = ByteCount;
0538   unsigned char *WriteBfrPartial = WriteBfrPtr;
0539   uint32_t AddressPartial = Address;
0540   uint32_t PageSize = Flash_Config_Table[FCTIndex].PageSize;
0541   if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) {
0542     PageSize *= 2;
0543   }
0544 
0545   while (ByteCountRemaining > 0) {
0546     /* Get write boundary */
0547     size_t WriteChunkLen = RTEMS_ALIGN_UP(AddressPartial + 1, PageSize);
0548 
0549     /* Get offset to write boundary */
0550     WriteChunkLen -= (size_t)AddressPartial;
0551 
0552     /* Cap short writes */
0553     if (WriteChunkLen > ByteCountRemaining) {
0554       WriteChunkLen = ByteCountRemaining;
0555     }
0556 
0557     Status = QspiPsu_NOR_Write_Page(
0558       QspiPsuPtr,
0559       AddressPartial,
0560       WriteChunkLen,
0561       WriteBfrPartial
0562     );
0563     if ( Status != XST_SUCCESS ) {
0564       return Status;
0565     }
0566 
0567     ByteCountRemaining -= WriteChunkLen;
0568     AddressPartial += WriteChunkLen;
0569     WriteBfrPartial += WriteChunkLen;
0570   }
0571   return Status;
0572 }
0573 
0574 int QspiPsu_NOR_Erase(
0575   XQspiPsu *QspiPsuPtr,
0576   u32 Address,
0577   u32 ByteCount
0578 )
0579 {
0580   u8 WriteEnableCmd;
0581   u8 ReadStatusCmd;
0582   u8 FlashStatus[2];
0583   int Sector;
0584   u32 RealAddr;
0585   u32 NumSect;
0586   int Status;
0587   u32 SectSize;
0588 
0589   WriteEnableCmd = WRITE_ENABLE_CMD;
0590 
0591   if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) {
0592     SectSize = (Flash_Config_Table[FCTIndex]).SectSize * 2;
0593     NumSect = (Flash_Config_Table[FCTIndex]).NumSect;
0594   } else if (QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED) {
0595     NumSect = (Flash_Config_Table[FCTIndex]).NumSect * 2;
0596     SectSize = (Flash_Config_Table[FCTIndex]).SectSize;
0597   } else {
0598     SectSize = (Flash_Config_Table[FCTIndex]).SectSize;
0599     NumSect = (Flash_Config_Table[FCTIndex]).NumSect;
0600   }
0601 
0602   /*
0603    * If erase size is same as the total size of the flash, use bulk erase
0604    * command or die erase command multiple times as required
0605    */
0606   if (ByteCount == NumSect * SectSize) {
0607 
0608     if (QspiPsuPtr->Config.ConnectionMode ==
0609         XQSPIPSU_CONNECTION_MODE_STACKED) {
0610       XQspiPsu_SelectFlash(QspiPsuPtr,
0611         XQSPIPSU_SELECT_FLASH_CS_LOWER,
0612         XQSPIPSU_SELECT_FLASH_BUS_LOWER);
0613     }
0614 
0615     if (Flash_Config_Table[FCTIndex].NumDie == 1) {
0616       /*
0617        * Call Bulk erase
0618        */
0619       BulkErase(QspiPsuPtr, CmdBfr);
0620     }
0621 
0622     if (Flash_Config_Table[FCTIndex].NumDie > 1) {
0623       /*
0624        * Call Die erase
0625        */
0626       DieErase(QspiPsuPtr, CmdBfr);
0627     }
0628     /*
0629      * If stacked mode, bulk erase second flash
0630      */
0631     if (QspiPsuPtr->Config.ConnectionMode ==
0632         XQSPIPSU_CONNECTION_MODE_STACKED) {
0633 
0634       XQspiPsu_SelectFlash(QspiPsuPtr,
0635         XQSPIPSU_SELECT_FLASH_CS_UPPER,
0636         XQSPIPSU_SELECT_FLASH_BUS_LOWER);
0637 
0638       if (Flash_Config_Table[FCTIndex].NumDie == 1) {
0639         /*
0640          * Call Bulk erase
0641          */
0642         BulkErase(QspiPsuPtr, CmdBfr);
0643       }
0644 
0645       if (Flash_Config_Table[FCTIndex].NumDie > 1) {
0646         /*
0647          * Call Die erase
0648          */
0649         DieErase(QspiPsuPtr, CmdBfr);
0650       }
0651     }
0652 
0653     return 0;
0654   }
0655 
0656   /*
0657    * If the erase size is less than the total size of the flash, use
0658    * sector erase command
0659    */
0660 
0661   /*
0662    * Calculate no. of sectors to erase based on byte count
0663    */
0664   u32 SectorStartBase = RTEMS_ALIGN_DOWN(Address, SectSize);
0665   u32 SectorEndTop = RTEMS_ALIGN_UP(Address + ByteCount, SectSize);
0666   NumSect = (SectorEndTop - SectorStartBase)/SectSize;
0667 
0668   for (Sector = 0; Sector < NumSect; Sector++) {
0669 
0670     /*
0671      * Translate address based on type of connection
0672      * If stacked assert the slave select based on address
0673      */
0674     RealAddr = GetRealAddr(QspiPsuPtr, Address);
0675 
0676     /*
0677      * Send the write enable command to the Flash so that it can be
0678      * written to, this needs to be sent as a separate
0679      * transfer before the write
0680      */
0681     FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
0682     FlashMsg[0].RxBfrPtr = NULL;
0683     FlashMsg[0].ByteCount = 1;
0684     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
0685     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
0686 
0687     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 1);
0688     if (Status != XST_SUCCESS) {
0689       return XST_FAILURE;
0690     }
0691 
0692     CmdBfr[COMMAND_OFFSET]   = SectorEraseCmd;
0693 
0694     /*
0695      * To be used only if 4B address sector erase cmd is
0696      * supported by flash
0697      */
0698     if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) {
0699       CmdBfr[ADDRESS_1_OFFSET] =
0700           (u8)((RealAddr & 0xFF000000) >> 24);
0701       CmdBfr[ADDRESS_2_OFFSET] =
0702           (u8)((RealAddr & 0xFF0000) >> 16);
0703       CmdBfr[ADDRESS_3_OFFSET] =
0704           (u8)((RealAddr & 0xFF00) >> 8);
0705       CmdBfr[ADDRESS_4_OFFSET] =
0706           (u8)(RealAddr & 0xFF);
0707       FlashMsg[0].ByteCount = 5;
0708     } else {
0709       CmdBfr[ADDRESS_1_OFFSET] =
0710           (u8)((RealAddr & 0xFF0000) >> 16);
0711       CmdBfr[ADDRESS_2_OFFSET] =
0712           (u8)((RealAddr & 0xFF00) >> 8);
0713       CmdBfr[ADDRESS_3_OFFSET] =
0714           (u8)(RealAddr & 0xFF);
0715       FlashMsg[0].ByteCount = 4;
0716     }
0717 
0718     FlashMsg[0].TxBfrPtr = CmdBfr;
0719     FlashMsg[0].RxBfrPtr = NULL;
0720     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
0721     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
0722 
0723     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 1);
0724     if (Status != XST_SUCCESS) {
0725       return XST_FAILURE;
0726     }
0727 
0728     /*
0729      * Wait for the erase command to be completed
0730      */
0731     while (1) {
0732       ReadStatusCmd = StatusCmd;
0733       FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
0734       FlashMsg[0].RxBfrPtr = NULL;
0735       FlashMsg[0].ByteCount = 1;
0736       FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
0737       FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
0738 
0739       FlashMsg[1].TxBfrPtr = NULL;
0740       FlashMsg[1].RxBfrPtr = FlashStatus;
0741       FlashMsg[1].ByteCount = 2;
0742       FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
0743       FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
0744       if (QspiPsuPtr->Config.ConnectionMode ==
0745           XQSPIPSU_CONNECTION_MODE_PARALLEL) {
0746         FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
0747       }
0748 
0749       Status = transfer_and_wait(QspiPsuPtr,
0750           FlashMsg, 2);
0751       if (Status != XST_SUCCESS) {
0752         return XST_FAILURE;
0753       }
0754 
0755       if (QspiPsuPtr->Config.ConnectionMode ==
0756           XQSPIPSU_CONNECTION_MODE_PARALLEL) {
0757         if (FSRFlag) {
0758           FlashStatus[1] &= FlashStatus[0];
0759         } else {
0760           FlashStatus[1] |= FlashStatus[0];
0761         }
0762       }
0763 
0764       if (FSRFlag) {
0765         if ((FlashStatus[1] & 0x80) != 0) {
0766           break;
0767         }
0768       } else {
0769         if ((FlashStatus[1] & 0x01) == 0) {
0770           break;
0771         }
0772       }
0773     }
0774     Address += SectSize;
0775   }
0776 
0777   return 0;
0778 }
0779 
0780 int QspiPsu_NOR_Read_Page(
0781   XQspiPsu *QspiPsuPtr,
0782   u32 Address,
0783   u32 ByteCount,
0784   u8 **ReadBfrPtr
0785 )
0786 {
0787   u32 RealAddr;
0788   u32 DiscardByteCnt;
0789   u32 FlashMsgCnt;
0790   int Status;
0791 
0792   *ReadBfrPtr = ReadBuffer;
0793 
0794   /* Check die boundary conditions if required for any flash */
0795   if (Flash_Config_Table[FCTIndex].NumDie > 1) {
0796 
0797     Status = MultiDieRead(QspiPsuPtr, Address, ByteCount, ReadCmd,
0798               CmdBfr, *ReadBfrPtr);
0799     if (Status != XST_SUCCESS)
0800       return XST_FAILURE;
0801   } else {
0802     /* For Dual Stacked, split and read for boundary crossing */
0803     /*
0804      * Translate address based on type of connection
0805      * If stacked assert the slave select based on address
0806      */
0807     RealAddr = GetRealAddr(QspiPsuPtr, Address);
0808 
0809     CmdBfr[COMMAND_OFFSET]   = ReadCmd;
0810     if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) {
0811       CmdBfr[ADDRESS_1_OFFSET] =
0812           (u8)((RealAddr & 0xFF000000) >> 24);
0813       CmdBfr[ADDRESS_2_OFFSET] =
0814           (u8)((RealAddr & 0xFF0000) >> 16);
0815       CmdBfr[ADDRESS_3_OFFSET] =
0816           (u8)((RealAddr & 0xFF00) >> 8);
0817       CmdBfr[ADDRESS_4_OFFSET] =
0818           (u8)(RealAddr & 0xFF);
0819       DiscardByteCnt = 5;
0820     } else {
0821       CmdBfr[ADDRESS_1_OFFSET] =
0822           (u8)((RealAddr & 0xFF0000) >> 16);
0823       CmdBfr[ADDRESS_2_OFFSET] =
0824           (u8)((RealAddr & 0xFF00) >> 8);
0825       CmdBfr[ADDRESS_3_OFFSET] =
0826           (u8)(RealAddr & 0xFF);
0827       DiscardByteCnt = 4;
0828     }
0829 
0830     FlashMsg[0].TxBfrPtr = CmdBfr;
0831     FlashMsg[0].RxBfrPtr = NULL;
0832     FlashMsg[0].ByteCount = DiscardByteCnt;
0833     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
0834     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
0835 
0836     FlashMsgCnt = 1;
0837 
0838     /* It is recommended to have a separate entry for dummy */
0839     if (ReadCmd == FAST_READ_CMD || ReadCmd == DUAL_READ_CMD ||
0840         ReadCmd == QUAD_READ_CMD || ReadCmd == FAST_READ_CMD_4B ||
0841         ReadCmd == DUAL_READ_CMD_4B ||
0842         ReadCmd == QUAD_READ_CMD_4B) {
0843       /* Update Dummy cycles as per flash specs for QUAD IO */
0844 
0845       /*
0846        * It is recommended that Bus width value during dummy
0847        * phase should be same as data phase
0848        */
0849       if (ReadCmd == FAST_READ_CMD ||
0850           ReadCmd == FAST_READ_CMD_4B) {
0851         FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
0852       }
0853 
0854       if (ReadCmd == DUAL_READ_CMD ||
0855           ReadCmd == DUAL_READ_CMD_4B) {
0856         FlashMsg[1].BusWidth =
0857           XQSPIPSU_SELECT_MODE_DUALSPI;
0858       }
0859 
0860       if (ReadCmd == QUAD_READ_CMD ||
0861           ReadCmd == QUAD_READ_CMD_4B) {
0862         FlashMsg[1].BusWidth =
0863           XQSPIPSU_SELECT_MODE_QUADSPI;
0864       }
0865 
0866       FlashMsg[1].TxBfrPtr = NULL;
0867       FlashMsg[1].RxBfrPtr = NULL;
0868       FlashMsg[1].ByteCount = DUMMY_CLOCKS;
0869       FlashMsg[1].Flags = 0;
0870 
0871       FlashMsgCnt++;
0872     }
0873 
0874     /* Dummy cycles need to be changed as per flash specs
0875      * for QUAD IO
0876      */
0877     if (ReadCmd == FAST_READ_CMD || ReadCmd == FAST_READ_CMD_4B)
0878       FlashMsg[FlashMsgCnt].BusWidth =
0879         XQSPIPSU_SELECT_MODE_SPI;
0880 
0881     if (ReadCmd == DUAL_READ_CMD || ReadCmd == DUAL_READ_CMD_4B)
0882       FlashMsg[FlashMsgCnt].BusWidth =
0883         XQSPIPSU_SELECT_MODE_DUALSPI;
0884 
0885     if (ReadCmd == QUAD_READ_CMD || ReadCmd == QUAD_READ_CMD_4B)
0886       FlashMsg[FlashMsgCnt].BusWidth =
0887         XQSPIPSU_SELECT_MODE_QUADSPI;
0888 
0889     FlashMsg[FlashMsgCnt].TxBfrPtr = NULL;
0890     FlashMsg[FlashMsgCnt].RxBfrPtr = *ReadBfrPtr;
0891     FlashMsg[FlashMsgCnt].ByteCount = ByteCount;
0892     FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_RX;
0893 
0894     if (QspiPsuPtr->Config.ConnectionMode ==
0895         XQSPIPSU_CONNECTION_MODE_PARALLEL) {
0896       FlashMsg[FlashMsgCnt].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
0897     }
0898 
0899     Status = transfer_and_wait(QspiPsuPtr, FlashMsg,
0900                 FlashMsgCnt + 1);
0901     if (Status != XST_SUCCESS)
0902       return XST_FAILURE;
0903   }
0904   rtems_cache_invalidate_multiple_data_lines(ReadBuffer, ByteCount);
0905   return 0;
0906 }
0907 
0908 /*****************************************************************************/
0909 /**
0910  *
0911  * This function performs a read. Default setting is in DMA mode.
0912  *
0913  * @param   QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
0914  * @param   Address contains the address of the first sector which needs to
0915  *      be erased.
0916  * @param   ByteCount contains the total size to be erased.
0917  * @param   ReadBfrPtr the read buffer to which valid received data
0918  *      should be written
0919  *
0920  * @return  XST_SUCCESS if successful, else XST_FAILURE.
0921  *
0922  * @note    None.
0923  *
0924  ******************************************************************************/
0925 int QspiPsu_NOR_Read(
0926   XQspiPsu *QspiPsuPtr,
0927   u32 Address,
0928   u32 ByteCount,
0929   u8 *ReadBfr
0930 ) {
0931   u8 *tmp_buffer = NULL;
0932   int status;
0933   int startAlign = 0;
0934 
0935   /* Align offset to two byte boundary */
0936   if (Address%2) {
0937     startAlign = 1;
0938     Address = Address - 1;
0939     ByteCount = ByteCount + 1;
0940   }
0941 
0942   while (ByteCount > XQSPI_FLASH_MAX_READ_SIZE) {
0943     /* Read block and copy to buffer */
0944     status = QspiPsu_NOR_Read_Page(QspiPsuPtr, Address,
0945       XQSPI_FLASH_MAX_READ_SIZE, &tmp_buffer);
0946 
0947     if (status == 0) {
0948       memcpy(ReadBfr, tmp_buffer + startAlign,
0949         XQSPI_FLASH_MAX_READ_SIZE - startAlign);
0950       /* Update count, offset and buffer pointer */
0951       ByteCount -= XQSPI_FLASH_MAX_READ_SIZE;
0952       ReadBfr += XQSPI_FLASH_MAX_READ_SIZE - startAlign;
0953       Address += XQSPI_FLASH_MAX_READ_SIZE;
0954       /* Clear startAlign once first block read */
0955       if (startAlign) {
0956         startAlign = 0;
0957       }
0958     } else {
0959       return status;
0960     }
0961   }
0962 
0963   status = QspiPsu_NOR_Read_Page(QspiPsuPtr, Address, ByteCount,
0964     &tmp_buffer);
0965 
0966   if (status == 0) {
0967     memcpy(ReadBfr, tmp_buffer + startAlign, ByteCount);
0968   }
0969   return status;
0970 }
0971 
0972 /*****************************************************************************/
0973 /**
0974  *
0975  * This function performs a read operation for multi die flash devices.
0976  * Default setting is in DMA mode.
0977  *
0978  * @param   QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
0979  * @param   Address contains the address of the first sector which needs to
0980  *      be erased.
0981  * @param   ByteCount contains the total size to be erased.
0982  * @param   Command is the command used to read data from the flash.
0983  *      Supports normal, fast, dual and quad read commands.
0984  * @param   WriteBfrPtr is pointer to the write buffer which contains data to be
0985  *      transmitted
0986  * @param   ReadBfrPtr is pointer to the read buffer to which valid received data
0987  *      should be written
0988  *
0989  * @return  XST_SUCCESS if successful, else XST_FAILURE.
0990  *
0991  * @note    None.
0992  *
0993  ******************************************************************************/
0994 static int MultiDieRead(
0995   XQspiPsu *QspiPsuPtr,
0996   u32 Address,
0997   u32 ByteCount,
0998   u8 Command,
0999   u8 *WriteBfrPtr,
1000   u8 *ReadBfrPtr
1001 )
1002 {
1003   u32 RealAddr;
1004   u32 DiscardByteCnt;
1005   u32 FlashMsgCnt;
1006   int Status;
1007   u32 cur_bank = 0;
1008   u32 nxt_bank = 0;
1009   u32 bank_size;
1010   u32 remain_len = ByteCount;
1011   u32 data_len;
1012   u32 transfer_len;
1013   u8 *ReadBuffer = ReadBfrPtr;
1014 
1015   /*
1016    * Some flash devices like N25Q512 have multiple dies
1017    * in it. Read operation in these devices is bounded
1018    * by its die segment. In a continuous read, across
1019    * multiple dies, when the last byte of the selected
1020    * die segment is read, the next byte read is the
1021    * first byte of the same die segment. This is Die
1022    * cross over issue. So to handle this issue, split
1023    * a read transaction, that spans across multiple
1024    * banks, into one read per bank. Bank size is 16MB
1025    * for single and dual stacked mode and 32MB for dual
1026    * parallel mode.
1027    */
1028   if (QspiPsuPtr->Config.ConnectionMode ==
1029       XQSPIPSU_CONNECTION_MODE_PARALLEL)
1030     bank_size = SIXTEENMB << 1;
1031   else
1032     bank_size = SIXTEENMB;
1033 
1034   while (remain_len) {
1035     cur_bank = Address / bank_size;
1036     nxt_bank = (Address + remain_len) / bank_size;
1037 
1038     if (cur_bank != nxt_bank) {
1039       transfer_len = (bank_size * (cur_bank  + 1)) - Address;
1040       if (remain_len < transfer_len)
1041         data_len = remain_len;
1042       else
1043         data_len = transfer_len;
1044     } else {
1045       data_len = remain_len;
1046     }
1047     /*
1048      * Translate address based on type of connection
1049      * If stacked assert the slave select based on address
1050      */
1051     RealAddr = GetRealAddr(QspiPsuPtr, Address);
1052 
1053     WriteBfrPtr[COMMAND_OFFSET]   = Command;
1054     if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) {
1055       WriteBfrPtr[ADDRESS_1_OFFSET] =
1056           (u8)((RealAddr & 0xFF000000) >> 24);
1057       WriteBfrPtr[ADDRESS_2_OFFSET] =
1058           (u8)((RealAddr & 0xFF0000) >> 16);
1059       WriteBfrPtr[ADDRESS_3_OFFSET] =
1060           (u8)((RealAddr & 0xFF00) >> 8);
1061       WriteBfrPtr[ADDRESS_4_OFFSET] =
1062           (u8)(RealAddr & 0xFF);
1063       DiscardByteCnt = 5;
1064     } else {
1065       WriteBfrPtr[ADDRESS_1_OFFSET] =
1066           (u8)((RealAddr & 0xFF0000) >> 16);
1067       WriteBfrPtr[ADDRESS_2_OFFSET] =
1068           (u8)((RealAddr & 0xFF00) >> 8);
1069       WriteBfrPtr[ADDRESS_3_OFFSET] =
1070           (u8)(RealAddr & 0xFF);
1071       DiscardByteCnt = 4;
1072     }
1073 
1074     FlashMsg[0].TxBfrPtr = WriteBfrPtr;
1075     FlashMsg[0].RxBfrPtr = NULL;
1076     FlashMsg[0].ByteCount = DiscardByteCnt;
1077     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1078     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1079 
1080     FlashMsgCnt = 1;
1081 
1082     /* It is recommended to have a separate entry for dummy */
1083     if (Command == FAST_READ_CMD || Command == DUAL_READ_CMD ||
1084         Command == QUAD_READ_CMD || Command == FAST_READ_CMD_4B ||
1085         Command == DUAL_READ_CMD_4B ||
1086         Command == QUAD_READ_CMD_4B) {
1087       /* Update Dummy cycles as per flash specs for QUAD IO */
1088 
1089       /*
1090        * It is recommended that Bus width value during dummy
1091        * phase should be same as data phase
1092        */
1093       if (Command == FAST_READ_CMD ||
1094           Command == FAST_READ_CMD_4B) {
1095         FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1096       }
1097 
1098       if (Command == DUAL_READ_CMD ||
1099           Command == DUAL_READ_CMD_4B) {
1100         FlashMsg[1].BusWidth =
1101           XQSPIPSU_SELECT_MODE_DUALSPI;
1102       }
1103 
1104       if (Command == QUAD_READ_CMD ||
1105           Command == QUAD_READ_CMD_4B) {
1106         FlashMsg[1].BusWidth =
1107           XQSPIPSU_SELECT_MODE_QUADSPI;
1108       }
1109 
1110       FlashMsg[1].TxBfrPtr = NULL;
1111       FlashMsg[1].RxBfrPtr = NULL;
1112       FlashMsg[1].ByteCount = DUMMY_CLOCKS;
1113       FlashMsg[1].Flags = 0;
1114 
1115       FlashMsgCnt++;
1116     }
1117 
1118     /* Dummy cycles need to be changed as per flash
1119      * specs for QUAD IO
1120      */
1121     if (Command == FAST_READ_CMD || Command == FAST_READ_CMD_4B)
1122       FlashMsg[FlashMsgCnt].BusWidth =
1123         XQSPIPSU_SELECT_MODE_SPI;
1124 
1125     if (Command == DUAL_READ_CMD || Command == DUAL_READ_CMD_4B)
1126       FlashMsg[FlashMsgCnt].BusWidth =
1127         XQSPIPSU_SELECT_MODE_DUALSPI;
1128 
1129     if (Command == QUAD_READ_CMD || Command == QUAD_READ_CMD_4B)
1130       FlashMsg[FlashMsgCnt].BusWidth =
1131         XQSPIPSU_SELECT_MODE_QUADSPI;
1132 
1133     FlashMsg[FlashMsgCnt].TxBfrPtr = NULL;
1134     FlashMsg[FlashMsgCnt].RxBfrPtr = ReadBuffer;
1135     FlashMsg[FlashMsgCnt].ByteCount = data_len;
1136     FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_RX;
1137 
1138     if (QspiPsuPtr->Config.ConnectionMode ==
1139         XQSPIPSU_CONNECTION_MODE_PARALLEL)
1140       FlashMsg[FlashMsgCnt].Flags |=
1141         XQSPIPSU_MSG_FLAG_STRIPE;
1142 
1143     Status = transfer_and_wait(QspiPsuPtr, FlashMsg,
1144                 FlashMsgCnt + 1);
1145     if (Status != XST_SUCCESS)
1146       return XST_FAILURE;
1147 
1148     ReadBuffer += data_len;
1149     Address += data_len;
1150     remain_len -= data_len;
1151   }
1152   rtems_cache_invalidate_multiple_data_lines(ReadBfrPtr, ByteCount);
1153   return 0;
1154 }
1155 
1156 /*****************************************************************************/
1157 /**
1158  *
1159  * This functions performs a bulk erase operation when the
1160  * flash device has a single die. Works for both Spansion and Micron
1161  *
1162  * @param   QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
1163  * @param   WriteBfrPtr is the pointer to command+address to be sent
1164  *
1165  * @return  XST_SUCCESS if successful, else XST_FAILURE.
1166  *
1167  * @note    None.
1168  *
1169  ******************************************************************************/
1170 static int BulkErase(
1171   XQspiPsu *QspiPsuPtr,
1172   u8 *WriteBfrPtr
1173 )
1174 {
1175   u8 WriteEnableCmd;
1176   u8 ReadStatusCmd;
1177   u8 FlashStatus[2];
1178   int Status;
1179 
1180   WriteEnableCmd = WRITE_ENABLE_CMD;
1181   /*
1182    * Send the write enable command to the Flash so that it can be
1183    * written to, this needs to be sent as a separate transfer before
1184    * the write
1185    */
1186   FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
1187   FlashMsg[0].RxBfrPtr = NULL;
1188   FlashMsg[0].ByteCount = 1;
1189   FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1190   FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1191 
1192   Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 1);
1193   if (Status != XST_SUCCESS) {
1194     return XST_FAILURE;
1195   }
1196 
1197   WriteBfrPtr[COMMAND_OFFSET]   = BULK_ERASE_CMD;
1198   FlashMsg[0].TxBfrPtr = WriteBfrPtr;
1199   FlashMsg[0].RxBfrPtr = NULL;
1200   FlashMsg[0].ByteCount = 1;
1201   FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1202   FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1203 
1204   Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 1);
1205   if (Status != XST_SUCCESS) {
1206     return XST_FAILURE;
1207   }
1208 
1209   /*
1210    * Wait for the write command to the Flash to be completed, it takes
1211    * some time for the data to be written
1212    */
1213   while (1) {
1214     ReadStatusCmd = StatusCmd;
1215     FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
1216     FlashMsg[0].RxBfrPtr = NULL;
1217     FlashMsg[0].ByteCount = 1;
1218     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1219     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1220 
1221     FlashMsg[1].TxBfrPtr = NULL;
1222     FlashMsg[1].RxBfrPtr = FlashStatus;
1223     FlashMsg[1].ByteCount = 2;
1224     FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1225     FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1226     if (QspiPsuPtr->Config.ConnectionMode ==
1227         XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1228       FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
1229     }
1230 
1231     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 2);
1232     if (Status != XST_SUCCESS) {
1233       return XST_FAILURE;
1234     }
1235 
1236     if (QspiPsuPtr->Config.ConnectionMode ==
1237         XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1238       if (FSRFlag) {
1239         FlashStatus[1] &= FlashStatus[0];
1240       } else {
1241         FlashStatus[1] |= FlashStatus[0];
1242       }
1243     }
1244 
1245     if (FSRFlag) {
1246       if ((FlashStatus[1] & 0x80) != 0) {
1247         break;
1248       }
1249     } else {
1250       if ((FlashStatus[1] & 0x01) == 0) {
1251         break;
1252       }
1253     }
1254   }
1255 
1256   return 0;
1257 }
1258 
1259 /*****************************************************************************/
1260 /**
1261  *
1262  * This functions performs a die erase operation on all the die in
1263  * the flash device. This function uses the die erase command for
1264  * Micron 512Mbit and 1Gbit
1265  *
1266  * @param   QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
1267  * @param   WriteBfrPtr is the pointer to command+address to be sent
1268  *
1269  * @return  XST_SUCCESS if successful, else XST_FAILURE.
1270  *
1271  * @note    None.
1272  *
1273  ******************************************************************************/
1274 static int DieErase(
1275   XQspiPsu *QspiPsuPtr,
1276   u8 *WriteBfrPtr
1277 )
1278 {
1279   u8 WriteEnableCmd;
1280   u8 DieCnt;
1281   u8 ReadStatusCmd;
1282   u8 FlashStatus[2];
1283   int Status;
1284   u32 DieSize = 0;
1285   u32 Address;
1286   u32 RealAddr;
1287   u32 SectSize = 0;
1288   u32 NumSect = 0;
1289 
1290   WriteEnableCmd = WRITE_ENABLE_CMD;
1291 
1292   if (QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1293     SectSize = (Flash_Config_Table[FCTIndex]).SectSize * 2;
1294   } else if (QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED) {
1295     NumSect = (Flash_Config_Table[FCTIndex]).NumSect * 2;
1296   } else {
1297     SectSize = (Flash_Config_Table[FCTIndex]).SectSize;
1298     NumSect = (Flash_Config_Table[FCTIndex]).NumSect;
1299   }
1300   DieSize = (NumSect * SectSize) / Flash_Config_Table[FCTIndex].NumDie;
1301 
1302   for (DieCnt = 0;
1303     DieCnt < Flash_Config_Table[FCTIndex].NumDie;
1304     DieCnt++) {
1305     /*
1306      * Send the write enable command to the Flash so that it can be
1307      * written to, this needs to be sent as a separate transfer
1308      * before the write
1309      */
1310     FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
1311     FlashMsg[0].RxBfrPtr = NULL;
1312     FlashMsg[0].ByteCount = 1;
1313     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1314     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1315 
1316     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 1);
1317     if (Status != XST_SUCCESS) {
1318       return XST_FAILURE;
1319     }
1320 
1321     WriteBfrPtr[COMMAND_OFFSET]   = DIE_ERASE_CMD;
1322 
1323     Address = DieSize * DieCnt;
1324     RealAddr = GetRealAddr(QspiPsuPtr, Address);
1325     /*
1326      * To be used only if 4B address sector erase cmd is
1327      * supported by flash
1328      */
1329     if (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) {
1330       WriteBfrPtr[ADDRESS_1_OFFSET] =
1331           (u8)((RealAddr & 0xFF000000) >> 24);
1332       WriteBfrPtr[ADDRESS_2_OFFSET] =
1333           (u8)((RealAddr & 0xFF0000) >> 16);
1334       WriteBfrPtr[ADDRESS_3_OFFSET] =
1335           (u8)((RealAddr & 0xFF00) >> 8);
1336       WriteBfrPtr[ADDRESS_4_OFFSET] =
1337           (u8)(RealAddr & 0xFF);
1338       FlashMsg[0].ByteCount = 5;
1339     } else {
1340       WriteBfrPtr[ADDRESS_1_OFFSET] =
1341           (u8)((RealAddr & 0xFF0000) >> 16);
1342       WriteBfrPtr[ADDRESS_2_OFFSET] =
1343           (u8)((RealAddr & 0xFF00) >> 8);
1344       WriteBfrPtr[ADDRESS_3_OFFSET] =
1345           (u8)(RealAddr & 0xFF);
1346       FlashMsg[0].ByteCount = 4;
1347     }
1348     FlashMsg[0].TxBfrPtr = WriteBfrPtr;
1349     FlashMsg[0].RxBfrPtr = NULL;
1350     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1351     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1352 
1353     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 1);
1354     if (Status != XST_SUCCESS) {
1355       return XST_FAILURE;
1356     }
1357 
1358     /*
1359      * Wait for the write command to the Flash to be completed,
1360      * it takes some time for the data to be written
1361      */
1362     while (1) {
1363       ReadStatusCmd = StatusCmd;
1364       FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
1365       FlashMsg[0].RxBfrPtr = NULL;
1366       FlashMsg[0].ByteCount = 1;
1367       FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1368       FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1369 
1370       FlashMsg[1].TxBfrPtr = NULL;
1371       FlashMsg[1].RxBfrPtr = FlashStatus;
1372       FlashMsg[1].ByteCount = 2;
1373       FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1374       FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1375       if (QspiPsuPtr->Config.ConnectionMode ==
1376           XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1377         FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
1378       }
1379 
1380       Status = transfer_and_wait(QspiPsuPtr,
1381           FlashMsg, 2);
1382       if (Status != XST_SUCCESS) {
1383         return XST_FAILURE;
1384       }
1385 
1386       if (QspiPsuPtr->Config.ConnectionMode ==
1387           XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1388         if (FSRFlag) {
1389           FlashStatus[1] &= FlashStatus[0];
1390         } else {
1391           FlashStatus[1] |= FlashStatus[0];
1392         }
1393       }
1394 
1395       if (FSRFlag) {
1396         if ((FlashStatus[1] & 0x80) != 0) {
1397           break;
1398         }
1399       } else {
1400         if ((FlashStatus[1] & 0x01) == 0) {
1401           break;
1402         }
1403       }
1404     }
1405   }
1406 
1407   return 0;
1408 }
1409 
1410 /*****************************************************************************/
1411 /**
1412  *
1413  * This functions translates the address based on the type of interconnection.
1414  * In case of stacked, this function asserts the corresponding slave select.
1415  *
1416  * @param   QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
1417  * @param   Address which is to be accessed (for erase, write or read)
1418  *
1419  * @return  RealAddr is the translated address - for single it is unchanged;
1420  *      for stacked, the lower flash size is subtracted;
1421  *      for parallel the address is divided by 2.
1422  *
1423  * @note    In addition to get the actual address to work on flash this
1424  *      function also selects the CS and BUS based on the configuration
1425  *      detected.
1426  *
1427  ******************************************************************************/
1428 static u32 GetRealAddr(
1429   XQspiPsu *QspiPsuPtr,
1430   u32 Address
1431 )
1432 {
1433   u32 RealAddr = 0;
1434 
1435   switch (QspiPsuPtr->Config.ConnectionMode) {
1436   case XQSPIPSU_CONNECTION_MODE_SINGLE:
1437     XQspiPsu_SelectFlash(QspiPsuPtr,
1438       XQSPIPSU_SELECT_FLASH_CS_LOWER,
1439       XQSPIPSU_SELECT_FLASH_BUS_LOWER);
1440     RealAddr = Address;
1441     break;
1442   case XQSPIPSU_CONNECTION_MODE_STACKED:
1443     /* Select lower or upper Flash based on sector address */
1444     if (Address & Flash_Config_Table[FCTIndex].FlashDeviceSize) {
1445 
1446       XQspiPsu_SelectFlash(QspiPsuPtr,
1447         XQSPIPSU_SELECT_FLASH_CS_UPPER,
1448         XQSPIPSU_SELECT_FLASH_BUS_LOWER);
1449       /*
1450        * Subtract first flash size when accessing second flash
1451        */
1452       RealAddr = Address &
1453         (~Flash_Config_Table[FCTIndex].FlashDeviceSize);
1454     }else{
1455       /*
1456        * Set selection to L_PAGE
1457        */
1458       XQspiPsu_SelectFlash(QspiPsuPtr,
1459         XQSPIPSU_SELECT_FLASH_CS_LOWER,
1460         XQSPIPSU_SELECT_FLASH_BUS_LOWER);
1461 
1462       RealAddr = Address;
1463 
1464     }
1465     break;
1466   case XQSPIPSU_CONNECTION_MODE_PARALLEL:
1467     /*
1468      * The effective address in each flash is the actual
1469      * address / 2
1470      */
1471     XQspiPsu_SelectFlash(QspiPsuPtr,
1472         XQSPIPSU_SELECT_FLASH_CS_BOTH,
1473         XQSPIPSU_SELECT_FLASH_BUS_BOTH);
1474     RealAddr = Address / 2;
1475     break;
1476   default:
1477     /* RealAddr wont be assigned in this case; */
1478   break;
1479 
1480   }
1481 
1482   return(RealAddr);
1483 }
1484 
1485 /*****************************************************************************/
1486 /**
1487  *
1488  * This function setups the interrupt system for a QspiPsu device.
1489  *
1490  * @param   QspiPsuInstancePtr is a pointer to the instance of the
1491  *      QspiPsu device.
1492  * @param   QspiPsuIntrId is the interrupt Id for an QSPIPSU device.
1493  *
1494  * @return  XST_SUCCESS if successful, otherwise XST_FAILURE.
1495  *
1496  * @note    None.
1497  *
1498  ******************************************************************************/
1499 static int QspiPsuSetupIntrSystem(
1500   XQspiPsu *QspiPsuInstancePtr,
1501   u16 QspiPsuIntrId
1502 )
1503 {
1504   return rtems_interrupt_handler_install(
1505     QspiPsuIntrId,
1506     NULL,
1507     RTEMS_INTERRUPT_UNIQUE,
1508     (rtems_interrupt_handler) XQspiPsu_InterruptHandler,
1509     QspiPsuInstancePtr
1510   );
1511 }
1512 
1513 /*****************************************************************************/
1514 /**
1515  * @brief
1516  * This API enters the flash device into 4 bytes addressing mode.
1517  * As per the Micron and ISSI spec, before issuing the command
1518  * to enter into 4 byte addr mode, a write enable command is issued.
1519  * For Macronix and Winbond flash parts write
1520  * enable is not required.
1521  *
1522  * @param   QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
1523  * @param   Enable is a either 1 or 0 if 1 then enters 4 byte if 0 exits.
1524  *
1525  * @return
1526  *      - XST_SUCCESS if successful.
1527  *      - XST_FAILURE if it fails.
1528  *
1529  *
1530  ******************************************************************************/
1531 static int FlashEnterExit4BAddMode(
1532   XQspiPsu *QspiPsuPtr,
1533   unsigned int Enable
1534 )
1535 {
1536   int Status;
1537   u8 WriteEnableCmd;
1538   u8 Cmd;
1539   u8 WriteDisableCmd;
1540   u8 ReadStatusCmd;
1541   u8 WriteBuffer[2] = {0};
1542   u8 FlashStatus[2] = {0};
1543 
1544   if (Enable) {
1545     Cmd = ENTER_4B_ADDR_MODE;
1546   } else {
1547     if (FlashMake == ISSI_ID_BYTE0)
1548       Cmd = EXIT_4B_ADDR_MODE_ISSI;
1549     else
1550       Cmd = EXIT_4B_ADDR_MODE;
1551   }
1552 
1553   switch (FlashMake) {
1554   case ISSI_ID_BYTE0:
1555   case MICRON_ID_BYTE0:
1556     WriteEnableCmd = WRITE_ENABLE_CMD;
1557     GetRealAddr(QspiPsuPtr, TEST_ADDRESS);
1558     /*
1559      * Send the write enable command to the Flash so that it can be
1560      * written to, this needs to be sent as a separate transfer
1561      * before the write
1562      */
1563     FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
1564     FlashMsg[0].RxBfrPtr = NULL;
1565     FlashMsg[0].ByteCount = 1;
1566     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1567     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1568 
1569     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 1);
1570     if (Status != XST_SUCCESS) {
1571       return XST_FAILURE;
1572     }
1573 
1574     break;
1575 
1576   case SPANSION_ID_BYTE0:
1577 
1578     /* Read Extended Addres Register */
1579     WriteBuffer[0] = BANK_REG_RD;
1580     FlashMsg[0].TxBfrPtr = &WriteBuffer[0];
1581     FlashMsg[0].RxBfrPtr = NULL;
1582     FlashMsg[0].ByteCount = 1;
1583     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1584     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1585 
1586     FlashMsg[1].TxBfrPtr = NULL;
1587     FlashMsg[1].RxBfrPtr = &WriteBuffer[1];
1588     FlashMsg[1].ByteCount = 1;
1589     FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1590     FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1591     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 2);
1592     if (Status != XST_SUCCESS) {
1593       return XST_FAILURE;
1594     }
1595     if (Enable) {
1596       WriteBuffer[0] = BANK_REG_WR;
1597       WriteBuffer[1] |= 1 << 7;
1598     } else {
1599       WriteBuffer[0] = BANK_REG_WR;
1600       WriteBuffer[1] &= ~(0x01 << 7);
1601     }
1602 
1603     FlashMsg[0].TxBfrPtr = &WriteBuffer[0];
1604     FlashMsg[0].RxBfrPtr = NULL;
1605     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1606     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1607     FlashMsg[0].ByteCount = 1;
1608     FlashMsg[1].TxBfrPtr = &WriteBuffer[1];
1609     FlashMsg[2].RxBfrPtr = NULL;
1610     FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1611     FlashMsg[2].Flags = XQSPIPSU_MSG_FLAG_TX;
1612     FlashMsg[2].ByteCount = 1;
1613 
1614     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 2);
1615     if (Status != XST_SUCCESS) {
1616       return XST_FAILURE;
1617     }
1618     WriteBuffer[0] = BANK_REG_RD;
1619     FlashMsg[0].TxBfrPtr = &WriteBuffer[0];
1620     FlashMsg[0].RxBfrPtr = NULL;
1621     FlashMsg[0].ByteCount = 1;
1622     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1623     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1624 
1625     FlashMsg[1].TxBfrPtr = NULL;
1626     FlashMsg[1].RxBfrPtr = &FlashStatus[0];
1627     FlashMsg[1].ByteCount = 1;
1628     FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1629     FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1630 
1631     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 2);
1632     if (Status != XST_SUCCESS) {
1633       return XST_FAILURE;
1634     }
1635 
1636     return Status;
1637 
1638   default:
1639     /*
1640      * For Macronix and Winbond flash parts
1641      * Write enable command is not required.
1642      */
1643     break;
1644   }
1645 
1646   GetRealAddr(QspiPsuPtr, TEST_ADDRESS);
1647 
1648   FlashMsg[0].TxBfrPtr = &Cmd;
1649   FlashMsg[0].RxBfrPtr = NULL;
1650   FlashMsg[0].ByteCount = 1;
1651   FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1652   FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1653 
1654   Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 1);
1655   if (Status != XST_SUCCESS) {
1656     return XST_FAILURE;
1657   }
1658 
1659   while (1) {
1660     ReadStatusCmd = StatusCmd;
1661 
1662     FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
1663     FlashMsg[0].RxBfrPtr = NULL;
1664     FlashMsg[0].ByteCount = 1;
1665     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1666     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1667 
1668     FlashMsg[1].TxBfrPtr = NULL;
1669     FlashMsg[1].RxBfrPtr = FlashStatus;
1670     FlashMsg[1].ByteCount = 2;
1671     FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1672     FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1673 
1674     if (QspiPsuPtr->Config.ConnectionMode ==
1675         XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1676       FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
1677     }
1678 
1679     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 2);
1680     if (Status != XST_SUCCESS) {
1681       return XST_FAILURE;
1682     }
1683 
1684     if (QspiPsuPtr->Config.ConnectionMode ==
1685         XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1686       if (FSRFlag) {
1687         FlashStatus[1] &= FlashStatus[0];
1688       } else {
1689         FlashStatus[1] |= FlashStatus[0];
1690       }
1691     }
1692 
1693     if (FSRFlag) {
1694       if ((FlashStatus[1] & 0x80) != 0) {
1695         break;
1696       }
1697     } else {
1698       if ((FlashStatus[1] & 0x01) == 0) {
1699         break;
1700       }
1701     }
1702   }
1703 
1704   switch (FlashMake) {
1705   case ISSI_ID_BYTE0:
1706   case MICRON_ID_BYTE0:
1707     WriteDisableCmd = WRITE_DISABLE_CMD;
1708     GetRealAddr(QspiPsuPtr, TEST_ADDRESS);
1709     /*
1710      * Send the write enable command to the Flash so that it can be
1711      * written to, this needs to be sent as a separate transfer
1712      * before the write
1713      */
1714     FlashMsg[0].TxBfrPtr = &WriteDisableCmd;
1715     FlashMsg[0].RxBfrPtr = NULL;
1716     FlashMsg[0].ByteCount = 1;
1717     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1718     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1719 
1720     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 1);
1721     if (Status != XST_SUCCESS) {
1722       return XST_FAILURE;
1723     }
1724 
1725     break;
1726 
1727   default:
1728     /*
1729      * For Macronix and Winbond flash parts
1730      * Write disable command is not required.
1731      */
1732     break;
1733   }
1734   return Status;
1735 }
1736 
1737 /*****************************************************************************/
1738 /**
1739  * @brief
1740  * This API enables Quad mode for the flash parts which require to enable quad
1741  * mode before using Quad commands.
1742  * For S25FL-L series flash parts this is required as the default configuration
1743  * is x1/x2 mode.
1744  *
1745  * @param   QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
1746  *
1747  * @return
1748  *      - XST_SUCCESS if successful.
1749  *      - XST_FAILURE if it fails.
1750  *
1751  *
1752  ******************************************************************************/
1753 static int FlashEnableQuadMode(XQspiPsu *QspiPsuPtr)
1754 {
1755   int Status;
1756   u8 WriteEnableCmd;
1757   u8 ReadStatusCmd;
1758   u8 FlashStatus[2];
1759   u8 StatusRegVal;
1760   u8 WriteBuffer[3] = {0};
1761 
1762   switch (FlashMake) {
1763   case SPANSION_ID_BYTE0:
1764     TxBfrPtr = READ_CONFIG_CMD;
1765     FlashMsg[0].TxBfrPtr = &TxBfrPtr;
1766     FlashMsg[0].RxBfrPtr = NULL;
1767     FlashMsg[0].ByteCount = 1;
1768     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1769     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1770 
1771     FlashMsg[1].TxBfrPtr = NULL;
1772     FlashMsg[1].RxBfrPtr = &WriteBuffer[2];
1773     FlashMsg[1].ByteCount = 1;
1774     FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1775     FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1776 
1777     Status = transfer_and_wait(QspiPsuPtr,
1778         FlashMsg, 2);
1779     if (Status != XST_SUCCESS) {
1780       return XST_FAILURE;
1781     }
1782 
1783     WriteEnableCmd = WRITE_ENABLE_CMD;
1784     /*
1785      * Send the write enable command to the Flash
1786      * so that it can be written to, this needs
1787      * to be sent as a separate transfer before
1788      * the write
1789      */
1790     FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
1791     FlashMsg[0].RxBfrPtr = NULL;
1792     FlashMsg[0].ByteCount = 1;
1793     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1794     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1795 
1796     Status = transfer_and_wait(QspiPsuPtr,
1797         FlashMsg, 1);
1798     if (Status != XST_SUCCESS) {
1799       return XST_FAILURE;
1800     }
1801 
1802     GetRealAddr(QspiPsuPtr, TEST_ADDRESS);
1803 
1804     WriteBuffer[0] = WRITE_CONFIG_CMD;
1805     WriteBuffer[1] |= 0x02;
1806     WriteBuffer[2] |= 0x01 << 1;
1807 
1808     FlashMsg[0].TxBfrPtr = &WriteBuffer[0];
1809     FlashMsg[0].RxBfrPtr = NULL;
1810     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1811     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1812     FlashMsg[0].ByteCount = 1;
1813     FlashMsg[1].TxBfrPtr = &WriteBuffer[1];
1814     FlashMsg[1].RxBfrPtr = NULL;
1815     FlashMsg[1].ByteCount = 2;
1816     FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1817     FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_TX;
1818 
1819     Status = transfer_and_wait(QspiPsuPtr,
1820         FlashMsg, 2);
1821     if (Status != XST_SUCCESS) {
1822       return XST_FAILURE;
1823     }
1824 
1825     while (1) {
1826       TxBfrPtr = READ_STATUS_CMD;
1827       FlashMsg[0].TxBfrPtr = &TxBfrPtr;
1828       FlashMsg[0].RxBfrPtr = NULL;
1829       FlashMsg[0].ByteCount = 1;
1830       FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1831       FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1832 
1833       FlashMsg[1].TxBfrPtr = NULL;
1834       FlashMsg[1].RxBfrPtr = FlashStatus;
1835       FlashMsg[1].ByteCount = 2;
1836       FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1837       FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1838 
1839       Status = transfer_and_wait(QspiPsuPtr,
1840           FlashMsg, 2);
1841       if (Status != XST_SUCCESS) {
1842         return XST_FAILURE;
1843       }
1844       if (QspiPsuPtr->Config.ConnectionMode ==
1845             XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1846         if (FSRFlag) {
1847           FlashStatus[1] &= FlashStatus[0];
1848         }else {
1849           FlashStatus[1] |= FlashStatus[0];
1850         }
1851       }
1852 
1853       if ((FlashStatus[1] & 0x01) == 0x00)
1854         break;
1855     }
1856     TxBfrPtr = READ_CONFIG_CMD;
1857     FlashMsg[0].TxBfrPtr = &TxBfrPtr;
1858     FlashMsg[0].RxBfrPtr = NULL;
1859     FlashMsg[0].ByteCount = 1;
1860     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1861     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1862 
1863     FlashMsg[1].TxBfrPtr = NULL;
1864     FlashMsg[1].RxBfrPtr = ReadBfrPtr;
1865     FlashMsg[1].ByteCount = 1;
1866     FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1867     FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1868 
1869     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 2);
1870     if (Status != XST_SUCCESS) {
1871       return XST_FAILURE;
1872     }
1873     break;
1874   case ISSI_ID_BYTE0:
1875     /*
1876      * Read Status Register to a buffer
1877      */
1878     ReadStatusCmd = READ_STATUS_CMD;
1879     FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
1880     FlashMsg[0].RxBfrPtr = NULL;
1881     FlashMsg[0].ByteCount = 1;
1882     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1883     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1884     FlashMsg[1].TxBfrPtr = NULL;
1885     FlashMsg[1].RxBfrPtr = FlashStatus;
1886     FlashMsg[1].ByteCount = 2;
1887     FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1888     FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1889     if (QspiPsuPtr->Config.ConnectionMode ==
1890         XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1891       FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
1892     }
1893     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 2);
1894     if (Status != XST_SUCCESS) {
1895       return XST_FAILURE;
1896     }
1897     if (QspiPsuPtr->Config.ConnectionMode ==
1898         XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1899       if (FSRFlag) {
1900         FlashStatus[1] &= FlashStatus[0];
1901       } else {
1902         FlashStatus[1] |= FlashStatus[0];
1903       }
1904     }
1905     /*
1906      * Set Quad Enable Bit in the buffer
1907      */
1908     StatusRegVal = FlashStatus[1];
1909     StatusRegVal |= 0x1 << QUAD_MODE_ENABLE_BIT;
1910 
1911     /*
1912      * Write enable
1913      */
1914     WriteEnableCmd = WRITE_ENABLE_CMD;
1915     /*
1916     * Send the write enable command to the Flash so that it can be
1917     * written to, this needs to be sent as a separate transfer
1918     * before the write
1919     */
1920     FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
1921     FlashMsg[0].RxBfrPtr = NULL;
1922     FlashMsg[0].ByteCount = 1;
1923     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1924     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1925     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 1);
1926     if (Status != XST_SUCCESS) {
1927       return XST_FAILURE;
1928     }
1929 
1930     /*
1931      * Write Status register
1932      */
1933     WriteBuffer[COMMAND_OFFSET] = WRITE_STATUS_CMD;
1934     FlashMsg[0].TxBfrPtr = WriteBuffer;
1935     FlashMsg[0].RxBfrPtr = NULL;
1936     FlashMsg[0].ByteCount = 1;
1937     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1938     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1939 
1940     FlashMsg[1].TxBfrPtr = &StatusRegVal;
1941     FlashMsg[1].RxBfrPtr = NULL;
1942     FlashMsg[1].ByteCount = 1;
1943     FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1944     FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_TX;
1945     if (QspiPsuPtr->Config.ConnectionMode ==
1946         XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1947       FlashMsg[1].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
1948     }
1949     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 2);
1950     if (Status != XST_SUCCESS) {
1951       return XST_FAILURE;
1952     }
1953 
1954     /*
1955      * Write Disable
1956      */
1957     WriteEnableCmd = WRITE_DISABLE_CMD;
1958     FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
1959     FlashMsg[0].RxBfrPtr = NULL;
1960     FlashMsg[0].ByteCount = 1;
1961     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1962     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1963     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 1);
1964     if (Status != XST_SUCCESS) {
1965       return XST_FAILURE;
1966     }
1967     break;
1968 
1969   case WINBOND_ID_BYTE0:
1970     ReadStatusCmd = READ_STATUS_REG_2_CMD;
1971     FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
1972     FlashMsg[0].RxBfrPtr = NULL;
1973     FlashMsg[0].ByteCount = 1;
1974     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1975     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
1976     FlashMsg[1].TxBfrPtr = NULL;
1977     FlashMsg[1].RxBfrPtr = FlashStatus;
1978     FlashMsg[1].ByteCount = 2;
1979     FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
1980     FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
1981     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 2);
1982     if (Status != XST_SUCCESS) {
1983       return XST_FAILURE;
1984     }
1985 
1986     if (QspiPsuPtr->Config.ConnectionMode ==
1987       XQSPIPSU_CONNECTION_MODE_PARALLEL) {
1988       if (FSRFlag) {
1989         FlashStatus[1] &= FlashStatus[0];
1990       } else {
1991         FlashStatus[1] |= FlashStatus[0];
1992       }
1993     }
1994     /*
1995      * Set Quad Enable Bit in the buffer
1996      */
1997     StatusRegVal = FlashStatus[1];
1998     StatusRegVal |= 0x1 << WB_QUAD_MODE_ENABLE_BIT;
1999     /*
2000      * Write Enable
2001      */
2002     WriteEnableCmd = WRITE_ENABLE_CMD;
2003     FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
2004     FlashMsg[0].RxBfrPtr = NULL;
2005     FlashMsg[0].ByteCount = 1;
2006     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
2007     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
2008     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 1);
2009     if (Status != XST_SUCCESS) {
2010       return XST_FAILURE;
2011     }
2012     /*
2013      * Write Status register
2014      */
2015     WriteBuffer[COMMAND_OFFSET] = WRITE_STATUS_REG_2_CMD;
2016     FlashMsg[0].TxBfrPtr = WriteBuffer;
2017     FlashMsg[0].RxBfrPtr = NULL;
2018     FlashMsg[0].ByteCount = 1;
2019     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
2020     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
2021 
2022     FlashMsg[1].TxBfrPtr = &StatusRegVal;
2023     FlashMsg[1].RxBfrPtr = NULL;
2024     FlashMsg[1].ByteCount = 1;
2025     FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
2026     FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_TX;
2027     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 2);
2028     if (Status != XST_SUCCESS) {
2029       return XST_FAILURE;
2030     }
2031 
2032     while (1) {
2033       ReadStatusCmd = READ_STATUS_CMD;
2034       FlashMsg[0].TxBfrPtr = &ReadStatusCmd;
2035       FlashMsg[0].RxBfrPtr = NULL;
2036       FlashMsg[0].ByteCount = 1;
2037       FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
2038       FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
2039       FlashMsg[1].TxBfrPtr = NULL;
2040       FlashMsg[1].RxBfrPtr = FlashStatus;
2041       FlashMsg[1].ByteCount = 2;
2042       FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
2043       FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
2044       Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 2);
2045       if (Status != XST_SUCCESS) {
2046         return XST_FAILURE;
2047       }
2048 
2049       if (QspiPsuPtr->Config.ConnectionMode ==
2050         XQSPIPSU_CONNECTION_MODE_PARALLEL) {
2051         if (FSRFlag) {
2052           FlashStatus[1] &= FlashStatus[0];
2053         } else {
2054           FlashStatus[1] |= FlashStatus[0];
2055         }
2056       }
2057       if ((FlashStatus[1] & 0x01) == 0x00) {
2058         break;
2059       }
2060     }
2061     /*
2062      * Write Disable
2063      */
2064     WriteEnableCmd = WRITE_DISABLE_CMD;
2065     FlashMsg[0].TxBfrPtr = &WriteEnableCmd;
2066     FlashMsg[0].RxBfrPtr = NULL;
2067     FlashMsg[0].ByteCount = 1;
2068     FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
2069     FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
2070     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, 2);
2071     if (Status != XST_SUCCESS) {
2072       return XST_FAILURE;
2073     }
2074     break;
2075 
2076   default:
2077     /*
2078      * Currently only S25FL-L series requires the
2079      * Quad enable bit to be set to 1.
2080      */
2081     Status = XST_SUCCESS;
2082     break;
2083   }
2084 
2085   return Status;
2086 }
2087 
2088 static int MultiDieReadEcc(
2089   XQspiPsu *QspiPsuPtr,
2090   u32 Address,
2091   u32 ByteCount,
2092   u8 *WriteBfrPtr,
2093   u8 *ReadBfrPtr
2094 );
2095 
2096 int QspiPsu_NOR_Read_Ecc(
2097   XQspiPsu *QspiPsuPtr,
2098   u32 Address,
2099   u8 *ReadBfrPtr
2100 )
2101 {
2102   u32 RealAddr;
2103   u32 DiscardByteCnt;
2104   u32 FlashMsgCnt;
2105   u8  EccBuffer[16];
2106   int ByteCount = sizeof(EccBuffer);
2107   int Status;
2108 
2109   /* Check die boundary conditions if required for any flash */
2110   if (Flash_Config_Table[FCTIndex].NumDie > 1) {
2111 
2112     Status = MultiDieReadEcc(QspiPsuPtr, Address, ByteCount,
2113               CmdBfr, EccBuffer);
2114     if (Status == XST_SUCCESS) {
2115       /* All bytes are the same, so copy one return byte into the output buffer */
2116       *ReadBfrPtr = EccBuffer[0];
2117     }
2118     return Status;
2119   }
2120 
2121   /* For Dual Stacked, split and read for boundary crossing */
2122   /*
2123    * Translate address based on type of connection
2124    * If stacked assert the slave select based on address
2125    */
2126   RealAddr = GetRealAddr(QspiPsuPtr, Address);
2127 
2128   CmdBfr[COMMAND_OFFSET]   = READ_ECCSR;
2129   CmdBfr[ADDRESS_1_OFFSET] =
2130       (u8)((RealAddr & 0xFF000000) >> 24);
2131   CmdBfr[ADDRESS_2_OFFSET] =
2132       (u8)((RealAddr & 0xFF0000) >> 16);
2133   CmdBfr[ADDRESS_3_OFFSET] =
2134       (u8)((RealAddr & 0xFF00) >> 8);
2135   CmdBfr[ADDRESS_4_OFFSET] =
2136       (u8)(RealAddr & 0xF0);
2137   DiscardByteCnt = 5;
2138 
2139   FlashMsgCnt = 0;
2140 
2141   FlashMsg[FlashMsgCnt].TxBfrPtr = CmdBfr;
2142   FlashMsg[FlashMsgCnt].RxBfrPtr = NULL;
2143   FlashMsg[FlashMsgCnt].ByteCount = DiscardByteCnt;
2144   FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
2145   FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_TX;
2146 
2147   FlashMsgCnt++;
2148 
2149   FlashMsg[FlashMsgCnt].TxBfrPtr = NULL;
2150   FlashMsg[FlashMsgCnt].RxBfrPtr = NULL;
2151   FlashMsg[FlashMsgCnt].ByteCount = DUMMY_CLOCKS;
2152   FlashMsg[FlashMsgCnt].Flags = 0;
2153 
2154   FlashMsgCnt++;
2155 
2156   FlashMsg[FlashMsgCnt].TxBfrPtr = NULL;
2157   FlashMsg[FlashMsgCnt].RxBfrPtr = EccBuffer;
2158   FlashMsg[FlashMsgCnt].ByteCount = ByteCount;
2159   FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
2160   FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_RX;
2161 
2162   if (QspiPsuPtr->Config.ConnectionMode ==
2163       XQSPIPSU_CONNECTION_MODE_PARALLEL) {
2164     FlashMsg[FlashMsgCnt].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
2165   }
2166 
2167   Status = transfer_and_wait(QspiPsuPtr, FlashMsg,
2168               FlashMsgCnt + 1);
2169   if (Status == XST_SUCCESS) {
2170     /* All bytes are the same, so copy one return byte into the output buffer */
2171     *ReadBfrPtr = EccBuffer[0];
2172   }
2173 
2174   return Status;
2175 }
2176 
2177 /*****************************************************************************/
2178 /**
2179  *
2180  * This function performs an ECC read operation for multi die flash devices.
2181  * Default setting is in DMA mode.
2182  *
2183  * @param   QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
2184  * @param   Address contains the address of the first sector which needs to
2185  *      be erased.
2186  * @param   ByteCount contains the total size to be erased.
2187  * @param   WriteBfrPtr is pointer to the write buffer which contains data to be
2188  *      transmitted
2189  * @param   ReadBfrPtr is pointer to the read buffer to which valid received data
2190  *      should be written
2191  *
2192  * @return  XST_SUCCESS if successful, else XST_FAILURE.
2193  *
2194  * @note    None.
2195  *
2196  ******************************************************************************/
2197 static int MultiDieReadEcc(
2198   XQspiPsu *QspiPsuPtr,
2199   u32 Address,
2200   u32 ByteCount,
2201   u8 *WriteBfrPtr,
2202   u8 *ReadBuffer
2203 )
2204 {
2205   u32 RealAddr;
2206   u32 DiscardByteCnt;
2207   u32 FlashMsgCnt;
2208   int Status;
2209   u32 cur_bank = 0;
2210   u32 nxt_bank = 0;
2211   u32 bank_size;
2212   u32 remain_len = ByteCount;
2213   u32 data_len;
2214   u32 transfer_len;
2215 
2216   /*
2217    * Some flash devices like N25Q512 have multiple dies
2218    * in it. Read operation in these devices is bounded
2219    * by its die segment. In a continuous read, across
2220    * multiple dies, when the last byte of the selected
2221    * die segment is read, the next byte read is the
2222    * first byte of the same die segment. This is Die
2223    * cross over issue. So to handle this issue, split
2224    * a read transaction, that spans across multiple
2225    * banks, into one read per bank. Bank size is 16MB
2226    * for single and dual stacked mode and 32MB for dual
2227    * parallel mode.
2228    */
2229   if (QspiPsuPtr->Config.ConnectionMode ==
2230       XQSPIPSU_CONNECTION_MODE_PARALLEL)
2231     bank_size = SIXTEENMB << 1;
2232   else
2233     bank_size = SIXTEENMB;
2234 
2235   while (remain_len) {
2236     cur_bank = Address / bank_size;
2237     nxt_bank = (Address + remain_len) / bank_size;
2238 
2239     if (cur_bank != nxt_bank) {
2240       transfer_len = (bank_size * (cur_bank  + 1)) - Address;
2241       if (remain_len < transfer_len)
2242         data_len = remain_len;
2243       else
2244         data_len = transfer_len;
2245     } else {
2246       data_len = remain_len;
2247     }
2248     /*
2249      * Translate address based on type of connection
2250      * If stacked assert the slave select based on address
2251      */
2252     RealAddr = GetRealAddr(QspiPsuPtr, Address);
2253 
2254     WriteBfrPtr[COMMAND_OFFSET]   = READ_ECCSR;
2255     WriteBfrPtr[ADDRESS_1_OFFSET] =
2256         (u8)((RealAddr & 0xFF000000) >> 24);
2257     WriteBfrPtr[ADDRESS_2_OFFSET] =
2258         (u8)((RealAddr & 0xFF0000) >> 16);
2259     WriteBfrPtr[ADDRESS_3_OFFSET] =
2260         (u8)((RealAddr & 0xFF00) >> 8);
2261     WriteBfrPtr[ADDRESS_4_OFFSET] =
2262         (u8)(RealAddr & 0xF0);
2263     DiscardByteCnt = 5;
2264 
2265     FlashMsgCnt = 0;
2266 
2267     FlashMsg[FlashMsgCnt].TxBfrPtr = WriteBfrPtr;
2268     FlashMsg[FlashMsgCnt].RxBfrPtr = NULL;
2269     FlashMsg[FlashMsgCnt].ByteCount = DiscardByteCnt;
2270     FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
2271     FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_TX;
2272 
2273     FlashMsgCnt++;
2274 
2275     FlashMsg[FlashMsgCnt].TxBfrPtr = NULL;
2276     FlashMsg[FlashMsgCnt].RxBfrPtr = NULL;
2277     FlashMsg[FlashMsgCnt].ByteCount = DUMMY_CLOCKS;
2278     FlashMsg[FlashMsgCnt].Flags = 0;
2279 
2280     FlashMsgCnt++;
2281 
2282     FlashMsg[FlashMsgCnt].TxBfrPtr = NULL;
2283     FlashMsg[FlashMsgCnt].RxBfrPtr = ReadBuffer;
2284     FlashMsg[FlashMsgCnt].ByteCount = data_len;
2285     FlashMsg[FlashMsgCnt].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
2286     FlashMsg[FlashMsgCnt].Flags = XQSPIPSU_MSG_FLAG_RX;
2287 
2288     if (QspiPsuPtr->Config.ConnectionMode ==
2289         XQSPIPSU_CONNECTION_MODE_PARALLEL)
2290       FlashMsg[FlashMsgCnt].Flags |=
2291         XQSPIPSU_MSG_FLAG_STRIPE;
2292 
2293     Status = transfer_and_wait(QspiPsuPtr, FlashMsg, FlashMsgCnt + 1);
2294     if (Status != XST_SUCCESS)
2295       return XST_FAILURE;
2296 
2297     ReadBuffer += data_len;
2298     Address += data_len;
2299     remain_len -= data_len;
2300   }
2301   return 0;
2302 }
2303 
2304 u32 QspiPsu_NOR_Get_Sector_Size(XQspiPsu *QspiPsuPtr)
2305 {
2306   if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) {
2307     return Flash_Config_Table[FCTIndex].SectSize * 2;
2308   }
2309   return Flash_Config_Table[FCTIndex].SectSize;
2310 }
2311 
2312 u32 QspiPsu_NOR_Get_Device_Size(XQspiPsu *QspiPsuPtr)
2313 {
2314   if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED
2315      || QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL) {
2316     return Flash_Config_Table[FCTIndex].FlashDeviceSize * 2;
2317   }
2318   return Flash_Config_Table[FCTIndex].FlashDeviceSize;
2319 }
2320 
2321 u32 QspiPsu_NOR_Get_Page_Size(XQspiPsu *QspiPsuPtr)
2322 {
2323   if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED) {
2324     return Flash_Config_Table[FCTIndex].PageSize * 2;
2325   }
2326   return Flash_Config_Table[FCTIndex].PageSize;
2327 }
2328 
2329 u32 QspiPsu_NOR_Get_JEDEC_ID(XQspiPsu *QspiPsuPtr)
2330 {
2331   return Flash_Config_Table[FCTIndex].jedec_id;
2332 }