last = off;
- datbuf = malloc(nand->writesize + nand->oobsize);
+ datbuf = malloc(nand->writesize);
oobbuf = malloc(nand->oobsize);
if (!datbuf || !oobbuf) {
puts("No memory for page buffer\n");
struct mtd_oob_ops ops;
memset(&ops, 0, sizeof(ops));
ops.datbuf = datbuf;
- ops.oobbuf = oobbuf; /* must exist, but oob data will be appended to ops.datbuf */
+ ops.oobbuf = oobbuf;
ops.len = nand->writesize;
ops.ooblen = nand->oobsize;
ops.mode = MTD_OOB_RAW;
}
puts("OOB:\n");
i = nand->oobsize >> 3;
+ p = oobbuf;
while (i--) {
printf("\t%02x %02x %02x %02x %02x %02x %02x %02x\n",
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
loff_t *off, loff_t *size)
{
int ret;
- loff_t maxsize;
+ loff_t maxsize = 0;
if (argc == 0) {
*off = 0;
return ret;
usage:
- return cmd_usage(cmdtp);
+ return CMD_RET_USAGE;
}
#endif
-static void nand_print_info(int idx)
+static void nand_print_and_set_info(int idx)
{
nand_info_t *nand = &nand_info[idx];
struct nand_chip *chip = nand->priv;
+ const int bufsz = 32;
+ char buf[bufsz];
+
printf("Device %d: ", idx);
if (chip->numchips > 1)
printf("%dx ", chip->numchips);
printf("%s, sector size %u KiB\n",
nand->name, nand->erasesize >> 10);
+ printf(" Page size %8d b\n", nand->writesize);
+ printf(" OOB size %8d b\n", nand->oobsize);
+ printf(" Erase size %8d b\n", nand->erasesize);
+
+ /* Set geometry info */
+ sprintf(buf, "%x", nand->writesize);
+ setenv("nand_writesize", buf);
+
+ sprintf(buf, "%x", nand->oobsize);
+ setenv("nand_oobsize", buf);
+
+ sprintf(buf, "%x", nand->erasesize);
+ setenv("nand_erasesize", buf);
}
int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
putc('\n');
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
if (nand_info[i].name)
- nand_print_info(i);
+ nand_print_and_set_info(i);
}
return 0;
}
if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE)
puts("no devices available\n");
else
- nand_print_info(dev);
+ nand_print_and_set_info(dev);
return 0;
}
nand_erase_options_t opts;
/* "clean" at index 2 means request to write cleanmarker */
int clean = argc > 2 && !strcmp("clean", argv[2]);
- int o = clean ? 3 : 2;
+ int scrub_yes = argc > 2 && !strcmp("-y", argv[2]);
+ int o = (clean || scrub_yes) ? 3 : 2;
int scrub = !strncmp(cmd, "scrub", 5);
- int part = 0;
- int chip = 0;
int spread = 0;
int args = 2;
+ const char *scrub_warn =
+ "Warning: "
+ "scrub option will erase all factory set bad blocks!\n"
+ " "
+ "There is no reliable way to recover them.\n"
+ " "
+ "Use this command only for testing purposes if you\n"
+ " "
+ "are sure of what you are doing!\n"
+ "\nReally scrub this NAND flash? <y/N>\n";
if (cmd[5] != 0) {
if (!strcmp(&cmd[5], ".spread")) {
spread = 1;
} else if (!strcmp(&cmd[5], ".part")) {
- part = 1;
args = 1;
} else if (!strcmp(&cmd[5], ".chip")) {
- chip = 1;
args = 0;
} else {
goto usage;
opts.spread = spread;
if (scrub) {
- puts("Warning: "
- "scrub option will erase all factory set "
- "bad blocks!\n"
- " "
- "There is no reliable way to recover them.\n"
- " "
- "Use this command only for testing purposes "
- "if you\n"
- " "
- "are sure of what you are doing!\n"
- "\nReally scrub this NAND flash? <y/N>\n");
-
- if (getc() == 'y') {
+ if (!scrub_yes)
+ puts(scrub_warn);
+
+ if (scrub_yes)
+ opts.scrub = 1;
+ else if (getc() == 'y') {
puts("y");
if (getc() == '\r')
opts.scrub = 1;
else
ret = nand_write_skip_bad(nand, off, &rwsize,
(u_char *)addr, 0);
+#ifdef CONFIG_CMD_NAND_TRIMFFS
+ } else if (!strcmp(s, ".trimffs")) {
+ if (read) {
+ printf("Unknown nand command suffix '%s'\n", s);
+ return 1;
+ }
+ ret = nand_write_skip_bad(nand, off, &rwsize,
+ (u_char *)addr,
+ WITH_DROP_FFS);
+#endif
#ifdef CONFIG_CMD_NAND_YAFFS
} else if (!strcmp(s, ".yaffs")) {
if (read) {
printf("Unknown nand command suffix '%s'.\n", s);
return 1;
}
- ret = nand_write_skip_bad(nand, off, &rwsize, (u_char *)addr, 1);
+ ret = nand_write_skip_bad(nand, off, &rwsize,
+ (u_char *)addr, WITH_YAFFS_OOB);
#endif
} else if (!strcmp(s, ".oob")) {
/* out-of-band data */
.mode = MTD_OOB_RAW
};
+ if (read)
+ ret = nand->read_oob(nand, off, &ops);
+ else
+ ret = nand->write_oob(nand, off, &ops);
+ } else if (!strcmp(s, ".raw")) {
+ /* Raw access */
+ mtd_oob_ops_t ops = {
+ .datbuf = (u8 *)addr,
+ .oobbuf = ((u8 *)addr) + nand->writesize,
+ .len = nand->writesize,
+ .ooblen = nand->oobsize,
+ .mode = MTD_OOB_RAW
+ };
+
+ rwsize = nand->writesize + nand->oobsize;
+
if (read)
ret = nand->read_oob(nand, off, &ops);
else
#endif
usage:
- return cmd_usage(cmdtp);
+ return CMD_RET_USAGE;
}
U_BOOT_CMD(
"nand write - addr off|partition size\n"
" read/write 'size' bytes starting at offset 'off'\n"
" to/from memory address 'addr', skipping bad blocks.\n"
+ "nand read.raw - addr off|partition\n"
+ "nand write.raw - addr off|partition\n"
+ " Use read.raw/write.raw to avoid ECC and access the page as-is.\n"
+#ifdef CONFIG_CMD_NAND_TRIMFFS
+ "nand write.trimffs - addr off|partition size\n"
+ " write 'size' bytes starting at offset 'off' from memory address\n"
+ " 'addr', skipping bad blocks and dropping any pages at the end\n"
+ " of eraseblocks that contain only 0xFF\n"
+#endif
#ifdef CONFIG_CMD_NAND_YAFFS
"nand write.yaffs - addr off|partition size\n"
" write 'size' bytes starting at offset 'off' with yaffs format\n"
" from memory address 'addr', skipping bad blocks.\n"
#endif
- "nand erase[.spread] [clean] [off [size]] - erase 'size' bytes "
+ "nand erase[.spread] [clean] off size - erase 'size' bytes "
"from offset 'off'\n"
" With '.spread', erase enough for given file size, otherwise,\n"
" 'size' includes skipped bad blocks.\n"
"nand erase.chip [clean] - erase entire chip'\n"
"nand bad - show bad blocks\n"
"nand dump[.oob] off - dump page\n"
- "nand scrub off size | scrub.part partition | scrub.chip\n"
+ "nand scrub [-y] off size | scrub.part partition | scrub.chip\n"
" really clean NAND erasing bad blocks (UNSAFE)\n"
"nand markbad off [...] - mark bad block(s) at offset (UNSAFE)\n"
"nand biterr off - make a bit error at offset (UNSAFE)"
ulong offset, ulong addr, char *cmd)
{
int r;
- char *ep, *s;
+ char *s;
size_t cnt;
image_header_t *hdr;
#if defined(CONFIG_FIT)
if (s != NULL &&
(strcmp(s, ".jffs2") && strcmp(s, ".e") && strcmp(s, ".i"))) {
printf("Unknown nand load suffix '%s'\n", s);
- show_boot_progress(-53);
+ bootstage_error(BOOTSTAGE_ID_NAND_SUFFIX);
return 1;
}
r = nand_read_skip_bad(nand, offset, &cnt, (u_char *) addr);
if (r) {
puts("** Read error\n");
- show_boot_progress (-56);
+ bootstage_error(BOOTSTAGE_ID_NAND_HDR_READ);
return 1;
}
- show_boot_progress (56);
+ bootstage_mark(BOOTSTAGE_ID_NAND_HDR_READ);
switch (genimg_get_format ((void *)addr)) {
case IMAGE_FORMAT_LEGACY:
hdr = (image_header_t *)addr;
- show_boot_progress (57);
+ bootstage_mark(BOOTSTAGE_ID_NAND_TYPE);
image_print_contents (hdr);
cnt = image_get_image_size (hdr);
break;
#endif
default:
- show_boot_progress (-57);
+ bootstage_error(BOOTSTAGE_ID_NAND_TYPE);
puts ("** Unknown image type\n");
return 1;
}
- show_boot_progress (57);
+ bootstage_mark(BOOTSTAGE_ID_NAND_TYPE);
r = nand_read_skip_bad(nand, offset, &cnt, (u_char *) addr);
if (r) {
puts("** Read error\n");
- show_boot_progress (-58);
+ bootstage_error(BOOTSTAGE_ID_NAND_READ);
return 1;
}
- show_boot_progress (58);
+ bootstage_mark(BOOTSTAGE_ID_NAND_READ);
#if defined(CONFIG_FIT)
/* This cannot be done earlier, we need complete FIT image in RAM first */
if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) {
if (!fit_check_format (fit_hdr)) {
- show_boot_progress (-150);
+ bootstage_error(BOOTSTAGE_ID_NAND_FIT_READ);
puts ("** Bad FIT image format\n");
return 1;
}
- show_boot_progress (151);
+ bootstage_mark(BOOTSTAGE_ID_NAND_FIT_READ_OK);
fit_print_contents (fit_hdr);
}
#endif
load_addr = addr;
- /* Check if we should attempt an auto-start */
- if (((ep = getenv("autostart")) != NULL) && (strcmp(ep, "yes") == 0)) {
- char *local_args[2];
-
- local_args[0] = cmd;
- local_args[1] = NULL;
-
- printf("Automatic boot of image at addr 0x%08lx ...\n", addr);
-
- do_bootm(cmdtp, 0, 1, local_args);
- return 1;
- }
- return 0;
+ return bootm_maybe_autostart(cmdtp, cmd);
}
int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
}
#endif
- show_boot_progress(52);
+ bootstage_mark(BOOTSTAGE_ID_NAND_PART);
switch (argc) {
case 1:
addr = CONFIG_SYS_LOAD_ADDR;
#if defined(CONFIG_CMD_MTDPARTS)
usage:
#endif
- show_boot_progress(-53);
- return cmd_usage(cmdtp);
+ bootstage_error(BOOTSTAGE_ID_NAND_SUFFIX);
+ return CMD_RET_USAGE;
}
+ bootstage_mark(BOOTSTAGE_ID_NAND_SUFFIX);
- show_boot_progress(53);
if (!boot_device) {
puts("\n** No boot device **\n");
- show_boot_progress(-54);
+ bootstage_error(BOOTSTAGE_ID_NAND_BOOT_DEVICE);
return 1;
}
- show_boot_progress(54);
+ bootstage_mark(BOOTSTAGE_ID_NAND_BOOT_DEVICE);
idx = simple_strtoul(boot_device, NULL, 16);
if (idx < 0 || idx >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[idx].name) {
printf("\n** Device %d not available\n", idx);
- show_boot_progress(-55);
+ bootstage_error(BOOTSTAGE_ID_NAND_AVAILABLE);
return 1;
}
- show_boot_progress(55);
+ bootstage_mark(BOOTSTAGE_ID_NAND_AVAILABLE);
return nand_load_image(cmdtp, &nand_info[idx], offset, addr, argv[0]);
}