/****************************************************************************** * Copyright (c) 2012 - 2020 Xilinx, Inc. All rights reserved. * SPDX-License-Identifier: MIT ******************************************************************************/ /*****************************************************************************/ /** * * @file qspi.c * * Contains code for the QSPI FLASH functionality. * *
* MODIFICATION HISTORY:
*
* Ver	Who	Date		Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a ecm	01/10/10 Initial release
* 3.00a mb  25/06/12 InitQspi, data is read first and required config bits
*                    are set
* 4.00a sg	02/28/13 Cleanup
* 					 Removed LPBK_DLY_ADJ register setting code as we use
* 					 divisor 8
* 5.00a sgd	05/17/13 Added Flash Size > 128Mbit support
* 					 Dual Stack support
*					 Fix for CR:721674 - FSBL- Failed to boot from Dual
*					                     stacked QSPI
* 6.00a kc  08/30/13 Fix for CR#722979 - Provide customer-friendly
*                                        changelogs in FSBL
*                    Fix for CR#739711 - FSBL not able to read Large QSPI
*                    					 (512M) in IO Mode
* 7.00a kc  10/25/13 Fix for CR#739968 - FSBL should do the QSPI config
*                    					 settings for Dual parallel
*                    					 configuration in IO mode
* 14.0 gan 01/13/16  Fix for CR#869081 - (2016.1)FSBL picks the qspi read
*                                        command from LQSPI_CFG register
*					 					 instead of hard coded read
*					 					 command (0x6B).
* 15.0 bsv 09/04/20  Add support for 2Gb flash parts
* 
* * @note * ******************************************************************************/ /***************************** Include Files *********************************/ #include "qspi.h" #include "image_mover.h" #ifdef XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR #include "xqspips_hw.h" #include "xqspips.h" /************************** Constant Definitions *****************************/ /* * The following constants map to the XPAR parameters created in the * xparameters.h file. They are defined here such that a user can easily * change all the needed parameters in one place. */ #define QSPI_DEVICE_ID XPAR_XQSPIPS_0_DEVICE_ID /* * The following constants define the commands which may be sent to the FLASH * device. */ #define QUAD_READ_CMD 0x6B #define READ_ID_CMD 0x9F #define WRITE_ENABLE_CMD 0x06 #define BANK_REG_RD 0x16 #define BANK_REG_WR 0x17 /* Bank register is called Extended Address Reg in Micron */ #define EXTADD_REG_RD 0xC8 #define EXTADD_REG_WR 0xC5 #define COMMAND_OFFSET 0 /* FLASH instruction */ #define ADDRESS_1_OFFSET 1 /* MSB byte of address to read or write */ #define ADDRESS_2_OFFSET 2 /* Middle byte of address to read or write */ #define ADDRESS_3_OFFSET 3 /* LSB byte of address to read or write */ #define DATA_OFFSET 4 /* Start of Data for Read/Write */ #define DUMMY_OFFSET 4 /* Dummy byte offset for fast, dual and quad reads */ #define DUMMY_SIZE 1 /* Number of dummy bytes for fast, dual and quad reads */ #define RD_ID_SIZE 4 /* Read ID command + 3 bytes ID response */ #define BANK_SEL_SIZE 2 /* BRWR or EARWR command + 1 byte bank value */ #define WRITE_ENABLE_CMD_SIZE 1 /* WE command */ /* * The following constants specify the extra bytes which are sent to the * FLASH on the QSPI interface, that are not data, but control information * which includes the command and address */ #define OVERHEAD_SIZE 4 /* * The following constants specify the max amount of data and the size of the * the buffer required to hold the data and overhead to transfer the data to * and from the FLASH. */ #define DATA_SIZE 4096 /* * The following defines are for dual flash interface. */ #define LQSPI_CR_FAST_READ 0x0000000B #define LQSPI_CR_FAST_DUAL_READ 0x0000003B #define LQSPI_CR_FAST_QUAD_READ 0x0000006B /* Fast Quad Read output */ #define LQSPI_CR_1_DUMMY_BYTE 0x00000100 /* 1 Dummy Byte between address and return data */ #define SINGLE_QSPI_CONFIG_FAST_READ (XQSPIPS_LQSPI_CR_LINEAR_MASK | \ LQSPI_CR_1_DUMMY_BYTE | \ LQSPI_CR_FAST_READ) #define SINGLE_QSPI_CONFIG_FAST_DUAL_READ (XQSPIPS_LQSPI_CR_LINEAR_MASK | \ LQSPI_CR_1_DUMMY_BYTE | \ LQSPI_CR_FAST_DUAL_READ) #define SINGLE_QSPI_CONFIG_FAST_QUAD_READ (XQSPIPS_LQSPI_CR_LINEAR_MASK | \ LQSPI_CR_1_DUMMY_BYTE | \ LQSPI_CR_FAST_QUAD_READ) #define DUAL_QSPI_CONFIG_FAST_QUAD_READ (XQSPIPS_LQSPI_CR_LINEAR_MASK | \ XQSPIPS_LQSPI_CR_TWO_MEM_MASK | \ XQSPIPS_LQSPI_CR_SEP_BUS_MASK | \ LQSPI_CR_1_DUMMY_BYTE | \ LQSPI_CR_FAST_QUAD_READ) #define DUAL_STACK_CONFIG_FAST_READ (XQSPIPS_LQSPI_CR_TWO_MEM_MASK | \ LQSPI_CR_1_DUMMY_BYTE | \ LQSPI_CR_FAST_READ) #define DUAL_STACK_CONFIG_FAST_DUAL_READ (XQSPIPS_LQSPI_CR_TWO_MEM_MASK | \ LQSPI_CR_1_DUMMY_BYTE | \ LQSPI_CR_FAST_DUAL_READ) #define DUAL_STACK_CONFIG_FAST_QUAD_READ (XQSPIPS_LQSPI_CR_TWO_MEM_MASK | \ LQSPI_CR_1_DUMMY_BYTE | \ LQSPI_CR_FAST_QUAD_READ) #define SINGLE_QSPI_IO_CONFIG_FAST_READ (LQSPI_CR_1_DUMMY_BYTE | \ LQSPI_CR_FAST_READ) #define SINGLE_QSPI_IO_CONFIG_FAST_DUAL_READ (LQSPI_CR_1_DUMMY_BYTE | \ LQSPI_CR_FAST_DUAL_READ) #define SINGLE_QSPI_IO_CONFIG_FAST_QUAD_READ (LQSPI_CR_1_DUMMY_BYTE | \ LQSPI_CR_FAST_QUAD_READ) #define DUAL_QSPI_IO_CONFIG_FAST_QUAD_READ (XQSPIPS_LQSPI_CR_TWO_MEM_MASK | \ XQSPIPS_LQSPI_CR_SEP_BUS_MASK | \ LQSPI_CR_1_DUMMY_BYTE | \ LQSPI_CR_FAST_QUAD_READ) #define QSPI_BUSWIDTH_ONE 0U #define QSPI_BUSWIDTH_TWO 1U #define QSPI_BUSWIDTH_FOUR 2U /**************************** Type Definitions *******************************/ /***************** Macros (Inline Functions) Definitions *********************/ /************************** Function Prototypes ******************************/ /************************** Variable Definitions *****************************/ XQspiPs QspiInstance; XQspiPs *QspiInstancePtr; u32 QspiFlashSize; u32 QspiFlashMake; extern u32 FlashReadBaseAddress; extern u8 LinearBootDeviceFlag; /* * The following variables are used to read and write to the eeprom and they * are global to avoid having large buffers on the stack */ u8 ReadBuffer[DATA_SIZE + DATA_OFFSET + DUMMY_SIZE]; u8 WriteBuffer[DATA_OFFSET + DUMMY_SIZE]; /******************************************************************************/ /** * * This function initializes the controller for the QSPI interface. * * @param None * * @return None * * @note None * ****************************************************************************/ u32 InitQspi(void) { XQspiPs_Config *QspiConfig; int Status; u32 ConfigCmd; 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_XQSPIPS_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); switch (XPAR_XQSPIPS_0_QSPI_BUS_WIDTH) { case QSPI_BUSWIDTH_ONE: { fsbl_printf(DEBUG_INFO,"QSPI is in 1-bit mode\r\n"); ConfigCmd = SINGLE_QSPI_CONFIG_FAST_READ; } break; case QSPI_BUSWIDTH_TWO: { fsbl_printf(DEBUG_INFO,"QSPI is in 2-bit mode\r\n"); ConfigCmd = SINGLE_QSPI_CONFIG_FAST_DUAL_READ; } break; case QSPI_BUSWIDTH_FOUR: { fsbl_printf(DEBUG_INFO,"QSPI is in 4-bit mode\r\n"); ConfigCmd = SINGLE_QSPI_CONFIG_FAST_QUAD_READ; } break; } /* * Single linear read */ XQspiPs_SetLqspiConfigReg(QspiInstancePtr, ConfigCmd); /* * Enable the controller */ XQspiPs_Enable(QspiInstancePtr); } else { switch (XPAR_XQSPIPS_0_QSPI_BUS_WIDTH) { case QSPI_BUSWIDTH_ONE: { fsbl_printf(DEBUG_INFO,"QSPI is in 1-bit mode\r\n"); ConfigCmd = SINGLE_QSPI_IO_CONFIG_FAST_READ; } break; case QSPI_BUSWIDTH_TWO: { fsbl_printf(DEBUG_INFO,"QSPI is in 2-bit mode\r\n"); ConfigCmd = SINGLE_QSPI_IO_CONFIG_FAST_DUAL_READ; } break; case QSPI_BUSWIDTH_FOUR: { fsbl_printf(DEBUG_INFO,"QSPI is in 4-bit mode\r\n"); ConfigCmd = SINGLE_QSPI_IO_CONFIG_FAST_QUAD_READ; } break; } /* * Single flash IO read */ XQspiPs_SetLqspiConfigReg(QspiInstancePtr, ConfigCmd); /* * Enable the controller */ XQspiPs_Enable(QspiInstancePtr); } } if (XPAR_XQSPIPS_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_FAST_QUAD_READ); /* * Enable the controller */ XQspiPs_Enable(QspiInstancePtr); } else { /* * Dual flash IO read */ XQspiPs_SetLqspiConfigReg(QspiInstancePtr, DUAL_QSPI_IO_CONFIG_FAST_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_XQSPIPS_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 */ switch (XPAR_XQSPIPS_0_QSPI_BUS_WIDTH) { case QSPI_BUSWIDTH_ONE: { fsbl_printf(DEBUG_INFO,"QSPI is in 1-bit mode\r\n"); ConfigCmd = DUAL_STACK_CONFIG_FAST_READ; } break; case QSPI_BUSWIDTH_TWO: { fsbl_printf(DEBUG_INFO,"QSPI is in 2-bit mode\r\n"); ConfigCmd = DUAL_STACK_CONFIG_FAST_DUAL_READ; } break; case QSPI_BUSWIDTH_FOUR: { fsbl_printf(DEBUG_INFO,"QSPI is in 4-bit mode\r\n"); ConfigCmd = DUAL_STACK_CONFIG_FAST_QUAD_READ; } break; } XQspiPs_SetLqspiConfigReg(QspiInstancePtr, ConfigCmd); } 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 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 "); } else if(ReadBuffer[1] == MACRONIX_ID) { QspiFlashMake = MACRONIX_ID; fsbl_printf(DEBUG_INFO, "MACRONIX "); } else if(ReadBuffer[1] == ISSI_ID) { QspiFlashMake = ISSI_ID; fsbl_printf(DEBUG_INFO, "ISSI "); } /* * Deduce flash Size */ if (ReadBuffer[3] == FLASH_SIZE_ID_8M) { QspiFlashSize = FLASH_SIZE_8M; fsbl_printf(DEBUG_INFO, "8M Bits\r\n"); } else if (ReadBuffer[3] == FLASH_SIZE_ID_16M) { QspiFlashSize = FLASH_SIZE_16M; fsbl_printf(DEBUG_INFO, "16M Bits\r\n"); } else if (ReadBuffer[3] == FLASH_SIZE_ID_32M) { QspiFlashSize = FLASH_SIZE_32M; fsbl_printf(DEBUG_INFO, "32M Bits\r\n"); } else if (ReadBuffer[3] == FLASH_SIZE_ID_64M) { QspiFlashSize = FLASH_SIZE_64M; fsbl_printf(DEBUG_INFO, "64M Bits\r\n"); } else 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) || (ReadBuffer[3] == MACRONIX_FLASH_1_8_V_MX66_ID_512) || (ReadBuffer[3] == MACRONIX_FLASH_SIZE_ID_512M)) { QspiFlashSize = FLASH_SIZE_512M; fsbl_printf(DEBUG_INFO, "512M Bits\r\n"); } else if ((ReadBuffer[3] == FLASH_SIZE_ID_1G) || (ReadBuffer[3] == MACRONIX_FLASH_SIZE_ID_1G)) { QspiFlashSize = FLASH_SIZE_1G; fsbl_printf(DEBUG_INFO, "1G Bits\r\n"); } else if ((ReadBuffer[3] == FLASH_SIZE_ID_2G) || (ReadBuffer[3] == MACRONIX_FLASH_SIZE_ID_2G)) { QspiFlashSize = FLASH_SIZE_2G; fsbl_printf(DEBUG_INFO, "2G Bits\r\n"); } 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 */ 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_XQSPIPS_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_XQSPIPS_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 %lu\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_XQSPIPS_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_XQSPIPS_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_XQSPIPS_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 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 * Macronix bank select is same as Micron */ if (QspiFlashMake == MICRON_ID || QspiFlashMake == MACRONIX_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 || QspiFlashMake == MACRONIX_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; } #endif