diff options
Diffstat (limited to 'common/cmd_nand.c')
| -rw-r--r-- | common/cmd_nand.c | 253 | 
1 files changed, 123 insertions, 130 deletions
| diff --git a/common/cmd_nand.c b/common/cmd_nand.c index 9e38bf768..520c15217 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -18,6 +18,7 @@   *   */  #include <common.h> +#include <linux/mtd/mtd.h>  #if defined(CONFIG_CMD_NAND) @@ -34,48 +35,58 @@  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); +                      u8 *part_num, struct part_info **part);  #endif -static int nand_dump_oob(nand_info_t *nand, ulong off) -{ -	return 0; -} - -static int nand_dump(nand_info_t *nand, ulong off) +static int nand_dump(nand_info_t *nand, ulong off, int only_oob)  {  	int i; -	u_char *buf, *p; +	u_char *datbuf, *oobbuf, *p; -	buf = malloc(nand->oobblock + nand->oobsize); -	if (!buf) { +	datbuf = malloc(nand->writesize + nand->oobsize); +	oobbuf = malloc(nand->oobsize); +	if (!datbuf || !oobbuf) {  		puts("No memory for page buffer\n");  		return 1;  	} -	off &= ~(nand->oobblock - 1); -	i = nand_read_raw(nand, buf, off, nand->oobblock, nand->oobsize); +	off &= ~(nand->writesize - 1); +	loff_t addr = (loff_t) off; +	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.len = nand->writesize; +	ops.ooblen = nand->oobsize; +	ops.mode = MTD_OOB_RAW; +	i = nand->read_oob(nand, addr, &ops);  	if (i < 0) {  		printf("Error (%d) reading page %08lx\n", i, off); -		free(buf); +		free(datbuf); +		free(oobbuf);  		return 1;  	}  	printf("Page %08lx dump:\n", off); -	i = nand->oobblock >> 4; p = buf; +	i = nand->writesize >> 4; +	p = datbuf; +		  	while (i--) { -		printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x" -			"  %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], -			p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); +		if (!only_oob) +			printf("\t%02x %02x %02x %02x %02x %02x %02x %02x" +			       "  %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], +			       p[8], p[9], p[10], p[11], p[12], p[13], p[14], +			       p[15]);  		p += 16;  	}  	puts("OOB:\n");  	i = nand->oobsize >> 3;  	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]); +		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]);  		p += 8;  	} -	free(buf); +	free(datbuf); +	free(oobbuf);  	return 0;  } @@ -155,7 +166,7 @@ out:  int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  { -	int i, dev, ret; +	int i, dev, ret = 0;  	ulong addr, off;  	size_t size;  	char *cmd, *s; @@ -182,8 +193,8 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  		for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) {  			if (nand_info[i].name)  				printf("Device %d: %s, sector size %u KiB\n", -					i, nand_info[i].name, -					nand_info[i].erasesize >> 10); + 				       i, nand_info[i].name, +				       nand_info[i].erasesize >> 10);  		}  		return 0;  	} @@ -196,7 +207,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  				puts("\nno devices available\n");  			else  				printf("\nDevice %d: %s\n", nand_curr_device, -					nand_info[nand_curr_device].name); +				       nand_info[nand_curr_device].name);  			return 0;  		}  		dev = (int)simple_strtoul(argv[2], NULL, 10); @@ -299,15 +310,14 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  		off = (int)simple_strtoul(argv[2], NULL, 16);  		if (s != NULL && strcmp(s, ".oob") == 0) -			ret = nand_dump_oob(nand, off); +			ret = nand_dump(nand, off, 1);  		else -			ret = nand_dump(nand, off); +			ret = nand_dump(nand, off, 0);  		return ret == 0 ? 1 : 0;  	} -	/* read write */  	if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {  		int read; @@ -322,43 +332,29 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  			return 1;  		s = strchr(cmd, '.'); -		if (s != NULL && -		    (!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i"))) { -			if (read) { -				/* read */ -				nand_read_options_t opts; -				memset(&opts, 0, sizeof(opts)); -				opts.buffer	= (u_char*) addr; -				opts.length	= size; -				opts.offset	= off; -				opts.quiet      = quiet; -				ret = nand_read_opts(nand, &opts); -			} else { -				/* write */ -				nand_write_options_t opts; -				memset(&opts, 0, sizeof(opts)); -				opts.buffer	= (u_char*) addr; -				opts.length	= size; -				opts.offset	= off; -				/* opts.forcejffs2 = 1; */ -				opts.pad	= 1; -				opts.blockalign = 1; -				opts.quiet      = quiet; -				ret = nand_write_opts(nand, &opts); -			} -		} else if (s != NULL && !strcmp(s, ".oob")) { -			/* read out-of-band data */ +		if (!s || !strcmp(s, ".jffs2") || +		    !strcmp(s, ".e") || !strcmp(s, ".i")) {  			if (read) -				ret = nand->read_oob(nand, off, size, &size, -						     (u_char *) addr); +				ret = nand_read_skip_bad(nand, off, &size, +				                         (u_char *)addr);  			else -				ret = nand->write_oob(nand, off, size, &size, -						      (u_char *) addr); -		} else { +				ret = nand_write_skip_bad(nand, off, &size, +				                          (u_char *)addr); +		} else if (s != NULL && !strcmp(s, ".oob")) { +			/* out-of-band data */ +			mtd_oob_ops_t ops = { +				.oobbuf = (u8 *)addr, +				.ooblen = size, +				.mode = MTD_OOB_RAW +			}; +  			if (read) -				ret = nand_read(nand, off, &size, (u_char *)addr); +				ret = nand->read_oob(nand, off, &ops);  			else -				ret = nand_write(nand, off, &size, (u_char *)addr); +				ret = nand->write_oob(nand, off, &ops); +		} else { +			printf("Unknown nand command suffix '%s'.\n", s); +			return 1;  		}  		printf(" %d bytes %s: %s\n", size, @@ -381,6 +377,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  		}  		return 1;  	} +  	if (strcmp(cmd, "biterr") == 0) {  		/* todo */  		return 1; @@ -395,7 +392,12 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  			if (!strcmp("status", argv[2]))  				status = 1;  		} - +/* + * ! BROKEN ! + * + * TODO: must be implemented and tested by someone with HW + */ +#if 0  		if (status) {  			ulong block_start = 0;  			ulong off; @@ -406,28 +408,28 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  			nand_chip->cmdfunc (nand, NAND_CMD_STATUS, -1, -1);  			printf("device is %swrite protected\n",  			       (nand_chip->read_byte(nand) & 0x80 ? -				"NOT " : "" ) ); +			       "NOT " : "")); -			for (off = 0; off < nand->size; off += nand->oobblock) { +			for (off = 0; off < nand->size; off += nand->writesize) {  				int s = nand_get_lock_status(nand, off);  				/* print message only if status has changed  				 * or at end of chip  				 */ -				if (off == nand->size - nand->oobblock +				if (off == nand->size - nand->writesize  				    || (s != last_status && off != 0))	{ -					printf("%08lx - %08lx: %8lu pages %s%s%s\n", +					printf("%08lx - %08lx: %8d pages %s%s%s\n",  					       block_start,  					       off-1, -					       (off-block_start)/nand->oobblock, +					       (off-block_start)/nand->writesize,  					       ((last_status & NAND_LOCK_STATUS_TIGHT) ? "TIGHT " : ""),  					       ((last_status & NAND_LOCK_STATUS_LOCK) ? "LOCK " : ""),  					       ((last_status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK " : ""));  				}  				last_status = s; -		       } +			}  		} else {  			if (!nand_lock(nand, tight)) {  				puts("NAND flash successfully locked\n"); @@ -436,6 +438,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  				return 1;  			}  		} +#endif  		return 0;  	} @@ -443,6 +446,12 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  		if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) < 0)  			return 1; +/* + * ! BROKEN ! + * + * TODO: must be implemented and tested by someone with HW + */ +#if 0  		if (!nand_unlock(nand, off, size)) {  			puts("NAND flash successfully unlocked\n");  		} else { @@ -450,6 +459,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  			     "write and erase will probably fail\n");  			return 1;  		} +#endif  		return 0;  	} @@ -459,54 +469,47 @@ usage:  }  U_BOOT_CMD(nand, 5, 1, do_nand, -	"nand    - NAND sub-system\n", -	"info                  - show available NAND devices\n" -	"nand device [dev]     - show or set current device\n" -	"nand read[.jffs2]     - addr off|partition size\n" -	"nand write[.jffs2]    - addr off|partition size - read/write `size' bytes starting\n" -	"    at offset `off' to/from memory address `addr'\n" -	"nand erase [clean] [off size] - erase `size' bytes from\n" -	"    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" -	"nand lock [tight] [status] - bring nand to lock state or display locked pages\n" -	"nand unlock [offset] [size] - unlock section\n"); +           "nand - NAND sub-system\n", +           "info - show available NAND devices\n" +           "nand device [dev] - show or set current device\n" +           "nand read - addr off|partition size\n" +           "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 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" +           "nand lock [tight] [status]\n" +           "    bring nand to lock state or display locked pages\n" +           "nand unlock [offset] [size] - unlock section\n");  static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand, -			   ulong offset, ulong addr, char *cmd) +                           ulong offset, ulong addr, char *cmd)  {  	int r;  	char *ep, *s;  	size_t cnt;  	image_header_t *hdr; -	int jffs2 = 0;  #if defined(CONFIG_FIT)  	const void *fit_hdr = NULL;  #endif  	s = strchr(cmd, '.');  	if (s != NULL && -	    (!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i"))) -		jffs2 = 1; +	    (strcmp(s, ".jffs2") && !strcmp(s, ".e") && !strcmp(s, ".i"))) { +		printf("Unknown nand load suffix '%s'\n", s); +		show_boot_progress(-53); +		return 1; +	}  	printf("\nLoading from %s, offset 0x%lx\n", nand->name, offset); -	cnt = nand->oobblock; -	if (jffs2) { -		nand_read_options_t opts; -		memset(&opts, 0, sizeof(opts)); -		opts.buffer	= (u_char*) addr; -		opts.length	= cnt; -		opts.offset	= offset; -		opts.quiet      = 1; -		r = nand_read_opts(nand, &opts); -	} else { -		r = nand_read(nand, offset, &cnt, (u_char *) addr); -	} - +	cnt = nand->writesize; +	r = nand_read(nand, offset, &cnt, (u_char *) addr);  	if (r) {  		puts("** Read error\n");  		show_boot_progress (-56); @@ -536,19 +539,10 @@ static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,  		puts ("** Unknown image type\n");  		return 1;  	} +	show_boot_progress (57); -	if (jffs2) { -		nand_read_options_t opts; -		memset(&opts, 0, sizeof(opts)); -		opts.buffer	= (u_char*) addr; -		opts.length	= cnt; -		opts.offset	= offset; -		opts.quiet      = 1; -		r = nand_read_opts(nand, &opts); -	} else { -		r = nand_read(nand, offset, &cnt, (u_char *) addr); -	} - +	/* FIXME: skip bad blocks */ +	r = nand_read(nand, offset, &cnt, (u_char *) addr);  	if (r) {  		puts("** Read error\n");  		show_boot_progress (-58); @@ -614,7 +608,7 @@ int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  			else  				addr = CFG_LOAD_ADDR;  			return nand_load_image(cmdtp, &nand_info[dev->id->num], -					       part->offset, addr, argv[0]); +			                       part->offset, addr, argv[0]);  		}  	}  #endif @@ -669,7 +663,7 @@ usage:  U_BOOT_CMD(nboot, 4, 1, do_nandboot,  	"nboot   - boot from NAND device\n", -	"[.jffs2] [partition] | [[[loadAddr] dev] offset]\n"); +	"[partition] | [[[loadAddr] dev] offset]\n");  #endif @@ -726,10 +720,10 @@ void archflashwp(void *archdata, int wp);  #define CONFIG_MTD_NAND_ECC_JFFS2  /* bits for nand_legacy_rw() `cmd'; or together as needed */ -#define NANDRW_READ	0x01 -#define NANDRW_WRITE	0x00 -#define NANDRW_JFFS2	0x02 -#define NANDRW_JFFS2_SKIP	0x04 +#define NANDRW_READ         0x01 +#define NANDRW_WRITE        0x00 +#define NANDRW_JFFS2	    0x02 +#define NANDRW_JFFS2_SKIP   0x04  /*   * Imports from nand_legacy.c @@ -839,11 +833,11 @@ int do_nand (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  		if (strncmp (argv[1], "read", 4) == 0 ||  		    strncmp (argv[1], "write", 5) == 0) { -			ulong	addr = simple_strtoul (argv[2], NULL, 16); -			off_t	off  = simple_strtoul (argv[3], NULL, 16); -			size_t	size = simple_strtoul (argv[4], NULL, 16); -			int	cmd = (strncmp (argv[1], "read", 4) == 0) ? -					NANDRW_READ : NANDRW_WRITE; +			ulong addr = simple_strtoul (argv[2], NULL, 16); +			off_t off = simple_strtoul (argv[3], NULL, 16); +			size_t size = simple_strtoul (argv[4], NULL, 16); +			int cmd = (strncmp (argv[1], "read", 4) == 0) ? +			          NANDRW_READ : NANDRW_WRITE;  			size_t total;  			int ret;  			char *cmdtail = strchr (argv[1], '.'); @@ -892,8 +886,7 @@ int do_nand (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  			ret = nand_legacy_rw (nand_dev_desc + curr_device,  					      cmd, off, size, -					      &total, -					      (u_char *) addr); +					      &total, (u_char *) addr);  			printf (" %d bytes %s: %s\n", total,  				(cmd & NANDRW_READ) ? "read" : "written", @@ -1000,11 +993,11 @@ int do_nandboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])  	show_boot_progress (55);  	printf ("\nLoading from device %d: %s at 0x%lx (offset 0x%lx)\n", -		dev, nand_dev_desc[dev].name, nand_dev_desc[dev].IO_ADDR, -		offset); +	    dev, nand_dev_desc[dev].name, nand_dev_desc[dev].IO_ADDR, +	    offset);  	if (nand_legacy_rw (nand_dev_desc + dev, NANDRW_READ, offset, -			SECTORSIZE, NULL, (u_char *)addr)) { +	                    SECTORSIZE, NULL, (u_char *)addr)) {  		printf ("** Read error on %d\n", dev);  		show_boot_progress (-56);  		return 1; @@ -1035,8 +1028,8 @@ int do_nandboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])  	show_boot_progress (57);  	if (nand_legacy_rw (nand_dev_desc + dev, NANDRW_READ, -			offset + SECTORSIZE, cnt, NULL, -			(u_char *)(addr+SECTORSIZE))) { +	                    offset + SECTORSIZE, cnt, NULL, +	                    (u_char *)(addr+SECTORSIZE))) {  		printf ("** Read error on %d\n", dev);  		show_boot_progress (-58);  		return 1; |