diff options
| -rw-r--r-- | common/cmd_nand.c | 107 | ||||
| -rw-r--r-- | common/env_nand.c | 46 | ||||
| -rw-r--r-- | include/environment.h | 21 | ||||
| -rw-r--r-- | include/nand.h | 9 | 
4 files changed, 176 insertions, 7 deletions
| diff --git a/common/cmd_nand.c b/common/cmd_nand.c index ea80555ef..a4c67c170 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -4,6 +4,10 @@   * (c) 1999 Machine Vision Holdings, Inc.   * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>   * + * Ported 'dynenv' to 'nand env.oob' command + * (C) 2010 Nanometrics, Inc. + * 'dynenv' -- Dynamic environment offset in NAND OOB + * (C) Copyright 2006-2007 OpenMoko, Inc.   * Added 16-bit nand support   * (C) 2004 Texas Instruments   */ @@ -193,6 +197,90 @@ static void do_nand_status(nand_info_t *nand)  }  #endif +#ifdef CONFIG_ENV_OFFSET_OOB +unsigned long nand_env_oob_offset; + +int do_nand_env_oob(cmd_tbl_t *cmdtp, nand_info_t *nand, +				 int argc, char * const argv[]) +{ +	int ret; +	uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)]; + +	char *cmd = argv[1]; + +	if (!strcmp(cmd, "get")) { +		ret = get_nand_env_oob(nand, &nand_env_oob_offset); +		if (!ret) +			printf("0x%08lx\n", nand_env_oob_offset); +		else +			return 1; +	} else if (!strcmp(cmd, "set")) { +		ulong addr; +		size_t dummy_size; +		struct mtd_oob_ops ops; + +		if (argc < 3) +			goto usage; + +		if (arg_off_size(argc-2, argv + 2, nand, &addr, +						  &dummy_size) < 0) { +			printf("Offset or partition name expected\n"); +			return 1; +		} + +		if (nand->oobavail < ENV_OFFSET_SIZE) { +			printf("Insufficient available OOB bytes: %d OOB bytes" +			    " available but %d required for env.oob support\n", +								nand->oobavail, +							      ENV_OFFSET_SIZE); +			return 1; +		} + +		if ((addr & (nand->erasesize - 1)) != 0) { +			printf("Environment offset must be block-aligned\n"); +			return 1; +		} + +		ops.datbuf = NULL; +		ops.mode = MTD_OOB_AUTO; +		ops.ooboffs = 0; +		ops.ooblen = ENV_OFFSET_SIZE; +		ops.oobbuf = (void *) oob_buf; + +		oob_buf[0] = ENV_OOB_MARKER; +		oob_buf[1] = addr / nand->erasesize; + +		ret = nand->write_oob(nand, ENV_OFFSET_SIZE, &ops); +		if (!ret) { +			ret = get_nand_env_oob(nand, &nand_env_oob_offset); +			if (ret) { +				printf("Error reading env offset in OOB\n"); +				return ret; +			} + +			if (addr != nand_env_oob_offset) { +				printf("Verification of env offset in OOB " +				       "failed: 0x%08lx expected but got " +				       "0x%08lx\n", addr, nand_env_oob_offset); +				return 1; +			} +		} else { +			printf("Error writing OOB block 0\n"); +			return ret; +		} +	} else { +		goto usage; +	} + +	return ret; + +usage: +	cmd_usage(cmdtp); +	return 1; +} + +#endif +  static void nand_print_info(int idx)  {  	nand_info_t *nand = &nand_info[idx]; @@ -272,9 +360,19 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  	    strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 &&  	    strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 &&  	    strcmp(cmd, "biterr") != 0 && -	    strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 ) +	    strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 +#ifdef CONFIG_ENV_OFFSET_OOB +	    && strcmp(cmd, "env.oob") != 0 +#endif +	    )  		goto usage; +#ifdef CONFIG_ENV_OFFSET_OOB +	/* this command operates only on the first nand device */ +	if (strcmp(cmd, "env.oob") == 0) +	      return do_nand_env_oob(cmdtp, &nand_info[0], argc - 1, argv + 1); +#endif +  	/* the following commands operate on the current device */  	if (nand_curr_device < 0 || nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||  	    !nand_info[nand_curr_device].name) { @@ -502,6 +600,13 @@ U_BOOT_CMD(nand, CONFIG_SYS_MAXARGS, 1, do_nand,  	"    bring nand to lock state or display locked pages\n"  	"nand unlock [offset] [size] - unlock section"  #endif +#ifdef CONFIG_ENV_OFFSET_OOB +	"\n" +	"nand env.oob - environment offset in OOB of block 0 of" +	"    first device.\n" +	"nand env.oob set off|partition - set enviromnent offset\n" +	"nand env.oob get - get environment offset" +#endif  );  static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand, diff --git a/common/env_nand.c b/common/env_nand.c index 50bc111a3..47d9848ac 100644 --- a/common/env_nand.c +++ b/common/env_nand.c @@ -38,6 +38,7 @@  #include <linux/stddef.h>  #include <malloc.h>  #include <nand.h> +#include <asm/errno.h>  #if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_NAND)  #define CMD_SAVEENV @@ -284,6 +285,40 @@ int readenv (size_t offset, u_char * buf)  	return 0;  } +#ifdef CONFIG_ENV_OFFSET_OOB +int get_nand_env_oob(nand_info_t *nand, unsigned long *result) +{ +	struct mtd_oob_ops ops; +	uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)]; +	int ret; + +	ops.datbuf = NULL; +	ops.mode = MTD_OOB_AUTO; +	ops.ooboffs = 0; +	ops.ooblen = ENV_OFFSET_SIZE; +	ops.oobbuf = (void *) oob_buf; + +	ret = nand->read_oob(nand, ENV_OFFSET_SIZE, &ops); + +	if (!ret) { +		if (oob_buf[0] == ENV_OOB_MARKER) { +			*result = oob_buf[1] * nand->erasesize; +		} else if (oob_buf[0] == ENV_OOB_MARKER_OLD) { +			*result = oob_buf[1]; +		} else { +			printf("No dynamic environment marker in OOB block 0" +									"\n"); +			ret = -ENOENT; +			goto fail; +		} +	} else { +		printf("error reading OOB block 0\n"); +	} +fail: +	return ret; +} +#endif +  #ifdef CONFIG_ENV_OFFSET_REDUND  void env_relocate_spec (void)  { @@ -353,6 +388,17 @@ void env_relocate_spec (void)  #if !defined(ENV_IS_EMBEDDED)  	int ret; +#if defined(CONFIG_ENV_OFFSET_OOB) +	ret = get_nand_env_oob(&nand_info[0], &nand_env_oob_offset); +	/* If unable to read environment offset from NAND OOB then fall through +	 * to the normal environment reading code below +	 */ +	if (!ret) +		printf("Found Environment offset in OOB..\n"); +	else +		return use_default(); +#endif +  	ret = readenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr);  	if (ret)  		return use_default(); diff --git a/include/environment.h b/include/environment.h index 203f73196..fbccf6ab0 100644 --- a/include/environment.h +++ b/include/environment.h @@ -74,15 +74,24 @@  #endif	/* CONFIG_ENV_IS_IN_FLASH */  #if defined(CONFIG_ENV_IS_IN_NAND) -# ifndef CONFIG_ENV_OFFSET -#  error "Need to define CONFIG_ENV_OFFSET when using CONFIG_ENV_IS_IN_NAND" -# endif +# if defined(CONFIG_ENV_OFFSET_OOB) +#  ifdef CONFIG_ENV_OFFSET_REDUND +#   error "CONFIG_ENV_OFFSET_REDUND is not supported when CONFIG_ENV_OFFSET_OOB" +#   error "is set" +#  endif +extern unsigned long nand_env_oob_offset; +#  define CONFIG_ENV_OFFSET nand_env_oob_offset +# else +#  ifndef CONFIG_ENV_OFFSET +#   error "Need to define CONFIG_ENV_OFFSET when using CONFIG_ENV_IS_IN_NAND" +#  endif +#  ifdef CONFIG_ENV_OFFSET_REDUND +#   define CONFIG_SYS_REDUNDAND_ENVIRONMENT +#  endif +# endif /* CONFIG_ENV_OFFSET_OOB */  # ifndef CONFIG_ENV_SIZE  #  error "Need to define CONFIG_ENV_SIZE when using CONFIG_ENV_IS_IN_NAND"  # endif -# ifdef CONFIG_ENV_OFFSET_REDUND -#  define CONFIG_SYS_REDUNDAND_ENVIRONMENT -# endif  #endif /* CONFIG_ENV_IS_IN_NAND */  #if defined(CONFIG_ENV_IS_IN_MG_DISK) diff --git a/include/nand.h b/include/nand.h index 2a81597a6..8bdf4191a 100644 --- a/include/nand.h +++ b/include/nand.h @@ -130,3 +130,12 @@ void board_nand_select_device(struct nand_chip *nand, int chip);  __attribute__((noreturn)) void nand_boot(void);  #endif + +#ifdef CONFIG_ENV_OFFSET_OOB +#define ENV_OOB_MARKER 0x30425645 /*"EVB0" in little-endian -- offset is stored +				    as block number*/ +#define ENV_OOB_MARKER_OLD 0x30564e45 /*"ENV0" in little-endian -- offset is +					stored as byte number */ +#define ENV_OFFSET_SIZE 8 +int get_nand_env_oob(nand_info_t *nand, unsigned long *result); +#endif |