aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/cmd_nand.c44
-rw-r--r--drivers/mtd/nand/nand_util.c31
-rw-r--r--include/nand.h7
3 files changed, 60 insertions, 22 deletions
diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index 41aaf7f26..dcccc1979 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -449,14 +449,40 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
* 0 1 2 3 4
* nand erase [clean] [off size]
*/
- if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0) {
+ if (strncmp(cmd, "erase", 5) == 0 || strncmp(cmd, "scrub", 5) == 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 = !strcmp(cmd, "scrub");
+ int scrub = !strncmp(cmd, "scrub", 5);
+ int part = 0;
+ int chip = 0;
+ int spread = 0;
+ int args = 2;
+
+ 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;
+ }
+ }
+
+ /*
+ * Don't allow missing arguments to cause full chip/partition
+ * erases -- easy to do accidentally, e.g. with a misspelled
+ * variable name.
+ */
+ if (argc != o + args)
+ goto usage;
- printf("\nNAND %s: ", scrub ? "scrub" : "erase");
+ printf("\nNAND %s: ", cmd);
/* skip first two or three arguments, look for offset and size */
if (arg_off_size(argc - o, argv + o, &dev, &off, &size) != 0)
return 1;
@@ -468,6 +494,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
opts.length = size;
opts.jffs2 = clean;
opts.quiet = quiet;
+ opts.spread = spread;
if (scrub) {
puts("Warning: "
@@ -648,11 +675,16 @@ 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 erase [clean] [off size] - erase 'size' bytes from\n"
- " offset 'off' (entire device if not specified)\n"
+ "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.part [clean] partition - erase entire mtd partition'\n"
+ "nand erase.chip [clean] - erase entire chip'\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 scrub 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)"
#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c
index 0f6779048..6a5dd372c 100644
--- a/drivers/mtd/nand/nand_util.c
+++ b/drivers/mtd/nand/nand_util.c
@@ -75,7 +75,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
{
struct jffs2_unknown_node cleanmarker;
erase_info_t erase;
- ulong erase_length;
+ unsigned long erase_length, erased_length; /* in blocks */
int bbtest = 1;
int result;
int percent_complete = -1;
@@ -84,13 +84,19 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
struct mtd_oob_ops oob_opts;
struct nand_chip *chip = meminfo->priv;
+ if ((opts->offset & (meminfo->writesize - 1)) != 0) {
+ printf("Attempt to erase non page aligned data\n");
+ return -1;
+ }
+
memset(&erase, 0, sizeof(erase));
memset(&oob_opts, 0, sizeof(oob_opts));
erase.mtd = meminfo;
erase.len = meminfo->erasesize;
erase.addr = opts->offset;
- erase_length = opts->length;
+ erase_length = lldiv(opts->length + meminfo->erasesize - 1,
+ meminfo->erasesize);
cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
@@ -114,15 +120,8 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
priv_nand->bbt = NULL;
}
- if (erase_length < meminfo->erasesize) {
- printf("Warning: Erase size 0x%08lx smaller than one " \
- "erase block 0x%08x\n",erase_length, meminfo->erasesize);
- printf(" Erasing 0x%08x instead\n", meminfo->erasesize);
- erase_length = meminfo->erasesize;
- }
-
- for (;
- erase.addr < opts->offset + erase_length;
+ for (erased_length = 0;
+ erased_length < erase_length;
erase.addr += meminfo->erasesize) {
WATCHDOG_RESET ();
@@ -135,6 +134,10 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
"0x%08llx "
" \n",
erase.addr);
+
+ if (!opts->spread)
+ erased_length++;
+
continue;
} else if (ret < 0) {
@@ -145,6 +148,8 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
}
}
+ erased_length++;
+
result = meminfo->erase(meminfo, &erase);
if (result != 0) {
printf("\n%s: MTD Erase failure: %d\n",
@@ -171,9 +176,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
}
if (!opts->quiet) {
- unsigned long long n =(unsigned long long)
- (erase.addr + meminfo->erasesize - opts->offset)
- * 100;
+ unsigned long long n = erased_length * 100ULL;
int percent;
do_div(n, erase_length);
diff --git a/include/nand.h b/include/nand.h
index 8bdf4191a..a4524113d 100644
--- a/include/nand.h
+++ b/include/nand.h
@@ -98,13 +98,16 @@ struct nand_read_options {
typedef struct nand_read_options nand_read_options_t;
struct nand_erase_options {
- ulong length; /* number of bytes to erase */
- ulong offset; /* first address in NAND to erase */
+ loff_t length; /* number of bytes to erase */
+ loff_t offset; /* first address in NAND to erase */
int quiet; /* don't display progress messages */
int jffs2; /* if true: format for jffs2 usage
* (write appropriate cleanmarker blocks) */
int scrub; /* if true, really clean NAND by erasing
* bad blocks (UNSAFE) */
+
+ /* Don't include skipped bad blocks in size to be erased */
+ int spread;
};
typedef struct nand_erase_options nand_erase_options_t;