flash擦除是以页扇区为单位擦除,16位的falsh是三字节模式读写,超过16位使用四字节模式读写。
#include "flashspi.h"
#include "hw_types.h"
#include "hw_cm_cefuse.h"
#include "hw_cm_device.h"
#include "hw_cm_dpll.h"
#include "hw_cm_gfx.h"
#include "hw_cm_mpu.h"
#include "hw_cm_per.h"
#include "hw_cm_rtc.h"
#include "hw_cm_wkup.h"
#include "hw_control_AM335x.h"
#include "hw_emif4d.h"
#include "soc_AM335x.h"
#include "mcspi.h"
#include "gpio_v2.h"
#include "plat_gpio.h"
#include "stdlib.h"
#include "plat_mcspi.h"
#ifdef AM335X_DRIVER
#define printf(...) ;
#endif
static UINT8 spiFlashTxBuf[SPIFLASH_PAGESIZE + 5];
static UINT8 spiFlashRxBuf[SPIFLASH_PAGESIZE + 5];
static UINT8 statusbuf[8];
UINT32 SPIInit(INT32 spiId, UINT8 spiClockDiv, UINT8 spiDir)
{
INT32 spiAddr;
switch(spiId)
{
case SPI_0:
spiAddr = MCSPI0_BASE_ADDR;
break;
case SPI_1:
spiAddr = MCSPI1_BASE_ADDR;
break;
}
HWREG(spiAddr + MCSPI_SYSCONFIG) |= (MCSPI_SYSCONFIG_SOFTRESET_INITIATE <<
MCSPI_SYSCONFIG_SOFTRESET_SHIFT);
/* Wait for reset to complete */
while(HWREG(spiAddr + MCSPI_SYSSTATUS) &
MCSPI_SYSSTATUS_RESETDONE_COMPLETED == 0);
/* Reset SPI - Bit is automatically reset by hardware*/
HWREG(spiAddr + MCSPI_SYSCONFIG) = ((MCSPI_SYSCONFIG_AUTOIDLE_ENABLE <<
MCSPI_SYSCONFIG_AUTOIDLE_SHIFT) | (MCSPI_SYSCONFIG_CLOCKACTIVITY_BOTH <<
MCSPI_SYSCONFIG_CLOCKACTIVITY_SHIFT) |
(MCSPI_SYSCONFIG_SIDLEMODE_WAKEUP << MCSPI_SYSCONFIG_SIDLEMODE_SHIFT));
/* gBoardID = 1; */ //For ICE board SPI Flash
/* SPI System Register Configuration*/
if (spiDir== 0)
{
HWREG(spiAddr + MCSPI_SYST) =
(1 << MCSPI_SYST_SPIDATDIR0_SHIFT);
}
else
{
HWREG(spiAddr + MCSPI_SYST) =
(1 << MCSPI_SYST_SPIDATDIR1_SHIFT);
}
/* Configure MCSPI Module */
HWREG(spiAddr + MCSPI_MODULCTRL) =
((HWREG(spiAddr + MCSPI_MODULCTRL) &
~(MCSPI_MODULCTRL_SYSTEM_TEST | MCSPI_MODULCTRL_MS))
| ( MCSPI_MODULCTRL_SINGLE_SINGLE << MCSPI_MODULCTRL_SINGLE_SHIFT ));
if (spiDir== 0)
{
HWREG ( spiAddr + MCSPI_CHCONF(0)) =
(( MCSPI_CH0CONF_DPE0_DISABLED << MCSPI_CH0CONF_DPE0_SHIFT )
| ( MCSPI_CH0CONF_WL_8BITS << MCSPI_CH0CONF_WL_SHIFT )
| ( spiClockDiv << MCSPI_CH0CONF_CLKD_SHIFT )
| ( MCSPI_CH0CONF_EPOL_ACTIVELOW << MCSPI_CH0CONF_EPOL_SHIFT )
| ( MCSPI_CH0CONF_PHA_EVEN << MCSPI_CH0CONF_PHA_SHIFT )
| ( MCSPI_CH0CONF_POL_ACTIVELOW << MCSPI_CH0CONF_POL_SHIFT ));
}
else
{
HWREG ( spiAddr + MCSPI_CHCONF(0)) =
(( MCSPI_CH0CONF_DPE1_DISABLED << MCSPI_CH0CONF_DPE1_SHIFT )
| ( MCSPI_CH0CONF_WL_8BITS << MCSPI_CH0CONF_WL_SHIFT )
| ( MCSPI_CH0CONF_IS_LINE1 << MCSPI_CH0CONF_IS_SHIFT )
| ( spiClockDiv << MCSPI_CH0CONF_CLKD_SHIFT )
| ( MCSPI_CH0CONF_EPOL_ACTIVELOW << MCSPI_CH0CONF_EPOL_SHIFT )
| ( MCSPI_CH0CONF_PHA_EVEN << MCSPI_CH0CONF_PHA_SHIFT )
| ( MCSPI_CH0CONF_POL_ACTIVELOW << MCSPI_CH0CONF_POL_SHIFT ));
}
/* gBoardID = 2; */ //For ICE Board SPI Flash
/* Configure MCSPI Channel 1 */
HWREG ( spiAddr + MCSPI_CHCONF(1)) =
(( MCSPI_CH1CONF_DPE1_DISABLED << MCSPI_CH1CONF_DPE1_SHIFT )
| ( MCSPI_CH1CONF_WL_8BITS << MCSPI_CH1CONF_WL_SHIFT )
| ( MCSPI_CH1CONF_IS_LINE1 << MCSPI_CH1CONF_IS_SHIFT )
| ( spiClockDiv << MCSPI_CH1CONF_CLKD_SHIFT )
| ( MCSPI_CH1CONF_EPOL_ACTIVELOW << MCSPI_CH1CONF_EPOL_SHIFT )
| ( MCSPI_CH1CONF_PHA_EVEN << MCSPI_CH1CONF_PHA_SHIFT )
| ( MCSPI_CH1CONF_POL_ACTIVELOW << MCSPI_CH1CONF_POL_SHIFT ));
/* Configure MCSPI Channel 2 */
HWREG ( spiAddr + MCSPI_CHCONF(2)) =
(( MCSPI_CH2CONF_DPE1_DISABLED << MCSPI_CH2CONF_DPE1_SHIFT )
| ( MCSPI_CH2CONF_WL_8BITS << MCSPI_CH2CONF_WL_SHIFT )
| ( MCSPI_CH2CONF_IS_LINE1 << MCSPI_CH2CONF_IS_SHIFT )
| ( MCSPI_CH2CONF_CLKD_DIVBY256 << MCSPI_CH2CONF_CLKD_SHIFT )
| ( MCSPI_CH2CONF_EPOL_ACTIVELOW << MCSPI_CH2CONF_EPOL_SHIFT )
| ( MCSPI_CH2CONF_PHA_EVEN << MCSPI_CH2CONF_PHA_SHIFT )
| ( MCSPI_CH2CONF_POL_ACTIVELOW << MCSPI_CH2CONF_POL_SHIFT ));
/* Configure MCSPI Channel 3 */
HWREG ( spiAddr + MCSPI_CHCONF(3)) =
(( MCSPI_CH3CONF_DPE1_DISABLED << MCSPI_CH3CONF_DPE1_SHIFT )
| ( MCSPI_CH3CONF_WL_8BITS << MCSPI_CH3CONF_WL_SHIFT )
| ( MCSPI_CH3CONF_IS_LINE1 << MCSPI_CH3CONF_IS_SHIFT )
| ( MCSPI_CH3CONF_CLKD_DIVBY256 << MCSPI_CH3CONF_CLKD_SHIFT )
| ( MCSPI_CH3CONF_EPOL_ACTIVELOW << MCSPI_CH3CONF_EPOL_SHIFT )
| ( MCSPI_CH3CONF_PHA_EVEN << MCSPI_CH3CONF_PHA_SHIFT )
| ( MCSPI_CH3CONF_POL_ACTIVELOW << MCSPI_CH3CONF_POL_SHIFT ));
return spiAddr;
}
void SPICycle( UINT32 spiAddr, UINT8 *buf, UINT16 len, UINT16 chNum )
{
UINT32 i;
/* Enable Channel */
if (chNum > 0)
chNum = 1; /*In SUBARTIC only two channels are used*/
HWREG ( spiAddr + MCSPI_CHCTRL(chNum)) = MCSPI_CH0CTRL_EN_ACTIVE;
GPIOCs_Write(6,0);
forLoop();
/* SPI access cycle */
HWREG ( spiAddr + MCSPI_CHCONF(chNum)) |=
( MCSPI_CH0CONF_FORCE_ASSERT << MCSPI_CH0CONF_FORCE_SHIFT ) ;
/* SPI System Register Configuration*/
HWREG(spiAddr + MCSPI_SYST) = (HWREG(spiAddr + MCSPI_SYST) &
~MCSPI_SYST_SPIEN_0);
for ( i = 0 ; i < len ; i++ )
{
/* Wait for transmit empty */
while ( ( HWREG(spiAddr + MCSPI_CHSTAT(chNum))
& TX_EMPTY_FLAG) == 0 );
HWREG (spiAddr + MCSPI_TX(chNum)) = buf[i]; // Write to TX buf
/* Wait for receive data full */
while ( (HWREG(spiAddr + MCSPI_CHSTAT(chNum))&
RX_FULL_FLAG) == 0 );
buf[i] = HWREG ( spiAddr + MCSPI_RX(chNum));// Read from RX buf
}
#if 0
for ( i = 0 ; i < len ; i++ )
UARTPrint1("SPI Data", buf[i]);
#endif
HWREG ( spiAddr + MCSPI_CHCONF(chNum)) =
(HWREG ( spiAddr + MCSPI_CHCONF(chNum)) &
~( MCSPI_CH0CONF_FORCE)) ;
HWREG(spiAddr + MCSPI_SYST) |= (1 << MCSPI_SYST_SPIEN_0_SHIFT);
GPIOCs_Write(6,1);
/* Disable Channel */
HWREG ( spiAddr + MCSPI_CHCTRL(chNum)) = MCSPI_CH0CTRL_EN_INACTIVE;
forLoop();
}
void SPIRead( UINT32 spiAddr, UINT8 *buf, UINT16 len, UINT16 chNum)
{
SPICycle( spiAddr, buf, len, chNum);
}
void SPIWrite( UINT32 spiAddr, UINT8 *buf, UINT16 len, UINT16 chNum)
{
SPICycle( spiAddr, buf, len, chNum);
}
void forLoop()
{
volatile int loop;
for(loop = 0; loop < 1000; loop++);
}
UINT8 spiFlashStatus( UINT32 spiAddr)
{
/* Issue read status command */
statusbuf[0] = SPIFLASH_CMD_RDSR;
statusbuf[1] = 0;
SPIRead(spiAddr, statusbuf, SPI_STATUS_LEN, SPI_FLASH_CH);
return statusbuf[1];
}
void setFlash4Byte(UINT32 spiAddr)
{
spiFlashTxBuf[0] = CMD_ENTER_4_BYTE;
SPIWrite(spiAddr, spiFlashTxBuf, SPI_WPEN_LEN, SPI_FLASH_CH);
}
INT32 SPI_FlashReadID (UINT32 spiAddr)
{
statusbuf[0] = SPIFLASH_CMD_READID;
statusbuf[1] = 0x00;
statusbuf[2] = 0x00;
statusbuf[3] = 0x00;
SPIRead(spiAddr, statusbuf, MFID_DEVID_LEN, SPI_FLASH_CH);
printf ("ID read is 0x%x.\r\n", statusbuf[1]);
printf ("ID read is 0x%x.\r\n", statusbuf[2]);
printf ("ID read is 0x%x.\r\n", statusbuf[3]);
return (0);
}
void SPI_FlashRead( UINT32 src, UINT32 *dst, UINT32 length, UINT32 spiAddr )
{
INT32 i, j = 0;
unsigned int allLen = 0, readLen = 0;
// Setup command
for (allLen = 0; allLen < length; allLen += SPIFLASH_PAGESIZE)
{
readLen = (length - allLen) > SPIFLASH_PAGESIZE ? SPIFLASH_PAGESIZE:(length - allLen);
spiFlashRxBuf[0] = SPIFLASH_CMD_READPAGE;
spiFlashTxBuf[1] = ( src >> SHIFT_24BIT);
spiFlashRxBuf[2] = ( src >> SHIFT_WORD );
spiFlashRxBuf[3] = ( src >> SHIFT_BYTE );
spiFlashRxBuf[4] = ( src >> 0 );
// Execute SPIFLASH read cycle
SPIRead(spiAddr, spiFlashRxBuf, readLen + 5, SPI_FLASH_CH);
for ( i = 0 ; i < length ; i++ )
{
dst[j] = spiFlashRxBuf[5+i];
j++;
}
src += readLen;
}
return;
}
UINT8 SPI_FlashErase(UINT32 offset, UINT32 length, UINT32 spiAddr )
{
UINT16 quitLoop = 0;
UINT32 itr;
printf("Flash erase offset = %d , length = %d \n",offset, length);
if (offset % SPIFLASH_SECTORSIZE || length % SPIFLASH_SECTORSIZE) {
printf("SF: Erase offset/length not multiple of sector size\n");
return 0xFF;
}
length /= SPIFLASH_SECTORSIZE;
/* Issue WPEN */
for (itr = 0; itr < length; itr++)
{
//printf("Erasing sector @ %d \n",offset);
if((spiFlashStatus( spiAddr )& FLASH_WEL_STATUS) != FLASH_WEL_STATUS)
{
spiFlashTxBuf[0] = SPIFLASH_CMD_WREN;
SPIWrite(spiAddr, spiFlashTxBuf, SPI_WPEN_LEN, SPI_FLASH_CH);
while(( spiFlashStatus( spiAddr ) & FLASH_WEL_STATUS ) != FLASH_WEL_STATUS )
{
quitLoop = quitLoop + 1;
if(quitLoop > 200)
break;
}
}
/* Issue Erase */
spiFlashTxBuf[0] = SPIFLASH_CMD_SCTR_ERASE;//SPIFLASH_CMD_ERASE;
spiFlashTxBuf[1] = ( UINT8 )( offset >> SHIFT_24BIT);
spiFlashTxBuf[2] = ( UINT8 )( offset >> SHIFT_WORD );
spiFlashTxBuf[3] = ( UINT8 )( offset >> SHIFT_BYTE );
spiFlashTxBuf[4] = ( UINT8 )( offset );
SPIWrite(spiAddr, spiFlashTxBuf, SPI_ERASE_LEN, SPI_FLASH_CH);
while( ( spiFlashStatus( spiAddr) & FLASH_STATUS ) );
#ifdef VERIFY_SECTOR_ERASE
verifyErasedSector(offset,spiAddr);
#endif
offset += SPIFLASH_SECTORSIZE;
}
return 0;
}
void SPI_FlashWrite( UINT32 src, UINT32 dst, UINT32 length, UINT32 spiAddr )
{
INT32 i;
INT32 bytesLeft;
INT32 bytesToProgram;
UINT8 *psrc;
UINT16 quitLoop;
volatile int loop;
/* Establish source */
psrc = ( UINT8 * )src;
bytesLeft = length;
while ( bytesLeft > 0 )
{
bytesToProgram = bytesLeft;
/* Most to program is SPIFLASH_CMD_BLOCKSIZE */
if ( bytesToProgram > SPIFLASH_PAGESIZE )
bytesToProgram = SPIFLASH_PAGESIZE;
/* Make sure you don't run off the end of a block */
if ( ( dst & SPIFLASH_PAGEMASK ) != ( ( dst + bytesToProgram )
& SPIFLASH_PAGEMASK ) )
bytesToProgram -= ( dst + bytesToProgram ) -
( ( dst + bytesToProgram ) & SPIFLASH_PAGEMASK );
/* Issue WPEN */
quitLoop = 0;
if((spiFlashStatus( spiAddr)& FLASH_WEL_STATUS) != FLASH_WEL_STATUS)
{
spiFlashTxBuf[0] = SPIFLASH_CMD_WREN;
SPIWrite(spiAddr, spiFlashTxBuf, SPI_WPEN_LEN, SPI_FLASH_CH);
while( ( spiFlashStatus( spiAddr) & FLASH_WEL_STATUS ) != FLASH_WEL_STATUS)
{
quitLoop = quitLoop + 1;
if(quitLoop > 200)
break;
}
}
/* Create command block for program operation */
spiFlashTxBuf[0] = SPIFLASH_CMD_WRITE;
spiFlashTxBuf[1] = ( UINT8 )( dst >> SHIFT_24BIT);
spiFlashTxBuf[2] = ( UINT8 )( dst >> SHIFT_WORD );
spiFlashTxBuf[3] = ( UINT8 )( dst >> SHIFT_BYTE );
spiFlashTxBuf[4] = ( UINT8 )( dst );
forLoop();
for ( i = 0 ; i < bytesToProgram ; i++ )
spiFlashTxBuf[5+i] = *psrc++;
/* Execute write command */
SPIWrite(spiAddr, spiFlashTxBuf, bytesToProgram + 5, SPI_FLASH_CH);
/* Wait while busy */
//while( ( spiFlashStatus( spiAddr) & FLASH_STATUS ) );
/* Get ready for next iteration */
bytesLeft -= bytesToProgram;
dst += bytesToProgram;
}
}
#ifndef _FLASHSPI_H_
#define _FLASHSPI_H_
#include "userType.h"
#define SPIFLASH_PAGESIZE 256 // 一个页大小
#define SPIFLASH_SECTORSIZE 4096 // 扇区大小
#define FPGA_SIZE 64*1024*1024
#define SPI_0 0
#define SPI_1 1
#define MCSPI0_BASE_ADDR SOC_SPI_0_REGS
#define MCSPI1_BASE_ADDR SOC_SPI_1_REGS
#define TX_EMPTY_FLAG 0x02
#define RX_FULL_FLAG 0x01
// READLEN
#define SPI_WPEN_LEN 1
#define SPI_STATUS_LEN 2
#define SPI_ERASE_LEN 5
#define MFID_DEVID_LEN 8
#define SHIFT_BYTE 8
#define SHIFT_WORD 16
#define SHIFT_24BIT 24
#define SPIFLASH_MANUF_ID 0xEF
#define SPI_FLASH_CH 0
#define SPIFLASH_PAGEMASK 0xffffffc0
// CMD
#define SPIFLASH_CMD_WREN 0x06
#define SPIFLASH_CMD_READ 0x03
#define SPIFLASH_CMD_WRDI 0x04
#define SPIFLASH_CMD_RDSR 0x05
#define SPIFLASH_CMD_WRITE 0x12
#define SPIFLASH_CMD_READPAGE 0x13
#define SPIFLASH_CMD_READID 0x9E
#define SPIFLASH_CMD_ERASE 0xD8
#define SPIFLASH_CMD_SCTR_ERASE 0x20
#define CMD_ENTER_4_BYTE 0xb7
#define FLASH_STATUS 0x01
#define FLASH_WEL_STATUS 0x02
UINT32 SPIInit(INT32 spiId, UINT8 spiClockDiv, UINT8 spiDir);
void SPICycle( UINT32 spiAddr, UINT8 *buf, UINT16 len, UINT16 chNum);
void SPIRead( UINT32 spiAddr, UINT8 *buf, UINT16 len, UINT16 chNum);
void SPIWrite( UINT32 spiAddr, UINT8 *buf, UINT16 len, UINT16 chNum);
INT32 SPI_FlashReadID (UINT32 spiAddr);
UINT8 SPI_FlashErase(UINT32 offset, UINT32 length, UINT32 spiAddr );
void SPI_FlashRead( UINT32 src, UINT32 *dst, UINT32 length, UINT32 spiAddr );
void SPI_FlashWrite( UINT32 src, UINT32 dst, UINT32 length, UINT32 spiAddr );
void forLoop();
void setFlash4Byte(UINT32 spiAddr);
UINT8 spiFlashStatus( UINT32 spiAddr);
#endif