diff options
| -rw-r--r-- | common/cmd_nand.c | 44 | ||||
| -rw-r--r-- | drivers/mtd/nand/nand_util.c | 31 | ||||
| -rw-r--r-- | include/nand.h | 7 | 
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; -		printf("\nNAND %s: ", scrub ? "scrub" : "erase"); +		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: ", 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; |