
On Thu, Aug 03, 2006 at 03:20:49PM +0200, Ladislav Michl wrote:
Hi,
currently nboot command is able to load kernel from given ofset of given nand chip. I hope others would find useful if it could load kernel from given partition, too. What about nboot.part - load from current partition (given by partition variable) nboot.part [part_name]
nboot.part is not necessary, so droped.
Comments and suggestions welcome and appreciated. Especialy ideas for some nice command name :-)
I'm leaving for one week holiday, please give it a try.
Best regards, ladis
diff --git a/common/env_nand.c b/common/env_nand.c index 0a05b09..4e92d3f 100644 --- a/common/env_nand.c +++ b/common/env_nand.c @@ -146,7 +146,7 @@ int saveenv(void) int ret = 0;
puts ("Erasing Nand..."); - if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE)) + if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE, 0)) return 1;
puts ("Writing to Nand... "); diff --git a/include/nand.h b/include/nand.h index 905115b..ccac9c1 100644 --- a/include/nand.h +++ b/include/nand.h @@ -48,7 +48,7 @@ static inline int nand_block_isbad(nand_ return info->block_isbad(info, ofs); }
-static inline int nand_erase(nand_info_t *info, ulong off, ulong size) +static inline int nand_erase(nand_info_t *info, ulong off, ulong size, int clean) { struct erase_info instr;
@@ -57,7 +57,7 @@ static inline int nand_erase(nand_info_t instr.len = size; instr.callback = 0;
- return info->erase(info, &instr); + return nand_erase_nand(info, &instr, clean); }
#endif diff --git a/common/cmd_nand.c b/common/cmd_nand.c index 21adb1b..27ee495 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -36,6 +36,15 @@ #endif #include <jffs2/jffs2.h> #include <nand.h>
+#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) + +/* parition handling routines */ +int mtdparts_init(void); +int id_parse(const char *id, const char **ret_id, u8 *dev_type, u8 *dev_num); +int find_dev_and_part(const char *id, struct mtd_device **dev, + u8 *part_num, struct part_info **part); +#endif + extern nand_info_t nand_info[]; /* info for NAND chips */
static int nand_dump_oob(nand_info_t *nand, ulong off) @@ -83,50 +92,58 @@ static int nand_dump(nand_info_t *nand,
/* ------------------------------------------------------------------------- */
-static void -arg_off_size(int argc, char *argv[], ulong *off, ulong *size, ulong totsize) +static int str2long(char *p, ulong *num) { - *off = 0; - *size = 0; - -#if defined(CONFIG_JFFS2_NAND) && defined(CFG_JFFS_CUSTOM_PART) - if (argc >= 1 && strcmp(argv[0], "partition") == 0) { - int part_num; - struct part_info *part; - const char *partstr; + char *endptr;
- if (argc >= 2) - partstr = argv[1]; - else - partstr = getenv("partition"); - - if (partstr) - part_num = (int)simple_strtoul(partstr, NULL, 10); - else - part_num = 0; + *num = simple_strtoul(p, &endptr, 16); + return (*p != '\0' && *endptr == '\0') ? 1 : 0; +}
- part = jffs2_part_info(part_num); - if (part == NULL) { - printf("\nInvalid partition %d\n", part_num); - return; +static int +arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, ulong *size) +{ + int idx = nand_curr_device; +#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) + struct mtd_device *dev; + struct part_info *part; + u8 pnum; + + if (argc == 1 && !(str2long(argv[0], off))) { + if ((mtdparts_init() == 0) && + (find_dev_and_part(argv[0], &dev, &pnum, &part) == 0)) { + if (dev->id->type != MTD_DEV_TYPE_NAND) { + puts("not a NAND device\n"); + return 1; + } + *off = part->offset; + *size = part->size; + idx = dev->id->num; + *nand = nand_info[idx]; + goto out; } - *size = part->size; - *off = (ulong)part->offset; - } else + } #endif - { - if (argc >= 1) - *off = (ulong)simple_strtoul(argv[0], NULL, 16); - else - *off = 0;
- if (argc >= 2) - *size = (ulong)simple_strtoul(argv[1], NULL, 16); - else - *size = totsize - *off; + if (argc >= 1) { + if (!(str2long(argv[0], off))) { + printf("'%s' is not a number\n", argv[0]); + return 1; + } + } else + *off = 0;
- } + if (argc >= 2) { + if (!(str2long(argv[1], size))) { + printf("'%s' is not a number\n", argv[1]); + return 1; + } + } else + *size = nand->size - *off;
+out: + printf("device %d offset 0x%x, size 0x%x ", idx, *off, *size); + return 0; }
int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) @@ -197,14 +214,20 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, return 0; }
+ /* + * Syntax is: + * 0 1 2 3 4 + * nand erase [clean] [off size] + */ if (strcmp(cmd, "erase") == 0) { - arg_off_size(argc - 2, argv + 2, &off, &size, nand->size); - if (off == 0 && size == 0) + /* "clean" at index 2 means request to erase OOB */ + int clean = (argc > 2 && strcmp(argv[2], "clean") == 0) ? 1 : 0; + int o = clean ? 3 : 2; + puts("\nNAND erase: "); + /* skip first two or three arguments, look for offset and size */ + if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0) return 1; - - printf("\nNAND erase: device %d offset 0x%x, size 0x%x ", - nand_curr_device, off, size); - ret = nand_erase(nand, off, size); + ret = nand_erase(nand, off, size, clean); printf("%s\n", ret ? "ERROR" : "OK");
return ret == 0 ? 0 : 1; @@ -241,13 +264,10 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, */ addr = (ulong)simple_strtoul(argv[2], NULL, 16);
- arg_off_size(argc - 3, argv + 3, &off, &size, nand->size); - if (off == 0 && size == 0) - return 1; - i = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */ - printf("\nNAND %s: device %d offset %u, size %u ... ", - i ? "read" : "write", nand_curr_device, off, size); + printf("\nNAND %s: ", i ? "read" : "write"); + if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0) + return 1;
if (i) ret = nand_read(nand, off, &size, (u_char *)addr); @@ -275,66 +295,23 @@ U_BOOT_CMD(nand, 5, 1, do_nand, " offset `off' (entire device if not specified)\n" "nand bad - show bad blocks\n" "nand dump[.oob] off - dump page\n" - "nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n" "nand markbad off - mark bad block at offset (UNSAFE)\n" "nand biterr off - make a bit error at offset (UNSAFE)\n");
-int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand, + ulong offset, ulong addr, char *cmd) { - char *boot_device = NULL; - char *ep; - int dev; int r; - ulong addr, cnt, offset = 0; + char *ep; + ulong cnt; image_header_t *hdr; - nand_info_t *nand;
- switch (argc) { - case 1: - addr = CFG_LOAD_ADDR; - boot_device = getenv("bootdevice"); - break; - case 2: - addr = simple_strtoul(argv[1], NULL, 16); - boot_device = getenv("bootdevice"); - break; - case 3: - addr = simple_strtoul(argv[1], NULL, 16); - boot_device = argv[2]; - break; - case 4: - addr = simple_strtoul(argv[1], NULL, 16); - boot_device = argv[2]; - offset = simple_strtoul(argv[3], NULL, 16); - break; - default: - printf("Usage:\n%s\n", cmdtp->usage); - SHOW_BOOT_PROGRESS(-1); - return 1; - } - - if (!boot_device) { - puts("\n** No boot device **\n"); - SHOW_BOOT_PROGRESS(-1); - return 1; - } - - dev = simple_strtoul(boot_device, &ep, 16); - - if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) { - printf("\n** Device %d not available\n", dev); - SHOW_BOOT_PROGRESS(-1); - return 1; - } - - nand = &nand_info[dev]; - printf("\nLoading from device %d: %s (offset 0x%lx)\n", - dev, nand->name, offset); + printf("\nLoading from %s, offset 0x%lx\n", nand->name, offset);
cnt = nand->oobblock; r = nand_read(nand, offset, &cnt, (u_char *) addr); if (r) { - printf("** Read error on %d\n", dev); + puts("** Read error\n"); SHOW_BOOT_PROGRESS(-1); return 1; } @@ -353,7 +330,7 @@ int do_nandboot(cmd_tbl_t * cmdtp, int f
r = nand_read(nand, offset, &cnt, (u_char *) addr); if (r) { - printf("** Read error on %d\n", dev); + puts("** Read error\n"); SHOW_BOOT_PROGRESS(-1); return 1; } @@ -367,7 +344,7 @@ int do_nandboot(cmd_tbl_t * cmdtp, int f char *local_args[2]; extern int do_bootm(cmd_tbl_t *, int, int, char *[]);
- local_args[0] = argv[0]; + local_args[0] = cmd; local_args[1] = NULL;
printf("Automatic boot of image at addr 0x%08lx ...\n", addr); @@ -378,9 +355,81 @@ int do_nandboot(cmd_tbl_t * cmdtp, int f return 0; }
-U_BOOT_CMD(nboot, 4, 1, do_nandboot, - "nboot - boot from NAND device\n", "loadAddr dev\n"); +int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + char *boot_device = NULL; + int idx; + ulong addr, offset = 0; +#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) + struct mtd_device *dev; + struct part_info *part; + u8 pnum; + + if (argc >= 2) { + char *p = (argc == 2) ? argv[1] : argv[2]; + if (!(str2long(p, &addr)) && (mtdparts_init() == 0) && + (find_dev_and_part(p, &dev, &pnum, &part) == 0)) { + if (dev->id->type != MTD_DEV_TYPE_NAND) { + puts("Not a NAND device\n"); + return 1; + } + if (argc > 3) + goto usage; + if (argc == 3) + addr = simple_strtoul(argv[2], NULL, 16); + else + addr = CFG_LOAD_ADDR; + return nand_load_image(cmdtp, &nand_info[dev->id->num], + part->offset, addr, argv[0]); + } + } +#endif
+ switch (argc) { + case 1: + addr = CFG_LOAD_ADDR; + boot_device = getenv("bootdevice"); + break; + case 2: + addr = simple_strtoul(argv[1], NULL, 16); + boot_device = getenv("bootdevice"); + break; + case 3: + addr = simple_strtoul(argv[1], NULL, 16); + boot_device = argv[2]; + break; + case 4: + addr = simple_strtoul(argv[1], NULL, 16); + boot_device = argv[2]; + offset = simple_strtoul(argv[3], NULL, 16); + break; + default: +usage: + printf("Usage:\n%s\n", cmdtp->usage); + SHOW_BOOT_PROGRESS(-1); + return 1; + } + + if (!boot_device) { + puts("\n** No boot device **\n"); + SHOW_BOOT_PROGRESS(-1); + return 1; + } + + idx = simple_strtoul(boot_device, NULL, 16); + + if (idx < 0 || idx >= CFG_MAX_NAND_DEVICE || !nand_info[idx].name) { + printf("\n** Device %d not available\n", idx); + SHOW_BOOT_PROGRESS(-1); + return 1; + } + + return nand_load_image(cmdtp, &nand_info[idx], offset, addr, argv[0]); +} + +U_BOOT_CMD(nboot, 4, 1, do_nandboot, + "nboot - boot from NAND device\n", + "[partition] | [[[load_addr] dev] offset]\n");
#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */