2942 lines
110 KiB
C
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
|