/** * * 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 initializes the controller for the QSPI interface. * * @param None * * @return None * * @note None * ****************************************************************************/ u32 InitQspi(void) { XQspiPs_Config *QspiConfig; int Status; QspiInstancePtr = &QspiInstance; /* * Set up the base address for access */ FlashReadBaseAddress = XPS_QSPI_LINEAR_BASEADDR; /* * Initialize the QSPI driver so that it's ready to use */ QspiConfig = XQspiPs_LookupConfig(QSPI_DEVICE_ID); if (NULL == QspiConfig) { return XST_FAILURE; } Status = XQspiPs_CfgInitialize(QspiInstancePtr, QspiConfig, QspiConfig->BaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Set Manual Chip select options and drive HOLD_B pin high. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_FORCE_SSELECT_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); /* * Set the prescaler for QSPI clock */ XQspiPs_SetClkPrescaler(QspiInstancePtr, XQSPIPS_CLK_PRESCALE_8); /* * Assert the FLASH chip select. */ XQspiPs_SetSlaveSelect(QspiInstancePtr); /* * Read Flash ID and extract Manufacture and Size information */ Status = FlashReadID(); if (Status != XST_SUCCESS) { return XST_FAILURE; } if (XPAR_PS7_QSPI_0_QSPI_MODE == SINGLE_FLASH_CONNECTION) { fsbl_printf(DEBUG_INFO,"QSPI is in single flash connection\r\n"); /* * For Flash size <128Mbit controller configured in linear mode */ if (QspiFlashSize <= FLASH_SIZE_16MB) { LinearBootDeviceFlag = 1; /* * Enable linear mode */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_LQSPI_MODE_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); /* * Single linear read */ XQspiPs_SetLqspiConfigReg(QspiInstancePtr, SINGLE_QSPI_CONFIG_QUAD_READ); /* * Enable the controller */ XQspiPs_Enable(QspiInstancePtr); } else { /* * Single flash IO read */ XQspiPs_SetLqspiConfigReg(QspiInstancePtr, SINGLE_QSPI_IO_CONFIG_QUAD_READ); /* * Enable the controller */ XQspiPs_Enable(QspiInstancePtr); } } if (XPAR_PS7_QSPI_0_QSPI_MODE == DUAL_PARALLEL_CONNECTION) { fsbl_printf(DEBUG_INFO,"QSPI is in Dual Parallel connection\r\n"); /* * For Single Flash size <128Mbit controller configured in linear mode */ if (QspiFlashSize <= FLASH_SIZE_16MB) { /* * Setting linear access flag */ LinearBootDeviceFlag = 1; /* * Enable linear mode */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_LQSPI_MODE_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); /* * Dual linear read */ XQspiPs_SetLqspiConfigReg(QspiInstancePtr, DUAL_QSPI_CONFIG_QUAD_READ); /* * Enable the controller */ XQspiPs_Enable(QspiInstancePtr); } else { /* * Dual flash IO read */ XQspiPs_SetLqspiConfigReg(QspiInstancePtr, DUAL_QSPI_IO_CONFIG_QUAD_READ); /* * Enable the controller */ XQspiPs_Enable(QspiInstancePtr); } /* * Total flash size is two time of single flash size */ QspiFlashSize = 2 * QspiFlashSize; } /* * It is expected to same flash size for both chip selection */ if (XPAR_PS7_QSPI_0_QSPI_MODE == DUAL_STACK_CONNECTION) { fsbl_printf(DEBUG_INFO,"QSPI is in Dual Stack connection\r\n"); QspiFlashSize = 2 * QspiFlashSize; /* * Enable two flash memories on separate buses */ XQspiPs_SetLqspiConfigReg(QspiInstancePtr, DUAL_STACK_CONFIG_READ); } return XST_SUCCESS; }
/****************************************************************************** * * 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); }
/***************************************************************************** * * The purpose of this function is to illustrate how to use the XQspiPs * device driver in single, parallel and stacked modes using * flash devices greater than 128Mb. * This function reads and writes data in I/O mode. * * @param None. * * @return XST_SUCCESS if successful, else XST_FAILURE. * * @note None. * *****************************************************************************/ int QspiG128FlashExample(XQspiPs *QspiInstancePtr, u16 QspiDeviceId) { int Status; u8 UniqueValue; int Count; int Page; XQspiPs_Config *QspiConfig; /* * Initialize the QSPI driver so that it's ready to use */ QspiConfig = XQspiPs_LookupConfig(QspiDeviceId); if (NULL == QspiConfig) { return XST_FAILURE; } Status = XQspiPs_CfgInitialize(QspiInstancePtr, QspiConfig, QspiConfig->BaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Perform a self-test to check hardware build */ Status = XQspiPs_SelfTest(QspiInstancePtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Set the pre-scaler for QSPI clock */ XQspiPs_SetClkPrescaler(QspiInstancePtr, XQSPIPS_CLK_PRESCALE_8); /* * Set Manual Start and Manual Chip select options and drive the * HOLD_B high. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_FORCE_SSELECT_OPTION | XQSPIPS_MANUAL_START_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); if(QspiConfig->ConnectionMode == XQSPIPS_CONNECTION_MODE_STACKED) { /* * Enable two flash memories, Shared bus (NOT separate bus), * L_PAGE selected by default */ XQspiPs_SetLqspiConfigReg(QspiInstancePtr, DUAL_STACK_CONFIG_WRITE); } if(QspiConfig->ConnectionMode == XQSPIPS_CONNECTION_MODE_PARALLEL) { /* * Enable two flash memories on separate buses */ XQspiPs_SetLqspiConfigReg(QspiInstancePtr, DUAL_QSPI_CONFIG_WRITE); } /* * Assert the Flash chip select. */ XQspiPs_SetSlaveSelect(QspiInstancePtr); /* * Read flash ID and obtain all flash related information * It is important to call the read id function before * performing proceeding to any operation, including * preparing the WriteBuffer */ FlashReadID(QspiInstancePtr, WriteBuffer, ReadBuffer); /* * Initialize MaxData according to page size. */ MaxData = PAGE_COUNT * (Flash_Config_Table[FCTIndex].PageSize); /* * Initialize the write buffer for a pattern to write to the Flash * and the read buffer to zero so it can be verified after the read, the * test value that is added to the unique value allows the value to be * changed in a debug environment to guarantee */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < Flash_Config_Table[FCTIndex].PageSize; Count++, UniqueValue++) { WriteBuffer[DATA_OFFSET + Count] = (u8)(UniqueValue + Test); } memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); /* * Erase the flash. */ FlashErase(QspiInstancePtr, TEST_ADDRESS, MaxData, WriteBuffer); /* * Write the data in the write buffer to the serial Flash a page at a * time, starting from TEST_ADDRESS */ for (Page = 0; Page < PAGE_COUNT; Page++) { FlashWrite(QspiInstancePtr, (Page * Flash_Config_Table[FCTIndex].PageSize) + TEST_ADDRESS, Flash_Config_Table[FCTIndex].PageSize, WRITE_CMD, WriteBuffer); } /* * I/O Read - for any flash size */ FlashRead(QspiInstancePtr, TEST_ADDRESS, MaxData, QUAD_READ_CMD, WriteBuffer, ReadBuffer); /* * Setup a pointer to the start of the data that was read into the read * buffer and verify the data read is the data that was written */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MaxData; Count++, UniqueValue++) { if (ReadBuffer[Count] != (u8)(UniqueValue + Test)) { return XST_FAILURE; } } /* * Initialize the write buffer for a pattern to write to the Flash * and the read buffer to zero so it can be verified after the read, the * test value that is added to the unique value allows the value to be * changed in a debug environment to guarantee */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < Flash_Config_Table[FCTIndex].PageSize; Count++, UniqueValue++) { WriteBuffer[DATA_OFFSET + Count] = (u8)(UniqueValue + Test); } memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); /* * Set Auto Start and Manual Chip select options and drive the * HOLD_B high. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_FORCE_SSELECT_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); /* * Erase the flash. */ FlashErase(QspiInstancePtr, TEST_ADDRESS, MaxData, WriteBuffer); /* * Write the data in the write buffer to the serial Flash a page at a * time, starting from TEST_ADDRESS */ for (Page = 0; Page < PAGE_COUNT; Page++) { FlashWrite(QspiInstancePtr, (Page * Flash_Config_Table[FCTIndex].PageSize) + TEST_ADDRESS, Flash_Config_Table[FCTIndex].PageSize, WRITE_CMD, WriteBuffer); } /* * I/O Read - for any flash size */ FlashRead(QspiInstancePtr, TEST_ADDRESS, MaxData, QUAD_READ_CMD, WriteBuffer, ReadBuffer); /* * Setup a pointer to the start of the data that was read into the read * buffer and verify the data read is the data that was written */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MaxData; Count++, UniqueValue++) { if (ReadBuffer[Count] != (u8)(UniqueValue + Test)) { return XST_FAILURE; } } return XST_SUCCESS; }
/***************************************************************************** * * The purpose of this function is to illustrate how to use the XQspiPs * device driver in Linear mode. This function writes data to the serial * FLASH in QSPI mode and reads data in Linear QSPI mode. * * @param None. * * @return XST_SUCCESS if successful, else XST_FAILURE. * * @note None. * *****************************************************************************/ int LinearQspiFlashExample(XQspiPs *QspiInstancePtr, u16 QspiDeviceId) { int Status; u8 UniqueValue; int Count; int Page; XQspiPs_Config *QspiConfig; /* * Initialize the QSPI driver so that it's ready to use */ QspiConfig = XQspiPs_LookupConfig(QspiDeviceId); if (NULL == QspiConfig) { return XST_FAILURE; } Status = XQspiPs_CfgInitialize(QspiInstancePtr, QspiConfig, QspiConfig->BaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Perform a self-test to check hardware build */ Status = XQspiPs_SelfTest(QspiInstancePtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Initialize the write buffer for a pattern to write to the FLASH * and the read buffer to zero so it can be verified after the read, the * test value that is added to the unique value allows the value to be * changed in a debug environment to guarantee */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < PAGE_SIZE; Count++, UniqueValue++) { WriteBuffer[DATA_OFFSET + Count] = (u8)(UniqueValue + Test); } memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); /* * Set the prescaler for QSPI clock */ XQspiPs_SetClkPrescaler(QspiInstancePtr, XQSPIPS_CLK_PRESCALE_8); /* * Set Manual Start and Manual Chip select options and drive the * HOLD_B high. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_FORCE_SSELECT_OPTION | XQSPIPS_MANUAL_START_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); /* * Assert the FLASH chip select. */ XQspiPs_SetSlaveSelect(QspiInstancePtr); FlashReadID(); /* * Erase the flash. */ FlashErase(QspiInstancePtr, TEST_ADDRESS, MAX_DATA); /* * Write the data in the write buffer to the serial FLASH a page at a * time, starting from TEST_ADDRESS */ for (Page = 0; Page < PAGE_COUNT; Page++) { FlashWrite(QspiInstancePtr, (Page * PAGE_SIZE) + TEST_ADDRESS, PAGE_SIZE, WRITE_CMD); } /* * Read from the flash in LQSPI mode. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_LQSPI_MODE_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); Status = XQspiPs_LqspiRead(QspiInstancePtr, ReadBuffer, TEST_ADDRESS, MAX_DATA); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Setup a pointer to the start of the data that was read into the read * buffer and verify the data read is the data that was written */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; Count++, UniqueValue++) { if (ReadBuffer[Count] != (u8)(UniqueValue + Test)) { return XST_FAILURE; } } /* * Initialize the write buffer for a pattern to write to the FLASH * and the read buffer to zero so it can be verified after the read, the * test value that is added to the unique value allows the value to be * changed in a debug environment to guarantee */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < PAGE_SIZE; Count++, UniqueValue++) { WriteBuffer[DATA_OFFSET + Count] = (u8)(UniqueValue + Test); } memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); /* * Set Auto Start and Manual Chip select options and drive the * HOLD_B high. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_FORCE_SSELECT_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); /* * Erase the flash. */ FlashErase(QspiInstancePtr, TEST_ADDRESS, MAX_DATA); /* * Write the data in the write buffer to the serial FLASH a page at a * time, starting from TEST_ADDRESS */ for (Page = 0; Page < PAGE_COUNT; Page++) { FlashWrite(QspiInstancePtr, (Page * PAGE_SIZE) + TEST_ADDRESS, PAGE_SIZE, WRITE_CMD); } /* * Read from the flash in LQSPI mode. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_LQSPI_MODE_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); Status = XQspiPs_LqspiRead(QspiInstancePtr, ReadBuffer, TEST_ADDRESS, MAX_DATA); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Setup a pointer to the start of the data that was read into the read * buffer and verify the data read is the data that was written */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; Count++, UniqueValue++) { if (ReadBuffer[Count] != (u8)(UniqueValue + Test)) { return XST_FAILURE; } } return XST_SUCCESS; }
/** * * This function sets the options for the QSPI device driver. The options control * how the device behaves relative to the QSPI bus. The device must be idle * rather than busy transferring data before setting these device options. * * @param InstancePtr is a pointer to the XQspiPs instance. * @param Options contains the specified options to be set. This is a bit * mask where a 1 means to turn the option on, and a 0 means to * turn the option off. One or more bit values may be contained in * the mask. See the bit definitions named XQSPIPS_*_OPTIONS in * the file xqspips.h. * * @return * - XST_SUCCESS if options are successfully set. * - XST_DEVICE_BUSY if the device is currently transferring data. * The transfer must complete or be aborted before setting options. * * @note * This function is not thread-safe. * ******************************************************************************/ int XQspiPs_SetOptions(XQspiPs *InstancePtr, u32 Options) { u32 ConfigReg; unsigned int Index; u32 QspiOptions; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Do not allow to modify the Control Register while a transfer is in * progress. Not thread-safe. */ if (InstancePtr->IsBusy) { return XST_DEVICE_BUSY; } QspiOptions = Options & XQSPIPS_LQSPI_MODE_OPTION; Options &= ~XQSPIPS_LQSPI_MODE_OPTION; ConfigReg = XQspiPs_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET); /* * Loop through the options table, turning the option on or off * depending on whether the bit is set in the incoming options flag. */ for (Index = 0; Index < XQSPIPS_NUM_OPTIONS; Index++) { if (Options & OptionsTable[Index].Option) { /* Turn it on */ ConfigReg |= OptionsTable[Index].Mask; } else { /* Turn it off */ ConfigReg &= ~(OptionsTable[Index].Mask); } } /* * Now write the control register. Leave it to the upper layers * to restart the device. */ XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_CR_OFFSET, ConfigReg); /* * Check for the LQSPI configuration options. */ ConfigReg = XQspiPs_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPS_LQSPI_CR_OFFSET); if (QspiOptions & XQSPIPS_LQSPI_MODE_OPTION) { XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_LQSPI_CR_OFFSET, XQSPIPS_LQSPI_CR_RST_STATE); XQspiPs_SetSlaveSelect(InstancePtr); } else { ConfigReg &= ~XQSPIPS_LQSPI_CR_LINEAR_MASK; XQspiPs_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPS_LQSPI_CR_OFFSET, ConfigReg); } return XST_SUCCESS; }
/***************************************************************************** * * The purpose of this function is to illustrate how to use the XQspiPs * device driver in Linear mode. This function writes data to the serial * FLASH in QSPI mode and reads data in Linear QSPI mode. * * @param None. * * @return XST_SUCCESS if successful, else XST_FAILURE. * * @note None. * *****************************************************************************/ int LinearQspiFlashExample(XQspiPs *QspiInstancePtr, u16 QspiDeviceId) { int Status; u8 UniqueValue; int Count; int Page; XQspiPs_Config *QspiConfig; /* * Initialize the QSPI driver so that it's ready to use */ QspiConfig = XQspiPs_LookupConfig(QspiDeviceId); if (NULL == QspiConfig) { return XST_FAILURE; } Status = XQspiPs_CfgInitialize(QspiInstancePtr, QspiConfig, QspiConfig->BaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Perform a self-test to check hardware build */ Status = XQspiPs_SelfTest(QspiInstancePtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Enable two flash memories on seperate buses */ XQspiPs_SetLqspiConfigReg(QspiInstancePtr, DUAL_QSPI_CONFIG_WRITE); /* * Set the QSPI device as a master and enable manual CS, manual start * and flash interface mode options and drive HOLD_B pin high. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_FORCE_SSELECT_OPTION | XQSPIPS_MANUAL_START_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); XQspiPs_SetClkPrescaler(QspiInstancePtr, XQSPIPS_CLK_PRESCALE_8); /* * Initialize the write buffer for a pattern to write to the FLASH * and the read buffer to zero so it can be verified after the read, the * test value that is added to the unique value allows the value to be * changed in a debug environment to guarantee */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < PAGE_SIZE; Count++, UniqueValue++) { WriteBuffer[DATA_OFFSET + Count] = (u8)(UniqueValue + Test); } memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); /* * Assert the FLASH chip select. */ XQspiPs_SetSlaveSelect(QspiInstancePtr); /* * Erase the flash sectors */ FlashErase(QspiInstancePtr, TEST_ADDRESS, MAX_DATA); /* * Write data to the two flash memories on seperate buses, starting from * TEST_ADDRESS. This is same as writing to a single flash memory. The * LQSPI controller takes care of splitting the data words and writing * them to the two flash memories. The user needs to take care of the * address translation */ for (Page = 0; Page < PAGE_COUNT; Page++) { FlashWrite(QspiInstancePtr, ((Page * PAGE_SIZE) + TEST_ADDRESS) / 2, PAGE_SIZE, WRITE_CMD); } /* * Read from the two flash memories on seperate buses in LQSPI mode. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_LQSPI_MODE_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); XQspiPs_SetLqspiConfigReg(QspiInstancePtr, DUAL_QSPI_CONFIG_QUAD_READ); Status = XQspiPs_LqspiRead(QspiInstancePtr, ReadBuffer, TEST_ADDRESS, MAX_DATA); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Setup a pointer to the start of the data that was read into the read * buffer and verify the data read is the data that was written */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; Count++, UniqueValue++) { if (ReadBuffer[Count] != WriteBuffer[DATA_OFFSET + (Count % PAGE_SIZE)]) { return XST_FAILURE; } } /* * Set the QSPI device as a master and enable manual CS, manual start * and flash interface mode options and drive HOLD_B pin high. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_FORCE_SSELECT_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); /* * Initialize the write buffer for a pattern to write to the FLASH * and the read buffer to zero so it can be verified after the read, the * test value that is added to the unique value allows the value to be * changed in a debug environment to guarantee */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < PAGE_SIZE; Count++, UniqueValue++) { WriteBuffer[DATA_OFFSET + Count] = (u8)(UniqueValue + Test); } memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); /* * Erase the flash sectors */ FlashErase(QspiInstancePtr, TEST_ADDRESS, MAX_DATA); /* * Write data to the two flash memories on seperate buses, starting from * TEST_ADDRESS. This is same as writing to a single flash memory. The * LQSPI controller takes care of splitting the data words and writing * them to the two flash memories. The user needs to take care of the * address translation */ for (Page = 0; Page < PAGE_COUNT; Page++) { FlashWrite(QspiInstancePtr, ((Page * PAGE_SIZE) + TEST_ADDRESS) / 2, PAGE_SIZE, WRITE_CMD); } /* * Read from the two flash memories on seperate buses in LQSPI mode. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_LQSPI_MODE_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); XQspiPs_SetLqspiConfigReg(QspiInstancePtr, DUAL_QSPI_CONFIG_QUAD_READ); Status = XQspiPs_LqspiRead(QspiInstancePtr, ReadBuffer, TEST_ADDRESS, MAX_DATA); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Setup a pointer to the start of the data that was read into the read * buffer and verify the data read is the data that was written */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; Count++, UniqueValue++) { if (ReadBuffer[Count] != WriteBuffer[DATA_OFFSET + (Count % PAGE_SIZE)]) { return XST_FAILURE; } } return XST_SUCCESS; }
/***************************************************************************** * * The purpose of this function is to illustrate how to use the XQspiPs * device driver in interrupt mode. This function writes and reads data * from a serial FLASH. * * @param None. * * @return XST_SUCCESS if successful else XST_FAILURE. * * @note * * This function calls other functions which contain loops that may be infinite * if interrupts are not working such that it may not return. If the device * slave select is not correct and the device is not responding on bus it will * read a status of 0xFF for the status register as the bus is pulled up. * *****************************************************************************/ int QspiFlashIntrExample(XScuGic *IntcInstancePtr, XQspiPs *QspiInstancePtr, u16 QspiDeviceId, u16 QspiIntrId) { int Status; u8 *BufferPtr; u8 UniqueValue; int Count; int Page; XQspiPs_Config *QspiConfig; /* * Initialize the QSPI driver so that it's ready to use */ QspiConfig = XQspiPs_LookupConfig(QspiDeviceId); if (NULL == QspiConfig) { return XST_FAILURE; } Status = XQspiPs_CfgInitialize(QspiInstancePtr, QspiConfig, QspiConfig->BaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Perform a self-test to check hardware build */ Status = XQspiPs_SelfTest(QspiInstancePtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Connect the Qspi device to the interrupt subsystem such that * interrupts can occur. This function is application specific */ Status = QspiSetupIntrSystem(IntcInstancePtr, QspiInstancePtr, QspiIntrId); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Setup the handler for the QSPI that will be called from the * interrupt context when an QSPI status occurs, specify a pointer to * the QSPI driver instance as the callback reference so the handler is * able to access the instance data */ XQspiPs_SetStatusHandler(QspiInstancePtr, QspiInstancePtr, (XQspiPs_StatusHandler) QspiHandler); /* * Set Manual Start and Manual Chip select options and drive the * HOLD_B high. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_FORCE_SSELECT_OPTION | XQSPIPS_MANUAL_START_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); /* * Set the operating clock frequency using the clock divider */ XQspiPs_SetClkPrescaler(QspiInstancePtr, XQSPIPS_CLK_PRESCALE_8); /* * Assert the FLASH chip select */ XQspiPs_SetSlaveSelect(QspiInstancePtr); /* * Initialize the write buffer for a pattern to write to the FLASH * and the read buffer to zero so it can be verified after the read, the * test value that is added to the unique value allows the value to be * changed in a debug environment to guarantee */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < PAGE_SIZE; Count++, UniqueValue++) { WriteBuffer[DATA_OFFSET + Count] = (u8)(UniqueValue + Test); } memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); FlashReadID(); /* * Erase the flash. */ FlashErase(QspiInstancePtr, TEST_ADDRESS, MAX_DATA); /* * Write the data in the write buffer to the serial FLASH a page at a * time, starting from TEST_ADDRESS */ for (Page = 0; Page < PAGE_COUNT; Page++) { FlashWrite(QspiInstancePtr, (Page * PAGE_SIZE) + TEST_ADDRESS, PAGE_SIZE, WRITE_CMD); } /* * Read the contents of the FLASH from TEST_ADDRESS, using Normal Read * command. */ FlashRead(QspiInstancePtr, TEST_ADDRESS, MAX_DATA, READ_CMD); /* * Setup a pointer to the start of the data that was read into the read * buffer and verify the data read is the data that was written */ BufferPtr = &ReadBuffer[DATA_OFFSET]; for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; Count++, UniqueValue++) { if (BufferPtr[Count] != (u8)(UniqueValue + Test)) { return XST_FAILURE; } } /* * Read the contents of the FLASH from TEST_ADDRESS, using Fast Read * command */ memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); FlashRead(QspiInstancePtr, TEST_ADDRESS, MAX_DATA, FAST_READ_CMD); /* * Setup a pointer to the start of the data that was read into the read * buffer and verify the data read is the data that was written */ BufferPtr = &ReadBuffer[DATA_OFFSET + DUMMY_SIZE]; for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; Count++, UniqueValue++) { if (BufferPtr[Count] != (u8)(UniqueValue + Test)) { return XST_FAILURE; } } /* * Read the contents of the FLASH from TEST_ADDRESS, using Dual Read * command */ memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); FlashRead(QspiInstancePtr, TEST_ADDRESS, MAX_DATA, DUAL_READ_CMD); /* * Setup a pointer to the start of the data that was read into the read * buffer and verify the data read is the data that was written */ BufferPtr = &ReadBuffer[DATA_OFFSET + DUMMY_SIZE]; for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; Count++, UniqueValue++) { if (BufferPtr[Count] != (u8)(UniqueValue + Test)) { return XST_FAILURE; } } /* * Read the contents of the FLASH from TEST_ADDRESS, using Quad Read * command */ memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); FlashRead(QspiInstancePtr, TEST_ADDRESS, MAX_DATA, QUAD_READ_CMD); /* * Setup a pointer to the start of the data that was read into the read * buffer and verify the data read is the data that was written */ BufferPtr = &ReadBuffer[DATA_OFFSET + DUMMY_SIZE]; for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; Count++, UniqueValue++) { if (BufferPtr[Count] != (u8)(UniqueValue + Test)) { return XST_FAILURE; } } /* * Set Auto Start and Manual Chip select options and drive the * HOLD_B high. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_FORCE_SSELECT_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); /* * Initialize the write buffer for a pattern to write to the FLASH * and the read buffer to zero so it can be verified after the read, the * test value that is added to the unique value allows the value to be * changed in a debug environment to guarantee */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < PAGE_SIZE; Count++, UniqueValue++) { WriteBuffer[DATA_OFFSET + Count] = (u8)(UniqueValue + Test); } memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); /* * Erase the flash. */ FlashErase(QspiInstancePtr, TEST_ADDRESS, MAX_DATA); /* * Write the data in the write buffer to the serial FLASH a page at a * time, starting from TEST_ADDRESS */ for (Page = 0; Page < PAGE_COUNT; Page++) { FlashWrite(QspiInstancePtr, (Page * PAGE_SIZE) + TEST_ADDRESS, PAGE_SIZE, WRITE_CMD); } /* * Read the contents of the FLASH from TEST_ADDRESS, using Normal Read * command. */ FlashRead(QspiInstancePtr, TEST_ADDRESS, MAX_DATA, READ_CMD); /* * Setup a pointer to the start of the data that was read into the read * buffer and verify the data read is the data that was written */ BufferPtr = &ReadBuffer[DATA_OFFSET]; for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; Count++, UniqueValue++) { if (BufferPtr[Count] != (u8)(UniqueValue + Test)) { return XST_FAILURE; } } /* * Read the contents of the FLASH from TEST_ADDRESS, using Fast Read * command */ memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); FlashRead(QspiInstancePtr, TEST_ADDRESS, MAX_DATA, FAST_READ_CMD); /* * Setup a pointer to the start of the data that was read into the read * buffer and verify the data read is the data that was written */ BufferPtr = &ReadBuffer[DATA_OFFSET + DUMMY_SIZE]; for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; Count++, UniqueValue++) { if (BufferPtr[Count] != (u8)(UniqueValue + Test)) { return XST_FAILURE; } } /* * Read the contents of the FLASH from TEST_ADDRESS, using Dual Read * command */ memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); FlashRead(QspiInstancePtr, TEST_ADDRESS, MAX_DATA, DUAL_READ_CMD); /* * Setup a pointer to the start of the data that was read into the read * buffer and verify the data read is the data that was written */ BufferPtr = &ReadBuffer[DATA_OFFSET + DUMMY_SIZE]; for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; Count++, UniqueValue++) { if (BufferPtr[Count] != (u8)(UniqueValue + Test)) { return XST_FAILURE; } } /* * Read the contents of the FLASH from TEST_ADDRESS, using Quad Read * command */ memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); FlashRead(QspiInstancePtr, TEST_ADDRESS, MAX_DATA, QUAD_READ_CMD); /* * Setup a pointer to the start of the data that was read into the read * buffer and verify the data read is the data that was written */ BufferPtr = &ReadBuffer[DATA_OFFSET + DUMMY_SIZE]; for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; Count++, UniqueValue++) { if (BufferPtr[Count] != (u8)(UniqueValue + Test)) { return XST_FAILURE; } } QspiDisableIntrSystem(IntcInstancePtr, QspiIntrId); return XST_SUCCESS; }
/** * * 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; }