#include #include "typedef.h" #include "amt630h.h" #include "uart.h" #include "timer.h" #include "gpio.h" #include "spi.h" #include "cp15.h" #include "sysinfo.h" #include "crc32.h" #include "update.h" #include "board.h" #include "os_adapt.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 int SpiNorBurn(void *buf, unsigned int offset, unsigned int size, int show_progress); extern void wdt_cpu_reboot(void); 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; } #ifdef SPI0_QSPI_MODE 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; } #endif 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 SpiWriteSta(uint8_t status) { SpiWriteEnable(); SetSpiDataMode(8); SetCSGpioEnable(1); rSPI_DR = SPI_WRITE_STATUS; rSPI_DR = status; SpiWaitIdle(); SetCSGpioEnable(0); SetSpiDataMode(32); } 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); } #ifdef SPI0_QSPI_MODE //********format********* //00 – Standard SPI Format // 01 – Dual SPI Format // 10 – Quad SPI Format // 11 – Reserved //********tmod********** //00 –- Transmit & Receive //01 –- Transmit Only //10 –- Receive Only //11 –- EEPROM Read static void SpiSetFrameFormatMode(unsigned char format, unsigned char tmod) { unsigned int val = 0; while((rSPI_SR & SPI_BUSY)); rSPI_SSIENR = 0; val = rSPI_CTLR0; val &= ~((0x3 << 21) | (0x3 << 8)); val |= ((format << 21) | (tmod << 8)); rSPI_CTLR0 = val; rSPI_SSIENR = 1; } static void SpiReadPageQuadMode(UINT32 pagenum, UINT32 *buf) { UINT32 addr; UINT32 val = 0; INT32 i; UINT8 tmpaddr[4]; (void)val; addr = pagenum*BYTESPERPAGE; tmpaddr[0] = addr; tmpaddr[1] = addr>>8; tmpaddr[2] = addr>>16; tmpaddr[3] = addr>>24; SpiEmptyRxFIFO(); SetCSGpioEnable(1); SpiSetFrameFormatMode(2, 2); rSPI_SSIENR = 0; if (addr_in_4_byte) { //set instruction 8bits,1byte mode; addr 32bit,4bytes mode; 6 dummy clocks rSPI_SPI_CTRLR0 = (6 << 11) | (2 << 8) | (8 << 2) | 1; rSPI_CTLR1 = WORDSPERPAGE - 1; rSPI_SSIENR = 1; rSPI_DR = SPI_QUAD_IO_READ_DATA + 1; rSPI_DR = (tmpaddr[0] << 24) | (tmpaddr[1] << 16) | (tmpaddr[2] << 8) | tmpaddr[3]; } else { //set instruction 8bits,1byte mode; addr 24bit,4bytes mode; 6 dummy clocks rSPI_SPI_CTRLR0 = (6 << 11) | (2 << 8) | (6 << 2) | 1; rSPI_CTLR1 = WORDSPERPAGE - 1; rSPI_SSIENR = 1; rSPI_DR = SPI_QUAD_IO_READ_DATA; rSPI_DR = (tmpaddr[0] << 16) | (tmpaddr[1] << 8) | (tmpaddr[2] << 0); } for(i=0; i 0x1000000) { addr_in_4_byte = 1; SpiEnable4ByteMode(); } break; } } if (!addr_in_4_byte) SpiDisable4ByteMode(); #ifdef SPI0_QSPI_MODE if((iupgrade_appsize; //根据串口升级的协议获取 new_appoffset = NEW_APPFOOSET; //升级的程序固定写在这个地址,预留3M int uup_file_type = sysinfo->reserved[9]; if(uup_file_type == UPFILE_TYPE_APP){ imageoff = AMT630_BIN_OFFSET; //固定的 运行区固定地址 }else if(uup_file_type == UPFILE_TYPE_ANIMATION){ imageoff = BOOTANIM_BIN_OFFSET; //固定的 运行区固定地址 }else if(uup_file_type == UPFILE_TYPE_RESOURCE){ imageoff = ROM_BIN_OFFSET; } //imageoff = AMT630_BIN_OFFSET; //固定的 运行区固定地址 SendUartString("start copy flash ok.\n"); //SpiReadPage(NEW_APPFOOSET / BYTESPERPAGE, buf); count_max = new_appsize/IMAGE_RW_SIZE; PrintVariableValueHex("max i ", count_max); for(i=0;ichecksum; pheader->checksum = 0; }else if (uup_file_type == UPFILE_TYPE_RESOURCE) {//资源文件 RomHeader *pheader = (RomHeader *)uup_buf; appchecksum = pheader->checksum; pheader->checksum = 0; } // unsigned int *tmp = (unsigned int *)(uup_buf + NEW_APPLDR_CHECKSUM_OFFSET); // appchecksum=*tmp; // *tmp=0; calchecksum = xcrc32(uup_buf, IMAGE_RW_SIZE, 0xffffffff); PrintVariableValueHex("appchecksum ", appchecksum); PrintVariableValueHex("calchecksum ", calchecksum); } else { calchecksum = xcrc32(uup_buf, IMAGE_RW_SIZE, calchecksum); // PrintVariableValueHex("calchecksum", calchecksum); } } if(new_appsize%IMAGE_RW_SIZE)//若最后一包数据不满0x10000 则存数据并且继续计算校验和 { // PrintVariableValueHex("update_progress_set ", 99); update_progress_set(99); uint32_t red_add,wri_add,size,count; int k; uup_buf_len = 0; count = (new_appsize%IMAGE_RW_SIZE )/0x1000; red_add = NEW_APPFOOSET+new_appsize- new_appsize%IMAGE_RW_SIZE; wri_add = imageoff+new_appsize- new_appsize%IMAGE_RW_SIZE; size = 0x1000; // PrintVariableValueHex("max k ", count); for(k=0;kupgrade_flag){//若最后一包数据不满0x1000 则存数据并且继续计算校验和 uint32_t add,add_size; add = sysinfo->upgrade_flag/256; add_size = sysinfo->upgrade_flag%256; uup_buf_len = 0; for(j=0;jupgrade_flag, 0); uup_buf_len = 0; calchecksum = xcrc32(uup_buf, sysinfo->upgrade_flag, calchecksum); // PrintVariableValueHex("end calchecksum", calchecksum); } } // PrintVariableValueHex("update_progress_set ", 100); update_progress_set(100); // SendUartString("end flash copy.\n"); PrintVariableValueHex("calchecksum", calchecksum); PrintVariableValueHex("appchecksum", appchecksum); // if(calchecksum==appchecksum) // { // SendUartString("crc32 OK\n"); sysinfo = GetSysInfo(); if (uup_file_type == UPFILE_TYPE_APP) //代码文件 sysinfo->app_size = new_appsize; sysinfo->image_offset=0x40000; sysinfo->upgrade_flag = 0; sysinfo->upgrade_appsize =0; sysinfo->reserved[9] =0; SaveSysInfo(sysinfo); wdt_cpu_reboot(); return 0; // } // else // { // SendUartString("crc32 ERROR\n"); // return -1; // } } static void SpiLoadImage(void (*readfunc)(UINT32, UINT32 *)) { unsigned int i = 0; UINT32 *buf = (UINT32*)IMAGE_ENTRY; UpFileHeader *header; UpFileInfo *appfile; UINT32 nPageCount; UINT32 nPageStart; UINT32 appsize; SysInfo *sysinfo = GetSysInfo(); PrintVariableValueHex("image_offset", sysinfo->image_offset); readfunc(sysinfo->image_offset / BYTESPERPAGE, buf); header = (UpFileHeader*)buf; appfile = &header->files[0]; if (appfile->offset & (BYTESPERPAGE - 1)) { SendUartString("\nImage positon is not align to flash pagesize, can't load.\r\n"); while(1); } if (sysinfo->app_size) appsize = sysinfo->app_size; else appsize = appfile->size; PrintVariableValueHex("appsize", appsize); nPageCount = (appsize + BYTESPERPAGE - 1) / BYTESPERPAGE; nPageStart = (appfile->offset + sysinfo->image_offset) / BYTESPERPAGE; for(i = nPageStart; i < nPageStart + nPageCount; i++) { readfunc(i, buf); buf += BYTESPERPAGE/4; } PrintVariableValueHex("upgrade_flag", sysinfo->upgrade_flag); PrintVariableValueHex("upgrade_appsize", sysinfo->upgrade_appsize); PrintVariableValueHex("checksum", sysinfo->checksum); if(sysinfo->upgrade_flag !=0 && sysinfo->upgrade_appsize!=0 ){ if(sysinfo->upgrade_flag == 0xffffffff && sysinfo->upgrade_appsize == 0xffffffff){ SysInfo *sysinfo = GetSysInfo(); sysinfo->upgrade_flag = 0; sysinfo->upgrade_appsize =0; SaveSysInfo(sysinfo); }else{ lcd_init(); wdt_stop(); SendUartString("update_logo_init... \r\n"); update_logo_init(); SendUartString("PWM2 .\r\n"); gpio_direction_output(6,1); flash_copy_demo(); wdt_start(); } } #ifdef MMU_ENABLE CP15_clean_dcache_for_dma(IMAGE_ENTRY, IMAGE_ENTRY + appsize); #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); #ifdef SPI0_QSPI_MODE SpiLoadImage(SpiReadPageQuadMode); #else SpiLoadImage(SpiReadPage); #endif funPtr = (void (*)(void))IMAGE_ENTRY; funPtr(); } static unsigned int pagecheck[WORDSPERPAGE]; /* offset is at least align to SECOTR_SIZE */ 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 */ int SpiNorBurn(void *buf, unsigned int offset, unsigned int size, int show_progress) { int i, j; int secstart, secnum; int blkstart, blknum; int pagestart, pagenum, pageburned; int remain = size; unsigned int *pbuf = (unsigned int *)buf; pagestart = offset / BYTESPERPAGE; pagenum = (size + BYTESPERPAGE - 1) / 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; if (show_progress) update_progress_set(pageburned * 100 / pagenum); } 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; if (show_progress) update_progress_set(pageburned * 100 / pagenum); } 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; if (show_progress) update_progress_set(pageburned * 100 / pagenum); } pagestart += PAGESPERSECTORS; } offset += secnum * BYTESPERSECTOR; } } } finish: if (show_progress) update_progress_set(100); return 0; } int FlashBurn(void *buf, unsigned int offset, unsigned int size, int show_progress) { return SpiNorBurn(buf, offset, size, show_progress); } int SpiReadSysInfo(SysInfo *info) { UINT32 *buf = (UINT32*)IMAGE_ENTRY; int pagestart; int pagenum; UINT32 checksum; UINT32 calc_checksum; int i; pagestart = SYSINFOA_OFFSET / BYTESPERPAGE; pagenum = (sizeof(SysInfo) + BYTESPERPAGE - 1) / BYTESPERPAGE; for(i = pagestart; i < pagestart + pagenum; i++) { SpiReadPage(i, buf); buf += BYTESPERPAGE/4; } checksum = *(UINT32*)(IMAGE_ENTRY + sizeof(SysInfo) - 4); calc_checksum = xcrc32((unsigned char*)IMAGE_ENTRY, sizeof(SysInfo) - 4, 0xffffffff); if (calc_checksum == checksum) { memcpy(info, (void*)IMAGE_ENTRY, sizeof(SysInfo)); return 0; } buf = (UINT32*)IMAGE_ENTRY; pagestart = SYSINFOB_OFFSET / BYTESPERPAGE; for(i = pagestart; i < pagestart + pagenum; i++) { SpiReadPage(i, buf); buf += BYTESPERPAGE/4; } checksum = *(UINT32*)(IMAGE_ENTRY + sizeof(SysInfo) - 4); calc_checksum = xcrc32((unsigned char*)IMAGE_ENTRY, sizeof(SysInfo) - 4, 0xffffffff); if (calc_checksum == checksum) { memcpy(info, (void*)IMAGE_ENTRY, sizeof(SysInfo)); return 0; } return -1; } void SpiWriteSysInfo(SysInfo *info) { SpiNorBurn(info, SYSINFOB_OFFSET, sizeof(SysInfo), 0); SpiNorBurn(info, SYSINFOA_OFFSET, sizeof(SysInfo), 0); } unsigned int SpiGetUpfileOffset(int type) { SysInfo *sysinfo = GetSysInfo(); if (type == UPFILE_TYPE_WHOLE) { if (sysinfo->image_offset == IMAGE_OFFSET) sysinfo->image_offset = IMAGEB_OFFSET; else sysinfo->image_offset = IMAGE_OFFSET; return sysinfo->image_offset; } else if (type == UPFILE_TYPE_FIRSTLDR) { return LOADER_OFFSET; } else if (type == UPFILE_TYPE_STEPLDR) { if (sysinfo->stepldr_offset == STEPLDRA_OFFSET) sysinfo->stepldr_offset = STEPLDRB_OFFSET; else sysinfo->stepldr_offset = STEPLDRA_OFFSET; return sysinfo->stepldr_offset; } else { unsigned int buf[WORDSPERPAGE]; UpFileHeader *header; UpFileInfo *appfile; unsigned int offset; int i; SpiReadPage(sysinfo->image_offset / BYTESPERPAGE, buf); header = (UpFileHeader*)buf; if (header->magic != MKTAG('U', 'P', 'D', 'F')) { SendUartString("old update file isn't found in flash, can't support module update.\n"); return 0xffffffff; } for (i = 0; i < header->filenum; i++) { appfile = &header->files[i]; if ((appfile->magic == UPFILE_APP_MAGIC && type == UPFILE_TYPE_APP) || (appfile->magic == MKTAG('R', 'O', 'M', 'A') && type == UPFILE_TYPE_RESOURCE) || (appfile->magic == MKTAG('B', 'A', 'N', 'I') && type == UPFILE_TYPE_ANIMATION)) { offset = appfile->offset; if (offset & (BYTESPERSECTOR - 1)) { SendUartString("offset isn't align to sector erase size, can't support module update.\n"); return 0xffffffff; } return offset + sysinfo->image_offset; } } } return 0xffffffff; } #endif