A27R版本修改
This commit is contained in:
747
A58-AMTLDR/Src/SpiBooter.c
Normal file
747
A58-AMTLDR/Src/SpiBooter.c
Normal file
@ -0,0 +1,747 @@
|
||||
#include <string.h>
|
||||
#include "typedef.h"
|
||||
#include "amt630h.h"
|
||||
#include "UartPrint.h"
|
||||
#include "timer.h"
|
||||
#include "spi.h"
|
||||
#include "cp15.h"
|
||||
#include "sysinfo.h"
|
||||
#include "crc32.h"
|
||||
#include "gpio.h"
|
||||
|
||||
|
||||
#if DEVICE_TYPE_SELECT == SPI_NOR_FLASH || DEVICE_TYPE_SELECT == EMMC_FLASH
|
||||
#define SPI_CS_GPIO 32
|
||||
|
||||
#define SPI_RXFIFO_FULL (1<<4)
|
||||
#define SPI_RXFIFO_NOTEMPTY (1<<3)
|
||||
#define SPI_TXFIFO_EMPTY (1<<2)
|
||||
#define SPI_TXFIFO_NOTFULL (1<<1)
|
||||
#define SPIFLASH_BUSY (1<<0)
|
||||
|
||||
/* SFUD support manufacturer JEDEC ID */
|
||||
#define SFUD_MF_ID_CYPRESS 0x01
|
||||
#define SFUD_MF_ID_FUJITSU 0x04
|
||||
#define SFUD_MF_ID_EON 0x1C
|
||||
#define SFUD_MF_ID_ATMEL 0x1F
|
||||
#define SFUD_MF_ID_MICRON 0x20
|
||||
#define SFUD_MF_ID_AMIC 0x37
|
||||
#define SFUD_MF_ID_SANYO 0x62
|
||||
#define SFUD_MF_ID_INTEL 0x89
|
||||
#define SFUD_MF_ID_ESMT 0x8C
|
||||
#define SFUD_MF_ID_FUDAN 0xA1
|
||||
#define SFUD_MF_ID_HYUNDAI 0xAD
|
||||
#define SFUD_MF_ID_SST 0xBF
|
||||
#define SFUD_MF_ID_MICRONIX 0xC2
|
||||
#define SFUD_MF_ID_GIGADEVICE 0xC8
|
||||
#define SFUD_MF_ID_ISSI 0xD5
|
||||
#define SFUD_MF_ID_WINBOND 0xEF
|
||||
|
||||
static void SpiWriteEnable(void);
|
||||
|
||||
/* flash chip information */
|
||||
typedef struct {
|
||||
char *name; /**< flash chip name */
|
||||
uint8_t mf_id; /**< manufacturer ID */
|
||||
uint8_t type_id; /**< memory type ID */
|
||||
uint8_t capacity_id; /**< capacity ID */
|
||||
uint32_t capacity; /**< flash capacity (bytes) */
|
||||
} flash_chip;
|
||||
|
||||
static const flash_chip flash_chip_table[] =
|
||||
{
|
||||
{"W25Q40BV", SFUD_MF_ID_WINBOND, 0x40, 0x13, 512L*1024L},
|
||||
{"W25Q16BV", SFUD_MF_ID_WINBOND, 0x40, 0x15, 2L*1024L*1024L},
|
||||
{"W25Q32BV", SFUD_MF_ID_WINBOND, 0x40, 0x16, 4L*1024L*1024L},
|
||||
{"W25Q64CV", SFUD_MF_ID_WINBOND, 0x40, 0x17, 8L*1024L*1024L},
|
||||
{"W25Q64DW", SFUD_MF_ID_WINBOND, 0x60, 0x17, 8L*1024L*1024L},
|
||||
{"W25Q128BV", SFUD_MF_ID_WINBOND, 0x40, 0x18, 16L*1024L*1024L},
|
||||
{"W25Q256FV", SFUD_MF_ID_WINBOND, 0x40, 0x19, 32L*1024L*1024L},
|
||||
{"W25H256JV", SFUD_MF_ID_WINBOND, 0x90, 0x19, 32L*1024L*1024L},
|
||||
{"W25Q512JVFM", SFUD_MF_ID_WINBOND, 0x70, 0x20, 64L*1024L*1024L},
|
||||
{"SST25VF080B", SFUD_MF_ID_SST, 0x25, 0x8E, 1L*1024L*1024L},
|
||||
{"SST25VF016B", SFUD_MF_ID_SST, 0x25, 0x41, 2L*1024L*1024L},
|
||||
{"EN25Q32B", SFUD_MF_ID_EON, 0x30, 0x16, 4L*1024L*1024L},
|
||||
{"GD25Q64B", SFUD_MF_ID_GIGADEVICE, 0x40, 0x17, 8L*1024L*1024L},
|
||||
{"GD25Q16B", SFUD_MF_ID_GIGADEVICE, 0x40, 0x15, 2L*1024L*1024L},
|
||||
{"GD25Q32C", SFUD_MF_ID_GIGADEVICE, 0x40, 0x16, 4L*1024L*1024L},
|
||||
{"S25FL216K", SFUD_MF_ID_CYPRESS, 0x40, 0x15, 2L*1024L*1024L},
|
||||
{"S25FL032P", SFUD_MF_ID_CYPRESS, 0x02, 0x15, 4L*1024L*1024L},
|
||||
{"A25L080", SFUD_MF_ID_AMIC, 0x30, 0x14, 1L*1024L*1024L},
|
||||
{"F25L004", SFUD_MF_ID_ESMT, 0x20, 0x13, 512L*1024L},
|
||||
{"PCT25VF016B", SFUD_MF_ID_SST, 0x25, 0x41, 2L*1024L*1024L},
|
||||
{"IS25LP128F", SFUD_MF_ID_ISSI, 0x60, 0x18, 16L*1024L*1024L},
|
||||
{"MX25L6433F", SFUD_MF_ID_MICRONIX, 0x20, 0x17, 8L*1024L*1024L},
|
||||
{"MX25L12845G", SFUD_MF_ID_MICRONIX, 0x20, 0x18, 16L*1024L*1024L},
|
||||
{"MX25L25645G", SFUD_MF_ID_MICRONIX, 0x20, 0x19, 32L*1024L*1024L},
|
||||
{"W25Q512JVFM", SFUD_MF_ID_WINBOND, 0x70, 0x20, 64L*1024L*1024L},
|
||||
{"GD25B512ME", SFUD_MF_ID_GIGADEVICE, 0x47, 0x1A, 64L*1024L*1024L},
|
||||
};
|
||||
|
||||
static int addr_in_4_byte = 0;
|
||||
|
||||
static void SetCSGpioEnable(int enable)
|
||||
{
|
||||
gpio_direction_output(SPI_CS_GPIO, !enable);
|
||||
}
|
||||
|
||||
static void SetSpiDataMode(unsigned int bitMode)
|
||||
{
|
||||
unsigned int val = 0;
|
||||
|
||||
(void)val;
|
||||
while((rSPI_SR & SPI_BUSY));
|
||||
rSPI_SSIENR = 0;
|
||||
val = rSPI_CTLR0;
|
||||
val &=~(0x1f<<16);
|
||||
val |=((bitMode-1)<<16);
|
||||
rSPI_CTLR0 = val;
|
||||
rSPI_SSIENR = 1;
|
||||
}
|
||||
|
||||
static void SpiWaitIdle(void)
|
||||
{
|
||||
while(rSPI_SR & SPIFLASH_BUSY);
|
||||
udelay(2);
|
||||
}
|
||||
|
||||
static void SpiEmptyRxFIFO(void)
|
||||
{
|
||||
INT32 data = 0;
|
||||
|
||||
(void)data;
|
||||
|
||||
while(rSPI_SR & SPI_RXFIFO_NOTEMPTY)
|
||||
data = rSPI_DR;
|
||||
}
|
||||
|
||||
/* static void SpiWriteSta2(uint8_t status)
|
||||
{
|
||||
SpiWriteEnable();
|
||||
SetSpiDataMode(8);
|
||||
SetCSGpioEnable(1);
|
||||
rSPI_DR = SPI_WRITE_STATUS2;
|
||||
rSPI_DR = status;
|
||||
SpiWaitIdle();
|
||||
SetCSGpioEnable(0);
|
||||
SetSpiDataMode(32);
|
||||
}
|
||||
|
||||
static UINT8 SpiReadSta2(void)
|
||||
{
|
||||
UINT8 status;
|
||||
|
||||
SetSpiDataMode(8);
|
||||
SetCSGpioEnable(1);
|
||||
rSPI_DR = SPI_READ_STATUS2;
|
||||
rSPI_DR = 0;
|
||||
while(!(rSPI_SR & SPI_RXFIFO_NOTEMPTY));
|
||||
status = rSPI_DR;
|
||||
while(!(rSPI_SR & SPI_RXFIFO_NOTEMPTY));
|
||||
status = rSPI_DR;
|
||||
PrintVariableValueHex("status s2 :", status);
|
||||
SpiWaitIdle();
|
||||
SetCSGpioEnable(0);
|
||||
SetSpiDataMode(32);
|
||||
return status;
|
||||
} */
|
||||
|
||||
static UINT8 SpiReadSta3(void)
|
||||
{
|
||||
UINT8 status;
|
||||
|
||||
SetSpiDataMode(8);
|
||||
SetCSGpioEnable(1);
|
||||
rSPI_DR = SPI_READ_STATUS3;
|
||||
rSPI_DR = 0;
|
||||
while(!(rSPI_SR & SPI_RXFIFO_NOTEMPTY));
|
||||
status = rSPI_DR;
|
||||
while(!(rSPI_SR & SPI_RXFIFO_NOTEMPTY));
|
||||
status = rSPI_DR;
|
||||
PrintVariableValueHex("status s3 :", status);
|
||||
SpiWaitIdle();
|
||||
SetCSGpioEnable(0);
|
||||
SetSpiDataMode(32);
|
||||
return status;
|
||||
}
|
||||
|
||||
static UINT8 SpiReadSta(void)
|
||||
{
|
||||
UINT8 status;
|
||||
|
||||
SetSpiDataMode(8);
|
||||
SetCSGpioEnable(1);
|
||||
rSPI_DR = SPI_READ_STATUS;
|
||||
rSPI_DR = 0;
|
||||
while(!(rSPI_SR & SPI_RXFIFO_NOTEMPTY));
|
||||
status = rSPI_DR;
|
||||
while(!(rSPI_SR & SPI_RXFIFO_NOTEMPTY));
|
||||
status = rSPI_DR;
|
||||
//PrintVariableValueHex("status:", status);
|
||||
SpiWaitIdle();
|
||||
SetCSGpioEnable(0);
|
||||
SetSpiDataMode(32);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void SpiDisable4ByteMode(void)
|
||||
{
|
||||
SetSpiDataMode(8);
|
||||
SetCSGpioEnable(1);
|
||||
rSPI_DR = SPI_DISABLE_4BYTE_MODE;
|
||||
while(!(rSPI_SR & SPI_TXFIFO_EMPTY));
|
||||
SpiWaitIdle();
|
||||
SetCSGpioEnable(0);
|
||||
SetSpiDataMode(32);
|
||||
}
|
||||
|
||||
static void SpiEnable4ByteMode(void)
|
||||
{
|
||||
SetSpiDataMode(8);
|
||||
SetCSGpioEnable(1);
|
||||
rSPI_DR = SPI_ENABLE_4BYTE_MODE;
|
||||
while(!(rSPI_SR & SPI_TXFIFO_EMPTY));
|
||||
SpiWaitIdle();
|
||||
SetCSGpioEnable(0);
|
||||
SetSpiDataMode(32);
|
||||
}
|
||||
|
||||
static void SpiReadPage(UINT32 pagenum, UINT32 *buf)
|
||||
{
|
||||
UINT32 addr;
|
||||
UINT32 val = 0;
|
||||
INT32 i, j;
|
||||
UINT8 tmpaddr[4];
|
||||
UINT8 *data = (UINT8*)buf;
|
||||
|
||||
(void)val;
|
||||
|
||||
addr = pagenum*BYTESPERPAGE;
|
||||
tmpaddr[0] = addr;
|
||||
tmpaddr[1] = addr>>8;
|
||||
tmpaddr[2] = addr>>16;
|
||||
tmpaddr[3] = addr>>24;
|
||||
|
||||
SpiEmptyRxFIFO();
|
||||
SetCSGpioEnable(1);
|
||||
|
||||
if (addr_in_4_byte) {
|
||||
SetSpiDataMode(8);
|
||||
rSPI_DR = SPI_4BYTEADDR_READ_DATA;
|
||||
rSPI_DR = tmpaddr[3];
|
||||
rSPI_DR = tmpaddr[2];
|
||||
rSPI_DR = tmpaddr[1];
|
||||
rSPI_DR = tmpaddr[0];
|
||||
for (i = 0; i < 5; i++) {
|
||||
while(!(rSPI_SR & SPI_RXFIFO_NOTEMPTY));
|
||||
val = rSPI_DR;
|
||||
}
|
||||
} else {
|
||||
rSPI_DR = (tmpaddr[0]<<24) | (tmpaddr[1]<<16) | (tmpaddr[2]<<8) | SPI_READ_DATA;
|
||||
while(!(rSPI_SR & SPI_RXFIFO_NOTEMPTY));
|
||||
val = rSPI_DR;
|
||||
}
|
||||
|
||||
if (addr_in_4_byte) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j = 0; j < WORDSPERPAGE; j++) {
|
||||
while(!(rSPI_SR & SPI_TXFIFO_NOTFULL));
|
||||
rSPI_DR = 0;
|
||||
}
|
||||
for (j = 0; j < WORDSPERPAGE; j++) {
|
||||
while(!(rSPI_SR & SPI_RXFIFO_NOTEMPTY));
|
||||
*data++ = rSPI_DR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < WORDSPERPAGE; i++) {
|
||||
while(!(rSPI_SR & SPI_TXFIFO_NOTFULL));
|
||||
rSPI_DR = 0;
|
||||
}
|
||||
for(i = 0; i < WORDSPERPAGE; i++) {
|
||||
while(!(rSPI_SR & SPI_RXFIFO_NOTEMPTY));
|
||||
*buf++ = rSPI_DR;
|
||||
}
|
||||
}
|
||||
|
||||
SpiWaitIdle();
|
||||
SetCSGpioEnable(0);
|
||||
if (addr_in_4_byte)
|
||||
SetSpiDataMode(32);
|
||||
}
|
||||
|
||||
void SpiSelectPad()
|
||||
{
|
||||
UINT32 val;
|
||||
val = rSYS_PAD_CTRL02;
|
||||
val &= ~0xfff;
|
||||
val |= (0x1<<10)|(0x1 << 8)|(0x1 << 6)|(0x1 << 4)| (0x1 << 2);
|
||||
rSYS_PAD_CTRL02 = val;
|
||||
|
||||
val = rSYS_SSP_CLK_CFG;
|
||||
val &= ~((0x1<<31)|(0x1<<30));
|
||||
val |= (0x1<<31)|(0x1<<30);
|
||||
rSYS_SSP_CLK_CFG = val;
|
||||
|
||||
//cs inactive first
|
||||
SetCSGpioEnable(0);
|
||||
}
|
||||
|
||||
void Reset(void)
|
||||
{
|
||||
SetSpiDataMode(8);
|
||||
rSPI_DR = 0x66;
|
||||
while((SpiReadSta() & SPI_BUSY));
|
||||
// while(!(SpiReadSta() & SPIFLASH_WRITEENABLE));
|
||||
rSPI_DR = 0x99;
|
||||
while((SpiReadSta() & SPI_BUSY));
|
||||
// while(!(SpiReadSta() & SPIFLASH_WRITEENABLE));
|
||||
|
||||
SetSpiDataMode(32);
|
||||
}
|
||||
|
||||
#define SPI0_CS0_GPIO 32
|
||||
#define SPI0_IO0_GPIO 34
|
||||
static void dwspi_jedec252_reset(void)
|
||||
{
|
||||
int i;
|
||||
int si = 0;
|
||||
UINT32 val;
|
||||
|
||||
val = rSYS_PAD_CTRL02;
|
||||
val &= ~((3 << 4) | 3);
|
||||
rSYS_PAD_CTRL02 = val;
|
||||
|
||||
gpio_direction_output(SPI0_CS0_GPIO, 1);
|
||||
gpio_direction_output(SPI0_IO0_GPIO, 1);
|
||||
udelay(300);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
gpio_direction_output(SPI0_CS0_GPIO, 0);
|
||||
gpio_direction_output(SPI0_IO0_GPIO, si);
|
||||
si = !si;
|
||||
udelay(300);
|
||||
gpio_direction_output(SPI0_CS0_GPIO, 1);
|
||||
udelay(300);
|
||||
}
|
||||
}
|
||||
|
||||
static void SpiReadDeviceId(UINT8 *mfid, UINT8 *devid)
|
||||
{
|
||||
UINT8 val[6];
|
||||
int i;
|
||||
SetSpiDataMode(8);
|
||||
SetCSGpioEnable(1);
|
||||
rSPI_DR = SPI_MF_DEVICE_ID;
|
||||
rSPI_DR = 0;
|
||||
rSPI_DR = 0;
|
||||
rSPI_DR = 0;
|
||||
rSPI_DR = 0;
|
||||
rSPI_DR = 0;
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
while(!(rSPI_SR & SPI_RXFIFO_NOTEMPTY));
|
||||
val[i] = rSPI_DR;
|
||||
}
|
||||
*mfid = val[4];
|
||||
*devid = val[5];
|
||||
SpiWaitIdle();
|
||||
SetCSGpioEnable(0);
|
||||
SetSpiDataMode(32);
|
||||
}
|
||||
|
||||
static void SpiReadJedecId(UINT8 *mfid, UINT8 *memid, UINT8 *capid)
|
||||
{
|
||||
UINT8 val[4];
|
||||
int i;
|
||||
|
||||
SetSpiDataMode(8);
|
||||
SetCSGpioEnable(1);
|
||||
rSPI_DR = SPI_READ_JEDEC_ID;
|
||||
rSPI_DR = 0;
|
||||
rSPI_DR = 0;
|
||||
rSPI_DR = 0;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
while(!(rSPI_SR & SPI_RXFIFO_NOTEMPTY));
|
||||
val[i] = rSPI_DR;
|
||||
}
|
||||
*mfid = val[1];
|
||||
*memid = val[2];
|
||||
*capid = val[3];
|
||||
SpiWaitIdle();
|
||||
SetCSGpioEnable(0);
|
||||
SetSpiDataMode(32);
|
||||
}
|
||||
|
||||
void SpiReadId(void)
|
||||
{
|
||||
UINT8 mfid,devid,memid,capid;
|
||||
|
||||
SpiReadDeviceId(&mfid,&devid);
|
||||
SpiReadJedecId(&mfid,&memid,&capid);
|
||||
PrintVariableValueHex("ManufacturerID: ", mfid);
|
||||
PrintVariableValueHex("DeviceID: ", devid);
|
||||
PrintVariableValueHex("Memory Type ID: ", memid);
|
||||
PrintVariableValueHex("Capacity ID: ", capid);
|
||||
}
|
||||
|
||||
int SpiInit(void)
|
||||
{
|
||||
uint8_t mfid, typeid, capid;
|
||||
unsigned int val;
|
||||
int i;
|
||||
|
||||
dwspi_jedec252_reset();
|
||||
SpiSelectPad();
|
||||
|
||||
val = rSYS_SOFT_RST;
|
||||
val &= ~(0x1<<8);
|
||||
rSYS_SOFT_RST = val;
|
||||
udelay(10);
|
||||
val |= (0x1<<8);
|
||||
rSYS_SOFT_RST = val;
|
||||
|
||||
rSPI_SSIENR = 0;
|
||||
rSPI_CTLR0 = 0;
|
||||
rSPI_CTLR0 |=(0<<21)|(0x1f<<16)|(0x0<<12)|(0x0<<8)|(0x0<<4);
|
||||
//rSPI_CTLR1 = 63;
|
||||
rSPI_BAUDR = 4;//42;//16;//2;
|
||||
rSPI_SER = 1;
|
||||
rSPI_IMR = 0;
|
||||
rSPI_SSIENR = 1;
|
||||
|
||||
// Reset();
|
||||
SpiReadJedecId(&mfid, &typeid, &capid);
|
||||
for (i = 0; i < sizeof(flash_chip_table) / sizeof(flash_chip); i++) {
|
||||
if ((flash_chip_table[i].mf_id == mfid)
|
||||
&& (flash_chip_table[i].type_id == typeid)
|
||||
&& (flash_chip_table[i].capacity_id == capid)) {
|
||||
if (flash_chip_table[i].capacity > 0x1000000) {
|
||||
PrintVariableValueHex("i is %x : ", i);
|
||||
addr_in_4_byte = 1;
|
||||
SpiEnable4ByteMode();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!addr_in_4_byte)
|
||||
SpiDisable4ByteMode();
|
||||
|
||||
#ifdef SPI0_QSPI_MODE
|
||||
uint8_t status = SpiReadSta2();
|
||||
status |= SPI_QE;
|
||||
SpiWriteSta2(status);
|
||||
#endif
|
||||
|
||||
SpiReadSta3();
|
||||
|
||||
udelay(10000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define SPI_READ_MAXLEN BYTESPERPAGE
|
||||
|
||||
static void SpiLoadStepldr(void (*readfunc)(UINT32, UINT32 *))
|
||||
{
|
||||
unsigned int i = 0;
|
||||
UINT32 *buf = (UINT32*)STEPLDR_ENTRY;
|
||||
UINT32 offset;
|
||||
UINT32 size;
|
||||
UINT32 nPageCount;
|
||||
UINT32 nPageStart;
|
||||
|
||||
if (ReadSysInfo()) {
|
||||
SendUartString("read sysinfo fail, try to load stepldr part a.\n");
|
||||
offset = STEPLDRA_OFFSET;
|
||||
size = STEPLDR_MAX_SIZE;
|
||||
} else {
|
||||
SysInfo *sysinfo = GetSysInfo();
|
||||
offset = sysinfo->stepldr_offset;
|
||||
size = sysinfo->stepldr_size;
|
||||
}
|
||||
|
||||
PrintVariableValueHex("stepldr offset: ", offset);
|
||||
|
||||
nPageCount = (size + BYTESPERPAGE - 1) / BYTESPERPAGE;
|
||||
nPageStart = offset / BYTESPERPAGE;
|
||||
for(i = nPageStart; i < nPageStart + nPageCount; i++)
|
||||
{
|
||||
readfunc(i, buf);
|
||||
buf += BYTESPERPAGE/4;
|
||||
}
|
||||
|
||||
#ifdef MMU_ENABLE
|
||||
CP15_clean_dcache_for_dma(STEPLDR_ENTRY, STEPLDR_ENTRY + size);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void SpiWriteEnable(void)
|
||||
{
|
||||
SetSpiDataMode(8);
|
||||
SetCSGpioEnable(1);
|
||||
rSPI_DR = SPI_WRITE_ENABLE;
|
||||
SpiWaitIdle();
|
||||
SetCSGpioEnable(0);
|
||||
while((SpiReadSta() & SPI_BUSY));
|
||||
while(!(SpiReadSta() & SPIFLASH_WRITEENABLE));
|
||||
SetSpiDataMode(32);
|
||||
}
|
||||
|
||||
static void SpiEraseSector(UINT32 sectorNum)
|
||||
{
|
||||
UINT32 addr;
|
||||
UINT8 tmpaddr[4];
|
||||
|
||||
addr = BYTESPERSECTOR*sectorNum;
|
||||
tmpaddr[0] = addr;
|
||||
tmpaddr[1] = addr>>8;
|
||||
tmpaddr[2] = addr>>16;
|
||||
tmpaddr[3] = addr>>24;
|
||||
|
||||
SpiWriteEnable();
|
||||
SetCSGpioEnable(1);
|
||||
if (addr_in_4_byte) {
|
||||
SetSpiDataMode(8);
|
||||
rSPI_DR = SPI_4BYTEADD_SECTOR_ERASE;
|
||||
rSPI_DR = tmpaddr[3];
|
||||
rSPI_DR = tmpaddr[2];
|
||||
rSPI_DR = tmpaddr[1];
|
||||
rSPI_DR = tmpaddr[0];
|
||||
} else {
|
||||
rSPI_DR = (tmpaddr[0]<<24) | (tmpaddr[1]<<16) | (tmpaddr[2]<<8) | SPI_SECTOR_ERASE;
|
||||
}
|
||||
SpiWaitIdle();
|
||||
SetCSGpioEnable(0);
|
||||
while((SpiReadSta() & SPIFLASH_WRITEENABLE));
|
||||
}
|
||||
|
||||
static void SpiEraseBlock(UINT32 blockNum)
|
||||
{
|
||||
UINT32 addr;
|
||||
UINT8 tmpaddr[4];
|
||||
|
||||
addr = BYTESPERBLOCK*blockNum;
|
||||
tmpaddr[0] = addr;
|
||||
tmpaddr[1] = addr>>8;
|
||||
tmpaddr[2] = addr>>16;
|
||||
tmpaddr[3] = addr>>24;
|
||||
|
||||
SpiWriteEnable();
|
||||
SetCSGpioEnable(1);
|
||||
if (addr_in_4_byte) {
|
||||
SetSpiDataMode(8);
|
||||
rSPI_DR = SPI_4BYTEADD_BLOCK_ERASE;
|
||||
rSPI_DR = tmpaddr[3];
|
||||
rSPI_DR = tmpaddr[2];
|
||||
rSPI_DR = tmpaddr[1];
|
||||
rSPI_DR = tmpaddr[0];
|
||||
} else {
|
||||
rSPI_DR = (tmpaddr[0]<<24) | (tmpaddr[1]<<16) | (tmpaddr[2]<<8) | SPI_BLOCK_ERASE;
|
||||
}
|
||||
SpiWaitIdle();
|
||||
SetCSGpioEnable(0);
|
||||
|
||||
while((SpiReadSta() & SPIFLASH_WRITEENABLE));
|
||||
}
|
||||
|
||||
static void SpiWritePage(UINT32 pagenum, UINT32 *buf)
|
||||
{
|
||||
UINT32 addr;
|
||||
UINT32 val = 0;;
|
||||
INT32 i;
|
||||
UINT8 tmpaddr[4];
|
||||
UINT8 *data = (UINT8*)buf;
|
||||
|
||||
(void)val;
|
||||
|
||||
addr = pagenum*BYTESPERPAGE;
|
||||
tmpaddr[0] = addr;
|
||||
tmpaddr[1] = addr>>8;
|
||||
tmpaddr[2] = addr>>16;
|
||||
tmpaddr[3] = addr>>24;
|
||||
|
||||
SpiWriteEnable();
|
||||
SetCSGpioEnable(1);
|
||||
if (addr_in_4_byte) {
|
||||
SetSpiDataMode(8);
|
||||
rSPI_DR = SPI_4BYTEADD_PAGE_PROGRAM;
|
||||
rSPI_DR = tmpaddr[3];
|
||||
rSPI_DR = tmpaddr[2];
|
||||
rSPI_DR = tmpaddr[1];
|
||||
rSPI_DR = tmpaddr[0];
|
||||
} else {
|
||||
rSPI_DR = (tmpaddr[0]<<24) | (tmpaddr[1]<<16) | (tmpaddr[2]<<8) | SPI_PAGE_PROGRAM;
|
||||
}
|
||||
|
||||
if (addr_in_4_byte) {
|
||||
for (i = 0; i < BYTESPERPAGE; i++) {
|
||||
while(!(rSPI_SR & SPI_TXFIFO_NOTFULL));
|
||||
rSPI_DR = *data++;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < WORDSPERPAGE; i++) {
|
||||
while(!(rSPI_SR & SPI_TXFIFO_NOTFULL));
|
||||
rSPI_DR = *buf++;
|
||||
}
|
||||
}
|
||||
SpiWaitIdle();
|
||||
SetCSGpioEnable(0);
|
||||
while(SpiReadSta() & SPI_BUSY);
|
||||
}
|
||||
|
||||
void bootFromSPI(void)
|
||||
{
|
||||
void (*funPtr)(void);
|
||||
|
||||
SpiLoadStepldr(SpiReadPage);
|
||||
|
||||
funPtr = (void (*)(void))STEPLDR_ENTRY;
|
||||
funPtr();
|
||||
}
|
||||
|
||||
static unsigned int pagecheck[WORDSPERPAGE];
|
||||
/* offset is at least align to SECOTR_SIZE */
|
||||
static int SpiNorBurnPage(int pagenum, unsigned int *buf)
|
||||
{
|
||||
int timeout = 3;
|
||||
unsigned int *tmp = (unsigned int *)buf;
|
||||
int i;
|
||||
|
||||
retry:
|
||||
SpiWritePage(pagenum, buf);
|
||||
SpiReadPage(pagenum, pagecheck);
|
||||
for (i = 0; i < WORDSPERPAGE; i++) {
|
||||
if (tmp[i] != pagecheck[i]) {
|
||||
if (timeout-- > 0) {
|
||||
PrintVariableValueHex("write: ", tmp[i]);
|
||||
PrintVariableValueHex("read: ", pagecheck[i]);
|
||||
SendUartString("burn check data fail, retry...\r\n");
|
||||
goto retry;
|
||||
} else {
|
||||
SendUartString("burn error!\r\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* offset is at least align to SECOTR_SIZE */
|
||||
static int SpiNorBurn(void *buf, unsigned int offset, unsigned int size)
|
||||
{
|
||||
int i, j;
|
||||
int secstart, secnum;
|
||||
int blkstart, blknum;
|
||||
int pagestart, pageburned;
|
||||
int remain = size;
|
||||
unsigned int *pbuf = (unsigned int *)buf;
|
||||
|
||||
pagestart = offset / BYTESPERPAGE;
|
||||
pageburned = 0;
|
||||
|
||||
while (remain > 0) {
|
||||
unsigned int tmp = offset & (BYTESPERBLOCK - 1);
|
||||
if (tmp) {
|
||||
tmp = (BYTESPERBLOCK - tmp) / BYTESPERSECTOR;
|
||||
secnum = (remain + BYTESPERSECTOR - 1) / BYTESPERSECTOR;
|
||||
secnum = min(tmp, secnum);
|
||||
secstart = offset / BYTESPERSECTOR;
|
||||
for (i = 0; i < secnum; i++) {
|
||||
SpiEraseSector(secstart + i);
|
||||
for (j = 0; j < PAGESPERSECTORS; j++) {
|
||||
if (SpiNorBurnPage(pagestart + j, pbuf))
|
||||
return -1;
|
||||
pbuf += WORDSPERPAGE;
|
||||
pageburned++;
|
||||
remain -= BYTESPERPAGE;
|
||||
if (remain <= 0) goto finish;
|
||||
}
|
||||
pagestart += PAGESPERSECTORS;
|
||||
}
|
||||
offset += secnum * BYTESPERSECTOR;
|
||||
} else {
|
||||
blkstart = offset / BYTESPERBLOCK;
|
||||
blknum = remain / BYTESPERBLOCK;
|
||||
for (i = 0; i < blknum; i++) {
|
||||
SpiEraseBlock(blkstart + i);
|
||||
for (j = 0; j < PAGESPERSECTORS * SECTORSPERBLOCK; j++) {
|
||||
if (SpiNorBurnPage(pagestart + j, pbuf))
|
||||
return -1;
|
||||
pbuf += WORDSPERPAGE;
|
||||
pageburned++;
|
||||
remain -= BYTESPERPAGE;
|
||||
if (remain <= 0) goto finish;
|
||||
}
|
||||
pagestart += PAGESPERSECTORS * SECTORSPERBLOCK;
|
||||
}
|
||||
offset += blknum * BYTESPERBLOCK;
|
||||
if (remain > 0) {
|
||||
secstart = offset / BYTESPERSECTOR;
|
||||
secnum = (remain + BYTESPERSECTOR - 1) / BYTESPERSECTOR;
|
||||
for (i = 0; i < secnum; i++) {
|
||||
SpiEraseSector(secstart + i);
|
||||
for (j = 0; j < PAGESPERSECTORS; j++) {
|
||||
if (SpiNorBurnPage(pagestart + j, pbuf))
|
||||
return -1;
|
||||
pbuf += WORDSPERPAGE;
|
||||
pageburned++;
|
||||
remain -= BYTESPERPAGE;
|
||||
if (remain <= 0) goto finish;
|
||||
}
|
||||
pagestart += PAGESPERSECTORS;
|
||||
}
|
||||
offset += secnum * BYTESPERSECTOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
finish:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FlashBurn(void *buf, unsigned int offset, unsigned int size)
|
||||
{
|
||||
return SpiNorBurn(buf, offset, size);
|
||||
}
|
||||
|
||||
int SpiReadSysInfo(SysInfo *info)
|
||||
{
|
||||
int pagestart;
|
||||
UINT32 checksum;
|
||||
UINT32 calc_checksum;
|
||||
UINT8 data[512];
|
||||
|
||||
pagestart = SYSINFOA_OFFSET / BYTESPERPAGE;
|
||||
SpiReadPage(pagestart, (UINT32 *)data);
|
||||
|
||||
checksum = *(UINT32*)((UINT32)data + sizeof(SysInfo) - 4);
|
||||
calc_checksum = xcrc32((unsigned char*)data, sizeof(SysInfo) - 4, 0xffffffff);
|
||||
if (calc_checksum == checksum) {
|
||||
memcpy(info, data, sizeof(SysInfo));
|
||||
return 0;
|
||||
}
|
||||
|
||||
pagestart = SYSINFOB_OFFSET / BYTESPERPAGE;
|
||||
SpiReadPage(pagestart, (UINT32 *)data);
|
||||
|
||||
checksum = *(UINT32*)((UINT32)data + sizeof(SysInfo) - 4);
|
||||
calc_checksum = xcrc32((unsigned char*)data, sizeof(SysInfo) - 4, 0xffffffff);
|
||||
if (calc_checksum == checksum) {
|
||||
memcpy(info, data, sizeof(SysInfo));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void SpiWriteSysInfo(SysInfo *info)
|
||||
{
|
||||
SpiNorBurn(info, SYSINFOB_OFFSET, sizeof(SysInfo));
|
||||
SpiNorBurn(info, SYSINFOA_OFFSET, sizeof(SysInfo));
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user