Files
banban/ql-kernel/threadx/nor_flash/SPI.c
T

2942 lines
110 KiB
C

/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
SPI.c
GENERAL DESCRIPTION
This file is for SPI nor flash.
EXTERNALIZED FUNCTIONS
INITIALIZATION AND SEQUENCING REQUIREMENTS
Copyright (c) 2019 by ASR micro. All Rights Reserved.
*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
*===========================================================================
EDIT HISTORY FOR MODULE
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
when who what, where, why
-------- ------ ----------------------------------------------------------
06/23/2014 zhoujin Created module
08/01/2019 leiyang Modify for Crane platform
===========================================================================*/
/*===========================================================================
INCLUDE FILES FOR MODULE
===========================================================================*/
#include "spi.h"
#include "uart.h"
#include "qspi_dma.h"
#include "osa.h"
#include "intc.h"
#include "cgpio.h"
#define QUEC_SPI_NOR_DMA //juson.zhang-2020/07/07:add for SPI NOR Flash in DMA
#define SSP_SR_TX_FIFO_NOT_FULL (1<<6)
#define SSP_SR_RX_FIFO_NOT_EMPTY (1<<14)
#define QUEC_SPI_NOR_DMA_WAITFLAG //pony add
extern uint32_t dma_read_status(uint32_t channel);
/*========================================================================
LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE
This section contains local definitions for constants, macros, types,
variables and other items needed by this module.
===========================================================================*/
/* Non-cache */
#pragma arm section rwdata="SSPCmd", zidata="SSPCmd"
__align(16) unsigned int TxCmd[2];
__align(16) unsigned char tx_1bytes[5];
__align(8) unsigned int DMA_PP[66];
#pragma arm section rwdata, zidata
/* Non-cache */
#pragma arm section rwdata="DMARdBuf", zidata="DMARdBuf"
__align(8) unsigned char DMA_Read_Buffer[MAX_TEST_SIZE+16] = {0};
#pragma arm section rwdata, zidata
#define spi_uart_log(fmt, args...) do { /*CPUartLogPrintf("[SPI]"fmt, ##args);*/ } while(0)
#define spi_uart_log_err(fmt, args...) do { RTI_LOG("[SPI]E-"fmt, ##args); } while(0)
extern BOOL assertFlag;
/*===========================================================================
EXTERN DEFINITIONS AND DECLARATIONS FOR MODULE
===========================================================================*/
/*===========================================================================
INTERNAL FUNCTION DEFINITIONS
===========================================================================*/
void SPINOR_Write_Read(unsigned char *cmd, unsigned char *data, unsigned char len);
unsigned int SPINOR_Page_Program_DMA(unsigned int Address, unsigned int Buffer, unsigned int Size);
unsigned int SPINOR_EraseBlock(unsigned int Addr);
unsigned int SPINOR_Endian_Convert (unsigned int in);
unsigned int SPINOR_WaitSSPComplete(void);
unsigned int SPINOR_ReadStatus(unsigned int Wait);
void SPINOR_DisableSSP(void);
void SPINOR_FireUpSSP(void);
void SPINOR_Reset(int sspport);
void SPINOR_ReadId(int sspport, unsigned int *pID);
void SPINOR_WriteEnable(void);
void Assert_CS(void);
void Deassert_CS(void);
unsigned int SPINOR_WaitForWEL(unsigned int Wait);
static FlashProperties_T FlashProp[3];
static unsigned char FlashProtect = 0;
static int GpioPinOfCS = 0;
static int SSPport = 0;
static OSSemaRef spiSem = NULL;
int quec_spi_pin_selflag = 0;
#ifdef QUEC_SPI_NOR_DMA_WAITFLAG
//add for dma wait flag 20200904
static OSFlagRef SSP_Flash_Tx_DMA_Done_FlgRef=NULL;
static OSFlagRef SSP_Flash_Rx_DMA_Done_FlgRef=NULL;
#endif
static unsigned int SSPBase[3] = {SSP0_BASE, SSP1_BASE, SSP2_BASE};
static unsigned int GpioOfCS[3] = {0,0,13};
static void XllpDmacStartTransferWithStopIrqEnable( XLLP_DMAC_CHANNEL_T aChannel )
{
UINT32 aTargetData;
aTargetData = XLLP_Return_PDmacHandle()->DCSR[aChannel];
aTargetData |= XLLP_DMAC_DCSR_RUN | XLLP_DMAC_DCSR_STOP_IRQ_EN;
XLLP_Return_PDmacHandle()->DCSR[aChannel] = aTargetData;
}
void quec_set_extflash_select_port(int port)
{
quec_spi_pin_selflag = port;
}
int quec_get_extflash_select_port(void)
{
return quec_spi_pin_selflag;
}
static unsigned int GetSSPBase()
{
return SSPBase[SSPport];
}
void SetSSPPort(int port)
{
SSPport = port;
}
int SPINOR_getSSPPort(void)
{
return SSPport;
}
static void SetCSGpio(int sspport, unsigned int gpio)
{
GpioOfCS[sspport] = gpio;
}
static void Assert_CS(void)
{
GpioSetLevel(GpioOfCS[SSPport], 0);
}
static void Deassert_CS(void)
{
GpioSetLevel(GpioOfCS[SSPport], 1);
}
static P_FlashProperties_T GetFlashProperties(int sspport)
{
return &FlashProp[sspport];
}
extern int quec_spi_pin_selflag;
static void ChipSelectSPI(int port, SSP_Clock clock )
{
unsigned int apbc_ssp_base = 0;
if (port == 0)
{
apbc_ssp_base = APBC_SSP0_CLK_RST;
//config clk, cs, rx, tx, hold, wp according to hardware,use cs as GPIO function.
#ifdef QUEC_SPI_NOR_DMA
if(quec_spi_pin_selflag == 1)//miles.ma 20221105 add
{
*(volatile unsigned int*)0xD401E160 = 0x1881; //ssp0_sclk--gpio33
*(volatile unsigned int*)0xD401E164 = 0x1880; //ssp0_frm --gpio34, cs use gpio function
SetCSGpio(port, 34); //set cs pin
*(volatile unsigned int*)0xD401E168 = 0x1881; //ssp0_rxd --gpio35
*(volatile unsigned int*)0xD401E16C = 0x1881; //ssp0_txd --gpio36
//ssp0_frm output high
GpioSetDirection(34, 1);
GpioSetLevel(34,1);
}
else
{
*(volatile unsigned int*)0xD401E11C = 0x1882; //ssp0_sclk--gpio16
*(volatile unsigned int*)0xD401E120 = 0x1880; //ssp0_frm --gpio17, cs use gpio function
SetCSGpio(port, 17); //set cs pin
//20230724 软件修改gpio18,19的func4作为spi功能
*(volatile unsigned int*)0xD401E124 = 0x1884; //ssp0_rxd --gpio18
*(volatile unsigned int*)0xD401E128 = 0x1884; //ssp0_txd --gpio19
//ssp0_frm output high
GpioSetDirection(17, 1);
GpioSetLevel(17,1);
}
#endif /* QUEC_SPI_NOR_DMA */
}
//20231129 增加ssp1,仅支持1602平台
else if (port == 1)
{
apbc_ssp_base = (unsigned int)APBC_SSP1_CLK_RST;
//config clk, cs, rx, tx, hold, wp according to hardware,use cs as GPIO function.
#ifdef QUEC_SPI_NOR_DMA
*(volatile unsigned int*)0xD401E0EC = 0x1882; //ssp1_sclk--gpio4
*(volatile unsigned int*)0xD401E0F0 = 0x1880; //ssp1_frm --gpio5, cs use gpio function
SetCSGpio(port, 5); //set cs pin
*(volatile unsigned int*)0xD401E0F4 = 0x1882; //ssp1_rxd --gpio6
*(volatile unsigned int*)0xD401E0F8 = 0x1882; //ssp1_txd --gpio7
GpioSetDirection(5, 1);
GpioSetLevel(5,1);
#endif /* QUEC_SPI_NOR_DMA */
}
else
{
apbc_ssp_base = APBC_SSP2_CLK_RST;
/*************************************************************************
config clk, cs, rx, tx, hold, wp according to hardware,use cs as GPIO function.
*steps:
*1. config clk,rx,tx as SSP function
*2. config cs as gpio functon and use SetCSGpio(ssppot, csgpionum)
*3. config hold&wp as gpio function, set output direction, set high level
*4. config cs with output direction and high level
*************************************************************************/
#ifdef QUEC_SPI_NOR_DMA
if(quec_spi_pin_selflag == 3)//miles.ma 20221105 add
{
*(volatile unsigned int*)0xD401E10C = 0x1881; //ssp2_sclk--gpio12
*(volatile unsigned int*)0xD401E110 = 0x1880; //ssp2_frm --gpio13, cs use gpio function
SetCSGpio(port, 13); //set cs pin
*(volatile unsigned int*)0xD401E114 = 0x1881; //ssp2_rxd --gpio14
*(volatile unsigned int*)0xD401E118 = 0x1881; //ssp2_txd --gpio15
//ssp2_frm output high
GpioSetDirection(13, 1);
GpioSetLevel(13,1);
}
else
{
*(volatile unsigned int*)0xD401E160 = 0x1882; //ssp2_sclk--gpio33
*(volatile unsigned int*)0xD401E164 = 0x1880; //ssp2_frm --gpio34, cs use gpio function
SetCSGpio(port, 34); //set cs pin
*(volatile unsigned int*)0xD401E168 = 0x1882; //ssp2_rxd --gpio35
*(volatile unsigned int*)0xD401E16C = 0x1882; //ssp2_txd --gpio36
//ssp2_frm output high
GpioSetDirection(34, 1);
GpioSetLevel(34,1);
}
#else
//ssp2_sclk--gpio12
*(volatile unsigned int*)0xD401E10C = 0x1081;
//ssp2_frm --gpio13, cs use gpio function
*(volatile unsigned int*)0xD401E110 = 0x1080;
//set cs pin
SetCSGpio(port, 13);
//ssp2_rxd --gpio14
*(volatile unsigned int*)0xD401E114 = 0x1081;
//ssp2_txd --gpio15
*(volatile unsigned int*)0xD401E118 = 0x1081;
//ssp2_hold--gpio85
*(volatile unsigned int*)0xD401E1F0 = 0x1080;
//ssp2_wp --gpio86
*(volatile unsigned int*)0xD401E1F4 = 0x1080;
//ssp2_hold,ssp2_wp output high
GpioSetDirection(85, 1);
GpioSetDirection(86, 1);
GpioSetLevel(85, 1);
GpioSetLevel(86, 1);
//ssp2_frm output high
GpioSetDirection(13, 1);
GpioSetLevel(13, 1);
#endif /* QUEC_SPI_NOR_DMA */
}
/*enabled SSP2 clock, then take out of reset
BIT 0: SSP 2 APB Bus Clock Enable/Disable.
0 = Clock off
1 = Clock on
BIT 1: SSP 2 Functional Clock Enable/Disable.
0 = Clock off
1 = Clock on
BIT 2: SSP 2 Reset Generation.
This field resets both the APB and functional domain.
0 = No Reset
1 = Reset
*/
spi_reg_write(apbc_ssp_base, BIT_0 | BIT_1 | BIT_2);
/*Functional Clock Select
0x0 = 6.5 MHz
0x1 = 13 MHz
0x2 = 26 MHz
0x3 = 52 MHz
All other values = Reserved, do not use
*/
switch(clock)
{
case SSP_CLOCK_13M:
{
spi_reg_write(apbc_ssp_base, BIT_0 | BIT_1 | (1 << 4)); // 13MHZ
break;
}
case SSP_CLOCK_26M:
{
spi_reg_write(apbc_ssp_base, BIT_0 | BIT_1 | (2 << 4)); // 26MHZ
break;
}
case SSP_CLOCK_52M:
{
spi_reg_write(apbc_ssp_base, BIT_0 | BIT_1 | (3 << 4)); // 52MHZ
break;
}
default:
{
spi_reg_write(apbc_ssp_base, BIT_0 | BIT_1 | (1 << 4)); // 13MHZ
break;
}
}
CPUartLogPrintf("apbc_ssp_base value:0x%02x",spi_reg_read(apbc_ssp_base));
return;
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* InitializeSPIDevice */
/* */
/* DESCRIPTION */
/* */
/* The function intializes SPI nor device */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
#if 0
BOOL CheckIf32MNOR( void )
{
P_FlashProperties_T pFlashP = GetFlashProperties(BOOT_FLASH);
if((pFlashP->BlockSize * pFlashP->NumBlocks) == 0x2000000)
{
return TRUE;
}
else
{
return FALSE;
}
}
#endif
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_ROW_DELAY */
/* */
/* DESCRIPTION */
/* */
/* The function delay some times. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
static void SPINOR_ROW_DELAY(unsigned int x)
{
volatile long i = 0;
i = x;
while (i > 0)
{
i--;
}
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_Endian_Convert */
/* */
/* DESCRIPTION */
/* */
/* The function is endian conversion function */
/* convert to big endian */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
static unsigned int SPINOR_Endian_Convert (unsigned int in)
{
unsigned int out;
out = in << 24;
out |= (in & 0xFF00) << 8;
out |= (in & 0xFF0000) >> 8;
out |= (in & 0xFF000000) >> 24;
return out;
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_DisableSSP */
/* */
/* DESCRIPTION */
/* */
/* The function disable SSP. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
static void SPINOR_DisableSSP(void)
{
//make sure SSP is disabled
spi_reg_bit_clr(SSP_TCR, SSP_TCR_SSE);
//reset SSP CR's
spi_reg_write(SSP_TCR, SSP_TCR_INITIAL);
spi_reg_write(SSP_FCR, SSP_FCR_INITIAL);
spi_reg_write(SSP_IER, SSP_IER_INITIAL);
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_FireUpSSP */
/* */
/* DESCRIPTION */
/* */
/* The function Enable SSP. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
static void SPINOR_FireUpSSP(void)
{
spi_reg_bit_set(SSP_TCR, SSP_TCR_SSE);
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_SSP_DSS */
/* */
/* DESCRIPTION */
/* */
/* The function Select Data Size. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
static void SPINOR_SSP_DSS(int DataSize)
{
switch(DataSize)
{
case 16:
{
spi_reg_bit_clr(SSP_TCR, SSP_TCR_DSS_MASK);
spi_reg_bit_set(SSP_TCR, SSP_TCR_DSS16);
break;
}
case 24:
{
spi_reg_bit_clr(SSP_TCR, SSP_TCR_DSS_MASK);
spi_reg_bit_set(SSP_TCR, SSP_TCR_DSS24);
break;
}
case 32:
{
spi_reg_bit_clr(SSP_TCR, SSP_TCR_DSS_MASK);
spi_reg_bit_set(SSP_TCR, SSP_TCR_DSS32);
break;
}
case 8:
{
spi_reg_bit_clr(SSP_TCR, SSP_TCR_DSS_MASK);
spi_reg_bit_set(SSP_TCR, SSP_TCR_DSS8);
break;
}
default:
{
break;
}
}
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_WaitSSPComplete */
/* */
/* DESCRIPTION */
/* */
/* The function wait for SSP completion. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
static unsigned int SPINOR_WaitSSPComplete(void)
{
volatile int timeout = 0;
timeout = 0xFFFFF;
//timeout = 0xFF;
while ((*SSP_STS & (SSP_STS_TFL | SSP_STS_TF_NF | SSP_STS_BSY)) != SSP_STS_TF_NF)
{
if((timeout--) <= 0)
{
spi_uart_log_err("SPINOR_WaitSSPComplete timeout");
return SSPWaitCompleteTimeOutError;
}
SPINOR_ROW_DELAY(DEFAULT_TIMEOUT);
}
return 0;
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_Write_Read */
/* */
/* DESCRIPTION */
/* */
/* The function use PIO mode to write and then read out the data. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
static void SPINOR_Write_Read(unsigned char *cmd, unsigned char *data, unsigned char len)
{
unsigned char i;
for (i = 0; i < len; i++)
{
BU_REG_WRITE8(SSP_DR, cmd[i]);
SPINOR_WaitSSPComplete();
data[i] = BU_REG_READ8(SSP_DR);
}
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_Reset */
/* */
/* DESCRIPTION */
/* */
/* The function reset SPI nor. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
static void SPINOR_Reset(int sspport)
{
unsigned int temp;
unsigned int Retval = 0;
SetSSPPort(sspport);
SPINOR_DisableSSP();
//fire it up
SPINOR_FireUpSSP();
Assert_CS();
spi_reg_write(SSP_DR, SPI_CMD_RELEASE_POWER_DOWN);
Retval = SPINOR_WaitSSPComplete();
if(Retval != 0)
{
spi_uart_log_err("SPINOR_Reset status 0x%x", Retval);
}
temp = *SSP_DR;
Deassert_CS();
SPINOR_DisableSSP();
SPINOR_ROW_DELAY(1000);
return;
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_SW_Reset */
/* */
/* DESCRIPTION */
/* */
/* The function reset SPI nor. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
void SPINOR_SW_Reset(int sspport)
{
unsigned int temp;
unsigned int Retval = 0;
unsigned short reset_cmd = 0x0;
//spi_uart_log_err("%s,enter",__func__);
SetSSPPort(sspport);
SPINOR_DisableSSP();
//setup in 16 bit mode
SPINOR_SSP_DSS(16);
reset_cmd = SPI_CMD_RESET_ENABLE<<8 | SPI_CMD_RESET;
//fire it up
SPINOR_FireUpSSP();
Assert_CS();
spi_reg_write(SSP_DR, reset_cmd);
Retval = SPINOR_WaitSSPComplete();
if(Retval != 0)
{
spi_uart_log_err("SPINOR_Reset status 0x%x", Retval);
}
temp = *SSP_DR;
Deassert_CS();
SPINOR_DisableSSP();
SPINOR_ROW_DELAY(1000);
return;
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_ReadStatus */
/* */
/* DESCRIPTION */
/* */
/* The function read SPI nor status. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
static unsigned int SPINOR_ReadStatus(unsigned int Wait)
{
unsigned int read = 0, ready = 0, dummy = 0, status = 0;
volatile int timeout = 0;
timeout = 0xFFFFF;
//timeout = 0xFF;
read = FALSE; //this flag gets set when we read first entry from fifo
//if the caller waits to 'Wait' for the BUSY to be cleared, start READY off as FALSE
//if the caller doesn't wait to wait, set READY as true, so we don't wait on the bit
ready = (Wait) ? FALSE : TRUE;
do{
//make sure SSP is disabled
SPINOR_DisableSSP();
//setup in 16 bit mode
SPINOR_SSP_DSS(16);
//fire it up
SPINOR_FireUpSSP();
Assert_CS();
//load the command + 1 dummy byte
*SSP_DR = SPI_CMD_READ_STATUS << 8;
//wait till the TX fifo is empty, then read out the status
if(SPINOR_WaitSSPComplete() != 0)
{
spi_uart_log_err("SPINOR_ReadStatus timeout");
return SSPWaitTxEmptyTimeOutError;
}
dummy = *SSP_DR;
Deassert_CS();
//set the READ flag, and read the status
read = TRUE;
status = dummy & 0xFF; //the status will be in the second byte
//set the READY flag if the status wait bit is cleared
if((status & 1) == 0) // operation complete (eg. not busy)?
ready = TRUE;
//make sure SSP is disabled
SPINOR_DisableSSP();
//if we've waited long enough, fail
if((timeout--) <= 0)
{
spi_uart_log_err("SSP Read Status 0x%x", *SSP_DR);
return SSPRdStatusTimeOutError;
}
//we need to wait until we read at least 1 valid status entry
//if we're waiting for the Write, wait till WIP bits goes to 0
}while ((!read) || (!ready));
//return last known status
return 0;
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_WaitForWEL */
/* */
/* DESCRIPTION */
/* */
/* The function wait for write enablle. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
static unsigned int SPINOR_WaitForWEL(unsigned int Wait)
{
unsigned int read = 0, ready = 0, dummy = 0, status = 0;
volatile int timeout = 0;
read = FALSE; //this flag gets set when we read first entry from fifo
//if the caller waits to 'Wait' for the BUSY to be cleared, start READY off as FALSE
//if the caller doesn't wait to wait, set READY as true, so we don't wait on the bit
ready = (Wait) ? FALSE : TRUE;
timeout = 0xFF;
do{
//make sure SSP is disabled
SPINOR_DisableSSP();
//setup in 16 bit mode
SPINOR_SSP_DSS(16);
//fire it up
SPINOR_FireUpSSP();
Assert_CS();
//load the command + 1 dummy byte
*SSP_DR = SPI_CMD_READ_STATUS << 8;
//wait till the TX fifo is empty, then read out the status
if(SPINOR_WaitSSPComplete() != 0)
{
spi_uart_log_err("Wait For WEL timeout");
return SSPWelWaitTxEmptyTimeOutError;
}
dummy = *SSP_DR;
Deassert_CS();
//set the READ flag, and read the status
read = TRUE;
status = dummy & 0xFF; //the status will be in the second byte
//set the READY flag if the status wait bit is cleared*/
/* WIP bit(S0):The Write in Progress (WIP) bit indicates whether the memory is busy in program/erase/write status register progress. */
/* When WIP bit sets to 1, means the device is busy in program/erase/write status register progress, */
/* when WIP bit sets 0, means the device is not in program/erase/write status register progress. */
/*WEL bit(S1):The Write Enable Latch (WEL) bit indicates the status of the internal Write Enable Latch. */
/*When set to 1 the internal Write Enable Latch is set, */
/*when set to 0 the internal Write Enable Latch is reset and no Write Status Register, Program or Erase command is accepted. */
if((status & 0x03) == 0x02) // Write Enable Latch and Operation not in Progress
ready = TRUE;
//make sure SSP is disabled
SPINOR_DisableSSP();
//if we've waited long enough, fail
if((timeout--) <= 0)
{
spi_uart_log_err("Wait For WEL, SSP Read Status 0x%x", *SSP_DR);
return SSPWaitForWELTimeOutError;
}
//we need to wait until we read at least 1 valid status entry
//if we're waiting for the Write, wait till WIP bits goes to 0
}while ((!read) || (!ready));
//return last known status
return 0;
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_WriteEnable */
/* */
/* DESCRIPTION */
/* */
/* The function enable SPI nor write operation. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
static void SPINOR_WriteEnable(void)
{
unsigned int temp;
unsigned int Retval = 0;
//make sure SSP is disabled
SPINOR_DisableSSP();
//fire it up
SPINOR_FireUpSSP();
Assert_CS();
//load the command
spi_reg_write(SSP_DR, SPI_CMD_WRITE_ENABLE);
//wait till TX fifo is empty
Retval = SPINOR_WaitSSPComplete();
if(Retval != 0)
{
spi_uart_log_err("SPINOR_WriteEnable status 0x%x", Retval);
}
temp = *SSP_DR;
Deassert_CS();
//make sure SSP is disabled
SPINOR_DisableSSP();
return;
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_ReadId */
/* */
/* DESCRIPTION */
/* */
/* The function read the Nor ID. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
void SPINOR_ReadId(int sspport, unsigned int *pID)
{
unsigned int ID;
unsigned int Retval = 0;
OSASemaphoreAcquire(spiSem, OS_SUSPEND);
SetSSPPort(sspport);
SPINOR_DisableSSP();
//setup in 32 bit mode
SPINOR_SSP_DSS(32);
//fire it up
SPINOR_FireUpSSP();
Assert_CS();
spi_reg_write(SSP_DR, (unsigned int)SPI_CMD_JEDEC_ID << 24);
Retval = SPINOR_WaitSSPComplete();
if(Retval != 0)
{
spi_uart_log_err("SPINOR_ReadId status 0x%x", Retval);
}
ID = *SSP_DR;
Deassert_CS();
//make sure SSP is disabled
//it must be executed lastly,
//because disable SP will result in RXFIFO/TXFIFO reset.
SPINOR_DisableSSP();
OSASemaphoreRelease(spiSem);
*pID = ID;
return;
}
//Kenney.wang 2020.09.28
//norflash sleep and wakeup
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_Sleep */
/* */
/* DESCRIPTION */
/* */
/* The function norflash into sleep mode. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
int SPINOR_Sleep(int sspport)
{
unsigned int sta;
unsigned int Retval = 0;
OSA_STATUS status;
if(spiSem)
{
status = OSASemaphoreAcquire(spiSem, OS_SUSPEND);
if (status != OS_SUCCESS)
{
spi_uart_log_err("%s: ssp not ready", __FUNCTION__);
return SSPNOTREADY;
}
}
else
{
spi_uart_log_err("%s: ssp not ready", __FUNCTION__);
return SSPNOTREADY;
}
SetSSPPort(sspport);
SPINOR_DisableSSP();
//setup in 8 bit mode
SPINOR_SSP_DSS(8);
//fire it up
SPINOR_FireUpSSP();
Assert_CS();
spi_reg_write(SSP_DR, SPI_CMD_POWER_DOWN);
Retval = SPINOR_WaitSSPComplete();
if(Retval != 0)
{
spi_uart_log_err("SPINOR_ReadId status 0x%xsssss", Retval);
}
sta = *SSP_DR;
Deassert_CS();
//make sure SSP is disabled
//it must be executed lastly,
//because disable SP will result in RXFIFO/TXFIFO reset.
SPINOR_DisableSSP();
if(spiSem)
OSASemaphoreRelease(spiSem);
else
{
spi_uart_log_err("%s: ssp not ready", __FUNCTION__);
return SSPNOTREADY;
}
return 0;
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_Wakeup */
/* */
/* DESCRIPTION */
/* */
/* The function norflash into wakeup mode. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
int SPINOR_Wakeup(int sspport)
{
unsigned int sta;
unsigned int Retval = 0;
OSA_STATUS status;
if(spiSem)
{
status = OSASemaphoreAcquire(spiSem, OS_SUSPEND);
if (status != OS_SUCCESS)
{
spi_uart_log_err("%s: ssp not ready", __FUNCTION__);
return SSPNOTREADY;
}
}
else
{
spi_uart_log_err("%s: ssp not ready", __FUNCTION__);
return SSPNOTREADY;
}
SetSSPPort(sspport);
SPINOR_DisableSSP();
//setup in 8 bit mode
SPINOR_SSP_DSS(8);
//fire it up
SPINOR_FireUpSSP();
Assert_CS();
spi_reg_write(SSP_DR, SPI_CMD_RELEASE_POWER_DOWN);
Retval = SPINOR_WaitSSPComplete();
if(Retval != 0)
{
spi_uart_log_err("SPINOR_ReadId status 0x%x", Retval);
}
sta = *SSP_DR;
Deassert_CS();
OsaTaskSleep(2, NULL);
//make sure SSP is disabled
//it must be executed lastly,
//because disable SP will result in RXFIFO/TXFIFO reset.
SPINOR_DisableSSP();
if(spiSem)
OSASemaphoreRelease(spiSem);
else
{
spi_uart_log_err("%s: ssp not ready", __FUNCTION__);
return SSPNOTREADY;
}
return 0;
}
//Kenney.wang 2020.09.28
//norflash sleep and wakeup
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_Page_Program_DMA */
/* */
/* DESCRIPTION */
/* */
/* The function do DMA page program operation. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
static unsigned int SPINOR_Page_Program_DMA(unsigned int Address, unsigned int Buffer, unsigned int Size)
{
#ifdef QUEC_SPI_NOR_DMA_WAITFLAG
//add for dma wait flag 20200904
OSA_STATUS os_status = OS_SUCCESS;
UINT32 flag_value = 0;
#endif
unsigned int *pWrite = NULL;
DMA_CMDx_T TX_Cmd, RX_Cmd;
unsigned char data[10];
unsigned int Retval = 0, i = 0;
volatile int timeout = 0;
TX_Cmd.value = 0;
TX_Cmd.bits.IncSrcAddr = 1;
TX_Cmd.bits.IncTrgAddr = 0;
TX_Cmd.bits.FlowSrc = 0;
TX_Cmd.bits.FlowTrg = 1;
TX_Cmd.bits.Width = 3;
TX_Cmd.bits.MaxBurstSize = 2;
TX_Cmd.bits.Length = Size;
tx_1bytes[0] = SPI_CMD_PROGRAM;
tx_1bytes[1] = (Address >> 16) & 0xFF;
tx_1bytes[2] = (Address >> 8) & 0xFF;
tx_1bytes[3] = (Address >> 0) & 0xFF;
ASSERT(Size <= 256);
memcpy(DMA_PP, (void*)Buffer, Size); //????? max size 256, DMA PP size 66
pWrite = (unsigned int *)DMA_PP;
if (SSPport == 0)
{
#ifdef QUEC_SPI_NOR_DMA_WAITFLAG
XllpDmacMapDeviceToChannel(DMA_REQ_SSP0_TX, DMA_DEV_SSP2_TX_CH);//map dma channel in DMA_RCMRx
#else
dma_map_device_to_channel(DMA_REQ_SSP0_TX, DMA_DEV_SSP2_TX_CH);
#endif
}
else if (SSPport == 1)
{
#ifdef QUEC_SPI_NOR_DMA_WAITFLAG
XllpDmacMapDeviceToChannel(DMA_REQ_SSP1_TX, DMA_DEV_SSP2_TX_CH);//map dma channel in DMA_RCMRx
#else
dma_map_device_to_channel(DMA_REQ_SSP1_TX, DMA_DEV_SSP2_TX_CH);
#endif
}
else if (SSPport == 2)
{
#ifdef QUEC_SPI_NOR_DMA_WAITFLAG
XllpDmacMapDeviceToChannel(DMA_REQ_SSP2_TX, DMA_DEV_SSP2_TX_CH);//map dma channel in DMA_RCMRx
#else
dma_map_device_to_channel(DMA_REQ_SSP2_TX, DMA_DEV_SSP2_TX_CH);
#endif
}
else
{
spi_uart_log_err("port1 not support");
return 1;
}
#ifdef QUEC_SPI_NOR_DMA_WAITFLAG
XllpDmacNoDescriptorFetch(DMA_DEV_SSP2_TX_CH);//set No-Descriptor Fetch bit in DMA_CSR031
alignChannel(DMA_DEV_SSP2_TX_CH, 1); //DALGNX |= 1 << SSP0_TX_CHANNEL
loadNonDescriptor((UINT32)pWrite, (UINT32)SSP_DR, &TX_Cmd, DMA_DEV_SSP2_TX_CH);
#else
set_user_aligment(DMA_DEV_SSP2_TX_CH);
dma_set_mode(DMA_MODE_NONFETCH, DMA_DEV_SSP2_TX_CH);
dma_set_reg_nf((unsigned int)pWrite, (unsigned int)SSP_DR, &TX_Cmd, DMA_DEV_SSP2_TX_CH);
#endif
SPINOR_DisableSSP();
//fire it up
SPINOR_FireUpSSP();
Assert_CS();
SPINOR_Write_Read(tx_1bytes, data, 4);
//make sure SSP is disabled
spi_reg_bit_clr(SSP_TCR, SSP_TCR_SSE);
//reset SSP CR's
spi_reg_write(SSP_TCR, SSP_TCR_INITIAL);
spi_reg_write(SSP_FCR, SSP_FCR_INITIAL);
spi_reg_write(SSP_IER, SSP_IER_INITIAL);
//setup in 32bit mode
spi_reg_bit_clr(SSP_TCR, SSP_TCR_DSS_MASK);
spi_reg_bit_set(SSP_TCR, SSP_TCR_DSS32);
spi_reg_bit_set(SSP_TCR, SSP_TCR_TRIAL);
spi_reg_write(SSP_FCR, SSP_FCR_DMA_PAGE_PROGRAM | SSP_FCR_TWE(2));
//setup IER
spi_reg_bit_set(SSP_IER, SSP_IER_TIE | SSP_IER_RIE);
//fire SSP up
spi_reg_bit_set(SSP_TCR, SSP_TCR_SSE);
#ifdef QUEC_SPI_NOR_DMA_WAITFLAG
if(!assertFlag)
{
//XllpDmacEnableStopIrqInterrupt(DMA_DEV_SSP2_TX_CH);
//XllpDmacStartTransfer(DMA_DEV_SSP2_TX_CH);分开配置有bug,原因未知
XllpDmacStartTransferWithStopIrqEnable(DMA_DEV_SSP2_TX_CH);
os_status = OSAFlagWait(SSP_Flash_Tx_DMA_Done_FlgRef, 0x01, OSA_FLAG_OR_CLEAR, &flag_value, 100);
if(os_status != OS_SUCCESS)
{
spi_uart_log_err("%s:ERROR,os_status=0x%x",__func__,os_status);
Retval = SSPTxChannelTimeOutError;
}
}
else
{
//Kick off DMA
dma_xfer_start(DMA_DEV_SSP2_TX_CH);
//timer loop waiting for dma to finish
//setup a timer to fail gracefully in case of error
timeout = 0xFFFFF;
//wait until the TX channel gets the stop unsigned interrupt and the TX fifo is drained
while( ((dma_read_status(DMA_DEV_SSP2_TX_CH) & XLLP_DMAC_DCSR_STOP_INTR) != XLLP_DMAC_DCSR_STOP_INTR) ||
((*SSP_STS & (SSP_STS_TFL | SSP_STS_TF_NF | SSP_STS_BSY)) != SSP_STS_TF_NF) )
{
//if we've waited long enough, fail
if((timeout--) <= 0)
{
spi_uart_log_err("write DMA Status 0x%x, SSP Status 0x%x", dma_read_status(DMA_DEV_SSP2_TX_CH), *SSP_STS);
Retval = SSPTxChannelTimeOutError;
break;
}
}
//if we errored out, kill the DMA transfers
if(Retval != 0)
{
dma_xfer_stop( DMA_DEV_SSP2_TX_CH );
}
}
#else
//Kick off DMA
dma_xfer_start(DMA_DEV_SSP2_TX_CH);
//timer loop waiting for dma to finish
//setup a timer to fail gracefully in case of error
timeout = 0xFFFFF;
//wait until the TX channel gets the stop unsigned interrupt and the TX fifo is drained
while( ((dma_read_status(DMA_DEV_SSP2_TX_CH) & XLLP_DMAC_DCSR_STOP_INTR) != XLLP_DMAC_DCSR_STOP_INTR) ||
((*SSP_STS & (SSP_STS_TFL | SSP_STS_TF_NF | SSP_STS_BSY)) != SSP_STS_TF_NF) )
{
//if we've waited long enough, fail
if((timeout--) <= 0)
{
spi_uart_log_err("write DMA Status 0x%x, SSP Status 0x%x", dma_read_status(DMA_DEV_SSP2_TX_CH), *SSP_STS);
Retval = SSPTxChannelTimeOutError;
break;
}
}
//if we errored out, kill the DMA transfers
if(Retval != 0)
{
dma_xfer_stop( DMA_DEV_SSP2_TX_CH );
}
#endif
SPINOR_WaitSSPComplete();
Deassert_CS();
//make sure SSP is disabled
SPINOR_DisableSSP();
#ifdef QUEC_SPI_NOR_DMA_WAITFLAG
if (SSPport == 0){
XllpDmacUnMapDeviceToChannel(DMA_REQ_SSP0_RX, DMA_DEV_SSP2_RX_CH);
XllpDmacUnMapDeviceToChannel(DMA_REQ_SSP0_TX, DMA_DEV_SSP2_TX_CH);
}
else if (SSPport == 1){
XllpDmacUnMapDeviceToChannel(DMA_REQ_SSP1_RX, DMA_DEV_SSP2_RX_CH);
XllpDmacUnMapDeviceToChannel(DMA_REQ_SSP1_TX, DMA_DEV_SSP2_TX_CH);
}
else if (SSPport == 2){
XllpDmacUnMapDeviceToChannel(DMA_REQ_SSP2_RX, DMA_DEV_SSP2_RX_CH);
XllpDmacUnMapDeviceToChannel(DMA_REQ_SSP2_TX, DMA_DEV_SSP2_TX_CH);
}
else
{
spi_uart_log_err("port1 not support");
return 1;
}
#endif
return Retval;
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_Read_DMA */
/* */
/* DESCRIPTION */
/* */
/* The function do DMA read operation. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
static unsigned int SPINOR_Read_DMA(unsigned int FlashOffset, unsigned int Buffer, unsigned int Size, unsigned int CopySize)
{
unsigned int i = 0;
unsigned char data[10];
unsigned int *temp_buff = NULL;
unsigned int read_size = 0, total_size = 0, Retval = 0, read_buff = 0;
DMA_CMDx_T RX_Cmd, TX_Cmd;
volatile int timeout = 0;
#ifdef QUEC_SPI_NOR_DMA_WAITFLAG
//add for dma wait flag 20200904
OSA_STATUS os_status = OS_SUCCESS;
UINT32 flag_value = 0;
#endif
read_buff = (unsigned int)DMA_Read_Buffer;
//fill out commands
RX_Cmd.value = 0;
RX_Cmd.bits.IncSrcAddr = 0;
RX_Cmd.bits.IncTrgAddr = 1;
RX_Cmd.bits.FlowSrc = 1;
RX_Cmd.bits.FlowTrg = 0;
RX_Cmd.bits.Width = 3;
RX_Cmd.bits.MaxBurstSize = 2;
RX_Cmd.bits.Length = Size;
TX_Cmd.value = 0;
TX_Cmd.bits.IncSrcAddr = 0;
TX_Cmd.bits.IncTrgAddr = 0;
TX_Cmd.bits.FlowSrc = 0;
TX_Cmd.bits.FlowTrg = 1;
TX_Cmd.bits.Width = 3;
TX_Cmd.bits.MaxBurstSize = 2;
TX_Cmd.bits.Length = Size;
TxCmd[0] = 0x00;
tx_1bytes[0] = SPI_CMD_READ;
tx_1bytes[1] = (FlashOffset >> 16) & 0xFF;
tx_1bytes[2] = (FlashOffset >> 8) & 0xFF;
tx_1bytes[3] = (FlashOffset >> 0) & 0xFF;
if (SSPport == 0)
{
#ifdef QUEC_SPI_NOR_DMA_WAITFLAG
//setup DMA
//Map Device to Channels
XllpDmacMapDeviceToChannel(DMA_REQ_SSP0_RX, DMA_DEV_SSP2_RX_CH);//map dma channel in DMA_RCMRx
XllpDmacMapDeviceToChannel(DMA_REQ_SSP0_TX, DMA_DEV_SSP2_TX_CH);//map dma channel in DMA_RCMRx
#else
dma_map_device_to_channel(DMA_REQ_SSP0_RX, DMA_DEV_SSP2_RX_CH);
dma_map_device_to_channel(DMA_REQ_SSP0_TX, DMA_DEV_SSP2_TX_CH);
#endif
}
else if (SSPport == 1)
{
#ifdef QUEC_SPI_NOR_DMA_WAITFLAG
//setup DMA
//Map Device to Channels
XllpDmacMapDeviceToChannel(DMA_REQ_SSP1_RX, DMA_DEV_SSP2_RX_CH);//map dma channel in DMA_RCMRx
XllpDmacMapDeviceToChannel(DMA_REQ_SSP1_TX, DMA_DEV_SSP2_TX_CH);//map dma channel in DMA_RCMRx
#else
dma_map_device_to_channel(DMA_REQ_SSP1_RX, DMA_DEV_SSP2_RX_CH);
dma_map_device_to_channel(DMA_REQ_SSP1_TX, DMA_DEV_SSP2_TX_CH);
#endif
}
else if (SSPport == 2)
{
#ifdef QUEC_SPI_NOR_DMA_WAITFLAG
//setup DMA
//Map Device to Channels
XllpDmacMapDeviceToChannel(DMA_REQ_SSP2_RX, DMA_DEV_SSP2_RX_CH);//map dma channel in DMA_RCMRx
XllpDmacMapDeviceToChannel(DMA_REQ_SSP2_TX, DMA_DEV_SSP2_TX_CH);//map dma channel in DMA_RCMRx
#else
dma_map_device_to_channel(DMA_REQ_SSP2_RX, DMA_DEV_SSP2_RX_CH);
dma_map_device_to_channel(DMA_REQ_SSP2_TX, DMA_DEV_SSP2_TX_CH);
#endif
}
else
{
spi_uart_log_err("port1 not support");
return 1;
}
#ifdef QUEC_SPI_NOR_DMA_WAITFLAG
XllpDmacNoDescriptorFetch(DMA_DEV_SSP2_RX_CH);//set No-Descriptor Fetch bit in DMA_CSR031
XllpDmacNoDescriptorFetch(DMA_DEV_SSP2_TX_CH);//set No-Descriptor Fetch bit in DMA_CSR031
//turn ON user alignment - in case buffer address is 64bit aligned
alignChannel(DMA_DEV_SSP2_RX_CH, 1); // 1 = user aligned (source and target addresses)
alignChannel(DMA_DEV_SSP2_TX_CH, 1); //DALGNX |= 1 << SSP0_TX_CHANNEL
loadNonDescriptor((UINT32)SSP_DR, (UINT32)read_buff, &RX_Cmd, DMA_DEV_SSP2_RX_CH);//CMDx=RX_Cmd.value, TADRx=read_buff, SADRx=SSP0_DR
loadNonDescriptor((UINT32)&TxCmd[0], (UINT32)SSP_DR, &TX_Cmd, DMA_DEV_SSP2_TX_CH);
#else
set_user_aligment(DMA_DEV_SSP2_TX_CH);
set_user_aligment(DMA_DEV_SSP2_RX_CH);
dma_set_mode(DMA_MODE_NONFETCH, DMA_DEV_SSP2_TX_CH);
dma_set_mode(DMA_MODE_NONFETCH, DMA_DEV_SSP2_RX_CH);
dma_set_reg_nf((unsigned int)SSP_DR, (unsigned int)read_buff, &RX_Cmd, DMA_DEV_SSP2_RX_CH);
dma_set_reg_nf((unsigned int)&TxCmd[0], (unsigned int)SSP_DR, &TX_Cmd, DMA_DEV_SSP2_TX_CH);
#endif
SPINOR_DisableSSP();
//fire it up
SPINOR_FireUpSSP();
Assert_CS();
SPINOR_Write_Read(tx_1bytes, data, 4);
//make sure SSP is disabled
spi_reg_bit_clr(SSP_TCR, SSP_TCR_SSE);
//reset SSP CR's
spi_reg_write(SSP_TCR, SSP_TCR_INITIAL);
spi_reg_write(SSP_FCR, SSP_FCR_INITIAL);
spi_reg_write(SSP_IER, SSP_IER_INITIAL);
spi_reg_write(SSP_TOR, SSP_TOR_TIMEOUT);
//setup in 32bit mode
spi_reg_bit_clr(SSP_TCR, SSP_TCR_DSS_MASK);
spi_reg_bit_set(SSP_TCR, SSP_TCR_DSS32);
spi_reg_write(SSP_FCR, SSP_FCR_DMA_READ|SSP_FCR_RRE(2)|SSP_FCR_RAFC);
spi_reg_bit_set(SSP_TCR, SSP_TCR_TRIAL);
//setup IER
spi_reg_bit_set(SSP_IER, SSP_IER_TIE | SSP_IER_RIE | SSP_IER_RTOIE);
//fire SSP up
spi_reg_bit_set(SSP_TCR, SSP_TCR_SSE);
#ifdef QUEC_SPI_NOR_DMA_WAITFLAG
if(!assertFlag)
{
//XllpDmacEnableStopIrqInterrupt(DMA_DEV_SSP2_TX_CH)
//XllpDmacEnableStopIrqInterrupt(DMA_DEV_SSP2_RX_CH);
XllpDmacStartTransfer(DMA_DEV_SSP2_TX_CH);//spi同步传输必须先开启tx传输再开启rx传输
//XllpDmacStartTransfer(DMA_DEV_SSP2_RX_CH);
XllpDmacStartTransferWithStopIrqEnable(DMA_DEV_SSP2_RX_CH);
os_status = OSAFlagWait(SSP_Flash_Rx_DMA_Done_FlgRef, 0x01, OSA_FLAG_OR_CLEAR, &flag_value, 100);
if(os_status != OS_SUCCESS)
{
spi_uart_log_err("%s:ERROR,os_status=0x%x,adress=0x%x,readsize=%d",__func__,os_status,FlashOffset,Size);
Retval = SSPRxChannelTimeOutError;
}
}
else
{
//Kick off DMA
dma_xfer_start(DMA_DEV_SSP2_TX_CH);
dma_xfer_start(DMA_DEV_SSP2_RX_CH);
//setup a timer to fail gracefully in case of error
timeout = 0x1FFFFF;
//wait until the RX channel gets the stop unsigned interrupt and the TX fifo is drained
while( ((dma_read_status(DMA_DEV_SSP2_RX_CH) & XLLP_DMAC_DCSR_STOP_INTR) != XLLP_DMAC_DCSR_STOP_INTR) ||
(*SSP_STS & (0xF8000 | BIT_14 | SSP_STS_BSY)) != 0xF8000)
//((*SSP_STS & (SSP_STS_TFL | SSP_STS_TF_NF | SSP_STS_BSY)) != SSP_STS_TF_NF) )
{
//if we've waited long enough, fail
if((timeout--) <= 0)
{
spi_uart_log_err("DMA Status 0x%x, SSP Status 0x%x", dma_read_status(DMA_DEV_SSP2_RX_CH), *SSP_STS);
Retval = SSPRxChannelTimeOutError;
break;
}
}
//if we errored out, kill the DMA transfers
if(Retval != 0)
{
dma_xfer_stop( DMA_DEV_SSP2_RX_CH );
dma_xfer_stop( DMA_DEV_SSP2_TX_CH );
}
}
#else
//Kick off DMA
dma_xfer_start(DMA_DEV_SSP2_TX_CH);
dma_xfer_start(DMA_DEV_SSP2_RX_CH);
//setup a timer to fail gracefully in case of error
timeout = 0x1FFFFF;
//wait until the RX channel gets the stop unsigned interrupt and the TX fifo is drained
while( ((dma_read_status(DMA_DEV_SSP2_RX_CH) & XLLP_DMAC_DCSR_STOP_INTR) != XLLP_DMAC_DCSR_STOP_INTR) ||
(*SSP_STS & (0xF8000 | BIT_14 | SSP_STS_BSY)) != 0xF8000)
//((*SSP_STS & (SSP_STS_TFL | SSP_STS_TF_NF | SSP_STS_BSY)) != SSP_STS_TF_NF) )
{
//if we've waited long enough, fail
if((timeout--) <= 0)
{
spi_uart_log_err("DMA Status 0x%x, SSP Status 0x%x", dma_read_status(DMA_DEV_SSP2_RX_CH), *SSP_STS);
Retval = SSPRxChannelTimeOutError;
break;
}
}
//if we errored out, kill the DMA transfers
if(Retval != 0)
{
dma_xfer_stop( DMA_DEV_SSP2_RX_CH );
dma_xfer_stop( DMA_DEV_SSP2_TX_CH );
}
#endif
SPINOR_WaitSSPComplete();
Deassert_CS();
//make sure SSP is disabled
spi_reg_bit_clr(SSP_TCR, SSP_TCR_SSE | SSP_TCR_HFL);
//reset SSP CR's
spi_reg_write(SSP_TCR, SSP_TCR_INITIAL);
spi_reg_write(SSP_FCR, SSP_FCR_INITIAL);
spi_reg_write(SSP_IER, SSP_IER_INITIAL);
spi_reg_write(SSP_TOR, 0);
#ifdef QUEC_SPI_NOR_DMA_WAITFLAG
//clear out DMA settings
if (SSPport == 0){
XllpDmacUnMapDeviceToChannel(DMA_REQ_SSP0_RX, DMA_DEV_SSP2_RX_CH);
XllpDmacUnMapDeviceToChannel(DMA_REQ_SSP0_TX, DMA_DEV_SSP2_TX_CH);
}
else if (SSPport == 1){
XllpDmacUnMapDeviceToChannel(DMA_REQ_SSP1_RX, DMA_DEV_SSP2_RX_CH);
XllpDmacUnMapDeviceToChannel(DMA_REQ_SSP1_TX, DMA_DEV_SSP2_TX_CH);
}
else if (SSPport == 2){
XllpDmacUnMapDeviceToChannel(DMA_REQ_SSP2_RX, DMA_DEV_SSP2_RX_CH);
XllpDmacUnMapDeviceToChannel(DMA_REQ_SSP2_TX, DMA_DEV_SSP2_TX_CH);
}
else
{
spi_uart_log_err("port1 not support");
return 1;
}
#endif
if(Retval == 0)
memcpy( (unsigned char *)Buffer, (unsigned char *)DMA_Read_Buffer, CopySize );
return Retval;
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_ReadStatus */
/* */
/* DESCRIPTION */
/* */
/* The function read SPI nor status. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
static unsigned int SPINOR_Erase_ReadStatus(unsigned int Wait, int waitime)
{
unsigned int read = 0, ready = 0, dummy = 0, status = 0;
volatile int timeout = 0;
//Kenney wang,2020.09.05 once sleep
timeout = waitime;
//timeout = 0xFFFFF;
read = FALSE; //this flag gets set when we read first entry from fifo
//if the caller waits to 'Wait' for the BUSY to be cleared, start READY off as FALSE
//if the caller doesn't wait to wait, set READY as true, so we don't wait on the bit
ready = (Wait) ? FALSE : TRUE;
do{
//make sure SSP is disabled
SPINOR_DisableSSP();
//setup in 16 bit mode
SPINOR_SSP_DSS(16);
//fire it up
SPINOR_FireUpSSP();
Assert_CS();
//load the command + 1 dummy byte
*SSP_DR = SPI_CMD_READ_STATUS << 8;
//wait till the TX fifo is empty, then read out the status
if(SPINOR_WaitSSPComplete() != 0)
{
spi_uart_log_err("SPINOR_ReadStatus timeout");
return SSPWaitTxEmptyTimeOutError;
}
dummy = *SSP_DR;
Deassert_CS();
//set the READ flag, and read the status
read = TRUE;
status = dummy & 0xFF; //the status will be in the second byte
//set the READY flag if the status wait bit is cleared
if((status & 1) == 0) // operation complete (eg. not busy)?
ready = TRUE;
else // Kenney wang,2020.09.05 once sleep 5ms reduce cpu loading
OsaTaskSleep(1, NULL);
//make sure SSP is disabled
SPINOR_DisableSSP();
//if we've waited long enough, fail
if((timeout--) <= 0)
{
spi_uart_log_err("SSP Read Status 0x%x", *SSP_DR);
return SSPRdStatusTimeOutError;
}
//we need to wait until we read at least 1 valid status entry
//if we're waiting for the Write, wait till WIP bits goes to 0
}while ((!read) || (!ready));
//return last known status
return 0;
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_EraseSector */
/* */
/* DESCRIPTION */
/* */
/* The function erase spi nor sector. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
static unsigned int SPINOR_EraseBlock(unsigned int Addr)
{
unsigned int temp, command;
unsigned int Retval = 0;
volatile int timeout = 0;
spi_uart_log("%s: 0x%x", __FUNCTION__, Addr);
timeout = 0xFF;
do {
//make sure the device is ready to be written to
Retval = SPINOR_ReadStatus(TRUE);
//get device ready to Program
SPINOR_WriteEnable();
Retval = SPINOR_WaitForWEL(TRUE);
} while( ((--timeout) > 0) && (Retval != 0) );
if(Retval != 0)
{
spi_uart_log_err("%s: not ready to erase", __FUNCTION__);
return Retval;
}
command = ((unsigned int)SPI_CMD_BLOCK_ERASE << 24);
command |= Addr & 0xFFFFFF;
SPINOR_DisableSSP();
//setup in 32 bit mode
SPINOR_SSP_DSS(32);
//fire it up
SPINOR_FireUpSSP();
Assert_CS();
spi_reg_write(SSP_DR, command);
//wait for TX fifo to empty AND busy signal to go away
Retval = SPINOR_WaitSSPComplete();
temp = *SSP_DR;
Deassert_CS();
//make sure SSP is disabled
SPINOR_DisableSSP();
//sleep 100ms
OsaTaskSleep(20, NULL);
Retval = SPINOR_Erase_ReadStatus(TRUE, 0x7D0);//time out 10s
return Retval;
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_EraseSector */
/* */
/* DESCRIPTION */
/* */
/* The function erase spi nor sector. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
static unsigned int SPINOR_EraseSector(unsigned int Addr)
{
unsigned int temp, command;
unsigned int Retval = 0;
volatile int timeout = 0;
spi_uart_log("%s: 0x%x", __FUNCTION__, Addr);
timeout = 0xFFFF;
do {
//make sure the device is ready to be written to
Retval = SPINOR_ReadStatus(TRUE);
//get device ready to Program
SPINOR_WriteEnable();
Retval = SPINOR_WaitForWEL(TRUE);
} while( ((--timeout) > 0) && (Retval != 0) );
if(Retval != 0)
{
spi_uart_log_err("%s: not ready to erase", __FUNCTION__);
return Retval;
}
command = SPI_CMD_SECTOR_ERASE << 24;
command |= Addr & 0xFFFFFF;
SPINOR_DisableSSP();
//setup in 32 bit mode
SPINOR_SSP_DSS(32);
//fire it up
SPINOR_FireUpSSP();
Assert_CS();
spi_reg_write(SSP_DR, command);
//wait for TX fifo to empty AND busy signal to go away
Retval = SPINOR_WaitSSPComplete();
temp = *SSP_DR;
Deassert_CS();
//make sure SSP is disabled
SPINOR_DisableSSP();
//sleep 40ms
//OsaTaskSleep(8, NULL);
Retval = SPINOR_Erase_ReadStatus(TRUE, 0x7D0);//time out 10s
return Retval;
}
static void QUEC_SPI_NOR_PIO_Write(unsigned char *buf, unsigned int len)
{
unsigned int out_index = 0,in_index = 0;
unsigned int tmp_rxfifo;
unsigned char TxFifoLevel, RxFifoLevel;
unsigned char miso_data;
int i;
SPINOR_DisableSSP();
SPINOR_SSP_DSS(8);
SPINOR_FireUpSSP();
//SpiCsEnalbe();
if(((*SSP_SR) & SSP_SR_TX_FIFO_NOT_FULL) == 0)
TxFifoLevel = 32; //1802s TxFIFO Trigger Level max vaule is 32
else
TxFifoLevel = ((*SSP_SR)>>7)&0x1f;
for(i=TxFifoLevel; i<32 && out_index<len; i++)
{
BU_REG_WRITE8(SSP_DR, buf[out_index++]);
//uart_printf("%s:buf_out[%d]=0x%x", __func__, out_index-1,buf_out[out_index-1]);
}
do{
tmp_rxfifo=*SSP_SR;
RxFifoLevel=((tmp_rxfifo>>15)&0x1f);
if(((tmp_rxfifo & SSP_SR_RX_FIFO_NOT_EMPTY) == 0) && RxFifoLevel == 0x1f)
{
RxFifoLevel=0;
}
else
{
RxFifoLevel++;
}
for(i = 0; i<RxFifoLevel && in_index<len; i++)
{
miso_data = BU_REG_READ8(SSP_DR);
in_index++;
if(out_index<len)
BU_REG_WRITE8(SSP_DR, buf[out_index++]);
//uart_printf("%s:buf_in[%d]=0x%x", __func__, in_index-1,buf_in[in_index-1]);
}
}while(in_index <len);
SPINOR_DisableSSP();
}
static void QUEC_SPI_NOR_PIO_Read(unsigned char *buf, unsigned int len, unsigned char mosi_status)
{
unsigned int out_index = 0,in_index = 0;
unsigned int tmp_rxfifo;
unsigned char TxFifoLevel, RxFifoLevel;
unsigned char mosi_data;
int i;
SPINOR_DisableSSP();
SPINOR_SSP_DSS(8);
SPINOR_FireUpSSP();
if(mosi_status)
mosi_data = 0xff;
else
mosi_data = 0x00;
//SpiCsEnalbe();
if(((*SSP_SR) & SSP_SR_TX_FIFO_NOT_FULL) == 0)
TxFifoLevel = 32; //1802s TxFIFO Trigger Level max vaule is 32
else
TxFifoLevel = ((*SSP_SR)>>7)&0x1f;
for(i=TxFifoLevel; i<32 && out_index<len; i++)
{
BU_REG_WRITE8(SSP_DR, mosi_data);
out_index++;
//uart_printf("%s:buf_out[%d]=0x%x", __func__, out_index-1,buf_out[out_index-1]);
}
do{
tmp_rxfifo=*SSP_SR;
RxFifoLevel=((tmp_rxfifo>>15)&0x1f);
if(((tmp_rxfifo & SSP_SR_RX_FIFO_NOT_EMPTY) == 0) && RxFifoLevel == 0x1f)
{
RxFifoLevel=0;
}
else
{
RxFifoLevel++;
}
for(i = 0; i<RxFifoLevel && in_index<len; i++)
{
buf[in_index++] = BU_REG_READ8(SSP_DR);
if(out_index<len)
BU_REG_WRITE8(SSP_DR, mosi_data);
out_index++;
//uart_printf("%s:buf_in[%d]=0x%x", __func__, in_index-1,buf_in[in_index-1]);
}
}while(in_index <len);
SPINOR_DisableSSP();
}
static unsigned int SPINOR_Page_Program_PIO(unsigned int Address, unsigned int Buffer, unsigned int Size)
{
unsigned char data[10];
unsigned int Retval = 0, i = 0;
unsigned char *pbuf = (unsigned char *)Buffer;
spi_uart_log("%s enter", __FUNCTION__);
tx_1bytes[0] = SPI_CMD_PROGRAM;
tx_1bytes[1] = (Address >> 16) & 0xFF;
tx_1bytes[2] = (Address >> 8) & 0xFF;
tx_1bytes[3] = (Address >> 0) & 0xFF;
Assert_CS();
SPINOR_Write_Read(tx_1bytes, data, 4);
QUEC_SPI_NOR_PIO_Write(tx_1bytes,4);
QUEC_SPI_NOR_PIO_Write(pbuf,Size);
Deassert_CS();
spi_uart_log("%s leave", __FUNCTION__);
return Retval;
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_Wipe */
/* */
/* DESCRIPTION */
/* */
/* The function do SPI Nor wipe operation. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
unsigned int SPINOR_Wipe(int sspport)
{
unsigned int temp;
unsigned int Retval = 0;
volatile int timeout = 0;
OSA_STATUS status;
status = OSASemaphoreAcquire(spiSem, OS_SUSPEND);
if (status != OS_SUCCESS)
{
spi_uart_log_err("%s: ssp not ready", __FUNCTION__);
return SSPNOTREADY;
}
SetSSPPort(sspport);
timeout = 0xFF;
do {
//make sure the device is ready to be written to
Retval = SPINOR_ReadStatus(TRUE);
//get device ready to Program
SPINOR_WriteEnable();
Retval = SPINOR_WaitForWEL(TRUE);
} while( ((--timeout) > 0) && (Retval != 0) );
if(Retval != 0)
{
OSASemaphoreRelease(spiSem);
return Retval;
}
// sequence for issuing the wipe command (aka chip erase, aka bulk erase)
//make sure SSP is disabled
SPINOR_DisableSSP();
//fire it up
SPINOR_FireUpSSP();
Assert_CS();
// write the command to the fifo. this starts the spi clock running and the command appears on the bus.
spi_reg_write(SSP_DR, SPI_CMD_CHIP_ERASE);
//wait for TX fifo to empty AND busy signal to go away
Retval = SPINOR_WaitSSPComplete();
temp = *SSP_DR;
Deassert_CS();
//make sure SSP is disabled
SPINOR_DisableSSP();
//sleep 5s
OsaTaskSleep(1000, NULL);
Retval = SPINOR_Erase_ReadStatus(TRUE, 0x8CA0);//time out 3min
OSASemaphoreRelease(spiSem);
return Retval;
}
unsigned int SPINOR_Write_PIO(int sspport, unsigned int Address, unsigned int Buffer, unsigned int Size)
{
volatile int timeout = 0;
unsigned int Retval = 0, total_size = 0, write_size = 0;
P_FlashProperties_T pFlashP = GetFlashProperties(sspport);
OSA_STATUS status;
spi_uart_log("%s: enter", __FUNCTION__);
if ((Address + Size) > (pFlashP->BlockSize * pFlashP->NumBlocks))
{
return FlashAddrOutOfRange;
}
status = OSASemaphoreAcquire(spiSem, OS_SUSPEND);
if (status != OS_SUCCESS)
{
spi_uart_log_err("%s: ssp not ready", __FUNCTION__);
return SSPNOTREADY;
}
SetSSPPort(sspport);
do {
timeout = 0xFF;
do {
//make sure the device is ready to be written to
Retval = SPINOR_ReadStatus(TRUE);
//get device ready to Program
SPINOR_WriteEnable();
Retval = SPINOR_WaitForWEL(TRUE);
} while( ((--timeout) > 0) && (Retval != 0) );
if(Retval != 0)
{
spi_uart_log_err("%s: not ready to write", __FUNCTION__);
break;
}
write_size = Size > WRITE_SIZE ? WRITE_SIZE : Size;
//write a byte
if (write_size == WRITE_SIZE)
{
Retval = SPINOR_Page_Program_PIO(Address, Buffer, WRITE_SIZE);
//update counters
Address+=WRITE_SIZE;
Buffer+=WRITE_SIZE;
Size-=WRITE_SIZE;
}
else
{
Retval = SPINOR_Page_Program_PIO(Address, Buffer, write_size);
Size=0;
}
Retval = SPINOR_ReadStatus(TRUE);
} while( (Size > 0) && (Retval == 0) );
OSASemaphoreRelease(spiSem);
spi_uart_log("%s: leave", __FUNCTION__);
return Retval;
}
unsigned int SPINOR_Read_PIO(int sspport, unsigned int FlashOffset, unsigned int Buffer, unsigned int Size)
{
unsigned int i = 0;
unsigned char data[10];
unsigned int *temp_buff = NULL;
unsigned int read_size = 0, total_size = 0, Retval = 0, read_buff = 0;
DMA_CMDx_T RX_Cmd, TX_Cmd;
volatile int timeout = 0;
OSA_STATUS status;
unsigned char * pbuf = (unsigned char *)Buffer;
P_FlashProperties_T pFlashP = GetFlashProperties(sspport);
spi_uart_log("%s enter", __FUNCTION__);
if ((FlashOffset + Size) > (pFlashP->BlockSize * pFlashP->NumBlocks))
{
spi_uart_log_err("%s: 0x%x is out of range", __FUNCTION__, FlashOffset);
return FlashAddrOutOfRange;
}
status = OSASemaphoreAcquire(spiSem, OS_SUSPEND);
if (status != OS_SUCCESS)
{
spi_uart_log_err("%s: ssp not ready", __FUNCTION__);
return SSPNOTREADY;
}
SetSSPPort(sspport);
tx_1bytes[0] = SPI_CMD_READ;
tx_1bytes[1] = (FlashOffset >> 16) & 0xFF;
tx_1bytes[2] = (FlashOffset >> 8) & 0xFF;
tx_1bytes[3] = (FlashOffset >> 0) & 0xFF;
Assert_CS();
QUEC_SPI_NOR_PIO_Write(tx_1bytes,4);
QUEC_SPI_NOR_PIO_Read(pbuf,Size,0x00);
Deassert_CS();
OSASemaphoreRelease(spiSem);
spi_uart_log("%s leave", __FUNCTION__);
return Retval;
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_Erase */
/* */
/* DESCRIPTION */
/* */
/* The function do SPI Nor erase operation. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
unsigned int SPINOR_EraseByBlock(int sspport, unsigned int Address, unsigned int Size)
{
unsigned int num = 0, i = 0;
unsigned int block_size = 0, Retval = 0;
OSA_STATUS status;
P_FlashProperties_T pFlashP = GetFlashProperties(sspport);
spi_uart_log("%s: enter", __FUNCTION__);
if ((Address + Size) > (pFlashP->BlockSize * pFlashP->NumBlocks))
{
spi_uart_log_err("%s: erase size is out of range", __FUNCTION__);
return FlashAddrOutOfRange;
}
block_size = pFlashP->BlockSize;
if ((Size % pFlashP->BlockSize) == 0)
{
num = Size / pFlashP->BlockSize;
}
else
{
num = (Size / pFlashP->BlockSize) + 1;
}
status = OSASemaphoreAcquire(spiSem, OS_SUSPEND);
if (status != OS_SUCCESS)
{
spi_uart_log_err("%s: ssp not ready", __FUNCTION__);
return SSPNOTREADY;
}
SetSSPPort(sspport);
for (i = 0; i < num; i++)
{
//erase this sector
Retval = SPINOR_EraseBlock(Address);
Address += block_size;
if (Retval != 0)
{
spi_uart_log_err("%s: eraseblock error", __FUNCTION__);
break;
}
}
OSASemaphoreRelease(spiSem);
spi_uart_log("%s: leave", __FUNCTION__);
return Retval;
}
unsigned int SPINOR_EraseBySector(int sspport, unsigned int Address, unsigned int Size)
{
unsigned int num = 0, i = 0;
unsigned int sector_size = 0, Retval = 0;
OSA_STATUS status;
P_FlashProperties_T pFlashP = GetFlashProperties(sspport);
spi_uart_log("%s: enter", __FUNCTION__);
if ((Address + Size) > (pFlashP->BlockSize * pFlashP->NumBlocks))
{
spi_uart_log_err("%s: erase size is out of range", __FUNCTION__);
return FlashAddrOutOfRange;
}
sector_size = pFlashP->SectorSize;
if ((Size % sector_size) == 0)
{
num = Size / sector_size;
}
else
{
num = (Size / sector_size) + 1;
}
status = OSASemaphoreAcquire(spiSem, OS_SUSPEND);
if (status != OS_SUCCESS)
{
spi_uart_log_err("%s: ssp not ready", __FUNCTION__);
return SSPNOTREADY;
}
SetSSPPort(sspport);
for (i = 0; i < num; i++)
{
//erase this sector
Retval = SPINOR_EraseSector(Address);
Address += sector_size;
if (Retval != 0)
{
spi_uart_log_err("%s: eraseblock error", __FUNCTION__);
break;
}
}
OSASemaphoreRelease(spiSem);
spi_uart_log("%s: leave", __FUNCTION__);
return Retval;
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_Wipe */
/* */
/* DESCRIPTION */
/* */
/* The function do SPI Nor wipe operation. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
unsigned int SPINOR_Write(int sspport, unsigned int Address, unsigned int Buffer, unsigned int Size)
{
volatile int timeout = 0;
OSA_STATUS status;
unsigned int Retval = 0, total_size = 0, write_size = 0;
P_FlashProperties_T pFlashP = GetFlashProperties(sspport);
spi_uart_log("%s: enter, size:%ld", __FUNCTION__, Size);
if ((Address + Size) > (pFlashP->BlockSize * pFlashP->NumBlocks))
{
spi_uart_log_err("%s: 0x%x is out of range", __FUNCTION__, Address);
return FlashAddrOutOfRange;
}
status = OSASemaphoreAcquire(spiSem, OS_SUSPEND);
if (status != OS_SUCCESS)
{
spi_uart_log_err("%s: ssp not ready", __FUNCTION__);
return SSPNOTREADY;
}
SetSSPPort(sspport);
do
{
timeout = 0xFF;
do
{
//make sure the device is ready to be written to
Retval = SPINOR_ReadStatus(TRUE);
//get device ready to Program
SPINOR_WriteEnable();
Retval = SPINOR_WaitForWEL(TRUE);
} while( ((--timeout) > 0) && (Retval != 0) );
if(Retval != 0)
{
spi_uart_log_err("%s: not ready to write", __FUNCTION__);
break;
}
write_size = Size > WRITE_SIZE ? WRITE_SIZE : Size;
Retval = SPINOR_Page_Program_DMA(Address, Buffer, write_size);
//update counters
Address += write_size;
Buffer += write_size;
Size -= write_size;
SPINOR_ReadStatus(TRUE);
} while( Size > 0 && Retval == 0);
OSASemaphoreRelease(spiSem);
spi_uart_log("%s: leave", __FUNCTION__);
return Retval;
}
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* SPINOR_Read */
/* */
/* DESCRIPTION */
/* */
/* The function do SPI Nor read operation. */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* None N/A */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
unsigned int SPINOR_Read(int sspport, unsigned int FlashOffset, unsigned int Buffer, unsigned int Size)
{
unsigned int Retval = 0, read_size = 0;
int count = 0;
OSA_STATUS status;
spi_uart_log("%s: enter,size:%ld", __FUNCTION__,Size);
P_FlashProperties_T pFlashP = GetFlashProperties(sspport);
if ((FlashOffset + Size) > (pFlashP->BlockSize * pFlashP->NumBlocks))
{
spi_uart_log_err("%s: 0x%x is out of range size %d", __FUNCTION__, FlashOffset,Size);
return FlashAddrOutOfRange;
}
status = OSASemaphoreAcquire(spiSem, OS_SUSPEND);
if (status != OS_SUCCESS)
{
spi_uart_log_err("%s: ssp not ready", __FUNCTION__);
return SSPNOTREADY;
}
SetSSPPort(sspport);
do
{
read_size = Size > SSP_DMA_READ_SIZE ? SSP_DMA_READ_SIZE : Size;
Retval = SPINOR_Read_DMA(FlashOffset, Buffer, read_size, read_size);
if (Retval == 0)
{
//update counters
FlashOffset += read_size;
Buffer += read_size;
Size -= read_size;
}
else
{
spi_uart_log_err("%s: try read again", __FUNCTION__);
count++;
}
} while(Size > 0 && count < 3);
OSASemaphoreRelease(spiSem);
spi_uart_log("%s: leave", __FUNCTION__);
return Retval;
}
#ifdef QUEC_SPI_NOR_DMA_WAITFLAG
//add for dma wait flag 20200904
UINT32 INT_count_flash_dma_rx = 0;
UINT32 INT_count_flash_dma_tx = 0;
int ssp_flash_dma_rx_complete_handler(uint32_t val) {
INT_count_flash_dma_rx++;
XllpDmacStopTransfer(DMA_DEV_SSP2_TX_CH);
XllpDmacStopTransfer(DMA_DEV_SSP2_RX_CH);
OSAFlagSet(SSP_Flash_Rx_DMA_Done_FlgRef, 0x01, OSA_FLAG_OR);
return 0;
}
int ssp_flash_dma_tx_complete_handler(uint32_t val) {
INT_count_flash_dma_tx++;
XllpDmacStopTransfer(DMA_DEV_SSP2_TX_CH);
OSAFlagSet(SSP_Flash_Tx_DMA_Done_FlgRef, 0x01, OSA_FLAG_OR);
return 0;
}
#endif
/*************************************************************************/
/* */
/* FUNCTION */
/* */
/* InitializeSPIDevice */
/* */
/* DESCRIPTION */
/* */
/* The function intializes SPI nor device */
/* */
/* CALLED BY */
/* */
/* Application */
/* */
/* CALLS */
/* */
/* Application The application function */
/* */
/* INPUTS */
/* */
/* sspport (0,1,2) */
/* sspclock: */
/* SSP_CLOCK_13M = 0x0, */
/* SSP_CLOCK_26M = 0x1, */
/* SSP_CLOCK_52M = 0x2, */
/* */
/* OUTPUTS */
/* */
/* None N/A */
/* */
/*************************************************************************/
#define quec_app_log(msg , ...) RTI_LOG("[QUEC APP]"msg"", ##__VA_ARGS__)
#define SPI_PORT_NUM 3
char SPI_NOR_INITED[SPI_PORT_NUM];
int InitializeSPIDevice(int sspport, int sspclock)
{
unsigned int SPI_FlashID = 0;
if (sspport < SSP_PORT_0 || sspport > SSP_PORT_2)
{
CPUartLogPrintf("InitializeSPIDevice,sspport err");
return -1;
}
if(SPI_NOR_INITED[sspport] == 1)
{
quec_app_log("[%s][%d]spi nor already init \r\n", __func__, __LINE__);
return 0;
}
P_FlashProperties_T pFlashP = GetFlashProperties(sspport);
//Config ssp clock, ssp pin
ChipSelectSPI(sspport, (SSP_Clock)sspclock);
//Have to setup Flash Properties info according to FLASH's datasheet
//these info will be used in APIs
pFlashP->BlockSize = 0x10000; // 64KB
pFlashP->NumBlocks = 0x100; // 256
pFlashP->PageSize = 0x100; // 256
pFlashP->SectorSize = 0x1000; // 4096
if (spiSem == NULL)
OSASemaphoreCreate(&spiSem, 1, OSA_FIFO);
#ifdef QUEC_SPI_NOR_DMA_WAITFLAG
//add for dma wait flag 20200904
dma_irq_callback_register(ssp_flash_dma_rx_complete_handler, DMA_DEV_SSP2_RX_CH);
dma_irq_callback_register(ssp_flash_dma_tx_complete_handler, DMA_DEV_SSP2_TX_CH);
if(SSP_Flash_Rx_DMA_Done_FlgRef == NULL)
{
ASSERT(OSAFlagCreate(&SSP_Flash_Rx_DMA_Done_FlgRef) == OS_SUCCESS);
}
if(SSP_Flash_Tx_DMA_Done_FlgRef == NULL)
{
ASSERT(OSAFlagCreate(&SSP_Flash_Tx_DMA_Done_FlgRef) == OS_SUCCESS);
}
//CPUartLogPrintf("%s:Rx_DMA[0x%lx],Tx_DMA[0x%lx]", __func__, SSP_Flash_Rx_DMA_Done_FlgRef, SSP_Flash_Tx_DMA_Done_FlgRef);
#endif
SPINOR_Reset(sspport);
SPINOR_ReadId(sspport, &SPI_FlashID);
CPUartLogPrintf("InitializeSPIDevice done, flash ID 0x%x", SPI_FlashID);
SPI_NOR_INITED[sspport] = 1;
return 0;
}
#ifdef SPI_TEST
void spi_test_task()
{
int sspport = SSP_PORT_0;
int size = 1000;
unsigned int count = 0;
char *wbuf = malloc(1000);
char *rbuf = malloc(1000);
int i = 0;
unsigned int address = 0;
int sectornum = 0;
int flash_id = 0;
InitializeSPIDevice(sspport,SSP_CLOCK_52M);
for (i = 0; i < size; i++)
wbuf[i] = 0x55;
P_FlashProperties_T pFlashP = GetFlashProperties(sspport);
SPINOR_ReadId(sspport, &flash_id);
uart_printf("[%s][%d]flash id:0x%x \r\n", __func__, __LINE__, flash_id);
while(1)
{
address = sectornum*pFlashP->SectorSize;
if (address > (pFlashP->BlockSize * pFlashP->NumBlocks))
{
address = 0;
sectornum = 0;
}
memset(rbuf, 0, size);
SPINOR_EraseBySector(sspport, address, size);
SPINOR_Write(sspport, address, wbuf, size);
SPINOR_Read(sspport, address, rbuf, size);
if (memcmp(wbuf, rbuf, size) != 0)
{
uart_printf("!!!spi test error, count:%d, address:%p \r\n", count, address);
}
else
{
uart_printf("spi test ok, count:%d, address:%p \r\n", count, address);
}
count++;
sectornum++;
OSATaskSleep(1000);
}
}
OSTaskRef spitesttaskref = NULL;
static void* spiteststack = NULL;
int spiflashtest(void)
{
spiteststack = malloc(2048);
OSATaskCreate(&spitesttaskref, spiteststack, 2048, 100, "spitest", spi_test_task, NULL);
}
#endif