diff --git a/src/epd/spi_flash.c b/src/epd/spi_flash.c index e74b996..0dab4f4 100644 --- a/src/epd/spi_flash.c +++ b/src/epd/spi_flash.c @@ -3,54 +3,50 @@ -#define SPI_CTRL0 *(volatile unsigned short*)(0x50001200) -#define SPI_RXTX0 *(volatile unsigned short*)(0x50001202) -#define SPI_RXTX1 *(volatile unsigned short*)(0x50001204) -#define SPI_IACK *(volatile unsigned short*)(0x50001206) -#define SPI_CTRL1 *(volatile unsigned short*)(0x50001208) - static int spio_clk; static int spio_cs; static int spio_di; static int spio_do; -#define BIT_8 0 -#define BIT_16 1 -#define BIT_32 2 - -static int spi_bitmode; - /******************************************************************************/ #define FSPI_CS(n) gpio_set(spio_cs, (n)); +#define FSPI_CK(n) gpio_set(spio_clk, (n)); +#define FSPI_SI(n) gpio_set(spio_di, (n)); +#define FSPI_SO() gpio_get(spio_do); -void fspi_set_bitmode(int mode) +#define FSPI_DELAY 10 + +void fspi_delay(void) { - spi_bitmode = mode; + int i; - SPI_CTRL0 &= 0xfe7e; - SPI_CTRL0 |= (mode&3)<<7; - SPI_CTRL0 |= 0x0001; + for(i=0; i>16; - } - SPI_RXTX0 = data; + int i, data; - while((SPI_CTRL0&0x2000)==0); - SPI_IACK = 0; + data = 0; + for(i=0; i<8; i++){ + FSPI_SI(byte&0x80); + FSPI_CK(0); + fspi_delay(); - data = SPI_RXTX0; - if(spi_bitmode==BIT_8){ - data &= 0xff; - }else if(spi_bitmode==BIT_32){ - data |= (SPI_RXTX1)<<16; + data <<= 1; + data |= FSPI_SO(); + + FSPI_CK(1); + fspi_delay(); + byte <<= 1; } + return data; } @@ -59,8 +55,8 @@ int fspi_config(u32 gpio_word) { spio_clk = (gpio_word>>24)&0xff; spio_cs = (gpio_word>>16)&0xff; - spio_do = (gpio_word>> 8)&0xff; - spio_di = (gpio_word>> 0)&0xff; + spio_di = (gpio_word>> 8)&0xff; + spio_do = (gpio_word>> 0)&0xff; return 0; } @@ -68,18 +64,14 @@ int fspi_config(u32 gpio_word) int fspi_init(void) { - SetBits16(CLK_PER_REG, SPI_ENABLE, 1); - + gpio_config(spio_clk, 0x0300, 0); gpio_config(spio_cs, 0x0300, 1); - gpio_config(spio_clk, 0x0307, 0); - gpio_config(spio_do, 0x0306, 1); - gpio_config(spio_di, 0x0105, 1); - - SPI_CTRL0 = 0x0010; - fspi_set_bitmode(BIT_32); + gpio_config(spio_di, 0x0300, 1); + gpio_config(spio_do, 0x0100, 1); FSPI_CS(0); - fspi_trans(0xab000000); + fspi_delay(); + fspi_trans(0xab); FSPI_CS(1); return 0; @@ -88,9 +80,6 @@ int fspi_init(void) int fspi_exit(void) { - SPI_CTRL0 = 0; - SetBits16(CLK_PER_REG, SPI_ENABLE, 0); - gpio_config(spio_cs, 0x0300, 1); gpio_config(spio_clk, 0x0300, 0); gpio_config(spio_do, 0x0300, 0); @@ -105,59 +94,68 @@ int fspi_exit(void) int sf_readid(void) { - fspi_set_bitmode(BIT_32); FSPI_CS(0); - fspi_trans(0x90000000); - int id = fspi_trans(0); - FSPI_CS(1); - - id = __REV(id); - id &= 0xffff; + fspi_delay(); - return id; + fspi_trans(0x90); + fspi_trans(0x00); + fspi_trans(0x00); + fspi_trans(0x00); + + int mid = fspi_trans(0); + int pid = fspi_trans(0); + FSPI_CS(1); + fspi_delay(); + + return (mid<<8)|pid; } int sf_status(int id) { int status; - int cmd = (id)? 0x3500 : 0x0500; + int cmd = (id)? 0x35 : 0x05; - fspi_set_bitmode(BIT_16); FSPI_CS(0); - status = fspi_trans(cmd); + fspi_delay(); + fspi_trans(cmd); + status = fspi_trans(0); FSPI_CS(1); + fspi_delay(); return status&0xff; } int sf_wstat(int id, int stat) { - int cmd = (id)? 0x3100 : 0x0100; - cmd |= stat; + int cmd = (id)? 0x31 : 0x01; // status write enable - fspi_set_bitmode(BIT_8); FSPI_CS(0); + fspi_delay(); fspi_trans(0x50); FSPI_CS(1); + fspi_delay(); - fspi_set_bitmode(BIT_16); FSPI_CS(0); + fspi_delay(); fspi_trans(cmd); + fspi_trans(stat); FSPI_CS(1); + fspi_delay(); return 0; } int sf_wen(int en) { - fspi_set_bitmode(BIT_8); FSPI_CS(0); + fspi_delay(); if(en) fspi_trans(0x06); else fspi_trans(0x04); FSPI_CS(1); + fspi_delay(); return 0; } @@ -170,10 +168,11 @@ int sf_wait(void) status = sf_status(0); if((status&1)==0) break; + fspi_delay(); } status |= sf_status(1)<<8; - return status&0x4000; + return status; } @@ -181,26 +180,37 @@ int sf_sector_erase(int cmd, int addr, int wait) { sf_wen(1); - fspi_set_bitmode(BIT_32); FSPI_CS(0); - fspi_trans((cmd<<24)|addr); + fspi_delay(); + fspi_trans(0x20); + fspi_trans((addr>>16)&0xff); + fspi_trans((addr>> 8)&0xff); + fspi_trans((addr>> 0)&0xff); FSPI_CS(1); + fspi_delay(); - if(wait) - sf_wait(); - - return 0; + if(wait){ + int status = sf_wait(); + return status; + }else{ + return 0; + } } int sf_erase(int addr, int size, int wait) { + int status; + while(size>0){ if((addr%0x8000)==0 && size>=0x8000){ - sf_sector_erase(ERASE_32K, addr, wait); + status = sf_sector_erase(ERASE_32K, addr, wait); + printk("sf_erase: %08x 32K stat=%04x\n", addr, status); addr += 0x8000; size -= 0x8000; - }else{ - sf_sector_erase(ERASE_4K, addr, wait); + }else + { + status = sf_sector_erase(ERASE_4K, addr, wait); + printk("sf_erase: %08x 4K stat=%04x\n", addr, status); addr += 0x1000; size -= 0x1000; } @@ -216,16 +226,20 @@ int sf_page_write(int addr, u8 *buf, int size) sf_wen(1); - fspi_set_bitmode(BIT_32); FSPI_CS(0); + fspi_delay(); - fspi_trans(0x02000000|addr); - for(i=0; i>16)&0xff); + fspi_trans((addr>> 8)&0xff); + fspi_trans((addr>> 0)&0xff); + + for(i=0; i>16)&0xff); + fspi_trans((addr>> 8)&0xff); + fspi_trans((addr>> 0)&0xff); - for(i=0; i=image_flag[1]) ? 0 : 1; + firm_flag = image_flag[active]+1; + int new_id = active^1; + + firm_addr = image_addr[new_id]; + // 擦除flash + printk("Erase %08x - %08x ...\n", firm_addr, firm_addr+firm_size+64); + sf_erase(firm_addr, firm_size+64, 1); + + arch_set_sleep_mode(ARCH_SLEEP_OFF); + }else if(buf[0]==0xa2){ + // 传输page的前128字节 + memcpy(ota_buf, buf+8, 128); + }else if(buf[0]==0xa3){ + // 传输page的后128字节 + memcpy(ota_buf+128, buf+8, 128); + if(ota_state==1){ + ota_buf[3] = firm_flag; + printk("Firm Header: %08x %08x %08x %08x\n", + *(u32*)(ota_buf+0), + *(u32*)(ota_buf+4), + *(u32*)(ota_buf+8), + *(u32*)(ota_buf+28) + ); + } + + int addr = firm_addr+(ota_state-1)*256; + sf_page_write(addr, ota_buf, 256); + int status = sf_wait(); + ota_state += 1; + }else if(buf[0]==0xa4){ + ota_state = 0; + arch_set_sleep_mode(ARCH_EXT_SLEEP_ON); + // Remap addres 0x00 to ROM and force execution + SetWord16(SYS_CTRL_REG, (GetWord16(SYS_CTRL_REG) & ~REMAP_ADR0) | SW_RESET ); + } + + return 0; +} + + +/******************************************************************************/ + diff --git a/src/epd/spi_flash_hwctl.c b/src/epd/spi_flash_hwctl.c new file mode 100644 index 0000000..6c009bb --- /dev/null +++ b/src/epd/spi_flash_hwctl.c @@ -0,0 +1,537 @@ + +#include "epd.h" + + + +#define SPI_CTRL0 *(volatile unsigned short*)(0x50001200) +#define SPI_RXTX0 *(volatile unsigned short*)(0x50001202) +#define SPI_RXTX1 *(volatile unsigned short*)(0x50001204) +#define SPI_IACK *(volatile unsigned short*)(0x50001206) +#define SPI_CTRL1 *(volatile unsigned short*)(0x50001208) + + +static int spio_clk; +static int spio_cs; +static int spio_di; +static int spio_do; + +#define BIT_8 0 +#define BIT_16 1 +#define BIT_32 2 + +static int spi_bitmode; + +/******************************************************************************/ + + +#define FSPI_CS(n) gpio_set(spio_cs, (n)); + +void fspi_set_bitmode(int mode) +{ + spi_bitmode = mode; + + SPI_CTRL0 &= 0xfe7e; + SPI_CTRL0 |= (mode&3)<<7; + SPI_CTRL0 |= 0x0001; +} + +int fspi_trans(int data) +{ + if(spi_bitmode==BIT_32){ + SPI_RXTX1 = data>>16; + } + SPI_RXTX0 = data; + + while((SPI_CTRL0&0x2000)==0); + SPI_IACK = 0; + + data = SPI_RXTX0; + if(spi_bitmode==BIT_8){ + data &= 0xff; + }else if(spi_bitmode==BIT_32){ + data |= (SPI_RXTX1)<<16; + } + return data; +} + + +int fspi_config(u32 gpio_word) +{ + spio_clk = (gpio_word>>24)&0xff; + spio_cs = (gpio_word>>16)&0xff; + spio_do = (gpio_word>> 8)&0xff; + spio_di = (gpio_word>> 0)&0xff; + + return 0; +} + + +int fspi_init(void) +{ + SetBits16(CLK_PER_REG, SPI_ENABLE, 1); + + gpio_config(spio_cs, 0x0300, 1); + gpio_config(spio_clk, 0x0307, 0); + gpio_config(spio_do, 0x0306, 1); + gpio_config(spio_di, 0x0105, 1); + + SPI_CTRL0 = 0x0010; + fspi_set_bitmode(BIT_32); + + FSPI_CS(0); + fspi_trans(0xab000000); + FSPI_CS(1); + + return 0; +} + + +int fspi_exit(void) +{ + SPI_CTRL0 = 0; + SetBits16(CLK_PER_REG, SPI_ENABLE, 0); + + gpio_config(spio_cs, 0x0300, 1); + gpio_config(spio_clk, 0x0300, 0); + gpio_config(spio_do, 0x0300, 0); + gpio_config(spio_di, 0x0100, 0); + return 0; +} + + +/******************************************************************************/ +/* SPI flash */ +/******************************************************************************/ + +int sf_readid(void) +{ + fspi_set_bitmode(BIT_32); + FSPI_CS(0); + fspi_trans(0x90000000); + int id = fspi_trans(0); + FSPI_CS(1); + + id = __REV(id); + id &= 0xffff; + + return id; +} + +int sf_status(int id) +{ + int status; + int cmd = (id)? 0x3500 : 0x0500; + + fspi_set_bitmode(BIT_16); + FSPI_CS(0); + status = fspi_trans(cmd); + FSPI_CS(1); + + return status&0xff; +} + +int sf_wstat(int id, int stat) +{ + int cmd = (id)? 0x3100 : 0x0100; + cmd |= stat; + + // status write enable + fspi_set_bitmode(BIT_8); + FSPI_CS(0); + fspi_trans(0x50); + FSPI_CS(1); + + fspi_set_bitmode(BIT_16); + FSPI_CS(0); + fspi_trans(cmd); + FSPI_CS(1); + + return 0; +} + +int sf_wen(int en) +{ + fspi_set_bitmode(BIT_8); + FSPI_CS(0); + if(en) + fspi_trans(0x06); + else + fspi_trans(0x04); + FSPI_CS(1); + + return 0; +} + +int sf_wait(void) +{ + int status; + + while(1){ + status = sf_status(0); + if((status&1)==0) + break; + } + + status |= sf_status(1)<<8; + return status&0x4000; +} + + +int sf_sector_erase(int cmd, int addr, int wait) +{ + sf_wen(1); + + fspi_set_bitmode(BIT_32); + FSPI_CS(0); + fspi_trans((cmd<<24)|addr); + FSPI_CS(1); + + if(wait){ + int status = sf_wait(); + return status; + }else{ + return 0; + } +} + +int sf_erase(int addr, int size, int wait) +{ + GLOBAL_INT_DISABLE(); + + int status; + while(size>0){ +// if((addr%0x8000)==0 && size>=0x8000){ +// status = sf_sector_erase(ERASE_32K, addr, wait); +// printk("sf_erase: %08x 32K stat=%04x\n", addr, status); +// addr += 0x8000; +// size -= 0x8000; +// }else + { + status = sf_sector_erase(ERASE_4K, addr, wait); + printk("sf_erase: %08x 4K stat=%04x\n", addr, status); + addr += 0x1000; + size -= 0x1000; + } + } + + GLOBAL_INT_RESTORE(); + return 0; +} + + +int sf_page_write(int addr, u8 *buf, int size) +{ + int i; + + GLOBAL_INT_DISABLE(); + sf_wen(1); + + fspi_set_bitmode(BIT_32); + FSPI_CS(0); + + fspi_trans(0x02000000|addr); + for(i=0; i> 8); + + return crc ^ ~0U; +} + + +/******************************************************************************/ + +extern int Region$$Table$$Base; +void sf_dumpp(int addr, int size); + +int selflash(int otp_boot) +{ + u8 pbuf[256]; + u32 *p32 = (u32*)pbuf; + int image_addr[2]; + int image_flag[2]; + + fspi_init(); + int id = sf_readid(); + printk("Flash ID: %08x\n", id); + + int region_table = (int)&Region$$Table$$Base; + int firm_size = *(u32*)(region_table+0x10) - 0x07fc0000; + printk("Firm size: %08x\n", firm_size); + u32 firm_crc = crc32(0, (u8*)0x07fc0000, firm_size); + printk("Firm crc: %08x\n", firm_crc); + printk("Firm ver: %08x\n", EPD_VERSION); + + + memset(pbuf, 0, 256); + if(otp_boot==0x1234a5a5){ + // 从OTP启动。读product header。 + sf_read(0x38000, 16, pbuf); + if(pbuf[0]!=0x70 || pbuf[1]!=0x52){ + printk("Build Product header ...\n"); + p32[0] = 0x00005270; + p32[1] = 0x00004000; + p32[2] = 0x0001f000; + sf_sector_erase(ERASE_4K, 0x38000, 1); + sf_page_write(0x38000, pbuf, 12); + sf_wait(); + } + image_addr[0] = p32[1]; + image_addr[1] = p32[2]; + + // 读image header + sf_read(image_addr[0], 32, pbuf+0 ); + sf_read(image_addr[1], 32, pbuf+32); + printk("Product iamge0: %08x: %08x %08x %08x %08x\n", image_addr[0], __REV(p32[0]), p32[1], p32[2], p32[7]); + printk(" iamge1: %08x: %08x %08x %08x %08x\n", image_addr[1], __REV(p32[8]), p32[9], p32[10],p32[15]); + + // 获取当前使用的image的id + image_flag[0] = -1; + image_flag[1] = -1; + if(pbuf[ 0]==0x70 && pbuf[ 1]==0x51 && pbuf[ 2]==0xaa){ + image_flag[0] = (signed char)pbuf[ 3]; + } + if(pbuf[32]==0x70 && pbuf[33]==0x51 && pbuf[34]==0xaa){ + image_flag[1] = (signed char)pbuf[35]; + } + int active = (image_flag[0]>=image_flag[1]) ? 0 : 1; + printk("Active image: %d flag: %02x\n", active, image_flag[active]); + + if(EPD_VERSION != p32[active*8+7]){ + // 当前运行的固件与flash中的固件不同 + // 将当前固件写入非活动的image中 + int new_flag = image_flag[active]+1; + int new_id = active^1; + + // 擦除flash + printk("Erase %08x ...\n", image_addr[new_id]); + sf_erase(image_addr[new_id], firm_size+64, 1); + // 初始化image header + memset(pbuf, 0xff, 64); + p32[0] = (new_flag<<24)|0x00aa5170; + p32[1] = firm_size; + p32[2] = firm_crc; + p32[7] = EPD_VERSION; + pbuf[0x20] = 0; + + // 写入flash + u8 *firm_data = (u8*)0x07fc0000; + int addr = image_addr[new_id]; + for(int i=0; i=image_flag[1]) ? 0 : 1; + firm_flag = image_flag[active]+1; + int new_id = active^1; + + firm_addr = image_addr[new_id]; + // 擦除flash + printk("Erase %08x - %08x ...\n", firm_addr, firm_addr+firm_size+64); + sf_erase(firm_addr, firm_size+64, 1); + + arch_set_sleep_mode(ARCH_SLEEP_OFF); + }else if(buf[0]==0xa2){ + // 传输page的前128字节 + memcpy(ota_buf, buf+8, 128); + }else if(buf[0]==0xa3){ + // 传输page的后128字节 + memcpy(ota_buf+128, buf+8, 128); + if(ota_state==1){ + ota_buf[3] = firm_flag; + printk("Firm Header: %08x %08x %08x %08x\n", + *(u32*)(ota_buf+0), + *(u32*)(ota_buf+4), + *(u32*)(ota_buf+8), + *(u32*)(ota_buf+28) + ); + } + + // 先等待上一次写操作完成 + //fspi_init(); + int addr = firm_addr+(ota_state-1)*256; + sf_page_write(addr, ota_buf, 256); + int status = sf_wait(); + //printk("page_write: %08x status:%04x\n", addr, status); + ota_state += 1; + }else if(buf[0]==0xa4){ + ota_state = 0; + arch_set_sleep_mode(ARCH_EXT_SLEEP_ON); + } + + return 0; +} + + +/******************************************************************************/ +