/** * * Read the flash in Linear QSPI mode. * * @param InstancePtr is a pointer to the XQspiPs instance. * @param RecvBufPtr is a pointer to a buffer for received data. * @param Address is the starting address within the flash from * from where data needs to be read. * @param ByteCount contains the number of bytes to receive. * * @return * - XST_SUCCESS if read is performed * - XST_FAILURE if Linear mode is not set * * @note None. * * ******************************************************************************/ int XQspiPs_LqspiRead(XQspiPs *InstancePtr, u8 *RecvBufPtr, u32 Address, unsigned ByteCount) { Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(RecvBufPtr != NULL); Xil_AssertNonvoid(ByteCount > 0); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); #ifndef XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR #define XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR 0xFC000000 #endif /* * Enable the controller */ XQspiPs_Enable(InstancePtr); if (XQspiPs_GetLqspiConfigReg(InstancePtr) & XQSPIPS_LQSPI_CR_LINEAR_MASK) { memcpy((void*)RecvBufPtr, (const void*)(XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR + Address), (size_t)ByteCount); return XST_SUCCESS; } else { return XST_FAILURE; } /* * Disable the controller */ XQspiPs_Disable(InstancePtr); }
/****************************************************************************** * * This function reads from the serial FLASH connected to the * QSPI interface. * * @param Address contains the address to read data from in the FLASH. * @param ByteCount contains the number of bytes to read. * * @return None. * * @note None. * ******************************************************************************/ void FlashRead(u32 Address, u32 ByteCount) { /* * Setup the write command with the specified address and data for the * FLASH */ u32 LqspiCrReg; u8 ReadCommand; LqspiCrReg = XQspiPs_GetLqspiConfigReg(QspiInstancePtr); ReadCommand = (u8) (LqspiCrReg & XQSPIPS_LQSPI_CR_INST_MASK); WriteBuffer[COMMAND_OFFSET] = ReadCommand; WriteBuffer[ADDRESS_1_OFFSET] = (u8)((Address & 0xFF0000) >> 16); WriteBuffer[ADDRESS_2_OFFSET] = (u8)((Address & 0xFF00) >> 8); WriteBuffer[ADDRESS_3_OFFSET] = (u8)(Address & 0xFF); ByteCount += 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(QspiInstancePtr, WriteBuffer, ReadBuffer, ByteCount + OVERHEAD_SIZE); }
/** * * 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 functions translates the address based on the type of interconnection. * In case of stacked, this function asserts the corresponding slave select. * * @param QspiPtr is a pointer to the QSPI driver component to use. * @param Address which is to be accessed (for erase, write or read) * * @return RealAddr is the translated address - for single it is unchanged; * for stacked, the lower flash size is subtracted; * for parallel the address is divided by 2. * * @note None. * ******************************************************************************/ u32 GetRealAddr(XQspiPs *QspiPtr, u32 Address) { u32 LqspiCr; u32 RealAddr; switch(QspiPtr->Config.ConnectionMode) { case XQSPIPS_CONNECTION_MODE_SINGLE: RealAddr = Address; break; case XQSPIPS_CONNECTION_MODE_STACKED: /* * Get the current LQSPI Config reg value */ LqspiCr = XQspiPs_GetLqspiConfigReg(QspiPtr); /* Select lower or upper Flash based on sector address */ if(Address & Flash_Config_Table[FCTIndex].FlashDeviceSize) { /* * Set selection to U_PAGE */ XQspiPs_SetLqspiConfigReg(QspiPtr, LqspiCr | XQSPIPS_LQSPI_CR_U_PAGE_MASK); /* * Subtract first flash size when accessing second flash */ RealAddr = Address & (~Flash_Config_Table[FCTIndex].FlashDeviceSize); }else{ /* * Set selection to L_PAGE */ XQspiPs_SetLqspiConfigReg(QspiPtr, LqspiCr & (~XQSPIPS_LQSPI_CR_U_PAGE_MASK)); RealAddr = Address; } /* * Assert the Flash chip select. */ XQspiPs_SetSlaveSelect(QspiPtr); break; case XQSPIPS_CONNECTION_MODE_PARALLEL: /* * The effective address in each flash is the actual * address / 2 */ RealAddr = Address / 2; break; default: /* RealAddr wont be assigned in this case; */ break; } return(RealAddr); }
/** * * This function erases the sectors in the serial FLASH connected to the * QSPI interface. * * @param InstancePtr is a pointer to the XIsf component to use. * @param Address contains the address of the first sector which needs to * be erased. * @param ByteCount contains the total size to be erased. * * @return None. * * @note None. * ******************************************************************************/ int FlashErase(XIsf *InstancePtr, u32 Address, u32 ByteCount) { int Status; int Sector; u32 LqspiCr; u32 NumSect; u32 SectorSize; u32 NumSectors; u32 Sector_Mask; /* * Get the value of Sector Size and Number of Sectors for the flash */ SectorSize = Isf.SectorSize; NumSectors = Isf.NumSectors; /* Get the sector mask value */ Sector_Mask = SectorMask(SectorSize); /* * If erase size is same as the total size of the flash, use bulk erase * command */ if (ByteCount == (NumSectors * SectorSize)) { #ifdef XPAR_XQSPIPS_0_DEVICE_ID if(ConfigPtr->ConnectionMode == XQSPIPS_CONNECTION_MODE_STACKED){ /* * Get the current LQSPI configuration register value */ LqspiCr = XQspiPs_GetLqspiConfigReg(InstancePtr->SpiInstPtr); /* * Set selection to L_PAGE */ XQspiPs_SetLqspiConfigReg(InstancePtr->SpiInstPtr, LqspiCr & (~XQSPIPS_LQSPI_CR_U_PAGE_MASK)); /* * Assert the Flash chip select. */ XQspiPs_SetSlaveSelect(InstancePtr->SpiInstPtr); } #endif /*XPAR_XQSPIPS_0_DEVICE_ID*/ /* * Call Bulk erase */ Status = XIsf_Erase(InstancePtr, XISF_BULK_ERASE, Address); if(Status != XST_SUCCESS) { return XST_FAILURE; } #ifdef XPAR_XQSPIPS_0_DEVICE_ID /* * If stacked mode, bulk erase second flash */ if(ConfigPtr->ConnectionMode == XQSPIPS_CONNECTION_MODE_STACKED){ /* * Get the current LQSPI configuration register value */ LqspiCr = XQspiPs_GetLqspiConfigReg(InstancePtr->SpiInstPtr); /* * Set selection to U_PAGE */ XQspiPs_SetLqspiConfigReg(InstancePtr->SpiInstPtr, LqspiCr | XQSPIPS_LQSPI_CR_U_PAGE_MASK); /* * Assert the Flash chip select. */ XQspiPs_SetSlaveSelect(InstancePtr->SpiInstPtr); /* * Call Bulk erase */ Status = XIsf_Erase(InstancePtr, XISF_BULK_ERASE, Address); if(Status != XST_SUCCESS) { return XST_FAILURE; } } #endif /*XPAR_XQSPIPS_0_DEVICE_ID*/ return Status; } /* * Calculate no. of sectors to erase based on byte count */ NumSect = ByteCount/SectorSize + 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) & Sector_Mask) == ((Address + (NumSect * SectorSize)) & Sector_Mask) ) { NumSect++; } /* * If the erase size is less than the total size of the flash, use * sector erase command */ for (Sector = 0; Sector < NumSect; Sector++) { /* * Perform the Sector Erase operation. */ Status = XIsf_Erase(InstancePtr, XISF_SECTOR_ERASE, Address); if(Status != XST_SUCCESS) { return XST_FAILURE; } Address += SectorSize; } return XST_SUCCESS; }