/** * * This function provides the QSPI FLASH interface for the Simplified header * functionality. * * @param SourceAddress is address in FLASH data space * @param DestinationAddress is address in DDR data space * @param LengthBytes is the length of the data in Bytes * * @return * - XST_SUCCESS if the write completes correctly * - XST_FAILURE if the write fails to completes correctly * * @note none. * ****************************************************************************/ u32 QspiAccess( u32 SourceAddress, u32 DestinationAddress, u32 LengthBytes) { u8 *BufferPtr; u32 Length = 0; u32 BankSel = 0; u32 LqspiCrReg; u32 Status; u8 BankSwitchFlag = 1; /* * Linear access check */ if (LinearBootDeviceFlag == 1) { /* * Check for non-word tail, add bytes to cover the end */ if ((LengthBytes%4) != 0){ LengthBytes += (4 - (LengthBytes & 0x00000003)); } memcpy((void*)DestinationAddress, (const void*)(SourceAddress + FlashReadBaseAddress), (size_t)LengthBytes); } else { /* * Non Linear access */ BufferPtr = (u8*)DestinationAddress; /* * Dual parallel connection actual flash is half */ if (XPAR_PS7_QSPI_0_QSPI_MODE == DUAL_PARALLEL_CONNECTION) { SourceAddress = SourceAddress/2; } while(LengthBytes > 0) { /* * Local of DATA_SIZE size used for read/write buffer */ if(LengthBytes > DATA_SIZE) { Length = DATA_SIZE; } else { Length = LengthBytes; } /* * Dual stack connection */ if (XPAR_PS7_QSPI_0_QSPI_MODE == DUAL_STACK_CONNECTION) { /* * Get the current LQSPI configuration value */ LqspiCrReg = XQspiPs_GetLqspiConfigReg(QspiInstancePtr); /* * Select lower or upper Flash based on sector address */ if (SourceAddress >= (QspiFlashSize/2)) { /* * Set selection to U_PAGE */ XQspiPs_SetLqspiConfigReg(QspiInstancePtr, LqspiCrReg | XQSPIPS_LQSPI_CR_U_PAGE_MASK); /* * Subtract first flash size when accessing second flash */ SourceAddress = SourceAddress - (QspiFlashSize/2); fsbl_printf(DEBUG_INFO, "stacked - upper CS \n\r"); /* * Assert the FLASH chip select. */ XQspiPs_SetSlaveSelect(QspiInstancePtr); } } /* * Select bank */ if ((SourceAddress >= FLASH_SIZE_16MB) && (BankSwitchFlag == 1)) { BankSel = SourceAddress/FLASH_SIZE_16MB; fsbl_printf(DEBUG_INFO, "Bank Selection %d\n\r", BankSel); Status = SendBankSelect(BankSel); if (Status != XST_SUCCESS) { fsbl_printf(DEBUG_INFO, "Bank Selection Failed\n\r"); return XST_FAILURE; } BankSwitchFlag = 0; } /* * If data to be read spans beyond the current bank, then * calculate length in current bank else no change in length */ if (XPAR_PS7_QSPI_0_QSPI_MODE == DUAL_PARALLEL_CONNECTION) { /* * In dual parallel mode, check should be for half * the length. */ if((SourceAddress & BANKMASK) != ((SourceAddress + (Length/2)) & BANKMASK)) { Length = (SourceAddress & BANKMASK) + FLASH_SIZE_16MB - SourceAddress; /* * Above length calculated is for single flash * Length should be doubled since dual parallel */ Length = Length * 2; BankSwitchFlag = 1; } } else { if((SourceAddress & BANKMASK) != ((SourceAddress + Length) & BANKMASK)) { Length = (SourceAddress & BANKMASK) + FLASH_SIZE_16MB - SourceAddress; BankSwitchFlag = 1; } } /* * Copying the image to local buffer */ FlashRead(SourceAddress, Length); /* * Moving the data from local buffer to DDR destination address */ memcpy(BufferPtr, &ReadBuffer[DATA_OFFSET + DUMMY_SIZE], Length); /* * Updated the variables */ LengthBytes -= Length; /* * For Dual parallel connection address increment should be half */ if (XPAR_PS7_QSPI_0_QSPI_MODE == DUAL_PARALLEL_CONNECTION) { SourceAddress += Length/2; } else { SourceAddress += Length; } BufferPtr = (u8*)((u32)BufferPtr + Length); } /* * Reset Bank selection to zero */ Status = SendBankSelect(0); if (Status != XST_SUCCESS) { fsbl_printf(DEBUG_INFO, "Bank Selection Reset Failed\n\r"); return XST_FAILURE; } if (XPAR_PS7_QSPI_0_QSPI_MODE == DUAL_STACK_CONNECTION) { /* * Reset selection to L_PAGE */ XQspiPs_SetLqspiConfigReg(QspiInstancePtr, LqspiCrReg & (~XQSPIPS_LQSPI_CR_U_PAGE_MASK)); fsbl_printf(DEBUG_INFO, "stacked - lower CS \n\r"); /* * Assert the FLASH chip select. */ XQspiPs_SetSlaveSelect(QspiInstancePtr); } } return XST_SUCCESS; }
/****************************************************************************** * * * This function erases the sectors in the serial Flash connected to the * QSPI interface. * * @param QspiPtr is a pointer to the QSPI 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 Pointer to the write buffer (which is to be transmitted) * * @return None. * * @note None. * ******************************************************************************/ void FlashErase(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 *WriteBfrPtr) { u8 WriteEnableCmd = { WRITE_ENABLE_CMD }; u8 ReadStatusCmd[] = { READ_STATUS_CMD, 0 }; /* Must send 2 bytes */ u8 FlashStatus[2]; int Sector; u32 RealAddr; u32 LqspiCr; u32 NumSect; u32 BankSel; u8 BankInitFlag = 1; u8 ReadFlagSRCmd[] = { READ_FLAG_STATUS_CMD, 0 }; u8 FlagStatus[2]; /* * 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 == ((Flash_Config_Table[FCTIndex]).NumSect * (Flash_Config_Table[FCTIndex]).SectSize) ) { if(QspiPtr->Config.ConnectionMode == XQSPIPS_CONNECTION_MODE_STACKED){ /* * Get the current LQSPI configuration register value */ LqspiCr = XQspiPs_GetLqspiConfigReg(QspiPtr); /* * Set selection to L_PAGE */ XQspiPs_SetLqspiConfigReg(QspiPtr, LqspiCr & (~XQSPIPS_LQSPI_CR_U_PAGE_MASK)); /* * Assert the Flash chip select. */ XQspiPs_SetSlaveSelect(QspiPtr); } if(Flash_Config_Table[FCTIndex].NumDie == 1) { /* * Call Bulk erase */ BulkErase(QspiPtr, WriteBfrPtr); } if(Flash_Config_Table[FCTIndex].NumDie > 1) { /* * Call Die erase */ DieErase(QspiPtr, WriteBfrPtr); } /* * If stacked mode, bulk erase second flash */ if(QspiPtr->Config.ConnectionMode == XQSPIPS_CONNECTION_MODE_STACKED){ /* * Get the current LQSPI configuration register value */ LqspiCr = XQspiPs_GetLqspiConfigReg(QspiPtr); /* * Set selection to U_PAGE */ XQspiPs_SetLqspiConfigReg(QspiPtr, LqspiCr | XQSPIPS_LQSPI_CR_U_PAGE_MASK); /* * Assert the Flash chip select. */ XQspiPs_SetSlaveSelect(QspiPtr); if(Flash_Config_Table[FCTIndex].NumDie == 1) { /* * Call Bulk erase */ BulkErase(QspiPtr, WriteBfrPtr); } if(Flash_Config_Table[FCTIndex].NumDie > 1) { /* * Call Die erase */ DieErase(QspiPtr, WriteBfrPtr); } } return; } /* * 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/(Flash_Config_Table[FCTIndex].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) & Flash_Config_Table[FCTIndex].SectMask) == ((Address + (NumSect * Flash_Config_Table[FCTIndex].SectSize)) & Flash_Config_Table[FCTIndex].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(QspiPtr, Address); /* * Initial bank selection */ if((BankInitFlag) && (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB)) { /* * Reset initial bank select flag */ BankInitFlag = 0; /* * Calculate initial bank */ BankSel = RealAddr/SIXTEENMB; /* * Select bank */ SendBankSelect(QspiPtr, WriteBfrPtr, BankSel); } /* * Check bank and send bank select if new bank */ if((BankSel != RealAddr/SIXTEENMB) && (Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB)) { /* * Calculate initial bank */ BankSel = RealAddr/SIXTEENMB; /* * Select bank */ SendBankSelect(QspiPtr, WriteBfrPtr, BankSel); } /* * Send the write enable command to the SEEPOM so that it can be * written to, this needs to be sent as a separate transfer * before the write */ XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL, sizeof(WriteEnableCmd)); /* * Setup the write command with the specified address and data * for the Flash */ /* * This ensures 3B address is sent to flash even with address * greater than 128Mb. */ WriteBfrPtr[COMMAND_OFFSET] = SEC_ERASE_CMD; WriteBfrPtr[ADDRESS_1_OFFSET] = (u8)(RealAddr >> 16); WriteBfrPtr[ADDRESS_2_OFFSET] = (u8)(RealAddr >> 8); WriteBfrPtr[ADDRESS_3_OFFSET] = (u8)(RealAddr & 0xFF); /* * Send the sector erase command and address; no receive buffer * is specified since there is nothing to receive */ XQspiPs_PolledTransfer(QspiPtr, WriteBfrPtr, NULL, SEC_ERASE_SIZE); if((Flash_Config_Table[FCTIndex].NumDie > 1) && (FlashMake == MICRON_ID_BYTE0)) { XQspiPs_PolledTransfer(QspiPtr, ReadFlagSRCmd, FlagStatus, sizeof(ReadFlagSRCmd)); } /* * Wait for the sector erase command to the Flash to be completed */ while (1) { /* * Poll the status register of the device to determine * when it completes, by sending a read status command * and receiving the status byte */ XQspiPs_PolledTransfer(QspiPtr, ReadStatusCmd, FlashStatus, sizeof(ReadStatusCmd)); /* * If the status indicates the write is done, then stop * waiting, if a value of 0xFF in the status byte is * read from the device and this loop never exits, the * device slave select is possibly incorrect such that * the device status is not being read */ if ((FlashStatus[1] & 0x01) == 0) { break; } } if((Flash_Config_Table[FCTIndex].NumDie > 1) && (FlashMake == MICRON_ID_BYTE0)) { XQspiPs_PolledTransfer(QspiPtr, ReadFlagSRCmd, FlagStatus, sizeof(ReadFlagSRCmd)); } Address += Flash_Config_Table[FCTIndex].SectSize; } }
/****************************************************************************** * * * This function writes to the serial Flash connected to the QSPI 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 QspiPtr is a pointer to the QSPI 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 Command is the command used to write data to the flash. QSPI * device supports only Page Program command to write data to the * flash. * @param Pointer to the write buffer (which is to be transmitted) * * @return None. * * @note None. * ******************************************************************************/ void FlashWrite(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 Command, u8 *WriteBfrPtr) { u8 WriteEnableCmd = { WRITE_ENABLE_CMD }; u8 ReadStatusCmd[] = { READ_STATUS_CMD, 0 }; /* Must send 2 bytes */ u8 FlashStatus[2]; u32 RealAddr; u32 BankSel; u8 ReadFlagSRCmd[] = {READ_FLAG_STATUS_CMD, 0}; u8 FlagStatus[2]; /* * Translate address based on type of connection * If stacked assert the slave select based on address */ RealAddr = GetRealAddr(QspiPtr, Address); /* * Bank Select */ if(Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) { /* * Calculate bank */ BankSel = RealAddr/SIXTEENMB; /* * Select bank */ SendBankSelect(QspiPtr, WriteBfrPtr, BankSel); } /* * 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 */ XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL, sizeof(WriteEnableCmd)); /* * Setup the write command with the specified address and data for the * Flash */ /* * This will ensure a 3B address is transferred even when address * is greater than 128Mb. */ WriteBfrPtr[COMMAND_OFFSET] = Command; WriteBfrPtr[ADDRESS_1_OFFSET] = (u8)((RealAddr & 0xFF0000) >> 16); WriteBfrPtr[ADDRESS_2_OFFSET] = (u8)((RealAddr & 0xFF00) >> 8); WriteBfrPtr[ADDRESS_3_OFFSET] = (u8)(RealAddr & 0xFF); /* * Send the write command, address, and data to the Flash to be * written, no receive buffer is specified since there is nothing to * receive */ XQspiPs_PolledTransfer(QspiPtr, WriteBfrPtr, NULL, ByteCount + OVERHEAD_SIZE); if((Flash_Config_Table[FCTIndex].NumDie > 1) && (FlashMake == MICRON_ID_BYTE0)) { XQspiPs_PolledTransfer(QspiPtr, ReadFlagSRCmd, FlagStatus, sizeof(ReadFlagSRCmd)); } /* * Wait for the write command to the Flash to be completed, it takes * some time for the data to be written */ while (1) { /* * Poll the status register of the Flash to determine when it * completes, by sending a read status command and receiving the * status byte */ XQspiPs_PolledTransfer(QspiPtr, ReadStatusCmd, FlashStatus, sizeof(ReadStatusCmd)); /* * If the status indicates the write is done, then stop waiting, * if a value of 0xFF in the status byte is read from the * device and this loop never exits, the device slave select is * possibly incorrect such that the device status is not being * read */ if ((FlashStatus[1] & 0x01) == 0) { break; } } if((Flash_Config_Table[FCTIndex].NumDie > 1) && (FlashMake == MICRON_ID_BYTE0)) { XQspiPs_PolledTransfer(QspiPtr, ReadFlagSRCmd, FlagStatus, sizeof(ReadFlagSRCmd)); } }
/****************************************************************************** * * 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 QspiPtr is a pointer to the QSPI driver component to use. * @param WritBfrPtr is the pointer to command+address to be sent * * @return None * * @note None. * ******************************************************************************/ void DieErase(XQspiPs *QspiPtr, u8 *WriteBfrPtr) { u8 WriteEnableCmd = { WRITE_ENABLE_CMD }; u8 DieCnt; u8 ReadFlagSRCmd[] = { READ_FLAG_STATUS_CMD, 0 }; u8 FlagStatus[2]; for(DieCnt = 0; DieCnt < Flash_Config_Table[FCTIndex].NumDie; DieCnt++) { /* * Select bank - the lower of the 2 banks in each die * This is specific to Micron flash */ SendBankSelect(QspiPtr, WriteBfrPtr, DieCnt*2); /* * Send the write enable command to the SEEPOM so that it can be * written to, this needs to be sent as a separate transfer * before the write */ XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL, sizeof(WriteEnableCmd)); /* * Setup the write command with the specified address and data * for the Flash */ /* * This ensures 3B address is sent to flash even with address * greater than 128Mb. * The address is the start address of die - MSB bits will be * derived from bank select by the flash */ WriteBfrPtr[COMMAND_OFFSET] = DIE_ERASE_CMD; WriteBfrPtr[ADDRESS_1_OFFSET] = 0x00; WriteBfrPtr[ADDRESS_2_OFFSET] = 0x00; WriteBfrPtr[ADDRESS_3_OFFSET] = 0x00; /* * Send the sector erase command and address; no receive buffer * is specified since there is nothing to receive */ XQspiPs_PolledTransfer(QspiPtr, WriteBfrPtr, NULL, DIE_ERASE_SIZE); /* * Wait for the sector erase command to the Flash to be completed */ while (1) { /* * Poll the status register of the device to determine * when it completes, by sending a read status command * and receiving the status byte */ XQspiPs_PolledTransfer(QspiPtr, ReadFlagSRCmd, FlagStatus, sizeof(ReadFlagSRCmd)); /* * If the status indicates the write is done, then stop * waiting, if a value of 0xFF in the status byte is * read from the device and this loop never exits, the * device slave select is possibly incorrect such that * the device status is not being read */ if ((FlagStatus[1] & 0x80) == 0x80) { break; } } } }
/****************************************************************************** * * This function performs an I/O read. * * @param QspiPtr is a pointer to the QSPI 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 Pointer to the write buffer which contains data to be transmitted * @param Pointer to the read buffer to which valid received data should be * written * * @return none. * * @note None. * ******************************************************************************/ void FlashRead(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 Command, u8 *WriteBfrPtr, u8 *ReadBfrPtr) { u32 RealAddr; u32 RealByteCnt; u32 BankSel; u32 BufferIndex; u32 TotalByteCnt; u8 ShiftSize; /* * Retain the actual byte count */ TotalByteCnt = ByteCount; while(((signed long)(ByteCount)) > 0) { /* * Translate address based on type of connection * If stacked assert the slave select based on address */ RealAddr = GetRealAddr(QspiPtr, Address); /* * Select bank */ if(Flash_Config_Table[FCTIndex].FlashDeviceSize > SIXTEENMB) { BankSel = RealAddr/SIXTEENMB; SendBankSelect(QspiPtr, WriteBfrPtr, BankSel); } /* * If data to be read spans beyond the current bank, then * calculate RealByteCnt in current bank. Else * RealByteCnt is the same as ByteCount */ if((Address & BANKMASK) != ((Address+ByteCount) & BANKMASK)) { RealByteCnt = (Address & BANKMASK) + SIXTEENMB - Address; }else { RealByteCnt = ByteCount; } /* * Setup the write command with the specified address and data for the * Flash */ WriteBfrPtr[COMMAND_OFFSET] = Command; WriteBfrPtr[ADDRESS_1_OFFSET] = (u8)((RealAddr & 0xFF0000) >> 16); WriteBfrPtr[ADDRESS_2_OFFSET] = (u8)((RealAddr & 0xFF00) >> 8); WriteBfrPtr[ADDRESS_3_OFFSET] = (u8)(RealAddr & 0xFF); if ((Command == FAST_READ_CMD) || (Command == DUAL_READ_CMD) || (Command == QUAD_READ_CMD)) { RealByteCnt += DUMMY_SIZE; } /* * Send the read command to the Flash to read the specified number * of bytes from the Flash, send the read command and address and * receive the specified number of bytes of data in the data buffer */ XQspiPs_PolledTransfer(QspiPtr, WriteBfrPtr, &(ReadBfrPtr[TotalByteCnt - ByteCount]), RealByteCnt + OVERHEAD_SIZE); /* * To discard the first 5 dummy bytes, shift the data in read buffer */ if((Command == FAST_READ_CMD) || (Command == DUAL_READ_CMD) || (Command == QUAD_READ_CMD)){ ShiftSize = OVERHEAD_SIZE + DUMMY_SIZE; }else{ ShiftSize = OVERHEAD_SIZE; } for(BufferIndex = (TotalByteCnt - ByteCount); BufferIndex < (TotalByteCnt - ByteCount) + RealByteCnt; BufferIndex++) { ReadBfrPtr[BufferIndex] = ReadBfrPtr[BufferIndex + ShiftSize]; } /* * Increase address to next bank */ Address = (Address & BANKMASK) + SIXTEENMB; /* * Decrease byte count by bytes already read. */ if ((Command == FAST_READ_CMD) || (Command == DUAL_READ_CMD) || (Command == QUAD_READ_CMD)) { ByteCount = ByteCount - (RealByteCnt - DUMMY_SIZE); }else { ByteCount = ByteCount - RealByteCnt; } } }
/** * This function is used to copy the data from QSPI flash to destination * address * * @param SrcAddress is the address of the QSPI flash where copy should * start from * * @param DestAddress is the address of the destination where it * should copy to * * @param Length Length of the bytes to be copied * * @return * - XFSBL_SUCCESS for successful copy * - errors as mentioned in xfsbl_error.h * *****************************************************************************/ u32 XFsbl_Qspi24Copy(u32 SrcAddress, PTRSIZE DestAddress, u32 Length) { u32 Status = XFSBL_SUCCESS; u32 QspiAddr=0; u32 BankSel=0; u32 RemainingBytes=0; u32 TransferBytes=0; u32 DiscardByteCnt; u8 BankSwitchFlag=0; XFsbl_Printf(DEBUG_INFO,"QSPI Reading Src 0x%0lx, Dest %0lx, Length %0lx\r\n", SrcAddress, DestAddress, Length); /** * Check the read length with Qspi flash size */ if ((SrcAddress + Length) > QspiFlashSize) { Status = XFSBL_ERROR_QSPI_LENGTH; XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_LENGTH\r\n"); goto END; } /** * Update no of bytes to be copied */ RemainingBytes = Length; while(RemainingBytes > 0) { if (RemainingBytes > DMA_DATA_TRAN_SIZE) { TransferBytes = DMA_DATA_TRAN_SIZE; } else { TransferBytes = RemainingBytes; } /** * Translate address based on type of connection * If stacked assert the slave select based on address */ QspiAddr = XFsbl_GetQspiAddr((u32 )SrcAddress); /** * Select bank * check logic for DualQspi */ if(QspiFlashSize > BANKSIZE) { BankSel = QspiAddr/BANKSIZE; Status = SendBankSelect(BankSel); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_QSPI_READ; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_QSPI_READ\r\n"); goto END; } } /** * If data to be read spans beyond the current bank, then * calculate Transfer Bytes in current bank. Else * transfer bytes are same * check logic for DualQspi */ if((QspiAddr & BANKMASK) != ((QspiAddr+TransferBytes) & BANKMASK)) { TransferBytes = (QspiAddr & BANKMASK) + BANKSIZE - QspiAddr; } XFsbl_Printf(DEBUG_INFO,"."); XFsbl_Printf(DEBUG_DETAILED, "QSPI Read Src 0x%0lx, Dest %0lx, Length %0lx\r\n", QspiAddr, DestAddress, TransferBytes); /** * Setup the read command with the specified address and data for the * Flash */ WriteBuffer[COMMAND_OFFSET] = ReadCommand; WriteBuffer[ADDRESS_1_OFFSET] = (u8)((QspiAddr & 0xFF0000) >> 16); WriteBuffer[ADDRESS_2_OFFSET] = (u8)((QspiAddr & 0xFF00) >> 8); WriteBuffer[ADDRESS_3_OFFSET] = (u8)(QspiAddr & 0xFF); DiscardByteCnt = 4; FlashMsg[0].TxBfrPtr = WriteBuffer; FlashMsg[0].RxBfrPtr = NULL; FlashMsg[0].ByteCount = DiscardByteCnt; FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI; FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX; /* It is recommended to have a separate entry for dummy */ if ((ReadCommand == FAST_READ_CMD_24BIT) || (ReadCommand == DUAL_READ_CMD_24BIT) || (ReadCommand == QUAD_READ_CMD_24BIT)) { /* 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 (ReadCommand == FAST_READ_CMD_24BIT) { FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI; } if (ReadCommand == DUAL_READ_CMD_24BIT) { FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_DUALSPI; } if (ReadCommand == QUAD_READ_CMD_24BIT) { FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI; } FlashMsg[1].TxBfrPtr = NULL; FlashMsg[1].RxBfrPtr = NULL; FlashMsg[1].ByteCount = DUMMY_CLOCKS; FlashMsg[1].Flags = 0; } if (ReadCommand == FAST_READ_CMD_24BIT) { FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_SPI; } if (ReadCommand == DUAL_READ_CMD_24BIT) { FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_DUALSPI; } if (ReadCommand == QUAD_READ_CMD_24BIT) { FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI; } FlashMsg[2].TxBfrPtr = NULL; FlashMsg[2].RxBfrPtr = (u8 *)DestAddress; FlashMsg[2].ByteCount = TransferBytes; FlashMsg[2].Flags = XQSPIPSU_MSG_FLAG_RX; if(QspiPsuInstancePtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_PARALLEL){ FlashMsg[2].Flags |= XQSPIPSU_MSG_FLAG_STRIPE; } /** * Send the read command to the Flash to read the specified number * of bytes from the Flash, send the read command and address and * receive the specified number of bytes of data in the data buffer */ Status = XQspiPsu_PolledTransfer(QspiPsuInstancePtr, FlashMsg, 3); if (Status != XST_SUCCESS) { Status = XFSBL_ERROR_QSPI_READ; XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n"); goto END; } /** * Update the variables */ RemainingBytes -= TransferBytes; DestAddress += TransferBytes; SrcAddress += TransferBytes; } if(BankSwitchFlag == 1) { /* * Reset Bank selection to zero */ Status = SendBankSelect(0); if (Status != XST_SUCCESS) { Status = XFSBL_ERROR_QSPI_READ; XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n"); goto END; } } END: return Status; }