diff --git a/main.c b/main.c index 1939445..402f026 100644 --- a/main.c +++ b/main.c @@ -83,24 +83,25 @@ static void usage(void) { printf("xfel(v1.2.1) - https://github.com/xboot/xfel\r\n"); printf("usage:\r\n"); - printf(" xfel version - Show chip version\r\n"); - printf(" xfel hexdump
- Dumps memory region in hex\r\n"); - printf(" xfel dump
- Binary memory dump to stdout\r\n"); - printf(" xfel exec
- Call function address\r\n"); - printf(" xfel read32
- Read 32-bits value from device memory\r\n"); - printf(" xfel write32
- Write 32-bits value to device memory\r\n"); - printf(" xfel read
- Read memory to file\r\n"); - printf(" xfel write
- Write file to memory\r\n"); - printf(" xfel reset - Reset device using watchdog\r\n"); - printf(" xfel sid - Show sid information\r\n"); - printf(" xfel jtag - Enable jtag debug\r\n"); - printf(" xfel ddr [type] - Initial ddr controller with optional type\r\n"); - printf(" xfel spinor - Detect spi nor flash\r\n"); - printf(" xfel spinor read
- Read spi nor flash to file\r\n"); - printf(" xfel spinor write
- Write file to spi nor flash\r\n"); - printf(" xfel spinand - Detect spi nand flash\r\n"); - printf(" xfel spinand read
- Read spi nand flash to file\r\n"); - printf(" xfel spinand write
- Write file to spi nand flash\r\n"); + printf(" xfel version - Show chip version\r\n"); + printf(" xfel hexdump
- Dumps memory region in hex\r\n"); + printf(" xfel dump
- Binary memory dump to stdout\r\n"); + printf(" xfel exec
- Call function address\r\n"); + printf(" xfel read32
- Read 32-bits value from device memory\r\n"); + printf(" xfel write32
- Write 32-bits value to device memory\r\n"); + printf(" xfel read
- Read memory to file\r\n"); + printf(" xfel write
- Write file to memory\r\n"); + printf(" xfel reset - Reset device using watchdog\r\n"); + printf(" xfel sid - Show sid information\r\n"); + printf(" xfel jtag - Enable jtag debug\r\n"); + printf(" xfel ddr [type] - Initial ddr controller with optional type\r\n"); + printf(" xfel spinor - Detect spi nor flash\r\n"); + printf(" xfel spinor read
- Read spi nor flash to file\r\n"); + printf(" xfel spinor write
- Write file to spi nor flash\r\n"); + printf(" xfel spinand - Detect spi nand flash\r\n"); + printf(" xfel spinand read
- Read spi nand flash to file\r\n"); + printf(" xfel spinand write
- Write file to spi nand flash\r\n"); + printf(" xfel spinand splwrite
- Write file to spi nand flash with spl mode\r\n"); } int main(int argc, char * argv[]) @@ -383,6 +384,21 @@ int main(int argc, char * argv[]) free(buf); } } + else if(!strcmp(argv[0], "splwrite") && (argc == 4)) + { + argc -= 1; + argv += 1; + uint32_t pagesz = strtoul(argv[0], NULL, 0); + uint64_t addr = strtoull(argv[1], NULL, 0); + uint64_t len; + void * buf = file_load(argv[2], &len); + if(buf) + { + if(!spinand_splwrite(&ctx, pagesz, addr, buf, len)) + printf("Can't write spi nand flash with spl mode\r\n"); + free(buf); + } + } else usage(); } diff --git a/spinand.c b/spinand.c index 3d11290..101af49 100644 --- a/spinand.c +++ b/spinand.c @@ -488,3 +488,119 @@ int spinand_write(struct xfel_ctx_t * ctx, uint64_t addr, void * buf, uint64_t l } return 0; } + +int spinand_splwrite(struct xfel_ctx_t * ctx, uint32_t pagesz, uint64_t addr, void * buf, uint64_t len) +{ + struct spinand_pdata_t pdat; + struct progress_t p; + uint64_t base, n; + int64_t cnt; + uint32_t esize, emask; + void * nbuf; + uint64_t nlen; + + if(spinand_helper_init(ctx, &pdat)) + { + esize = pdat.info.page_size * pdat.info.pages_per_block; + emask = esize - 1; + if((pagesz <= 0) || (pagesz > pdat.info.page_size)) + pagesz = pdat.info.page_size; + if(pagesz & 0x3ff) + { + printf("The valid page size is not 1k alignable and thus not supported\r\n"); + return 0; + } + uint8_t * pbuf = buf; + if(memcmp(&pbuf[4], "eGON.BT0", 8) != 0) + { + printf("Invalid a eGON boot image\r\n"); + return 0; + } + uint32_t splsz = (pbuf[19] << 24) | (pbuf[18] << 16) | (pbuf[17] << 8) | (pbuf[16] << 0); + if(splsz > len) + { + printf("The spl size is too large, please check!\r\n"); + return 0; + } + uint32_t tsplsz = (splsz * pdat.info.page_size / pagesz + esize) & ~emask; + if(addr >= tsplsz) + { + int copies = 0; + nlen = 0; + while(nlen < addr) + { + nlen += tsplsz; + copies++; + } + nlen += len; + nbuf = malloc(nlen); + if(nbuf) + { + uint8_t * pb = buf; + uint8_t * pnb = nbuf; + memset(pnb, 0xff, nlen); + for(int i = 0; i < splsz; i += pagesz) + { + memcpy(pnb, pb, pagesz); + pb += pagesz; + pnb += pdat.info.page_size; + } + for(int i = 1; i < copies; i++) + { + memcpy(nbuf + tsplsz * i, nbuf, tsplsz); + } + memcpy(nbuf + (nlen - len), buf, len); + } + else + return 0; + } + else + { + nlen = tsplsz; + nbuf = malloc(nlen); + if(nbuf) + { + uint8_t * pb = buf; + uint8_t * pnb = nbuf; + memset(pnb, 0xff, nlen); + for(int i = 0; i < splsz; i += pagesz) + { + memcpy(pnb, pb, pagesz); + pb += pagesz; + pnb += pdat.info.page_size; + } + } + else + return 0; + } + uint8_t * pnbuf = nbuf; + base = 0 & ~emask; + cnt = ((0 & emask) + nlen + esize) & ~emask; + progress_start(&p, cnt); + while(cnt > 0) + { + n = cnt > esize ? esize : cnt; + spinand_helper_erase(ctx, &pdat, base, n); + base += n; + cnt -= n; + progress_update(&p, n); + } + base = 0; + cnt = nlen; + progress_start(&p, cnt); + while(cnt > 0) + { + n = cnt > 65536 ? 65536 : cnt; + spinand_helper_write(ctx, &pdat, base, pnbuf, n); + base += n; + cnt -= n; + pnbuf += n; + progress_update(&p, n); + } + progress_stop(&p); + if(nbuf) + free(nbuf); + return 1; + } + return 0; +} diff --git a/spinand.h b/spinand.h index 021172f..2670c4d 100644 --- a/spinand.h +++ b/spinand.h @@ -10,6 +10,7 @@ extern "C" { int spinand_detect(struct xfel_ctx_t * ctx, char * name, uint64_t * capacity); int spinand_read(struct xfel_ctx_t * ctx, uint64_t addr, void * buf, uint64_t len); int spinand_write(struct xfel_ctx_t * ctx, uint64_t addr, void * buf, uint64_t len); +int spinand_splwrite(struct xfel_ctx_t * ctx, uint32_t pagesz, uint64_t addr, void * buf, uint64_t len); #ifdef __cplusplus }