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
}