diff options
| author | Stefan Roese <sr@denx.de> | 2006-10-28 15:55:52 +0200 | 
|---|---|---|
| committer | Stefan Roese <sr@denx.de> | 2006-10-28 17:11:10 +0200 | 
| commit | 856f054410cef52d868feb330168b2a4c4091328 (patch) | |
| tree | 75995d4bfa2f99852917e5ca035406dd91f6953f /common/cmd_nand.c | |
| parent | 07a69a18c2ecfda904231fdf23e2523ea7792eb6 (diff) | |
| download | olio-uboot-2014.01-856f054410cef52d868feb330168b2a4c4091328.tar.xz olio-uboot-2014.01-856f054410cef52d868feb330168b2a4c4091328.zip | |
[PATCH] NAND: Partition name support added to NAND subsystem
chpart, nboot and NAND subsystem related commands now accept also partition
name to specify offset.
Signed-off-by: Ladislav Michl <ladis@linux-mips.org>
Signed-off-by: Stefan Roese <sr@denx.de>
Diffstat (limited to 'common/cmd_nand.c')
| -rw-r--r-- | common/cmd_nand.c | 344 | 
1 files changed, 193 insertions, 151 deletions
| diff --git a/common/cmd_nand.c b/common/cmd_nand.c index 4fb3b6596..7286726f1 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -36,6 +36,15 @@  #include <jffs2/jffs2.h>  #include <nand.h> +#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) + +/* parition handling routines */ +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); +#endif +  extern nand_info_t nand_info[];       /* info for NAND chips */  static int nand_dump_oob(nand_info_t *nand, ulong off) @@ -83,50 +92,75 @@ static int nand_dump(nand_info_t *nand, ulong off)  /* ------------------------------------------------------------------------- */ -static void -arg_off_size(int argc, char *argv[], ulong *off, ulong *size, ulong totsize) +static inline int str2long(char *p, ulong *num)  { -	*off = 0; -	*size = 0; +	char *endptr; -#if defined(CONFIG_JFFS2_NAND) && defined(CFG_JFFS_CUSTOM_PART) -	if (argc >= 1 && strcmp(argv[0], "partition") == 0) { -		int part_num; -		struct part_info *part; -		const char *partstr; - -		if (argc >= 2) -			partstr = argv[1]; -		else -			partstr = getenv("partition"); +	*num = simple_strtoul(p, &endptr, 16); +	return (*p != '\0' && *endptr == '\0') ? 1 : 0; +} -		if (partstr) -			part_num = (int)simple_strtoul(partstr, NULL, 10); -		else -			part_num = 0; +static int +arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, ulong *size) +{ +	int idx = nand_curr_device; +#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) +	struct mtd_device *dev; +	struct part_info *part; +	u8 pnum; -		part = jffs2_part_info(part_num); -		if (part == NULL) { -			printf("\nInvalid partition %d\n", part_num); -			return; +	if (argc >= 1 && !(str2long(argv[0], off))) { +		if ((mtdparts_init() == 0) && +		    (find_dev_and_part(argv[0], &dev, &pnum, &part) == 0)) { +			if (dev->id->type != MTD_DEV_TYPE_NAND) { +				puts("not a NAND device\n"); +				return -1; +			} +			*off = part->offset; +			if (argc >= 2) { +				if (!(str2long(argv[1], size))) { +					printf("'%s' is not a number\n", argv[1]); +					return -1; +				} +				if (*size > part->size) +					*size = part->size; +			} else { +				*size = part->size; +			} +			idx = dev->id->num; +			*nand = nand_info[idx]; +			goto out;  		} -		*size = part->size; -		*off = (ulong)part->offset; -	} else +	}  #endif -	{ -		if (argc >= 1) -			*off = (ulong)simple_strtoul(argv[0], NULL, 16); -		else -			*off = 0; -		if (argc >= 2) -			*size = (ulong)simple_strtoul(argv[1], NULL, 16); -		else -			*size = totsize - *off; +	if (argc >= 1) { +		if (!(str2long(argv[0], off))) { +			printf("'%s' is not a number\n", argv[0]); +			return -1; +		} +	} else { +		*off = 0; +	} +	if (argc >= 2) { +		if (!(str2long(argv[1], size))) { +			printf("'%s' is not a number\n", argv[1]); +			return -1; +		} +	} else { +		*size = nand->size - *off;  	} +#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) +out: +#endif +	printf("device %d ", idx); +	if (*size == nand->size) +		puts("whole chip\n"); +	else +		printf("offset 0x%x, size 0x%x\n", *off, *size); +	return 0;  }  int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) @@ -213,35 +247,22 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  		return 0;  	} +	/* +	 * Syntax is: +	 *   0    1     2       3    4 +	 *   nand erase [clean] [off size] +	 */  	if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0) {  		nand_erase_options_t opts; -		int clean = argc >= 3 && !strcmp("clean", argv[2]); -		int rest_argc = argc - 2; -		char **rest_argv = argv + 2; +		/* "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"); -		if (clean) { -			rest_argc--; -			rest_argv++; -		} - -		if (rest_argc == 0) { - -			printf("\nNAND %s: device %d whole chip\n", -			       cmd, -			       nand_curr_device); - -			off = size = 0; -		} else { -			arg_off_size(rest_argc, rest_argv, &off, &size, -				     nand->size); - -			if (off == 0 && size == 0) -				return 1; - -			printf("\nNAND %s: device %d offset 0x%x, size 0x%x\n", -			       cmd, nand_curr_device, off, size); -		} +		printf("\nNAND %s: ", scrub ? "scrub" : "erase"); +		/* skip first two or three arguments, look for offset and size */ +		if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0) +			return 1;  		memset(&opts, 0, sizeof(opts));  		opts.offset = off; @@ -250,23 +271,22 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  		opts.quiet  = quiet;  		if (scrub) { -			printf("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" -				); +			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' && getc() == '\r') {  				opts.scrub = 1;  			} else { -				printf("scrub aborted\n"); +				puts("scrub aborted\n");  				return -1;  			}  		} @@ -301,13 +321,10 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  		addr = (ulong)simple_strtoul(argv[2], NULL, 16); -		arg_off_size(argc - 3, argv + 3, &off, &size, nand->size); -		if (off == 0 && size == 0) -			return 1; -  		read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */ -		printf("\nNAND %s: device %d offset %u, size %u ... ", -		       read ? "read" : "write", nand_curr_device, off, size); +		printf("\nNAND %s: ", read ? "read" : "write"); +		if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0) +			return 1;  		s = strchr(cmd, '.');  		if (s != NULL && @@ -334,15 +351,13 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  				opts.quiet      = quiet;  				ret = nand_write_opts(nand, &opts);  			} -			printf("%s\n", ret ? "ERROR" : "OK"); -			return ret == 0 ? 0 : 1; +		} else { +			if (read) +				ret = nand_read(nand, off, &size, (u_char *)addr); +			else +				ret = nand_write(nand, off, &size, (u_char *)addr);  		} -		if (read) -			ret = nand_read(nand, off, &size, (u_char *)addr); -		else -			ret = nand_write(nand, off, &size, (u_char *)addr); -  		printf(" %d bytes %s: %s\n", size,  		       read ? "read" : "written", ret ? "ERROR" : "OK"); @@ -412,9 +427,9 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  		       }  		} else {  			if (!nand_lock(nand, tight)) { -				printf ("NAND flash successfully locked\n"); +				puts("NAND flash successfully locked\n");  			} else { -				printf ("Error locking NAND flash. \n"); +				puts("Error locking NAND flash\n");  				return 1;  			}  		} @@ -422,19 +437,14 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  	}  	if (strcmp(cmd, "unlock") == 0) { -		if (argc == 2) { -			off = 0; -			size = nand->size; -		} else { -			arg_off_size(argc - 2, argv + 2, &off, &size, -				     nand->size); -		} +		if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) < 0) +			return 1;  		if (!nand_unlock(nand, off, size)) { -			printf("NAND flash successfully unlocked\n"); +			puts("NAND flash successfully unlocked\n");  		} else { -			printf("Error unlocking NAND flash. " -			       "Write and erase will probably fail\n"); +			puts("Error unlocking NAND flash, " +			     "write and erase will probably fail\n");  			return 1;  		}  		return 0; @@ -449,8 +459,8 @@ 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 size\n" -	"nand write[.jffs2]    - addr off size - read/write `size' bytes starting\n" +	"nand read[.jffs2]     - addr off|partition size\n" +	"nand write[.jffs2]    - addr off|partiton 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" @@ -462,62 +472,20 @@ U_BOOT_CMD(nand, 5, 1, do_nand,  	"nand lock [tight] [status] - bring nand to lock state or display locked pages\n"  	"nand unlock [offset] [size] - unlock section\n"); -int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand, +			   ulong offset, ulong addr, char *cmd)  { -	char *boot_device = NULL; -	char *ep; -	int dev;  	int r; -	ulong addr, cnt, offset = 0; +	char *ep; +	ulong cnt;  	image_header_t *hdr; -	nand_info_t *nand; -	switch (argc) { -	case 1: -		addr = CFG_LOAD_ADDR; -		boot_device = getenv("bootdevice"); -		break; -	case 2: -		addr = simple_strtoul(argv[1], NULL, 16); -		boot_device = getenv("bootdevice"); -		break; -	case 3: -		addr = simple_strtoul(argv[1], NULL, 16); -		boot_device = argv[2]; -		break; -	case 4: -		addr = simple_strtoul(argv[1], NULL, 16); -		boot_device = argv[2]; -		offset = simple_strtoul(argv[3], NULL, 16); -		break; -	default: -		printf("Usage:\n%s\n", cmdtp->usage); -		SHOW_BOOT_PROGRESS(-1); -		return 1; -	} - -	if (!boot_device) { -		puts("\n** No boot device **\n"); -		SHOW_BOOT_PROGRESS(-1); -		return 1; -	} - -	dev = simple_strtoul(boot_device, &ep, 16); - -	if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) { -		printf("\n** Device %d not available\n", dev); -		SHOW_BOOT_PROGRESS(-1); -		return 1; -	} - -	nand = &nand_info[dev]; -	printf("\nLoading from device %d: %s (offset 0x%lx)\n", -	       dev, nand->name, offset); +	printf("\nLoading from %s, offset 0x%lx\n", nand->name, offset);  	cnt = nand->oobblock;  	r = nand_read(nand, offset, &cnt, (u_char *) addr);  	if (r) { -		printf("** Read error on %d\n", dev); +		puts("** Read error\n");  		SHOW_BOOT_PROGRESS(-1);  		return 1;  	} @@ -536,7 +504,7 @@ int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  	r = nand_read(nand, offset, &cnt, (u_char *) addr);  	if (r) { -		printf("** Read error on %d\n", dev); +		puts("** Read error\n");  		SHOW_BOOT_PROGRESS(-1);  		return 1;  	} @@ -550,7 +518,7 @@ int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  		char *local_args[2];  		extern int do_bootm(cmd_tbl_t *, int, int, char *[]); -		local_args[0] = argv[0]; +		local_args[0] = cmd;  		local_args[1] = NULL;  		printf("Automatic boot of image at addr 0x%08lx ...\n", addr); @@ -561,9 +529,83 @@ int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])  	return 0;  } -U_BOOT_CMD(nboot, 4, 1, do_nandboot, -	"nboot   - boot from NAND device\n", "loadAddr dev\n"); +int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ +	char *boot_device = NULL; +	int idx; +	ulong addr, offset = 0; +#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) +	struct mtd_device *dev; +	struct part_info *part; +	u8 pnum; +	if (argc >= 2) { +		char *p = (argc == 2) ? argv[1] : argv[2]; +		if (!(str2long(p, &addr)) && (mtdparts_init() == 0) && +		    (find_dev_and_part(p, &dev, &pnum, &part) == 0)) { +			if (dev->id->type != MTD_DEV_TYPE_NAND) { +				puts("Not a NAND device\n"); +				return 1; +			} +			if (argc > 3) +				goto usage; +			if (argc == 3) +				addr = simple_strtoul(argv[2], NULL, 16); +			else +				addr = CFG_LOAD_ADDR; +			return nand_load_image(cmdtp, &nand_info[dev->id->num], +					       part->offset, addr, argv[0]); +		} +	} +#endif + +	switch (argc) { +	case 1: +		addr = CFG_LOAD_ADDR; +		boot_device = getenv("bootdevice"); +		break; +	case 2: +		addr = simple_strtoul(argv[1], NULL, 16); +		boot_device = getenv("bootdevice"); +		break; +	case 3: +		addr = simple_strtoul(argv[1], NULL, 16); +		boot_device = argv[2]; +		break; +	case 4: +		addr = simple_strtoul(argv[1], NULL, 16); +		boot_device = argv[2]; +		offset = simple_strtoul(argv[3], NULL, 16); +		break; +	default: +#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE) +usage: +#endif +		printf("Usage:\n%s\n", cmdtp->usage); +		SHOW_BOOT_PROGRESS(-1); +		return 1; +	} + +	if (!boot_device) { +		puts("\n** No boot device **\n"); +		SHOW_BOOT_PROGRESS(-1); +		return 1; +	} + +	idx = simple_strtoul(boot_device, NULL, 16); + +	if (idx < 0 || idx >= CFG_MAX_NAND_DEVICE || !nand_info[idx].name) { +		printf("\n** Device %d not available\n", idx); +		SHOW_BOOT_PROGRESS(-1); +		return 1; +	} + +	return nand_load_image(cmdtp, &nand_info[idx], offset, addr, argv[0]); +} + +U_BOOT_CMD(nboot, 4, 1, do_nandboot, +	"nboot   - boot from NAND device\n", +	"[partition] | [[[loadAddr] dev] offset]\n");  #endif				/* (CONFIG_COMMANDS & CFG_CMD_NAND) */ |