/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====* 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>15)&0x1f); if(((tmp_rxfifo & SSP_SR_RX_FIFO_NOT_EMPTY) == 0) && RxFifoLevel == 0x1f) { RxFifoLevel=0; } else { RxFifoLevel++; } for(i = 0; i>7)&0x1f; for(i=TxFifoLevel; i<32 && out_index>15)&0x1f); if(((tmp_rxfifo & SSP_SR_RX_FIFO_NOT_EMPTY) == 0) && RxFifoLevel == 0x1f) { RxFifoLevel=0; } else { RxFifoLevel++; } for(i = 0; i> 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