fsbl_qspi.c
/******************************************************************************
*
* Copyright (C) 2015 - 17 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xfsbl_qspi.c
*
* This is the file which contains qspi related code for the FSBL.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00 kc 10/21/13 Initial release
* 2.00 sg 12/03/15 Added GQSPI driver support
* 32Bit boot mode support
* 3.0 bv 12/02/16 Made compliance to MISRAC 2012 guidelines
* ds 01/03/17 Add support for Micron QSPI 2G part
* 4.0 tjs 10/16/18 Added support for QPI mode in Macronix flash parts.
* sk 03/13/19 Added dual parallel support and QPI support for 24bit
* boot mode for Macronix flash parts.
*
* </pre>
*
* @note
*
******************************************************************************/
/***************************** Include Files *********************************/
#include "xfsbl_hw.h"
#include "xparameters.h"
#include "xil_cache.h"
#ifdef XFSBL_QSPI
#include "xqspipsu.h"
#include "xfsbl_qspi.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_XQSPIPSU_0_DEVICE_ID
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
static u32 FlashReadID(XQspiPsu *QspiPsuPtr);
static u32 MacronixEnable4B(XQspiPsu *QspiPsuPtr);
static u32 MacronixEnableQPIMode(XQspiPsu *QspiPsuPtr, int Enable);
/************************** Variable Definitions *****************************/
static XQspiPsu QspiPsuInstance;
static u32 QspiFlashSize=0U;
static u32 QspiFlashMake=0U;
static u32 ReadCommand=0U;
static XQspiPsu_Msg FlashMsg[5];
static u8 IssiIdFlag=0U;
static u8 TxBfrPtr __attribute__ ((aligned(32)));
static u8 ReadBuffer[10] __attribute__ ((aligned(32)));
static u8 WriteBuffer[10] __attribute__ ((aligned(32)));
static u32 MacronixFlash = 0U;
void delay_ms(int count)
{
unsigned int value = count*1670000;
unsigned int i=0;
while(1)
{
i++;
if(i > (value-10))
{
XFsbl_Printf(DEBUG_PRINT_ALWAYS,"\n\r");
break;
}
}
}
int Set_S25HL512T_config(void)
{
int cfg1_addr = 0x02;
int cfg3_addr = 0x04;
u8 cfg1_default = 0x02; //Quad data width is 4bits.
u8 cfg3_default = 0x08; //Uniform Sector Architecture
u8 value;
XFsbl_Qspi32Init(0); //for sd boot,first init the qspi
Flash_enter_4byte_address(&QspiPsuInstance);
Flash_read_any_register(&QspiPsuInstance,cfg1_addr,&value);
if(value != cfg1_default)
{
Flash_write_enable(&QspiPsuInstance);
Flash_write_any_register(&QspiPsuInstance,cfg1_addr,cfg1_default);
XFsbl_Printf(DEBUG_PRINT_ALWAYS,
"Qspi Quad width reset to 4 bits,value = 0x%x \n\r",value);
usleep_A53(500000);
}
Flash_read_any_register(&QspiPsuInstance,cfg3_addr,&value);
if(value != cfg3_default)
{
Flash_write_enable(&QspiPsuInstance);
Flash_write_any_register(&QspiPsuInstance,cfg3_addr,cfg3_default);
XFsbl_Printf(DEBUG_PRINT_ALWAYS,
"Qspi reset to uniform sector,value = 0x%x \n\r",value);
usleep_A53(500000);
}
return 0;
}
/*
* For S25HL512T
*/
int Flash_enter_4byte_address(XQspiPsu *QspiPsuPtr)
{
int Status;
XQspiPsu_Msg FlashMsg[5];
/*
* set 4 byte address mode.
*/
TxBfrPtr = 0xb7;
FlashMsg[0].TxBfrPtr = &TxBfrPtr;
FlashMsg[0].RxBfrPtr = NULL;
FlashMsg[0].ByteCount = 1;
FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 1);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
return 0;
}
/*
* For S25HL512T
*/
int Flash_write_enable(XQspiPsu *QspiPsuPtr)
{
int Status;
/*
* set 4 byte address mode.
*/
TxBfrPtr = 0x06;
FlashMsg[0].TxBfrPtr = &TxBfrPtr;
FlashMsg[0].RxBfrPtr = NULL;
FlashMsg[0].ByteCount = 1;
FlashMsg[0].BusWidth = 1; //XQSPIPSU_SELECT_MODE_SPI
FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 1);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
return 0;
}
/*
* For S25HL512T
*/
int Flash_read_any_register(XQspiPsu *QspiPsuPtr,int address,u8 *rxbuffer)
{
int Status;
u8 wrbuffer[8];
XQspiPsu_Msg FlashMsg[5];
wrbuffer[0] = 0x65;
wrbuffer[1] = (address>>24)&0xff;
wrbuffer[2] = (address>>16)&0xff;
wrbuffer[3] = (address>>8)&0xff;
wrbuffer[4] = (address>>0)&0xff;
FlashMsg[0].TxBfrPtr = wrbuffer;
FlashMsg[0].RxBfrPtr = NULL;
FlashMsg[0].ByteCount = 5;
FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
FlashMsg[1].TxBfrPtr = NULL;
FlashMsg[1].RxBfrPtr = NULL;
FlashMsg[1].ByteCount = DUMMY_CLOCKS;
FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
FlashMsg[1].Flags = 0;
FlashMsg[2].TxBfrPtr = NULL;
FlashMsg[2].RxBfrPtr = rxbuffer;
FlashMsg[2].ByteCount = 1;
FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
FlashMsg[2].Flags = XQSPIPSU_MSG_FLAG_RX;
Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 3);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
return 0;
}
/*
* For S25HL512T
*/
int Flash_write_any_register(XQspiPsu *QspiPsuPtr,int address,u8 value)
{
int Status;
XQspiPsu_Msg FlashMsg[5];
u8 wrbuffer[8],value1 = value;
int DiscardByteCnt;
wrbuffer[0] = 0x71;
wrbuffer[1] = (u8)((address & 0xFF000000) >> 24);
wrbuffer[2] = (u8)((address & 0xFF0000) >> 16);
wrbuffer[3] = (u8)((address & 0xFF00) >> 8);
wrbuffer[4] = (u8)(address & 0xFF);
DiscardByteCnt = 5;
FlashMsg[0].TxBfrPtr = wrbuffer;
FlashMsg[0].RxBfrPtr = NULL;
FlashMsg[0].ByteCount = DiscardByteCnt;
FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
FlashMsg[1].TxBfrPtr = &value1;
FlashMsg[1].RxBfrPtr = NULL;
FlashMsg[1].ByteCount = 1;
FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_TX;
Status = XQspiPsu_PolledTransfer(QspiPsuPtr, FlashMsg, 2);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
return 0;
}
/******************************************************************************
*
* 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.
*
******************************************************************************/
static u32 FlashReadID(XQspiPsu *QspiPsuPtr)
{
s32 Status;
u32 UStatus;
/*
* Read ID
*/
TxBfrPtr = READ_ID_CMD;
FlashMsg[0].TxBfrPtr = &TxBfrPtr;
FlashMsg[0].RxBfrPtr = NULL;
FlashMsg[0].ByteCount = 1;
FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
FlashMsg[1].TxBfrPtr = NULL;
FlashMsg[1].RxBfrPtr = ReadBuffer;
FlashMsg[1].ByteCount = 4;
FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
Status = XQspiPsu_PolledTransfer(QspiPsuPtr, &FlashMsg[0], 2);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_FAILURE;
goto END;
}
XFsbl_Printf(DEBUG_GENERAL, "FlashID=0x%x 0x%x 0x%x\n\r", ReadBuffer[0],
ReadBuffer[1], ReadBuffer[2]);
/*
* Deduce flash make
*/
MacronixFlash = 0U;
if (ReadBuffer[0] == MICRON_ID) {
QspiFlashMake = MICRON_ID;
XFsbl_Printf(DEBUG_INFO, "MICRON ");
} else if(ReadBuffer[0] == SPANSION_ID) {
QspiFlashMake = SPANSION_ID;
XFsbl_Printf(DEBUG_INFO, "SPANSION ");
} else if(ReadBuffer[0] == WINBOND_ID) {
QspiFlashMake = WINBOND_ID;
XFsbl_Printf(DEBUG_INFO, "WINBOND ");
} else if(ReadBuffer[0] == MACRONIX_ID) {
QspiFlashMake = MACRONIX_ID;
XFsbl_Printf(DEBUG_INFO, "MACRONIX ");
MacronixFlash = 1U;
} else if(ReadBuffer[0] == ISSI_ID) {
QspiFlashMake = ISSI_ID;
XFsbl_Printf(DEBUG_INFO, "ISSI ");
}
else if(ReadBuffer[0] == 0x34) //spansion s25hl512t
{
QspiFlashMake = 0x34;
XFsbl_Printf(DEBUG_INFO, "SPANSION ");
}
else {
UStatus = XFSBL_ERROR_UNSUPPORTED_QSPI;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_UNSUPPORTED_QSPI\r\n");
goto END;
}
/*
* Deduce flash Size
*/
if (ReadBuffer[2] == FLASH_SIZE_ID_8M) {
QspiFlashSize = FLASH_SIZE_8M;
XFsbl_Printf(DEBUG_INFO, "8M Bits\r\n");
} else if (ReadBuffer[2] == FLASH_SIZE_ID_16M) {
QspiFlashSize = FLASH_SIZE_16M;
XFsbl_Printf(DEBUG_INFO, "16M Bits\r\n");
} else if (ReadBuffer[2] == FLASH_SIZE_ID_32M) {
QspiFlashSize = FLASH_SIZE_32M;
XFsbl_Printf(DEBUG_INFO, "32M Bits\r\n");
} else if (ReadBuffer[2] == FLASH_SIZE_ID_64M) {
QspiFlashSize = FLASH_SIZE_64M;
XFsbl_Printf(DEBUG_INFO, "64M Bits\r\n");
} else if (ReadBuffer[2] == FLASH_SIZE_ID_128M) {
QspiFlashSize = FLASH_SIZE_128M;
XFsbl_Printf(DEBUG_INFO, "128M Bits\r\n");
} else if ((ReadBuffer[2] == FLASH_SIZE_ID_256M)
|| (ReadBuffer[2] == MACRONIX_FLASH_1_8_V_MX25_ID_256)) {
QspiFlashSize = FLASH_SIZE_256M;
XFsbl_Printf(DEBUG_INFO, "256M Bits\r\n");
} else if ((ReadBuffer[2] == FLASH_SIZE_ID_512M)
|| (ReadBuffer[2] == MACRONIX_FLASH_SIZE_ID_512M)
|| (ReadBuffer[2] == MACRONIX_FLASH_1_8_V_MX66_ID_512)) {
QspiFlashSize = FLASH_SIZE_512M;
XFsbl_Printf(DEBUG_INFO, "512M Bits\r\n");
} else if ((ReadBuffer[2] == FLASH_SIZE_ID_1G)
|| (ReadBuffer[2] == MACRONIX_FLASH_SIZE_ID_1G)
|| (ReadBuffer[2] == MACRONIX_FLASH_1_8_V_SIZE_ID_1G)) {
QspiFlashSize = FLASH_SIZE_1G;
XFsbl_Printf(DEBUG_INFO, "1G Bits\r\n");
} else if (ReadBuffer[2] == FLASH_SIZE_ID_2G) {
QspiFlashSize = FLASH_SIZE_2G;
XFsbl_Printf(DEBUG_INFO, "2G Bits\r\n");
}else {
UStatus = XFSBL_ERROR_UNSUPPORTED_QSPI;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_UNSUPPORTED_QSPI\r\n");
goto END;
}
/* Enable ID flag for ISSI 128M Qspi to enable
* DUAL_READ_CMD_24BIT ReadCommand
*/
if((QspiFlashMake==ISSI_ID) && (QspiFlashSize==FLASH_SIZE_128M))
{
IssiIdFlag=1;
}
UStatus = XFSBL_SUCCESS;
END:
return UStatus;
}
/*****************************************************************************/
/**
* This function is used to initialize the qspi controller and driver
*
* @param None
*
* @return None
*
*****************************************************************************/
u32 XFsbl_Qspi24Init(u32 DeviceFlags)
{
XQspiPsu_Config *QspiConfig;
s32 Status;
u32 UStatus;
u32 QspiMode;
/**
* Initialize the QSPI driver so that it's ready to use
*/
QspiConfig = XQspiPsu_LookupConfig(QSPI_DEVICE_ID);
if (NULL == QspiConfig) {
UStatus = XFSBL_ERROR_QSPI_INIT;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_INIT\r\n");
goto END;
}
Status = XQspiPsu_CfgInitialize(&QspiPsuInstance, QspiConfig,
QspiConfig->BaseAddress);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_ERROR_QSPI_INIT;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_INIT\r\n");
goto END;
}
/*
* Set Manual Start
*/
Status = XQspiPsu_SetOptions(&QspiPsuInstance, XQSPIPSU_MANUAL_START_OPTION);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_ERROR_QSPI_MANUAL_START;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_MANUAL_START\r\n");
goto END;
}
/*
* Set the pre-scaler for QSPI clock
*/
Status = XQspiPsu_SetClkPrescaler(&QspiPsuInstance, XQSPIPSU_CLK_PRESCALE_8);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_ERROR_QSPI_PRESCALER_CLK;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_PRESCALER_CLK\r\n");
goto END;
}
XQspiPsu_SelectFlash(&QspiPsuInstance,
XQSPIPSU_SELECT_FLASH_CS_LOWER, XQSPIPSU_SELECT_FLASH_BUS_LOWER);
/*
* Configure the qspi in linear mode if running in XIP
* TBD: XIP Support
*/
switch ((u32)(XPAR_PSU_QSPI_0_QSPI_MODE)) {
case XQSPIPSU_CONNECTION_MODE_SINGLE:
{
XFsbl_Printf(DEBUG_INFO,"QSPI is in single flash connection\r\n");
} break;
case XQSPIPSU_CONNECTION_MODE_PARALLEL:
{
XFsbl_Printf(DEBUG_INFO,"QSPI is in Dual Parallel connection\r\n");
} break;
case XQSPIPSU_CONNECTION_MODE_STACKED:
{
XFsbl_Printf(DEBUG_INFO,"QSPI is in Dual Stack connection\r\n");
}break;
default:
{
Status = XFSBL_ERROR_INVALID_QSPI_CONNECTION;
XFsbl_Printf(DEBUG_GENERAL,
"XFSBL_ERROR_INVALID_QSPI_CONNECTION\r\n");
}
break;
}
if(Status != XFSBL_SUCCESS) {
UStatus = (u32)Status;
goto END;
}
switch (QspiPsuInstance.Config.BusWidth) {
case XFSBL_QSPI_BUSWIDTH_ONE:
{
XFsbl_Printf(DEBUG_INFO,"QSPI is using 1 bit bus\r\n");
ReadCommand = FAST_READ_CMD_24BIT;
} break;
case XFSBL_QSPI_BUSWIDTH_TWO:
{
XFsbl_Printf(DEBUG_INFO,"QSPI is using 2 bit bus\r\n");
ReadCommand = DUAL_READ_CMD_24BIT;
} break;
case XFSBL_QSPI_BUSWIDTH_FOUR:
{
XFsbl_Printf(DEBUG_INFO,"QSPI is using 4 bit bus\r\n");
ReadCommand = QUAD_READ_CMD_24BIT;
}break;
}
/**
* Read Flash ID and extract Manufacture and Size information
*/
UStatus = FlashReadID(&QspiPsuInstance);
if (UStatus != XFSBL_SUCCESS) {
goto END;
}
/**
* add code for 1x, 2x and 4x
*
*/
if(IssiIdFlag==1U) {
ReadCommand = DUAL_READ_CMD_24BIT;
}
if ((MacronixFlash == 1U) &&
(QspiPsuInstance.Config.BusWidth == XFSBL_QSPI_BUSWIDTH_FOUR)) {
ReadCommand = QUAD_READ_CMD_24BIT2;
}
/**
* add code: For a Stacked connection, read second Flash ID
*/
QspiMode=QspiPsuInstance.Config.ConnectionMode;
if ((QspiMode ==(XQSPIPSU_CONNECTION_MODE_PARALLEL)) ||
(QspiMode ==(XQSPIPSU_CONNECTION_MODE_STACKED) )) {
QspiFlashSize = 2 * QspiFlashSize;
}
END:
return UStatus;
}
/******************************************************************************
*
* This functions translates the address based on the type of interconnection.
* In case of stacked, this function asserts the corresponding slave select.
*
* @param Address which is to be accessed
*
* @return QspiAddr is the actual flash address to be accessed - for single
* it is unchanged; for stacked, the lower flash size is subtracted;
* for parallel the address is divided by 2.
*
* @note None.
*
*
******************************************************************************/
static u32 XFsbl_GetQspiAddr(u32 Address )
{
u32 RealAddr;
switch(QspiPsuInstance.Config.ConnectionMode) {
case XQSPIPSU_CONNECTION_MODE_SINGLE:
XQspiPsu_SelectFlash(&QspiPsuInstance,
XQSPIPSU_SELECT_FLASH_CS_LOWER,
XQSPIPSU_SELECT_FLASH_BUS_LOWER);
RealAddr = Address;
break;
case XQSPIPSU_CONNECTION_MODE_STACKED:
/*
* Select lower or upper Flash based on sector address
*/
if(Address >= (QspiFlashSize/2U)) {
XQspiPsu_SelectFlash(&QspiPsuInstance,
XQSPIPSU_SELECT_FLASH_CS_UPPER,
XQSPIPSU_SELECT_FLASH_BUS_LOWER);
/*
* Subtract first flash size when accessing second flash
*/
RealAddr = Address - (QspiFlashSize/2U);
}else{
/*
* Set selection to L_PAGE
*/
XQspiPsu_SelectFlash(&QspiPsuInstance,
XQSPIPSU_SELECT_FLASH_CS_LOWER,
XQSPIPSU_SELECT_FLASH_BUS_LOWER);
RealAddr = Address;
}
break;
case XQSPIPSU_CONNECTION_MODE_PARALLEL:
/*
* The effective address in each flash is the actual
* address / 2
*/
XQspiPsu_SelectFlash(&QspiPsuInstance,
XQSPIPSU_SELECT_FLASH_CS_BOTH, XQSPIPSU_SELECT_FLASH_BUS_BOTH);
RealAddr = Address / 2U;
break;
default:
/*
* We should never reach here as error will be triggered during
* QSPI Init for invalid connection mode. Hence, assign a value (0)
* to RealAddr, to avoid warning.
*/
RealAddr = 0U;
break;
}
return(RealAddr);
}
/******************************************************************************
*
* 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.
*
*
******************************************************************************/
static u32 SendBankSelect(u32 BankSel)
{
s32 Status;
u32 UStatus;
/*
* 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
*/
TxBfrPtr = WRITE_ENABLE_CMD;
FlashMsg[0].TxBfrPtr = &TxBfrPtr;
FlashMsg[0].RxBfrPtr = NULL;
FlashMsg[0].ByteCount = 1;
FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
Status = XQspiPsu_PolledTransfer(&QspiPsuInstance, &FlashMsg[0], 1);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_ERROR_QSPI_READ;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n");
goto END;
}
/*
* Send the Extended address register write command
* written, no receive buffer required
*/
WriteBuffer[COMMAND_OFFSET] = EXTADD_REG_WR_CMD;
WriteBuffer[ADDRESS_1_OFFSET] = (u8)BankSel;
FlashMsg[0].TxBfrPtr = WriteBuffer;
FlashMsg[0].RxBfrPtr = NULL;
FlashMsg[0].ByteCount = 2;
FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
Status = XQspiPsu_PolledTransfer(&QspiPsuInstance, &FlashMsg[0], 1);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_ERROR_QSPI_READ;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n");
goto END;
}
}
if (QspiFlashMake == SPANSION_ID) {
/*
* Send the Extended address register write command
* written, no receive buffer required
*/
WriteBuffer[COMMAND_OFFSET] = BANK_REG_WR_CMD;
WriteBuffer[ADDRESS_1_OFFSET] = (u8)BankSel;
FlashMsg[0].TxBfrPtr = WriteBuffer;
FlashMsg[0].RxBfrPtr = NULL;
FlashMsg[0].ByteCount = 2;
FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
Status = XQspiPsu_PolledTransfer(&QspiPsuInstance, &FlashMsg[0], 1);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_ERROR_QSPI_READ;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n");
goto END;
}
}
/*
* For testing - Read bank to verify
*/
if ((QspiFlashMake == MICRON_ID) || (QspiFlashMake == MACRONIX_ID)) {
/*
* Extended address register read command
*/
WriteBuffer[COMMAND_OFFSET] = EXTADD_REG_RD_CMD;
FlashMsg[0].TxBfrPtr = WriteBuffer;
FlashMsg[0].RxBfrPtr = NULL;
FlashMsg[0].ByteCount = 1;
FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
FlashMsg[1].TxBfrPtr = NULL;
FlashMsg[1].RxBfrPtr = ReadBuffer;
FlashMsg[1].ByteCount = 1;
FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
Status = XQspiPsu_PolledTransfer(&QspiPsuInstance, &FlashMsg[0], 2);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_ERROR_QSPI_READ;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n");
goto END;
}
}
if (QspiFlashMake == SPANSION_ID) {
/*
* Bank register read command
*/
WriteBuffer[COMMAND_OFFSET] = BANK_REG_RD_CMD;
FlashMsg[0].TxBfrPtr = WriteBuffer;
FlashMsg[0].RxBfrPtr = NULL;
FlashMsg[0].ByteCount = 1;
FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
FlashMsg[1].TxBfrPtr = NULL;
FlashMsg[1].RxBfrPtr = ReadBuffer;
FlashMsg[1].ByteCount = 1;
FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_RX;
Status = XQspiPsu_PolledTransfer(&QspiPsuInstance, &FlashMsg[0], 2);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_ERROR_QSPI_READ;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n");
goto END;
}
if (ReadBuffer[0] != BankSel) {
XFsbl_Printf(DEBUG_INFO, "Bank Select %d != Register Read %d\n\r", BankSel,
ReadBuffer[0]);
UStatus = XFSBL_ERROR_QSPI_READ;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n");
goto END;
}
}
UStatus = XFSBL_SUCCESS;
/* Winbond can be added here */
END:
return UStatus;
}
/*****************************************************************************/
/**
* This function is used to copy the data from QSPI flash to destination
* address
*
* @param SrcAddress is the address of the QSPI flash where copy should
* start from
*
* @param DestAddress is the address of the destination where it
* should copy to
*
* @param Length Length of the bytes to be copied
*
* @return
* - XFSBL_SUCCESS for successful copy
* - errors as mentioned in xfsbl_error.h
*
*****************************************************************************/
u32 XFsbl_Qspi24Copy(u32 SrcAddress, PTRSIZE DestAddress, u32 Length)
{
u32 Status;
u32 QspiAddr, OrigAddr;
u32 BankSel;
u32 RemainingBytes;
u32 TransferBytes;
u32 DiscardByteCnt;
u8 BankSwitchFlag=0U;
u32 BankSize;
u32 BankMask;
s32 SStatus;
XFsbl_Printf(DEBUG_INFO,"QSPI Reading Src 0x%0lx, Dest %0lx, Length %0lx\r\n",
SrcAddress, DestAddress, Length);
/**
* Check the read length with Qspi flash size
*/
if ((SrcAddress + Length) > QspiFlashSize)
{
Status = XFSBL_ERROR_QSPI_LENGTH;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_LENGTH\r\n");
goto END;
}
/* Multiply bank size & mask in case of Dual Parallel */
if (QspiPsuInstance.Config.ConnectionMode ==
XQSPIPSU_CONNECTION_MODE_PARALLEL){
BankSize = SINGLEBANKSIZE * 2U;
BankMask = SINGLEBANKMASK * 2U;
}
else
{
BankSize = SINGLEBANKSIZE;
BankMask = SINGLEBANKMASK;
}
/**
* Update no of bytes to be copied
*/
RemainingBytes = Length;
while(RemainingBytes > 0U) {
if (RemainingBytes > DMA_DATA_TRAN_SIZE)
{
TransferBytes = DMA_DATA_TRAN_SIZE;
} else {
TransferBytes = RemainingBytes;
}
/**
* Translate address based on type of connection
* If stacked assert the slave select based on address
*/
QspiAddr = XFsbl_GetQspiAddr((u32 )SrcAddress);
/**
* Multiply address by 2 in case of Dual Parallel
* This address is used to calculate the bank crossing
* condition
*/
if (QspiPsuInstance.Config.ConnectionMode ==
XQSPIPSU_CONNECTION_MODE_PARALLEL){
OrigAddr = QspiAddr * 2U;
} else {
OrigAddr = QspiAddr;
}
/**
* Select bank
* check logic for DualQspi
*/
if(QspiFlashSize > BankSize) {
BankSel = QspiAddr/BANKSIZE;
Status = SendBankSelect(BankSel);
if (Status != XFSBL_SUCCESS) {
Status = XFSBL_ERROR_QSPI_READ;
XFsbl_Printf(DEBUG_GENERAL,
"XFSBL_ERROR_QSPI_READ\r\n");
goto END;
}
}
/**
* If data to be read spans beyond the current bank, then
* calculate Transfer Bytes in current bank. Else
* transfer bytes are same
*/
if ((OrigAddr & BankMask) != ((OrigAddr + TransferBytes) & BankMask)) {
TransferBytes = (OrigAddr & BankMask) + BankSize - OrigAddr;
}
XFsbl_Printf(DEBUG_INFO,".");
XFsbl_Printf(DEBUG_DETAILED,
"QSPI Read Src 0x%0lx, Dest %0lx, Length %0lx\r\n",
QspiAddr, DestAddress, TransferBytes);
/**
* Setup the read command with the specified address and data for the
* Flash
*/
if ((MacronixFlash == 1U) &&
(QspiPsuInstance.Config.BusWidth == XFSBL_QSPI_BUSWIDTH_FOUR)) {
/* Enable QPI mode */
SStatus = MacronixEnableQPIMode(&QspiPsuInstance, ENABLE_QPI);
if (SStatus != XFSBL_SUCCESS) {
Status = XFSBL_ERROR_QSPI_READ;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n");
goto END;
}
/*Command*/
WriteBuffer[COMMAND_OFFSET] = (u8)ReadCommand;
DiscardByteCnt = 1;
/*MACRONIX is in QPI MODE 4-4-4*/
FlashMsg[0].TxBfrPtr = WriteBuffer;
FlashMsg[0].RxBfrPtr = NULL;
FlashMsg[0].ByteCount = DiscardByteCnt;
FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI;
FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
/*Address*/
WriteBuffer[ADDRESS_1_OFFSET] = (u8)((QspiAddr & 0xFF0000U) >> 16);
WriteBuffer[ADDRESS_2_OFFSET] = (u8)((QspiAddr & 0xFF00U) >> 8);
WriteBuffer[ADDRESS_3_OFFSET] = (u8)(QspiAddr & 0xFFU);
DiscardByteCnt = 3;
FlashMsg[1].TxBfrPtr = &WriteBuffer[ADDRESS_1_OFFSET];
FlashMsg[1].RxBfrPtr = NULL;
FlashMsg[1].ByteCount = DiscardByteCnt;
FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI;
FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_TX;
/*Dummy*/
/*Default Dummy is 6 when QPI READ MODE(ECH)*/
FlashMsg[2].TxBfrPtr = NULL;
FlashMsg[2].RxBfrPtr = NULL;
FlashMsg[2].ByteCount = DUMMY_CLOCKS_MACRONIX;
FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI;
FlashMsg[2].Flags = 0U;
/*Data*/
FlashMsg[3].TxBfrPtr = NULL;
FlashMsg[3].RxBfrPtr = (u8 *)DestAddress;
FlashMsg[3].ByteCount = TransferBytes;
FlashMsg[3].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI;
FlashMsg[3].Flags = XQSPIPSU_MSG_FLAG_RX;
if(QspiPsuInstance.Config.ConnectionMode ==
XQSPIPSU_CONNECTION_MODE_PARALLEL){
FlashMsg[3].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
}
SStatus = XQspiPsu_PolledTransfer(&QspiPsuInstance, &FlashMsg[0], 4);
if (SStatus != XFSBL_SUCCESS) {
Status = XFSBL_ERROR_QSPI_READ;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n");
goto END;
}
/* Disable QPI mode */
SStatus = MacronixEnableQPIMode(&QspiPsuInstance, DISABLE_QPI);
if (SStatus != XFSBL_SUCCESS) {
Status = XFSBL_ERROR_QSPI_READ;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n");
goto END;
}
} else {
WriteBuffer[COMMAND_OFFSET] = (u8)ReadCommand;
WriteBuffer[ADDRESS_1_OFFSET] = (u8)((QspiAddr & 0xFF0000U) >> 16);
WriteBuffer[ADDRESS_2_OFFSET] = (u8)((QspiAddr & 0xFF00U) >> 8);
WriteBuffer[ADDRESS_3_OFFSET] = (u8)(QspiAddr & 0xFFU);
DiscardByteCnt = 4;
FlashMsg[0].TxBfrPtr = WriteBuffer;
FlashMsg[0].RxBfrPtr = NULL;
FlashMsg[0].ByteCount = DiscardByteCnt;
FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
/* It is recommended to have a separate entry for dummy */
if ((ReadCommand == FAST_READ_CMD_24BIT) || (ReadCommand == DUAL_READ_CMD_24BIT) ||
(ReadCommand == QUAD_READ_CMD_24BIT)) {
/* Update Dummy cycles as per flash specs for QUAD IO */
/*
* It is recommended that Bus width value during dummy
* phase should be same as data phase
*/
if (ReadCommand == FAST_READ_CMD_24BIT) {
FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
}
if (ReadCommand == DUAL_READ_CMD_24BIT) {
FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_DUALSPI;
}
if (ReadCommand == QUAD_READ_CMD_24BIT) {
FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI;
}
FlashMsg[1].TxBfrPtr = NULL;
FlashMsg[1].RxBfrPtr = NULL;
FlashMsg[1].ByteCount = DUMMY_CLOCKS;
FlashMsg[1].Flags = 0U;
}
if (ReadCommand == FAST_READ_CMD_24BIT) {
FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
}
if (ReadCommand == DUAL_READ_CMD_24BIT) {
FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_DUALSPI;
}
if (ReadCommand == QUAD_READ_CMD_24BIT) {
FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI;
}
FlashMsg[2].TxBfrPtr = NULL;
FlashMsg[2].RxBfrPtr = (u8 *)DestAddress;
FlashMsg[2].ByteCount = TransferBytes;
FlashMsg[2].Flags = XQSPIPSU_MSG_FLAG_RX;
if(QspiPsuInstance.Config.ConnectionMode ==
XQSPIPSU_CONNECTION_MODE_PARALLEL){
FlashMsg[2].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
}
/**
* 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
*/
SStatus = XQspiPsu_PolledTransfer(&QspiPsuInstance, &FlashMsg[0], 3);
if (SStatus != XFSBL_SUCCESS) {
Status = XFSBL_ERROR_QSPI_READ;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n");
goto END;
}
}
/**
* Update the variables
*/
RemainingBytes -= TransferBytes;
DestAddress += TransferBytes;
SrcAddress += TransferBytes;
}
if(BankSwitchFlag == 1U)
{
/*
* Reset Bank selection to zero
*/
Status = SendBankSelect(0);
if (Status != XFSBL_SUCCESS) {
Status = XFSBL_ERROR_QSPI_READ;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n");
goto END;
}
}
else
{
Status = XFSBL_SUCCESS;
}
END:
return (u32)Status;
}
/*****************************************************************************/
/**
* This function is used to release the Qspi settings
*
* @param None
*
* @return None
*
*****************************************************************************/
u32 XFsbl_Qspi24Release(void)
{
u32 Status = XFSBL_SUCCESS;
return Status;
}
/*****************************************************************************/
/**
* This function is used to initialize the qspi controller and driver
*
* @param None
*
* @return None
*
*****************************************************************************/
u32 XFsbl_Qspi32Init(u32 DeviceFlags)
{
XQspiPsu_Config *QspiConfig;
s32 Status;
u32 QspiMode;
u32 UStatus;
/**
* Initialize the QSPI driver so that it's ready to use
*/
QspiConfig = XQspiPsu_LookupConfig(QSPI_DEVICE_ID);
if (NULL == QspiConfig) {
UStatus = XFSBL_ERROR_QSPI_INIT;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_INIT\r\n");
goto END;
}
Status = XQspiPsu_CfgInitialize(&QspiPsuInstance, QspiConfig,
QspiConfig->BaseAddress);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_ERROR_QSPI_INIT;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_INIT\r\n");
goto END;
}
/*
* Set Manual Start
*/
Status = XQspiPsu_SetOptions(&QspiPsuInstance, XQSPIPSU_MANUAL_START_OPTION);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_ERROR_QSPI_MANUAL_START;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_MANUAL_START\r\n");
goto END;
}
/*
* Set the pre-scaler for QSPI clock
*/
Status = XQspiPsu_SetClkPrescaler(&QspiPsuInstance, XQSPIPSU_CLK_PRESCALE_4);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_ERROR_QSPI_PRESCALER_CLK;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_PRESCALER_CLK\r\n");
goto END;
}
XQspiPsu_SelectFlash(&QspiPsuInstance,
XQSPIPSU_SELECT_FLASH_CS_LOWER, XQSPIPSU_SELECT_FLASH_BUS_LOWER);
/*
* Configure the qspi in linear mode if running in XIP
* TBD
*/
switch ((u32)XPAR_PSU_QSPI_0_QSPI_MODE) {
case XQSPIPSU_CONNECTION_MODE_SINGLE:
{
XFsbl_Printf(DEBUG_INFO,"QSPI is in single flash connection\r\n");
} break;
case XQSPIPSU_CONNECTION_MODE_PARALLEL:
{
XFsbl_Printf(DEBUG_INFO,"QSPI is in Dual Parallel connection\r\n");
} break;
case XQSPIPSU_CONNECTION_MODE_STACKED:
{
XFsbl_Printf(DEBUG_INFO,"QSPI is in Dual Stack connection\r\n");
}break;
default:
{
Status = XFSBL_ERROR_INVALID_QSPI_CONNECTION;
XFsbl_Printf(DEBUG_GENERAL,
"XFSBL_ERROR_INVALID_QSPI_CONNECTION\r\n");
}
break;
}
if(Status != XFSBL_SUCCESS) {
UStatus = (u32)Status;
goto END;
}
switch (QspiPsuInstance.Config.BusWidth) {
case XFSBL_QSPI_BUSWIDTH_ONE:
{
XFsbl_Printf(DEBUG_INFO,"QSPI is using 1 bit bus\r\n");
ReadCommand = FAST_READ_CMD_32BIT;
} break;
case XFSBL_QSPI_BUSWIDTH_TWO:
{
XFsbl_Printf(DEBUG_INFO,"QSPI is using 2 bit bus\r\n");
ReadCommand = DUAL_READ_CMD_32BIT;
} break;
case XFSBL_QSPI_BUSWIDTH_FOUR:
{
XFsbl_Printf(DEBUG_INFO,"QSPI is using 4 bit bus\r\n");
ReadCommand = QUAD_READ_CMD_32BIT;
}break;
}
/**
* Read Flash ID and extract Manufacture and Size information
*/
UStatus = FlashReadID(&QspiPsuInstance);
if (UStatus != XFSBL_SUCCESS) {
goto END;
}
if (MacronixFlash == 1U) {
if (QspiPsuInstance.Config.BusWidth == XFSBL_QSPI_BUSWIDTH_FOUR) {
ReadCommand = QUAD_READ_CMD_24BIT2;
}
if (QspiPsuInstance.Config.ConnectionMode ==
XQSPIPSU_CONNECTION_MODE_PARALLEL) {
XQspiPsu_SelectFlash(&QspiPsuInstance,
XQSPIPSU_SELECT_FLASH_CS_BOTH,
XQSPIPSU_SELECT_FLASH_BUS_BOTH);
Status = MacronixEnable4B(&QspiPsuInstance);
} else {
XQspiPsu_SelectFlash(&QspiPsuInstance,
XQSPIPSU_SELECT_FLASH_CS_LOWER,
XQSPIPSU_SELECT_FLASH_BUS_LOWER);
Status = MacronixEnable4B(&QspiPsuInstance);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_FAILURE;
goto END;
}
if (QspiPsuInstance.Config.ConnectionMode ==
XQSPIPSU_CONNECTION_MODE_STACKED) {
XQspiPsu_SelectFlash(&QspiPsuInstance,
XQSPIPSU_SELECT_FLASH_CS_UPPER,
XQSPIPSU_SELECT_FLASH_BUS_LOWER);
Status = MacronixEnable4B(&QspiPsuInstance);
}
}
}
/**
* add code: For a Stacked connection, read second Flash ID
*/
QspiMode = QspiPsuInstance.Config.ConnectionMode;
if ((QspiMode ==
(s32)(XQSPIPSU_CONNECTION_MODE_PARALLEL)) ||
(QspiMode ==
(s32)(XQSPIPSU_CONNECTION_MODE_STACKED)) ) {
QspiFlashSize = 2 * QspiFlashSize;
}
END:
return UStatus;
}
/******************************************************************************
*
* Static API used for Macronix flash to enable 4BYTE mode
*
* @param QspiPsuPtr Pointer to QSPI instance.
*
* @return XFSBL_SUCCESS if success, otherwise XFSBL_FAILURE.
*
* @note None.
*
******************************************************************************/
static u32 MacronixEnable4B(XQspiPsu *QspiPsuPtr)
{
s32 Status;
u32 UStatus;
XFsbl_Printf(DEBUG_GENERAL,"MACRONIX_FLASH_MODE\r\n");
/*Enable register write*/
TxBfrPtr = WRITE_ENABLE_CMD;
FlashMsg[0].TxBfrPtr = &TxBfrPtr;
FlashMsg[0].RxBfrPtr = NULL;
FlashMsg[0].ByteCount = 1;
FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
Status = XQspiPsu_PolledTransfer(QspiPsuPtr, &FlashMsg[0], 1);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_FAILURE;
goto END;
}
/*Enable 4 byte mode*/
TxBfrPtr = 0xB7;
FlashMsg[0].TxBfrPtr = &TxBfrPtr;
FlashMsg[0].RxBfrPtr = NULL;
FlashMsg[0].ByteCount = 1;
FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
Status = XQspiPsu_PolledTransfer(QspiPsuPtr, &FlashMsg[0], 1);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_FAILURE;
goto END;
}
XFsbl_Printf(DEBUG_GENERAL,"MACRONIX_ENABLE_4BYTE_DONE\r\n");
UStatus = XFSBL_SUCCESS;
END:
return UStatus;
}
/******************************************************************************
*
* Static API used for Macronix flash to enable or disable QPI mode
*
* @param QspiPsuPtr Pointer to QSPI instance.
* @param Enable valid values are 0 (disable) and 1 (enable).
*
* @return XFSBL_SUCCESS if success, otherwise XFSBL_ERROR_QSPI_READ.
*
* @note None.
*
******************************************************************************/
static u32 MacronixEnableQPIMode(XQspiPsu *QspiPsuPtr, int Enable)
{
s32 Status;
u32 UStatus;
/*Enable register write*/
TxBfrPtr = WRITE_ENABLE_CMD;
FlashMsg[0].TxBfrPtr = &TxBfrPtr;
FlashMsg[0].RxBfrPtr = NULL;
FlashMsg[0].ByteCount = 1;
if (Enable == ENABLE_QPI) {
FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
} else {
FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI;
}
FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
Status = XQspiPsu_PolledTransfer(&QspiPsuInstance, &FlashMsg[0], 1);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_ERROR_QSPI_READ;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n");
goto END;
}
if (Enable == ENABLE_QPI)
TxBfrPtr = 0x35;
else
TxBfrPtr = 0xF5;
FlashMsg[0].TxBfrPtr = &TxBfrPtr;
FlashMsg[0].RxBfrPtr = NULL;
FlashMsg[0].ByteCount = 1;
if (Enable == ENABLE_QPI) {
FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
} else {
FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI;
}
FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
Status = XQspiPsu_PolledTransfer(&QspiPsuInstance, &FlashMsg[0], 1);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_ERROR_QSPI_READ;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n");
goto END;
}
UStatus = XFSBL_SUCCESS;
END:
return UStatus;
}
/*****************************************************************************/
/**
* This function is used to copy the data from QSPI flash to destination
* address
*
* @param SrcAddress is the address of the QSPI flash where copy should
* start from
*
* @param DestAddress is the address of the destination where it
* should copy to
*
* @param Length Length of the bytes to be copied
*
* @return
* - XFSBL_SUCCESS for successful copy
* - errors as mentioned in xfsbl_error.h
*
*****************************************************************************/
u32 XFsbl_Qspi32Copy(u32 SrcAddress, PTRSIZE DestAddress, u32 Length)
{
s32 Status;
u32 QspiAddr;
u32 RemainingBytes;
u32 TransferBytes;
u32 DiscardByteCnt;
u32 UStatus;
XFsbl_Printf(DEBUG_INFO,"QSPI Reading Src 0x%0lx, Dest %0lx, Length %0lx\r\n",
SrcAddress, DestAddress, Length);
/**
* Check the read length with Qspi flash size
*/
if ((SrcAddress + Length) > QspiFlashSize)
{
UStatus = XFSBL_ERROR_QSPI_LENGTH;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_LENGTH\r\n");
goto END;
}
/**
* Update no of bytes to be copied
*/
RemainingBytes = Length;
while(RemainingBytes > 0U) {
if (RemainingBytes > DMA_DATA_TRAN_SIZE)
{
TransferBytes = DMA_DATA_TRAN_SIZE;
} else {
TransferBytes = RemainingBytes;
}
/**
* Translate address based on type of connection
* If stacked assert the slave select based on address
*/
QspiAddr = XFsbl_GetQspiAddr((u32 )SrcAddress);
XFsbl_Printf(DEBUG_INFO,".");
XFsbl_Printf(DEBUG_DETAILED,
"QSPI Read Src 0x%0lx, Dest %0lx, Length %0lx\r\n",
QspiAddr, DestAddress, TransferBytes);
/**
* Setup the read command with the specified address and data for the
* Flash
*/
if ((MacronixFlash == 1U) &&
(QspiPsuInstance.Config.BusWidth == XFSBL_QSPI_BUSWIDTH_FOUR)) {
/* Enable QPI mode */
Status = MacronixEnableQPIMode(&QspiPsuInstance, ENABLE_QPI);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_ERROR_QSPI_READ;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n");
goto END;
}
/*Command*/
WriteBuffer[COMMAND_OFFSET] = (u8)ReadCommand;
DiscardByteCnt = 1;
/*MACRONIX is in QPI MODE 4-4-4*/
FlashMsg[0].TxBfrPtr = WriteBuffer;
FlashMsg[0].RxBfrPtr = NULL;
FlashMsg[0].ByteCount = DiscardByteCnt;
FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI;
FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
/*Address*/
WriteBuffer[ADDRESS_1_OFFSET] = (u8)((QspiAddr & 0xFF000000U) >> 24);
WriteBuffer[ADDRESS_2_OFFSET] = (u8)((QspiAddr & 0xFF0000U) >> 16);
WriteBuffer[ADDRESS_3_OFFSET] = (u8)((QspiAddr & 0xFF00U) >> 8);
WriteBuffer[ADDRESS_4_OFFSET] = (u8)(QspiAddr & 0xFFU);
DiscardByteCnt = 4;
FlashMsg[1].TxBfrPtr = &WriteBuffer[ADDRESS_1_OFFSET];
FlashMsg[1].RxBfrPtr = NULL;
FlashMsg[1].ByteCount = DiscardByteCnt;
FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI;
FlashMsg[1].Flags = XQSPIPSU_MSG_FLAG_TX;
/*Dummy*/
/*Default Dummy is 6 when QPI READ MODE(ECH)*/
FlashMsg[2].TxBfrPtr = NULL;
FlashMsg[2].RxBfrPtr = NULL;
FlashMsg[2].ByteCount = DUMMY_CLOCKS_MACRONIX;
FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI;
FlashMsg[2].Flags = 0U;
/*Data*/
FlashMsg[3].TxBfrPtr = NULL;
FlashMsg[3].RxBfrPtr = (u8 *)DestAddress;
FlashMsg[3].ByteCount = TransferBytes;
FlashMsg[3].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI;
FlashMsg[3].Flags = XQSPIPSU_MSG_FLAG_RX;
if(QspiPsuInstance.Config.ConnectionMode ==
XQSPIPSU_CONNECTION_MODE_PARALLEL){
FlashMsg[3].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
}
Status = XQspiPsu_PolledTransfer(&QspiPsuInstance, &FlashMsg[0], 4);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_ERROR_QSPI_READ;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n");
goto END;
}
/* Disable QPI mode */
Status = MacronixEnableQPIMode(&QspiPsuInstance, DISABLE_QPI);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_ERROR_QSPI_READ;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n");
goto END;
}
} else {
WriteBuffer[COMMAND_OFFSET] = (u8)ReadCommand;
WriteBuffer[ADDRESS_1_OFFSET] = (u8)((QspiAddr & 0xFF000000U) >> 24);
WriteBuffer[ADDRESS_2_OFFSET] = (u8)((QspiAddr & 0xFF0000U) >> 16);
WriteBuffer[ADDRESS_3_OFFSET] = (u8)((QspiAddr & 0xFF00U) >> 8);
WriteBuffer[ADDRESS_4_OFFSET] = (u8)(QspiAddr & 0xFFU);
DiscardByteCnt = 5;
FlashMsg[0].TxBfrPtr = WriteBuffer;
FlashMsg[0].RxBfrPtr = NULL;
FlashMsg[0].ByteCount = DiscardByteCnt;
FlashMsg[0].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
FlashMsg[0].Flags = XQSPIPSU_MSG_FLAG_TX;
/*
* It is recommended to have a separate entry for dummy
*/
if ((ReadCommand == FAST_READ_CMD_32BIT) ||
(ReadCommand == DUAL_READ_CMD_32BIT) ||
(ReadCommand == QUAD_READ_CMD_32BIT)) {
/* Update Dummy cycles as per flash specs for QUAD IO */
/*
* It is recommended that Bus width value during dummy
* phase should be same as data phase
*/
if (ReadCommand == FAST_READ_CMD_32BIT) {
FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
}
if (ReadCommand == DUAL_READ_CMD_32BIT) {
FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_DUALSPI;
}
if (ReadCommand == QUAD_READ_CMD_32BIT) {
FlashMsg[1].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI;
}
FlashMsg[1].TxBfrPtr = NULL;
FlashMsg[1].RxBfrPtr = NULL;
FlashMsg[1].ByteCount = DUMMY_CLOCKS;
FlashMsg[1].Flags = 0U;
}
if (ReadCommand == FAST_READ_CMD_32BIT) {
FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_SPI;
}
if (ReadCommand == DUAL_READ_CMD_32BIT) {
FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_DUALSPI;
}
if (ReadCommand == QUAD_READ_CMD_32BIT) {
FlashMsg[2].BusWidth = XQSPIPSU_SELECT_MODE_QUADSPI;
}
FlashMsg[2].TxBfrPtr = NULL;
FlashMsg[2].RxBfrPtr = (u8 *)DestAddress;
FlashMsg[2].ByteCount = TransferBytes;
FlashMsg[2].Flags = XQSPIPSU_MSG_FLAG_RX;
if(QspiPsuInstance.Config.ConnectionMode ==
XQSPIPSU_CONNECTION_MODE_PARALLEL){
FlashMsg[2].Flags |= XQSPIPSU_MSG_FLAG_STRIPE;
}
/**
* 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
*/
Status = XQspiPsu_PolledTransfer(&QspiPsuInstance, &FlashMsg[0], 3);
if (Status != XFSBL_SUCCESS) {
UStatus = XFSBL_ERROR_QSPI_READ;
XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_QSPI_READ\r\n");
goto END;
}
}
/**
* Update the variables
*/
RemainingBytes -= TransferBytes;
DestAddress += TransferBytes;
SrcAddress += TransferBytes;
}
UStatus = XFSBL_SUCCESS;
END:
return UStatus;
}
/*****************************************************************************/
/**
* This function is used to release the Qspi settings
*
* @param None
*
* @return None
*
*****************************************************************************/
u32 XFsbl_Qspi32Release(void)
{
u32 Status = XFSBL_SUCCESS;
return Status;
}
#endif /* endof XFSBL_QSPI */