/****************************************************************************** * * * 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. * * @return None. * * @note None. * ******************************************************************************/ void FlashWrite(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 Command) { u8 WriteEnableCmd = { WRITE_ENABLE_CMD }; u8 ReadStatusCmd[] = { READ_STATUS_CMD, 0 }; /* must send 2 bytes */ u8 FlashStatus[2]; /* * Send the write enable command to the FLASH so that it can be * written to, this needs to be sent as a seperate transfer before * the write */ XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL, sizeof(WriteEnableCmd)); /* * Setup the write command with the specified address and data for the * FLASH */ WriteBuffer[COMMAND_OFFSET] = Command; WriteBuffer[ADDRESS_1_OFFSET] = (u8)((Address & 0xFF0000) >> 16); WriteBuffer[ADDRESS_2_OFFSET] = (u8)((Address & 0xFF00) >> 8); WriteBuffer[ADDRESS_3_OFFSET] = (u8)(Address & 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, WriteBuffer, NULL, ByteCount + OVERHEAD_SIZE); /* * 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; } } }
/****************************************************************************** * * This functions performs a bulk erase operation when the * flash device has a single die. Works for both Spansion and Micron * * @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 BulkErase(XQspiPs *QspiPtr, u8 *WriteBfrPtr) { u8 WriteEnableCmd = { WRITE_ENABLE_CMD }; u8 ReadStatusCmd[] = { READ_STATUS_CMD, 0 }; /* Must send 2 bytes */ u8 FlashStatus[2]; /* * 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 erase */ XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL, sizeof(WriteEnableCmd)); /* * Setup the bulk erase command */ WriteBfrPtr[COMMAND_OFFSET] = BULK_ERASE_CMD; /* * Send the bulk erase command; no receive buffer is specified * since there is nothing to receive */ XQspiPs_PolledTransfer(QspiPtr, WriteBfrPtr, NULL, BULK_ERASE_SIZE); /* * Wait for the 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; } } }
/****************************************************************************** * * 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 reads serial FLASH ID connected to the SPI interface. * It then deduces the make and size of the flash and obtains the * connection mode to point to corresponding parameters in the flash * configuration table. The flash driver will function based on this and * it presently supports Micron and Spansion - 128, 256 and 512Mbit and * Winbond 128Mbit * * @param none * * @return XST_SUCCESS if read id, otherwise XST_FAILURE. * * @note None. * ******************************************************************************/ u32 FlashReadID(void) { u32 Status; /* * Read ID in Auto mode. */ WriteBuffer[COMMAND_OFFSET] = READ_ID_CMD; WriteBuffer[ADDRESS_1_OFFSET] = 0x00; /* 3 dummy bytes */ WriteBuffer[ADDRESS_2_OFFSET] = 0x00; WriteBuffer[ADDRESS_3_OFFSET] = 0x00; Status = XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, ReadBuffer, RD_ID_SIZE); if (Status != XST_SUCCESS) { return XST_FAILURE; } fsbl_printf(DEBUG_INFO,"Single Flash Information\r\n"); fsbl_printf(DEBUG_INFO,"FlashID=0x%x 0x%x 0x%x\r\n", ReadBuffer[1], ReadBuffer[2], ReadBuffer[3]); /* * Deduce flash make */ if (ReadBuffer[1] == MICRON_ID) { QspiFlashMake = MICRON_ID; fsbl_printf(DEBUG_INFO, "MICRON "); } else if(ReadBuffer[1] == SPANSION_ID) { QspiFlashMake = SPANSION_ID; fsbl_printf(DEBUG_INFO, "SPANSION "); } else if(ReadBuffer[1] == WINBOND_ID) { QspiFlashMake = WINBOND_ID; fsbl_printf(DEBUG_INFO, "WINBOND "); } /* * Deduce flash Size */ if (ReadBuffer[3] == FLASH_SIZE_ID_128M) { QspiFlashSize = FLASH_SIZE_128M; fsbl_printf(DEBUG_INFO, "128M Bits\r\n"); } else if (ReadBuffer[3] == FLASH_SIZE_ID_256M) { QspiFlashSize = FLASH_SIZE_256M; fsbl_printf(DEBUG_INFO, "256M Bits\r\n"); } else if (ReadBuffer[3] == FLASH_SIZE_ID_512M) { QspiFlashSize = FLASH_SIZE_512M; fsbl_printf(DEBUG_INFO, "512M Bits\r\n"); } else if (ReadBuffer[3] == FLASH_SIZE_ID_1G) { QspiFlashSize = FLASH_SIZE_1G; fsbl_printf(DEBUG_INFO, "1G Bits\r\n"); } return XST_SUCCESS; }
/****************************************************************************** * * This functions selects the current bank * * @param QspiPtr is a pointer to the QSPI driver component to use. * @param Pointer to the write buffer which contains data to be transmitted * @param BankSel is the bank to be selected in the flash device(s). * * @return XST_SUCCESS if bank selected, otherwise XST_FAILURE. * * @note None. * ******************************************************************************/ int SendBankSelect(XQspiPs *QspiPtr, u8 *WriteBfrPtr, u32 BankSel) { u8 WriteEnableCmd = { WRITE_ENABLE_CMD }; /* * Bank select commands for Micron and Spansion are different */ if(FlashMake == MICRON_ID_BYTE0) { /* * For Micron command WREN should be sent first * except for some specific feature set */ XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL, sizeof(WriteEnableCmd)); WriteBfrPtr[COMMAND_OFFSET] = EXTADD_REG_WR; WriteBfrPtr[ADDRESS_1_OFFSET] = BankSel; /* * Send the Extended address register write command * written, no receive buffer required */ XQspiPs_PolledTransfer(QspiPtr, WriteBfrPtr, NULL, BANK_SEL_SIZE); } if(FlashMake == SPANSION_ID_BYTE0) { WriteBfrPtr[COMMAND_OFFSET] = BANK_REG_WR; WriteBfrPtr[ADDRESS_1_OFFSET] = BankSel; /* * Send the Extended address register write command * written, no receive buffer required */ XQspiPs_PolledTransfer(QspiPtr, WriteBfrPtr, NULL, BANK_SEL_SIZE); } /* Winbond can be added here */ return XST_SUCCESS; }
/****************************************************************************** * * 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 */ WriteBuffer[COMMAND_OFFSET] = QUAD_READ_CMD; 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 reads serial FLASH ID connected to the SPI interface. * * @param None. * * @return XST_SUCCESS if read id, otherwise XST_FAILURE. * * @note None. * ******************************************************************************/ int FlashReadID(void) { int Status; /* * Read ID in Auto mode. */ WriteBuffer[COMMAND_OFFSET] = READ_ID; WriteBuffer[ADDRESS_1_OFFSET] = 0x23; /* 3 dummy bytes */ WriteBuffer[ADDRESS_2_OFFSET] = 0x08; WriteBuffer[ADDRESS_3_OFFSET] = 0x09; Status = XQspiPs_PolledTransfer(&QspiInstance, WriteBuffer, ReadBuffer, RD_ID_SIZE); if (Status != XST_SUCCESS) { return XST_FAILURE; } xil_printf("FlashID=0x%x 0x%x 0x%x\n\r", ReadBuffer[1], ReadBuffer[2], ReadBuffer[3]); return XST_SUCCESS; }
/****************************************************************************** * * This functions selects the current bank * * @param BankSel is the bank to be selected in the flash device(s). * * @return XST_SUCCESS if bank selected * XST_FAILURE if selection failed * @note None. * ******************************************************************************/ u32 SendBankSelect(u8 BankSel) { u32 Status; /* * bank select commands for Micron and Spansion are different */ if (QspiFlashMake == MICRON_ID) { /* * For micron command WREN should be sent first * except for some specific feature set */ WriteBuffer[COMMAND_OFFSET] = WRITE_ENABLE_CMD; Status = XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, NULL, WRITE_ENABLE_CMD_SIZE); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Send the Extended address register write command * written, no receive buffer required */ WriteBuffer[COMMAND_OFFSET] = EXTADD_REG_WR; WriteBuffer[ADDRESS_1_OFFSET] = BankSel; Status = XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, NULL, BANK_SEL_SIZE); if (Status != XST_SUCCESS) { return XST_FAILURE; } } if (QspiFlashMake == SPANSION_ID) { WriteBuffer[COMMAND_OFFSET] = BANK_REG_WR; WriteBuffer[ADDRESS_1_OFFSET] = BankSel; /* * Send the Extended address register write command * written, no receive buffer required */ Status = XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, NULL, BANK_SEL_SIZE); if (Status != XST_SUCCESS) { return XST_FAILURE; } } /* * For testing - Read bank to verify */ if (QspiFlashMake == SPANSION_ID) { WriteBuffer[COMMAND_OFFSET] = BANK_REG_RD; WriteBuffer[ADDRESS_1_OFFSET] = 0x00; /* * Send the Extended address register write command * written, no receive buffer required */ Status = XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, ReadBuffer, BANK_SEL_SIZE); if (Status != XST_SUCCESS) { return XST_FAILURE; } } if (QspiFlashMake == MICRON_ID) { WriteBuffer[COMMAND_OFFSET] = EXTADD_REG_RD; WriteBuffer[ADDRESS_1_OFFSET] = 0x00; /* * Send the Extended address register write command * written, no receive buffer required */ Status = XQspiPs_PolledTransfer(QspiInstancePtr, WriteBuffer, ReadBuffer, BANK_SEL_SIZE); if (Status != XST_SUCCESS) { return XST_FAILURE; } } if (ReadBuffer[1] != BankSel) { fsbl_printf(DEBUG_INFO, "BankSel %d != Register Read %d\n\r", BankSel, ReadBuffer[1]); return XST_FAILURE; } return XST_SUCCESS; }
/****************************************************************************** * * This function reads serial Flash ID connected to the SPI interface. * It then deduces the make and size of the flash and obtains the * connection mode to point to corresponding parameters in the flash * configuration table. The flash driver will function based on this and * it presently supports Micron and Spansion - 128, 256 and 512Mbit and * Winbond 128Mbit * * @param QspiPtr is a pointer to the QSPI driver component to use. * @param Pointer to the write buffer (which is to be transmitted) * @param Pointer to the read buffer to which valid received data should be * written * * @return XST_SUCCESS if read id, otherwise XST_FAILURE. * * @note None. * ******************************************************************************/ int FlashReadID(XQspiPs *QspiPtr, u8 *WriteBfrPtr, u8 *ReadBfrPtr) { int Status; int StartIndex; /* * Read ID in Auto mode. */ WriteBfrPtr[COMMAND_OFFSET] = READ_ID; WriteBfrPtr[ADDRESS_1_OFFSET] = 0x23; /* 3 dummy bytes */ WriteBfrPtr[ADDRESS_2_OFFSET] = 0x08; WriteBfrPtr[ADDRESS_3_OFFSET] = 0x09; Status = XQspiPs_PolledTransfer(QspiPtr, WriteBfrPtr, ReadBfrPtr, RD_ID_SIZE); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Deduce flash make */ if(ReadBfrPtr[1] == MICRON_ID_BYTE0) { FlashMake = MICRON_ID_BYTE0; StartIndex = MICRON_INDEX_START; }else if(ReadBfrPtr[1] == SPANSION_ID_BYTE0) { FlashMake = SPANSION_ID_BYTE0; StartIndex = SPANSION_INDEX_START; }else if(ReadBfrPtr[1] == WINBOND_ID_BYTE0) { FlashMake = WINBOND_ID_BYTE0; StartIndex = WINBOND_INDEX_START; } /* * If valid flash ID, then check connection mode & size and * assign corresponding index in the Flash configuration table */ if(((FlashMake == MICRON_ID_BYTE0) || (FlashMake = SPANSION_ID_BYTE0)|| (FlashMake == WINBOND_ID_BYTE0)) && (ReadBfrPtr[3] == MICRON_ID_BYTE2_128)) { switch(QspiPtr->Config.ConnectionMode) { case XQSPIPS_CONNECTION_MODE_SINGLE: FCTIndex = FLASH_CFG_TBL_SINGLE_128_SP + StartIndex; break; case XQSPIPS_CONNECTION_MODE_PARALLEL: FCTIndex = FLASH_CFG_TBL_PARALLEL_128_SP + StartIndex; break; case XQSPIPS_CONNECTION_MODE_STACKED: FCTIndex = FLASH_CFG_TBL_STACKED_128_SP + StartIndex; break; default: FCTIndex = 0; break; } } /* 256 and 512Mbit supported only for Micron and Spansion, not Winbond */ if(((FlashMake == MICRON_ID_BYTE0) || (FlashMake = SPANSION_ID_BYTE0)) && (ReadBfrPtr[3] == MICRON_ID_BYTE2_256)) { switch(QspiPtr->Config.ConnectionMode) { case XQSPIPS_CONNECTION_MODE_SINGLE: FCTIndex = FLASH_CFG_TBL_SINGLE_256_SP + StartIndex; break; case XQSPIPS_CONNECTION_MODE_PARALLEL: FCTIndex = FLASH_CFG_TBL_PARALLEL_256_SP + StartIndex; break; case XQSPIPS_CONNECTION_MODE_STACKED: FCTIndex = FLASH_CFG_TBL_STACKED_256_SP + StartIndex; break; default: FCTIndex = 0; break; } } if(((FlashMake == MICRON_ID_BYTE0) || (FlashMake = SPANSION_ID_BYTE0)) && (ReadBfrPtr[3] == MICRON_ID_BYTE2_512)) { switch(QspiPtr->Config.ConnectionMode) { case XQSPIPS_CONNECTION_MODE_SINGLE: FCTIndex = FLASH_CFG_TBL_SINGLE_512_SP + StartIndex; break; case XQSPIPS_CONNECTION_MODE_PARALLEL: FCTIndex = FLASH_CFG_TBL_PARALLEL_512_SP + StartIndex; break; case XQSPIPS_CONNECTION_MODE_STACKED: FCTIndex = FLASH_CFG_TBL_STACKED_512_SP + StartIndex; break; default: FCTIndex = 0; break; } } /* * 1Gbit Single connection supported for Spansion. * The ConnectionMode will indicate stacked as this part has 2 SS * The device ID will indicate 512Mbit. * This configuration is handled as the above 512Mbit stacked configuration */ /* 1Gbit single, parallel and stacked supported for Micron */ if((FlashMake == MICRON_ID_BYTE0) && (ReadBfrPtr[3] == MICRON_ID_BYTE2_1G)) { switch(QspiPtr->Config.ConnectionMode) { case XQSPIPS_CONNECTION_MODE_SINGLE: FCTIndex = FLASH_CFG_TBL_SINGLE_1GB_MC; break; case XQSPIPS_CONNECTION_MODE_PARALLEL: FCTIndex = FLASH_CFG_TBL_PARALLEL_1GB_MC; break; case XQSPIPS_CONNECTION_MODE_STACKED: FCTIndex = FLASH_CFG_TBL_STACKED_1GB_MC; break; default: FCTIndex = 0; break; } } xil_printf("FlashID=0x%x 0x%x 0x%x\n\r", ReadBfrPtr[1], ReadBfrPtr[2], ReadBfrPtr[3]); 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 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. * * @return None. * * @note None. * ******************************************************************************/ void FlashErase(XQspiPs *QspiPtr, u32 Address, u32 ByteCount) { u8 WriteEnableCmd = { WRITE_ENABLE_CMD }; u8 ReadStatusCmd[] = { READ_STATUS_CMD, 0 }; /* must send 2 bytes */ u8 FlashStatus[2]; int Sector; /* * If erase size is same as the total size of the flash, use bulk erase * command */ if (ByteCount == (NUM_SECTORS * SECTOR_SIZE)) { /* * Send the write enable command to the FLASH so that it can be * written to, this needs to be sent as a seperate transfer * before the erase */ XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL, sizeof(WriteEnableCmd)); /* * Setup the bulk erase command */ WriteBuffer[COMMAND_OFFSET] = BULK_ERASE_CMD; /* * Send the bulk erase command; no receive buffer is specified * since there is nothing to receive */ XQspiPs_PolledTransfer(QspiPtr, WriteBuffer, NULL, BULK_ERASE_SIZE); /* * Wait for the 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; } } return; } /* * If the erase size is less than the total size of the flash, use * sector erase command */ for (Sector = 0; Sector < ((ByteCount / SECTOR_SIZE) + 1); Sector++) { /* * Send the write enable command to the SEEPOM so that it can be * written to, this needs to be sent as a seperate transfer * before the write */ XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL, sizeof(WriteEnableCmd)); /* * Setup the write command with the specified address and data * for the FLASH */ WriteBuffer[COMMAND_OFFSET] = SEC_ERASE_CMD; WriteBuffer[ADDRESS_1_OFFSET] = (u8)(Address >> 16); WriteBuffer[ADDRESS_2_OFFSET] = (u8)(Address >> 8); WriteBuffer[ADDRESS_3_OFFSET] = (u8)(Address & 0xFF); /* * Send the sector erase command and address; no receive buffer * is specified since there is nothing to receive */ XQspiPs_PolledTransfer(QspiPtr, WriteBuffer, NULL, SEC_ERASE_SIZE); /* * Wait for the sector erse 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; } } Address += SECTOR_SIZE; } }