* Added 16-bit nand support
* (C) 2004 Texas Instruments
*
- * Copyright 2010 Freescale Semiconductor
+ * Copyright 2010, 2012 Freescale Semiconductor
* The portions of this file whose copyright is held by Freescale and which
* are not considered a derived work of GPL v2-only code may be distributed
* and/or modified under the terms of the GNU General Public License as
loff_t *off, loff_t *size)
{
int ret;
- loff_t maxsize;
+ loff_t maxsize = 0;
if (argc == 0) {
*off = 0;
setenv("nand_erasesize", buf);
}
+static int raw_access(nand_info_t *nand, ulong addr, loff_t off, ulong count,
+ int read)
+{
+ int ret = 0;
+
+ while (count--) {
+ /* 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
+ };
+
+ if (read)
+ ret = nand->read_oob(nand, off, &ops);
+ else
+ ret = nand->write_oob(nand, off, &ops);
+
+ if (ret) {
+ printf("%s: error at offset %llx, ret %d\n",
+ __func__, (long long)off, ret);
+ break;
+ }
+
+ addr += nand->writesize + nand->oobsize;
+ off += nand->writesize;
+ }
+
+ return ret;
+}
+
int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
int i, ret = 0;
if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
size_t rwsize;
+ ulong pagecount = 1;
int read;
+ int raw;
if (argc < 4)
goto usage;
read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
printf("\nNAND %s: ", read ? "read" : "write");
- if (arg_off_size(argc - 3, argv + 3, &dev, &off, &size) != 0)
- return 1;
nand = &nand_info[dev];
- rwsize = size;
s = strchr(cmd, '.');
+
+ if (s && !strcmp(s, ".raw")) {
+ raw = 1;
+
+ if (arg_off(argv[3], &dev, &off, &size))
+ return 1;
+
+ if (argc > 4 && !str2long(argv[4], &pagecount)) {
+ printf("'%s' is not a number\n", argv[4]);
+ return 1;
+ }
+
+ if (pagecount * nand->writesize > size) {
+ puts("Size exceeds partition or device limit\n");
+ return -1;
+ }
+
+ rwsize = pagecount * (nand->writesize + nand->oobsize);
+ } else {
+ if (arg_off_size(argc - 3, argv + 3, &dev,
+ &off, &size) != 0)
+ return 1;
+
+ rwsize = size;
+ }
+
if (!s || !strcmp(s, ".jffs2") ||
!strcmp(s, ".e") || !strcmp(s, ".i")) {
if (read)
return 1;
}
ret = nand_write_skip_bad(nand, off, &rwsize,
- (u_char *)addr, WITH_YAFFS_OOB);
+ (u_char *)addr,
+ WITH_INLINE_OOB);
#endif
} else if (!strcmp(s, ".oob")) {
/* out-of-band data */
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
- ret = nand->write_oob(nand, off, &ops);
+ } else if (raw) {
+ ret = raw_access(nand, addr, off, pagecount, read);
} else {
printf("Unknown nand command suffix '%s'.\n", s);
return 1;
"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"
+ "nand read.raw - addr off|partition [count]\n"
+ "nand write.raw - addr off|partition [count]\n"
+ " Use read.raw/write.raw to avoid ECC and access the flash 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"
if (s != NULL &&
(strcmp(s, ".jffs2") && strcmp(s, ".e") && strcmp(s, ".i"))) {
printf("Unknown nand load suffix '%s'\n", s);
- show_boot_error(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_error(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_error(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_error(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_error(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
}
#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_error(53);
+ 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_error(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_error(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]);
}