zynq_lvgl/sw/swss/zynq_fsbl/qspi.c
2024-10-20 23:34:36 +08:00

860 lines
23 KiB
C

/******************************************************************************
* Copyright (c) 2012 - 2020 Xilinx, Inc. All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/
/*****************************************************************************/
/**
*
* @file qspi.c
*
* Contains code for the QSPI FLASH functionality.
*
* <pre>
* 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
* </pre>
*
* @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