diff --git a/dump.scr b/dump.scr index 64b5f6b..93d19ac 100644 --- a/dump.scr +++ b/dump.scr @@ -1,16 +1,18 @@ echo "Dumping script" nquery 0 -set NAND_IGNORE_ECC 1 +#set NAND_RAW 1 set NAND_ECCPOS 3 rebuildcfg boot echo "Configured for bootloader IO!" -ndump 0 0 64 "dump/nand.bin" +ndump_oob 0 0 128 "dump/nand.bin" -set NAND_IGNORE_ECC +exit + +set NAND_RAW set NAND_ECCPOS 8 rebuildcfg boot diff --git a/ingenic.c b/ingenic.c index 268410b..f84db2b 100644 --- a/ingenic.c +++ b/ingenic.c @@ -488,7 +488,10 @@ int ingenic_query_nand(void *hndl, int cs, nand_info_t *info) { int ingenic_dump_nand(void *hndl, int cs, int start, int pages, int type, const char *filename) { HANDLE; - + + int raw = type & NAND_RAW; + type &= ~NAND_RAW; + int page_size = (handle->nand.nand_ps + (type == NO_OOB ? 0 : handle->nand.nand_os)); int chunk_pages = STAGE2_IOBUF / page_size; @@ -500,8 +503,6 @@ int ingenic_dump_nand(void *hndl, int cs, int start, int pages, int type, const void *iobuf = malloc(chunk_pages * page_size); int ret = 0; - int ignore_ecc = type & IGNORE_ECC; - type &= ~IGNORE_ECC; while(pages > 0) { int chunk = pages < chunk_pages ? pages : chunk_pages; @@ -517,7 +518,7 @@ int ingenic_dump_nand(void *hndl, int cs, int start, int pages, int type, const if(ret == -1) break; - ret = ingenic_nandop(handle->usb, cs, NAND_READ, type); + ret = ingenic_nandop(handle->usb, cs, raw ? NAND_READ_RAW : NAND_READ, type); if(ret == -1) break; @@ -543,7 +544,7 @@ int ingenic_dump_nand(void *hndl, int cs, int start, int pages, int type, const if(ret == -1) return -1; - if(result[3] != 0 && !ignore_ecc) { + if(result[3] != 0 && !raw) { debug(LEVEL_ERROR, "Ingenic: ECC failure while reading NAND. See UART output for details\n"); errno = EIO; @@ -586,3 +587,79 @@ int ingenic_erase_nand(void *hndl, int cs, int start, int blocks) { return 0; } + +int ingenic_program_nand(void *hndl, int cs, int start, int type, const char *filename) { + HANDLE; + + int page_size = (handle->nand.nand_ps + (type == NO_OOB ? 0 : handle->nand.nand_os)); + int chunk_pages = STAGE2_IOBUF / page_size; + + FILE *in = fopen(filename, "rb"); + + if(in == NULL) + return -1; + + fseek(in, 0, SEEK_END); + int file_size = ftell(in); + fseek(in, 0, SEEK_SET); + + int pages = file_size / page_size; + int ret = 0; + + void *iobuf = malloc(chunk_pages * page_size); + + debug(LEVEL_INFO, "Programming %d pages from %d (%d bytes, %d bytes/page)\n", pages, start, file_size, page_size); + + while(pages > 0) { + int chunk = pages < chunk_pages ? pages : chunk_pages; + int bytes = chunk * page_size; + + debug(LEVEL_DEBUG, "Writing %d pages from %d\n", chunk, start); + + ret = fread(iobuf, 1, bytes, in); + + if(ret != bytes) { + debug(LEVEL_ERROR, "fread: %d\n", ret); + + ret = -1; + errno = EIO; + + break; + } + + if(usbdev_sendbulk(handle->usb, iobuf, bytes) == -1) + return -1; + + ret = ingenic_wordop(handle->usb, VR_SET_DATA_ADDRESS, start); + + if(ret == -1) + break; + + ret = ingenic_wordop(handle->usb, VR_SET_DATA_LENGTH, chunk); + + if(ret == -1) + break; + + ret = ingenic_nandop(handle->usb, cs, NAND_PROGRAM, type); + + if(ret == -1) + break; + + uint16_t result[4]; + + ret = usbdev_recvbulk(handle->usb, result, sizeof(result)); + + if(ret == -1) + return -1; + + hexdump(result, ret); + + start += chunk; + pages -= chunk; + } + + free(iobuf); + fclose(in); + + return ret; +} diff --git a/ingenic.h b/ingenic.h index bec6432..dd2cbcb 100644 --- a/ingenic.h +++ b/ingenic.h @@ -52,7 +52,7 @@ #define OOB_ECC 0 #define OOB_NO_ECC 1 #define NO_OOB 2 -#define IGNORE_ECC (1 << 7) +#define NAND_RAW (1 << 7) typedef struct { /* debug args */ @@ -136,6 +136,7 @@ int ingenic_go(void *hndl, uint32_t address); int ingenic_query_nand(void *hndl, int cs, nand_info_t *info); int ingenic_dump_nand(void *hndl, int cs, int start, int pages, int type, const char *filename); +int ingenic_program_nand(void *hndl, int cs, int start, int type, const char *filename); int ingenic_erase_nand(void *hndl, int cs, int start, int blocks); #endif diff --git a/usbboot_cmdset.c b/usbboot_cmdset.c index 9ad88f1..fa4c6a8 100644 --- a/usbboot_cmdset.c +++ b/usbboot_cmdset.c @@ -31,6 +31,7 @@ static int usbboot_go(int argc, char *argv[]); static int usbboot_nquery(int argc, char *argv[]); static int usbboot_ndump(int argc, char *argv[]); static int usbboot_nerase(int argc, char *argv[]); +static int usbboot_nprogram(int argc, char *argv[]); const shell_command_t usbboot_cmdset[] = { @@ -42,6 +43,8 @@ const shell_command_t usbboot_cmdset[] = { { "ndump", " - Dump NAND to file", usbboot_ndump }, { "ndump_oob", " - Dump NAND with OOB to file", usbboot_ndump }, { "nerase", " - Erase NAND blocks", usbboot_nerase }, + { "nprogram", " - Program NAND from file", usbboot_nprogram }, + { "nprogram_oob", " - Program NAND with OOB from file", usbboot_nprogram }, { NULL, NULL, NULL } }; @@ -123,8 +126,8 @@ static int usbboot_ndump(int argc, char *argv[]) { int type = strcmp(argv[0], "ndump_oob") ? NO_OOB : OOB_ECC; - if(cfg_getenv("NAND_IGNORE_ECC")) - type |= IGNORE_ECC; + if(cfg_getenv("NAND_RAW")) + type |= NAND_RAW; int ret = ingenic_dump_nand(shell_device(), atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), type, argv[4]); @@ -149,3 +152,28 @@ static int usbboot_nerase(int argc, char *argv[]) { return ret; } + +static int usbboot_nprogram(int argc, char *argv[]) { + if(argc != 4) { + printf("Usage: %s \n", argv[0]); + + return -1; + } + + int type = strcmp(argv[0], "nprogram_oob") ? NO_OOB : OOB_ECC; + + if(strcmp(argv[0], "nprogram_oob") == 0) { + if(cfg_getenv("NAND_RAW")) + type = OOB_ECC; + else + type = OOB_NO_ECC; + } else + type = NO_OOB; + + int ret = ingenic_program_nand(shell_device(), atoi(argv[1]), atoi(argv[2]), type, argv[3]); + + if(ret == -1) + perror("ingenic_program_nand"); + + return ret; +}