Merge remote-tracking branch 'origin/master'
diff --git a/README b/README
index 5a86ae9..b5c1c03 100644
--- a/README
+++ b/README
@@ -815,6 +815,8 @@
 		CONFIG_CMD_EDITENV	  edit env variable
 		CONFIG_CMD_EEPROM	* EEPROM read/write support
 		CONFIG_CMD_ELF		* bootelf, bootvx
+		CONFIG_CMD_ENV_CALLBACK	* display details about env callbacks
+		CONFIG_CMD_ENV_FLAGS	* display details about env flags
 		CONFIG_CMD_EXPORTENV	* export the environment
 		CONFIG_CMD_EXT2		* ext2 command support
 		CONFIG_CMD_EXT4		* ext4 command support
@@ -824,8 +826,10 @@
 		CONFIG_CMD_FDOS		* Dos diskette Support
 		CONFIG_CMD_FLASH	  flinfo, erase, protect
 		CONFIG_CMD_FPGA		  FPGA device initialization support
+		CONFIG_CMD_GETTIME	* Get time since boot
 		CONFIG_CMD_GO		* the 'go' command (exec code)
 		CONFIG_CMD_GREPENV	* search environment
+		CONFIG_CMD_HASH		* calculate hash / digest
 		CONFIG_CMD_HWFLOW	* RTS/CTS hw flow control
 		CONFIG_CMD_I2C		* I2C serial bus support
 		CONFIG_CMD_IDE		* IDE harddisk support
@@ -860,6 +864,7 @@
 		CONFIG_CMD_PING		* send ICMP ECHO_REQUEST to network
 					  host
 		CONFIG_CMD_PORTIO	* Port I/O
+		CONFIG_CMD_READ		* Read raw data from partition
 		CONFIG_CMD_REGINFO	* Register dump
 		CONFIG_CMD_RUN		  run command in env variable
 		CONFIG_CMD_SAVES	* save S record dump
@@ -1485,6 +1490,11 @@
 
 		Support drawing of RLE8-compressed bitmaps on the LCD.
 
+		CONFIG_I2C_EDID
+
+		Enables an 'i2c edid' command which can read EDID
+		information over I2C from an attached LCD display.
+
 
 - Splash Screen Support: CONFIG_SPLASH_SCREEN
 
@@ -2179,6 +2189,11 @@
 		serial# is unaffected by this, i. e. it remains
 		read-only.]
 
+		The same can be accomplished in a more flexible way
+		for any variable by configuring the type of access
+		to allow for those variables in the ".flags" variable
+		or define CONFIG_ENV_FLAGS_LIST_STATIC.
+
 - Protected RAM:
 		CONFIG_PRAM
 
@@ -2409,6 +2424,23 @@
 		A better solution is to properly configure the firewall,
 		but sometimes that is not allowed.
 
+- Hashing support:
+		CONFIG_CMD_HASH
+
+		This enables a generic 'hash' command which can produce
+		hashes / digests from a few algorithms (e.g. SHA1, SHA256).
+
+		CONFIG_HASH_VERIFY
+
+		Enable the hash verify command (hash -v). This adds to code
+		size a little.
+
+		CONFIG_SHA1 - support SHA1 hashing
+		CONFIG_SHA256 - support SHA256 hashing
+
+		Note: There is also a sha1sum command, which should perhaps
+		be deprecated in favour of 'hash sha1'.
+
 - Show boot progress:
 		CONFIG_SHOW_BOOT_PROGRESS
 
@@ -3087,6 +3119,49 @@
 	cases. This setting can be used to tune behaviour; see
 	lib/hashtable.c for details.
 
+- CONFIG_ENV_FLAGS_LIST_DEFAULT
+- CONFIG_ENV_FLAGS_LIST_STATIC
+	Enable validation of the values given to enviroment variables when
+	calling env set.  Variables can be restricted to only decimal,
+	hexadecimal, or boolean.  If CONFIG_CMD_NET is also defined,
+	the variables can also be restricted to IP address or MAC address.
+
+	The format of the list is:
+		type_attribute = [s|d|x|b|i|m]
+		access_atribute = [a|r|o|c]
+		attributes = type_attribute[access_atribute]
+		entry = variable_name[:attributes]
+		list = entry[,list]
+
+	The type attributes are:
+		s - String (default)
+		d - Decimal
+		x - Hexadecimal
+		b - Boolean ([1yYtT|0nNfF])
+		i - IP address
+		m - MAC address
+
+	The access attributes are:
+		a - Any (default)
+		r - Read-only
+		o - Write-once
+		c - Change-default
+
+	- CONFIG_ENV_FLAGS_LIST_DEFAULT
+		Define this to a list (string) to define the ".flags"
+		envirnoment variable in the default or embedded environment.
+
+	- CONFIG_ENV_FLAGS_LIST_STATIC
+		Define this to a list (string) to define validation that
+		should be done if an entry is not found in the ".flags"
+		environment variable.  To override a setting in the static
+		list, simply add an entry for the same variable name to the
+		".flags" variable.
+
+- CONFIG_ENV_ACCESS_IGNORE_FORCE
+	If defined, don't allow the -f switch to env set override variable
+	access flags.
+
 The following definitions that deal with the placement and management
 of environment data (variable area); in general, we support the
 following configurations:
@@ -4188,6 +4263,36 @@
 only effect after the next boot (yes, that's just like Windoze :-).
 
 
+Callback functions for environment variables:
+---------------------------------------------
+
+For some environment variables, the behavior of u-boot needs to change
+when their values are changed.  This functionailty allows functions to
+be associated with arbitrary variables.  On creation, overwrite, or
+deletion, the callback will provide the opportunity for some side
+effect to happen or for the change to be rejected.
+
+The callbacks are named and associated with a function using the
+U_BOOT_ENV_CALLBACK macro in your board or driver code.
+
+These callbacks are associated with variables in one of two ways.  The
+static list can be added to by defining CONFIG_ENV_CALLBACK_LIST_STATIC
+in the board configuration to a string that defines a list of
+associations.  The list must be in the following format:
+
+	entry = variable_name[:callback_name]
+	list = entry[,list]
+
+If the callback name is not specified, then the callback is deleted.
+Spaces are also allowed anywhere in the list.
+
+Callbacks can also be associated by defining the ".callbacks" variable
+with the same list format above.  Any association in ".callbacks" will
+override any association in the static list. You can define
+CONFIG_ENV_CALLBACK_LIST_DEFAULT to a list (string) to define the
+".callbacks" envirnoment variable in the default or embedded environment.
+
+
 Command Line Parsing:
 =====================
 
diff --git a/arch/arm/cpu/arm926ejs/mxs/clock.c b/arch/arm/cpu/arm926ejs/mxs/clock.c
index bfea6ab..4ff19c3 100644
--- a/arch/arm/cpu/arm926ejs/mxs/clock.c
+++ b/arch/arm/cpu/arm926ejs/mxs/clock.c
@@ -333,6 +333,8 @@
 		return mx28_get_sspclk(MXC_SSPCLK2);
 	case MXC_SSP3_CLK:
 		return mx28_get_sspclk(MXC_SSPCLK3);
+	case MXC_XTAL_CLK:
+		return XTAL_FREQ_KHZ * 1000;
 	}
 
 	return 0;
diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c
index 4f3b451..21e45d2 100644
--- a/arch/arm/cpu/armv7/exynos/clock.c
+++ b/arch/arm/cpu/armv7/exynos/clock.c
@@ -732,6 +732,21 @@
 	return aclk_66;
 }
 
+static unsigned long exynos4_get_i2c_clk(void)
+{
+	struct exynos4_clock *clk =
+		(struct exynos4_clock *)samsung_get_base_clock();
+	unsigned long sclk, aclk_100;
+	unsigned int ratio;
+
+	sclk = get_pll_clk(APLL);
+
+	ratio = (readl(&clk->div_top)) >> 4;
+	ratio &= 0xf;
+	aclk_100 = sclk / (ratio + 1);
+	return aclk_100;
+}
+
 unsigned long get_pll_clk(int pllreg)
 {
 	if (cpu_is_exynos5())
@@ -752,6 +767,8 @@
 {
 	if (cpu_is_exynos5()) {
 		return exynos5_get_i2c_clk();
+	} else if (cpu_is_exynos4()) {
+		return exynos4_get_i2c_clk();
 	} else {
 		debug("I2C clock is not set for this CPU\n");
 		return 0;
diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c
index 7776add..44ce072 100644
--- a/arch/arm/cpu/armv7/exynos/pinmux.c
+++ b/arch/arm/cpu/armv7/exynos/pinmux.c
@@ -265,10 +265,74 @@
 	return 0;
 }
 
+static void exynos4_i2c_config(int peripheral, int flags)
+{
+	struct exynos4_gpio_part1 *gpio1 =
+		(struct exynos4_gpio_part1 *) samsung_get_base_gpio_part1();
+
+	switch (peripheral) {
+	case PERIPH_ID_I2C0:
+		s5p_gpio_cfg_pin(&gpio1->d1, 0, GPIO_FUNC(0x2));
+		s5p_gpio_cfg_pin(&gpio1->d1, 1, GPIO_FUNC(0x2));
+		break;
+	case PERIPH_ID_I2C1:
+		s5p_gpio_cfg_pin(&gpio1->d1, 2, GPIO_FUNC(0x2));
+		s5p_gpio_cfg_pin(&gpio1->d1, 3, GPIO_FUNC(0x2));
+		break;
+	case PERIPH_ID_I2C2:
+		s5p_gpio_cfg_pin(&gpio1->a0, 6, GPIO_FUNC(0x3));
+		s5p_gpio_cfg_pin(&gpio1->a0, 7, GPIO_FUNC(0x3));
+		break;
+	case PERIPH_ID_I2C3:
+		s5p_gpio_cfg_pin(&gpio1->a1, 2, GPIO_FUNC(0x3));
+		s5p_gpio_cfg_pin(&gpio1->a1, 3, GPIO_FUNC(0x3));
+		break;
+	case PERIPH_ID_I2C4:
+		s5p_gpio_cfg_pin(&gpio1->b, 2, GPIO_FUNC(0x3));
+		s5p_gpio_cfg_pin(&gpio1->b, 3, GPIO_FUNC(0x3));
+		break;
+	case PERIPH_ID_I2C5:
+		s5p_gpio_cfg_pin(&gpio1->b, 6, GPIO_FUNC(0x3));
+		s5p_gpio_cfg_pin(&gpio1->b, 7, GPIO_FUNC(0x3));
+		break;
+	case PERIPH_ID_I2C6:
+		s5p_gpio_cfg_pin(&gpio1->c1, 3, GPIO_FUNC(0x4));
+		s5p_gpio_cfg_pin(&gpio1->c1, 4, GPIO_FUNC(0x4));
+		break;
+	case PERIPH_ID_I2C7:
+		s5p_gpio_cfg_pin(&gpio1->d0, 2, GPIO_FUNC(0x3));
+		s5p_gpio_cfg_pin(&gpio1->d0, 3, GPIO_FUNC(0x3));
+		break;
+	}
+}
+
+static int exynos4_pinmux_config(int peripheral, int flags)
+{
+	switch (peripheral) {
+	case PERIPH_ID_I2C0:
+	case PERIPH_ID_I2C1:
+	case PERIPH_ID_I2C2:
+	case PERIPH_ID_I2C3:
+	case PERIPH_ID_I2C4:
+	case PERIPH_ID_I2C5:
+	case PERIPH_ID_I2C6:
+	case PERIPH_ID_I2C7:
+		exynos4_i2c_config(peripheral, flags);
+		break;
+	default:
+		debug("%s: invalid peripheral %d", __func__, peripheral);
+		return -1;
+	}
+
+	return 0;
+}
+
 int exynos_pinmux_config(int peripheral, int flags)
 {
 	if (cpu_is_exynos5())
 		return exynos5_pinmux_config(peripheral, flags);
+	else if (cpu_is_exynos4())
+		return exynos4_pinmux_config(peripheral, flags);
 	else {
 		debug("pinmux functionality not supported\n");
 		return -1;
diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h
index 2cd4ae1..3073ca1 100644
--- a/arch/arm/include/asm/arch-exynos/cpu.h
+++ b/arch/arm/include/asm/arch-exynos/cpu.h
@@ -28,6 +28,8 @@
 #define EXYNOS4_ADDR_BASE		0x10000000
 
 /* EXYNOS4 */
+#define EXYNOS4_I2C_SPACING		0x10000
+
 #define EXYNOS4_GPIO_PART3_BASE		0x03860000
 #define EXYNOS4_PRO_ID			0x10000000
 #define EXYNOS4_SYSREG_BASE		0x10010000
diff --git a/arch/arm/include/asm/arch-mxs/clock.h b/arch/arm/include/asm/arch-mxs/clock.h
index 1700fe3..3d39ef2 100644
--- a/arch/arm/include/asm/arch-mxs/clock.h
+++ b/arch/arm/include/asm/arch-mxs/clock.h
@@ -35,6 +35,7 @@
 	MXC_SSP1_CLK,
 	MXC_SSP2_CLK,
 	MXC_SSP3_CLK,
+	MXC_XTAL_CLK,
 };
 
 enum mxs_ioclock {
diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c
index 22a4d9c..e0cb635 100644
--- a/arch/arm/lib/board.c
+++ b/arch/arm/lib/board.c
@@ -540,15 +540,13 @@
 	flash_size = flash_init();
 	if (flash_size > 0) {
 # ifdef CONFIG_SYS_FLASH_CHECKSUM
-		char *s = getenv("flashchecksum");
-
 		print_size(flash_size, "");
 		/*
 		 * Compute and print flash CRC if flashchecksum is set to 'y'
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf("  CRC: %08X", crc32(0,
 				(const unsigned char *) CONFIG_SYS_FLASH_BASE,
 				flash_size));
diff --git a/arch/m68k/include/asm/string.h b/arch/m68k/include/asm/string.h
index e0773a8..ecf5e56 100644
--- a/arch/m68k/include/asm/string.h
+++ b/arch/m68k/include/asm/string.h
@@ -16,7 +16,7 @@
 #endif
 
 extern int strcasecmp(const char *, const char *);
-extern int strncasecmp(const char *, const char *, int);
+extern int strncasecmp(const char *, const char *, __kernel_size_t);
 extern char * strcpy(char *,const char *);
 extern char * strncpy(char *,const char *, __kernel_size_t);
 extern __kernel_size_t strlen(const char *);
diff --git a/arch/m68k/lib/board.c b/arch/m68k/lib/board.c
index 02d73fd..794b867 100644
--- a/arch/m68k/lib/board.c
+++ b/arch/m68k/lib/board.c
@@ -462,8 +462,7 @@
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		s = getenv ("flashchecksum");
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf ("  CRC: %08X",
 					crc32 (0,
 						   (const unsigned char *) CONFIG_SYS_FLASH_BASE,
diff --git a/arch/microblaze/lib/board.c b/arch/microblaze/lib/board.c
index efd63cd..a7c2f76 100644
--- a/arch/microblaze/lib/board.c
+++ b/arch/microblaze/lib/board.c
@@ -74,7 +74,6 @@
 	gd = (gd_t *) (CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_GBL_DATA_OFFSET);
 	bd = (bd_t *) (CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_GBL_DATA_OFFSET \
 						- GENERATED_BD_INFO_SIZE);
-	__maybe_unused char *s;
 #if defined(CONFIG_CMD_FLASH)
 	ulong flash_size = 0;
 #endif
@@ -143,8 +142,7 @@
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		s = getenv ("flashchecksum");
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf ("  CRC: %08X",
 				crc32(0, (const u8 *)bd->bi_flashstart,
 							flash_size)
diff --git a/arch/mips/lib/board.c b/arch/mips/lib/board.c
index 7ddd778..d79e183 100644
--- a/arch/mips/lib/board.c
+++ b/arch/mips/lib/board.c
@@ -24,6 +24,7 @@
 #include <common.h>
 #include <command.h>
 #include <malloc.h>
+#include <serial.h>
 #include <stdio_dev.h>
 #include <version.h>
 #include <net.h>
@@ -46,7 +47,7 @@
  * mips_io_port_base is the begin of the address space to which x86 style
  * I/O ports are mapped.
  */
-unsigned long mips_io_port_base = -1;
+const unsigned long mips_io_port_base = -1;
 
 int __board_early_init_f(void)
 {
@@ -262,6 +263,8 @@
 
 	monitor_flash_len = (ulong)&uboot_end_data - dest_addr;
 
+	serial_initialize();
+
 #if defined(CONFIG_NEEDS_MANUAL_RELOC)
 	/*
 	 * We have to relocate the command table manually
diff --git a/arch/powerpc/cpu/mpc85xx/mp.c b/arch/powerpc/cpu/mpc85xx/mp.c
index e1197ac..43d4836 100644
--- a/arch/powerpc/cpu/mpc85xx/mp.c
+++ b/arch/powerpc/cpu/mpc85xx/mp.c
@@ -46,10 +46,8 @@
  */
 int hold_cores_in_reset(int verbose)
 {
-	const char *s = getenv("mp_holdoff");
-
 	/* Default to no, overriden by 'y', 'yes', 'Y', 'Yes', or '1' */
-	if (s && (*s == 'y' || *s == 'Y' || *s == '1')) {
+	if (getenv_yesno("mp_holdoff") == 1) {
 		if (verbose) {
 			puts("Secondary cores are being held in reset.\n");
 			puts("See 'mp_holdoff' environment variable\n");
diff --git a/arch/powerpc/include/asm/string.h b/arch/powerpc/include/asm/string.h
index d912a6b..036805e 100644
--- a/arch/powerpc/include/asm/string.h
+++ b/arch/powerpc/include/asm/string.h
@@ -14,7 +14,7 @@
 #define __HAVE_ARCH_MEMCHR
 
 extern int strcasecmp(const char *, const char *);
-extern int strncasecmp(const char *, const char *, int);
+extern int strncasecmp(const char *, const char *, __kernel_size_t);
 extern char * strcpy(char *,const char *);
 extern char * strncpy(char *,const char *, __kernel_size_t);
 extern __kernel_size_t strlen(const char *);
diff --git a/arch/powerpc/lib/board.c b/arch/powerpc/lib/board.c
index 1b051e1..6a7bf4b 100644
--- a/arch/powerpc/lib/board.c
+++ b/arch/powerpc/lib/board.c
@@ -739,16 +739,13 @@
 		flash_size = 0;
 	} else if ((flash_size = flash_init()) > 0) {
 #ifdef CONFIG_SYS_FLASH_CHECKSUM
-		char *s;
-
 		print_size(flash_size, "");
 		/*
 		 * Compute and print flash CRC if flashchecksum is set to 'y'
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		s = getenv("flashchecksum");
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf("  CRC: %08X",
 			       crc32(0,
 				     (const unsigned char *)
@@ -841,9 +838,7 @@
 	 * "i2cfast" into account
 	 */
 	{
-		char *s = getenv("i2cfast");
-
-		if (s && ((*s == 'y') || (*s == 'Y'))) {
+		if (getenv_yesno("i2cfast") == 1) {
 			bd->bi_iic_fast[0] = 1;
 			bd->bi_iic_fast[1] = 1;
 		}
diff --git a/arch/sparc/include/asm/string.h b/arch/sparc/include/asm/string.h
index c6bbc20..af6faea 100644
--- a/arch/sparc/include/asm/string.h
+++ b/arch/sparc/include/asm/string.h
@@ -40,7 +40,7 @@
 */
 
 extern int strcasecmp(const char *, const char *);
-extern int strncasecmp(const char *, const char *, int);
+extern int strncasecmp(const char *, const char *, __kernel_size_t);
 extern char *strcpy(char *, const char *);
 extern char *strncpy(char *, const char *, __kernel_size_t);
 extern __kernel_size_t strlen(const char *);
diff --git a/arch/sparc/lib/board.c b/arch/sparc/lib/board.c
index 32d025a..1b5e995 100644
--- a/arch/sparc/lib/board.c
+++ b/arch/sparc/lib/board.c
@@ -284,8 +284,7 @@
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		s = getenv("flashchecksum");
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf("  CRC: %08lX",
 			       crc32(0, (const unsigned char *)CONFIG_SYS_FLASH_BASE,
 				     flash_size)
diff --git a/board/Marvell/db64360/db64360.c b/board/Marvell/db64360/db64360.c
index 6cae686..38769e0 100644
--- a/board/Marvell/db64360/db64360.c
+++ b/board/Marvell/db64360/db64360.c
@@ -834,15 +834,11 @@
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata, runaddress, runwalk;
 
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
+	runaddress = getenv_yesno("testdramaddress") == 1;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 
 /*    rundata = 1; */
 /*    runaddress = 0; */
diff --git a/board/Marvell/db64460/db64460.c b/board/Marvell/db64460/db64460.c
index d4f58b3..ddb7ed5 100644
--- a/board/Marvell/db64460/db64460.c
+++ b/board/Marvell/db64460/db64460.c
@@ -834,15 +834,11 @@
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata, runaddress, runwalk;
 
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
+	runaddress = getenv_yesno("testdramaddress") == 1;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 
 /*    rundata = 1; */
 /*    runaddress = 0; */
diff --git a/board/esd/cpci750/cpci750.c b/board/esd/cpci750/cpci750.c
index 98051fb..d7deae4 100644
--- a/board/esd/cpci750/cpci750.c
+++ b/board/esd/cpci750/cpci750.c
@@ -953,22 +953,18 @@
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata    = 0;
 	int runaddress = 0;
 	int runwalk    = 0;
 
 #ifdef CONFIG_SYS_DRAM_TEST_DATA
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
 #endif
 #ifdef CONFIG_SYS_DRAM_TEST_ADDRESS
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
+	runaddress = getenv_yesno("testdramaddress") == 1;
 #endif
 #ifdef CONFIG_SYS_DRAM_TEST_WALK
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 #endif
 
 	if ((rundata == 1) || (runaddress == 1) || (runwalk == 1)) {
diff --git a/board/esd/pmc440/cmd_pmc440.c b/board/esd/pmc440/cmd_pmc440.c
index f1ffb7b..e9a78a3 100644
--- a/board/esd/pmc440/cmd_pmc440.c
+++ b/board/esd/pmc440/cmd_pmc440.c
@@ -391,7 +391,7 @@
 	nextbase -= ((CONFIG_ENV_SIZE + 4096 - 1) & ~(4096 - 1));
 	envp = (env_t *)nextbase;
 	res = (char *)envp->data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/board/gw8260/gw8260.c b/board/gw8260/gw8260.c
index 77a1e1d..64c54d5 100644
--- a/board/gw8260/gw8260.c
+++ b/board/gw8260/gw8260.c
@@ -544,15 +544,11 @@
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata, runaddress, runwalk;
 
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
+	runaddress = getenv_yesno("testdramaddress") == 1;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 
 	if ((rundata == 1) || (runaddress == 1) || (runwalk == 1)) {
 		printf ("Testing RAM ... ");
diff --git a/board/prodrive/p3mx/p3mx.c b/board/prodrive/p3mx/p3mx.c
index 389affc..c3fd191 100644
--- a/board/prodrive/p3mx/p3mx.c
+++ b/board/prodrive/p3mx/p3mx.c
@@ -768,22 +768,18 @@
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata    = 0;
 	int runaddress = 0;
 	int runwalk    = 0;
 
 #ifdef CONFIG_SYS_DRAM_TEST_DATA
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
 #endif
 #ifdef CONFIG_SYS_DRAM_TEST_ADDRESS
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
+	runaddress = getenv_yesno("testdramaddress") == 1;
 #endif
 #ifdef CONFIG_SYS_DRAM_TEST_WALK
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 #endif
 
 	if ((rundata == 1) || (runaddress == 1) || (runwalk == 1))
diff --git a/common/Makefile b/common/Makefile
index c29a7d8..c774395 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -30,6 +30,7 @@
 COBJS-y += main.o
 COBJS-y += command.o
 COBJS-y += exports.o
+COBJS-y += hash.o
 COBJS-$(CONFIG_SYS_HUSH_PARSER) += hush.o
 COBJS-y += s_record.o
 COBJS-y += xyzModem.o
@@ -43,7 +44,10 @@
 COBJS-y += cmd_version.o
 
 # environment
+COBJS-y += env_attr.o
+COBJS-y += env_callback.o
 COBJS-y += env_common.o
+COBJS-y += env_flags.o
 COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o
 COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o
 XCOBJS-$(CONFIG_ENV_IS_EMBEDDED) += env_embedded.o
@@ -100,8 +104,10 @@
 COBJS-$(CONFIG_CMD_FPGA) += cmd_fpga.o
 endif
 COBJS-$(CONFIG_CMD_FS_GENERIC) += cmd_fs.o
+COBJS-$(CONFIG_CMD_GETTIME) += cmd_gettime.o
 COBJS-$(CONFIG_CMD_GPIO) += cmd_gpio.o
 COBJS-$(CONFIG_CMD_I2C) += cmd_i2c.o
+COBJS-$(CONFIG_CMD_HASH) += cmd_hash.o
 COBJS-$(CONFIG_CMD_IDE) += cmd_ide.o
 COBJS-$(CONFIG_CMD_IMMAP) += cmd_immap.o
 COBJS-$(CONFIG_CMD_INI) += cmd_ini.o
@@ -117,6 +123,7 @@
 COBJS-$(CONFIG_ID_EEPROM) += cmd_mac.o
 COBJS-$(CONFIG_CMD_MD5SUM) += cmd_md5sum.o
 COBJS-$(CONFIG_CMD_MEMORY) += cmd_mem.o
+COBJS-$(CONFIG_CMD_IO) += cmd_io.o
 COBJS-$(CONFIG_CMD_MFSL) += cmd_mfsl.o
 COBJS-$(CONFIG_MII) += miiphyutil.o
 COBJS-$(CONFIG_CMD_MII) += miiphyutil.o
@@ -141,6 +148,7 @@
 COBJS-y += cmd_pcmcia.o
 COBJS-$(CONFIG_CMD_PORTIO) += cmd_portio.o
 COBJS-$(CONFIG_CMD_PXE) += cmd_pxe.o
+COBJS-$(CONFIG_CMD_READ) += cmd_read.o
 COBJS-$(CONFIG_CMD_REGINFO) += cmd_reginfo.o
 COBJS-$(CONFIG_CMD_REISER) += cmd_reiser.o
 COBJS-$(CONFIG_CMD_SATA) += cmd_sata.o
@@ -184,6 +192,7 @@
 COBJS-$(CONFIG_CONSOLE_MUX) += iomux.o
 COBJS-y += flash.o
 COBJS-$(CONFIG_CMD_KGDB) += kgdb.o kgdb_stubs.o
+COBJS-$(CONFIG_I2C_EDID) += edid.o
 COBJS-$(CONFIG_KALLSYMS) += kallsyms.o
 COBJS-$(CONFIG_LCD) += lcd.o
 COBJS-$(CONFIG_LYNXKDI) += lynxkdi.o
@@ -192,6 +201,7 @@
 COBJS-$(CONFIG_UPDATE_TFTP) += update.o
 COBJS-$(CONFIG_USB_KEYBOARD) += usb_kbd.o
 COBJS-$(CONFIG_CMD_DFU) += cmd_dfu.o
+COBJS-$(CONFIG_CMD_GPT) += cmd_gpt.o
 endif
 
 ifdef CONFIG_SPL_BUILD
@@ -200,7 +210,10 @@
 COBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o
 COBJS-$(CONFIG_SPL_YMODEM_SUPPORT) += xyzModem.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += cmd_nvedit.o
+COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_attr.o
+COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_callback.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_common.o
+COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_flags.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_nowhere.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o
 endif
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index 4dbe952..f7595c0 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -537,7 +537,7 @@
 		}
 			break;
 #endif
-#if defined(CONFIG_OF_LIBFDT)
+#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB)
 		case BOOTM_STATE_FDT:
 		{
 			boot_fdt_add_mem_rsv_regions(&images.lmb,
diff --git a/common/cmd_gettime.c b/common/cmd_gettime.c
new file mode 100644
index 0000000..d7d36a9
--- /dev/null
+++ b/common/cmd_gettime.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ *
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Get Timer overflows after 2^32 / CONFIG_SYS_HZ (32Khz) = 131072 sec
+ */
+#include <common.h>
+#include <command.h>
+
+static int do_gettime(cmd_tbl_t *cmdtp, int flag, int argc,
+		      char * const argv[])
+{
+	unsigned long int val = get_timer(0);
+
+#ifdef CONFIG_SYS_HZ
+	printf("Timer val: %lu\n", val);
+	printf("Seconds : %lu\n", val / CONFIG_SYS_HZ);
+	printf("Remainder : %lu\n", val % CONFIG_SYS_HZ);
+	printf("sys_hz = %lu\n", (unsigned long int)CONFIG_SYS_HZ);
+#else
+	printf("CONFIG_SYS_HZ not defined");
+	printf("Timer Val %lu", val);
+#endif
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	gettime,	1,	1,	do_gettime,
+	"get timer val elapsed,\n",
+	"get time elapsed from uboot start\n"
+);
diff --git a/common/cmd_gpt.c b/common/cmd_gpt.c
new file mode 100644
index 0000000..da7705d
--- /dev/null
+++ b/common/cmd_gpt.c
@@ -0,0 +1,333 @@
+/*
+ * cmd_gpt.c -- GPT (GUID Partition Table) handling command
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * author: Lukasz Majewski <l.majewski@samsung.com>
+ * author: Piotr Wilczek <p.wilczek@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <command.h>
+#include <mmc.h>
+#include <part_efi.h>
+#include <exports.h>
+#include <linux/ctype.h>
+
+#ifndef CONFIG_PARTITION_UUIDS
+#error CONFIG_PARTITION_UUIDS must be enabled for CONFIG_CMD_GPT to be enabled
+#endif
+
+/**
+ * extract_env(): Expand env name from string format '&{env_name}'
+ *                and return pointer to the env (if the env is set)
+ *
+ * @param str - pointer to string
+ * @param env - pointer to pointer to extracted env
+ *
+ * @return - zero on successful expand and env is set
+ */
+static char extract_env(const char *str, char **env)
+{
+	char *e, *s;
+
+	if (!str || strlen(str) < 4)
+		return -1;
+
+	if ((strncmp(str, "${", 2) == 0) && (str[strlen(str) - 1] == '}')) {
+		s = strdup(str);
+		if (s == NULL)
+			return -1;
+		memset(s + strlen(s) - 1, '\0', 1);
+		memmove(s, s + 2, strlen(s) - 1);
+		e = getenv(s);
+		free(s);
+		if (e == NULL) {
+			printf("Environmental '%s' not set\n", str);
+			return -1; /* env not set */
+		}
+		*env = e;
+		return 0;
+	}
+
+	return -1;
+}
+
+/**
+ * extract_val(): Extract value from a key=value pair list (comma separated).
+ *                Only value for the given key is returend.
+ *                Function allocates memory for the value, remember to free!
+ *
+ * @param str - pointer to string with key=values pairs
+ * @param key - pointer to the key to search for
+ *
+ * @return - pointer to allocated string with the value
+ */
+static char *extract_val(const char *str, const char *key)
+{
+	char *v, *k;
+	char *s, *strcopy;
+	char *new = NULL;
+
+	strcopy = strdup(str);
+	if (strcopy == NULL)
+		return NULL;
+
+	s = strcopy;
+	while (s) {
+		v = strsep(&s, ",");
+		if (!v)
+			break;
+		k = strsep(&v, "=");
+		if (!k)
+			break;
+		if  (strcmp(k, key) == 0) {
+			new = strdup(v);
+			break;
+		}
+	}
+
+	free(strcopy);
+
+	return new;
+}
+
+/**
+ * set_gpt_info(): Fill partition information from string
+ *		function allocates memory, remember to free!
+ *
+ * @param dev_desc - pointer block device descriptor
+ * @param str_part - pointer to string with partition information
+ * @param str_disk_guid - pointer to pointer to allocated string with disk guid
+ * @param partitions - pointer to pointer to allocated partitions array
+ * @param parts_count - number of partitions
+ *
+ * @return - zero on success, otherwise error
+ *
+ */
+static int set_gpt_info(block_dev_desc_t *dev_desc,
+			const char *str_part,
+			char **str_disk_guid,
+			disk_partition_t **partitions,
+			u8 *parts_count)
+{
+	char *tok, *str, *s;
+	int i;
+	char *val, *p;
+	int p_count;
+	disk_partition_t *parts;
+	int errno = 0;
+
+	debug("%s: MMC lba num: 0x%x %d\n", __func__,
+	      (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba);
+
+	if (str_part == NULL)
+		return -1;
+
+	str = strdup(str_part);
+
+	/* extract disk guid */
+	s = str;
+	tok = strsep(&s, ";");
+	val = extract_val(tok, "uuid_disk");
+	if (!val) {
+		free(str);
+		return -2;
+	}
+	if (extract_env(val, &p))
+		p = val;
+	*str_disk_guid = strdup(p);
+	free(val);
+
+	if (strlen(s) == 0)
+		return -3;
+
+	i = strlen(s) - 1;
+	if (s[i] == ';')
+		s[i] = '\0';
+
+	/* calculate expected number of partitions */
+	p_count = 1;
+	p = s;
+	while (*p) {
+		if (*p++ == ';')
+			p_count++;
+	}
+
+	/* allocate memory for partitions */
+	parts = calloc(sizeof(disk_partition_t), p_count);
+
+	/* retrive partions data from string */
+	for (i = 0; i < p_count; i++) {
+		tok = strsep(&s, ";");
+
+		if (tok == NULL)
+			break;
+
+		/* uuid */
+		val = extract_val(tok, "uuid");
+		if (!val) { /* 'uuid' is mandatory */
+			errno = -4;
+			goto err;
+		}
+		if (extract_env(val, &p))
+			p = val;
+		if (strlen(p) >= sizeof(parts[i].uuid)) {
+			printf("Wrong uuid format for partition %d\n", i);
+			errno = -4;
+			goto err;
+		}
+		strcpy((char *)parts[i].uuid, p);
+		free(val);
+
+		/* name */
+		val = extract_val(tok, "name");
+		if (!val) { /* name is mandatory */
+			errno = -4;
+			goto err;
+		}
+		if (extract_env(val, &p))
+			p = val;
+		if (strlen(p) >= sizeof(parts[i].name)) {
+			errno = -4;
+			goto err;
+		}
+		strcpy((char *)parts[i].name, p);
+		free(val);
+
+		/* size */
+		val = extract_val(tok, "size");
+		if (!val) { /* 'size' is mandatory */
+			errno = -4;
+			goto err;
+		}
+		if (extract_env(val, &p))
+			p = val;
+		parts[i].size = ustrtoul(p, &p, 0);
+		parts[i].size /= dev_desc->blksz;
+		free(val);
+
+		/* start address */
+		val = extract_val(tok, "start");
+		if (val) { /* start address is optional */
+			if (extract_env(val, &p))
+				p = val;
+			parts[i].start = ustrtoul(p, &p, 0);
+			parts[i].start /= dev_desc->blksz;
+			free(val);
+		}
+	}
+
+	*parts_count = p_count;
+	*partitions = parts;
+	free(str);
+
+	return 0;
+err:
+	free(str);
+	free(*str_disk_guid);
+	free(parts);
+
+	return errno;
+}
+
+static int gpt_mmc_default(int dev, const char *str_part)
+{
+	int ret;
+	char *str_disk_guid;
+	u8 part_count = 0;
+	disk_partition_t *partitions = NULL;
+
+	struct mmc *mmc = find_mmc_device(dev);
+
+	if (mmc == NULL) {
+		printf("%s: mmc dev %d NOT available\n", __func__, dev);
+		return CMD_RET_FAILURE;
+	}
+
+	if (!str_part)
+		return -1;
+
+	/* fill partitions */
+	ret = set_gpt_info(&mmc->block_dev, str_part,
+			&str_disk_guid, &partitions, &part_count);
+	if (ret) {
+		if (ret == -1)
+			printf("No partition list provided\n");
+		if (ret == -2)
+			printf("Missing disk guid\n");
+		if ((ret == -3) || (ret == -4))
+			printf("Partition list incomplete\n");
+		return -1;
+	}
+
+	/* save partitions layout to disk */
+	gpt_restore(&mmc->block_dev, str_disk_guid, partitions, part_count);
+	free(str_disk_guid);
+	free(partitions);
+
+	return 0;
+}
+
+/**
+ * do_gpt(): Perform GPT operations
+ *
+ * @param cmdtp - command name
+ * @param flag
+ * @param argc
+ * @param argv
+ *
+ * @return zero on success; otherwise error
+ */
+static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	int ret = CMD_RET_SUCCESS;
+	int dev = 0;
+	char *pstr;
+
+	if (argc < 5)
+		return CMD_RET_USAGE;
+
+	/* command: 'write' */
+	if ((strcmp(argv[1], "write") == 0) && (argc == 5)) {
+		/* device: 'mmc' */
+		if (strcmp(argv[2], "mmc") == 0) {
+			/* check if 'dev' is a number */
+			for (pstr = argv[3]; *pstr != '\0'; pstr++)
+				if (!isdigit(*pstr)) {
+					printf("'%s' is not a number\n",
+						argv[3]);
+					return CMD_RET_USAGE;
+				}
+			dev = (int)simple_strtoul(argv[3], NULL, 10);
+			/* write to mmc */
+			if (gpt_mmc_default(dev, argv[4]))
+				return CMD_RET_FAILURE;
+		}
+	} else {
+		return CMD_RET_USAGE;
+	}
+	return ret;
+}
+
+U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
+	"GUID Partition Table",
+	"<command> <interface> <dev> <partions_list>\n"
+	" - GUID partition table restoration\n"
+	" Restore GPT information on a device connected\n"
+	" to interface\n"
+);
diff --git a/common/cmd_hash.c b/common/cmd_hash.c
new file mode 100644
index 0000000..689c608
--- /dev/null
+++ b/common/cmd_hash.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2012 The Chromium OS Authors.
+ *
+ * (C) Copyright 2011
+ * Joe Hershberger, National Instruments, joe.hershberger@ni.com
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <hash.h>
+
+static int do_hash(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+#ifdef CONFIG_HASH_VERIFY
+	int verify = 0;
+
+	if (!strcmp(argv[1], "-v")) {
+		verify = 1;
+		argc--;
+		argv++;
+	}
+#endif
+	/* Move forward to 'algorithm' parameter */
+	argc--;
+	argv++;
+	return hash_command(*argv, verify, cmdtp, flag, argc - 1, argv + 1);
+}
+
+#ifdef CONFIG_HASH_VERIFY
+U_BOOT_CMD(
+	hash,	6,	1,	do_hash,
+	"compute hash message digest",
+	"algorithm address count [[*]sum_dest]\n"
+		"    - compute message digest [save to env var / *address]\n"
+	"hash -v algorithm address count [*]sum\n"
+		"    - verify hash of memory area with env var / *address"
+);
+#else
+U_BOOT_CMD(
+	hash,	5,	1,	do_hash,
+	"compute message digest",
+	"algorithm address count [[*]sum_dest]\n"
+		"    - compute message digest [save to env var / *address]"
+);
+#endif
diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c
index 4438db5..4380794 100644
--- a/common/cmd_i2c.c
+++ b/common/cmd_i2c.c
@@ -78,10 +78,12 @@
 
 #include <common.h>
 #include <command.h>
+#include <edid.h>
 #include <environment.h>
 #include <i2c.h>
 #include <malloc.h>
 #include <asm/byteorder.h>
+#include <linux/compiler.h>
 
 /* Display values from last command.
  * Memory modify remembered values are different from display memory.
@@ -132,35 +134,65 @@
 
 #define DISP_LINE_LEN	16
 
-/* implement possible board specific board init */
-static void __def_i2c_init_board(void)
+/**
+ * i2c_init_board() - Board-specific I2C bus init
+ *
+ * This function is the default no-op implementation of I2C bus
+ * initialization. This function can be overriden by board-specific
+ * implementation if needed.
+ */
+__weak
+void i2c_init_board(void)
 {
 	return;
 }
-void i2c_init_board(void)
-	__attribute__((weak, alias("__def_i2c_init_board")));
 
 /* TODO: Implement architecture-specific get/set functions */
-static unsigned int __def_i2c_get_bus_speed(void)
+
+/**
+ * i2c_get_bus_speed() - Return I2C bus speed
+ *
+ * This function is the default implementation of function for retrieveing
+ * the current I2C bus speed in Hz.
+ *
+ * A driver implementing runtime switching of I2C bus speed must override
+ * this function to report the speed correctly. Simple or legacy drivers
+ * can use this fallback.
+ *
+ * Returns I2C bus speed in Hz.
+ */
+__weak
+unsigned int i2c_get_bus_speed(void)
 {
 	return CONFIG_SYS_I2C_SPEED;
 }
-unsigned int i2c_get_bus_speed(void)
-	__attribute__((weak, alias("__def_i2c_get_bus_speed")));
 
-static int __def_i2c_set_bus_speed(unsigned int speed)
+/**
+ * i2c_set_bus_speed() - Configure I2C bus speed
+ * @speed:	Newly set speed of the I2C bus in Hz
+ *
+ * This function is the default implementation of function for setting
+ * the I2C bus speed in Hz.
+ *
+ * A driver implementing runtime switching of I2C bus speed must override
+ * this function to report the speed correctly. Simple or legacy drivers
+ * can use this fallback.
+ *
+ * Returns zero on success, negative value on error.
+ */
+__weak
+int i2c_set_bus_speed(unsigned int speed)
 {
 	if (speed != CONFIG_SYS_I2C_SPEED)
 		return -1;
 
 	return 0;
 }
-int i2c_set_bus_speed(unsigned int)
-	__attribute__((weak, alias("__def_i2c_set_bus_speed")));
 
-/*
- * get_alen: small parser helper function to get address length
- * returns the address length
+/**
+ * get_alen() - Small parser helper function to get address length
+ *
+ * Returns the address length.
  */
 static uint get_alen(char *arg)
 {
@@ -178,11 +210,19 @@
 	return alen;
 }
 
-/*
+/**
+ * do_i2c_read() - Handle the "i2c read" command-line command
+ * @cmdtp:	Command data struct pointer
+ * @flag:	Command flag
+ * @argc:	Command-line argument count
+ * @argv:	Array of command-line arguments
+ *
+ * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
+ * on error.
+ *
  * Syntax:
  *	i2c read {i2c_chip} {devaddr}{.0, .1, .2} {len} {memaddr}
  */
-
 static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	u_char	chip;
@@ -271,7 +311,16 @@
 	return 0;
 }
 
-/*
+/**
+ * do_i2c_md() - Handle the "i2c md" command-line command
+ * @cmdtp:	Command data struct pointer
+ * @flag:	Command flag
+ * @argc:	Command-line argument count
+ * @argv:	Array of command-line arguments
+ *
+ * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
+ * on error.
+ *
  * Syntax:
  *	i2c md {i2c_chip} {addr}{.0, .1, .2} {len}
  */
@@ -363,8 +412,15 @@
 	return 0;
 }
 
-
-/* Write (fill) memory
+/**
+ * do_i2c_mw() - Handle the "i2c mw" command-line command
+ * @cmdtp:	Command data struct pointer
+ * @flag:	Command flag
+ * @argc:	Command-line argument count
+ * @argv:	Array of command-line arguments
+ *
+ * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
+ * on error.
  *
  * Syntax:
  *	i2c mw {i2c_chip} {addr}{.0, .1, .2} {data} [{count}]
@@ -421,10 +477,20 @@
 #endif
 	}
 
-	return (0);
+	return 0;
 }
 
-/* Calculate a CRC on memory
+/**
+ * do_i2c_crc() - Handle the "i2c crc32" command-line command
+ * @cmdtp:	Command data struct pointer
+ * @flag:	Command flag
+ * @argc:	Command-line argument count
+ * @argv:	Array of command-line arguments
+ *
+ * Calculate a CRC on memory
+ *
+ * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
+ * on error.
  *
  * Syntax:
  *	i2c crc32 {i2c_chip} {addr}{.0, .1, .2} {count}
@@ -481,13 +547,22 @@
 	return 0;
 }
 
-/* Modify memory.
+/**
+ * mod_i2c_mem() - Handle the "i2c mm" and "i2c nm" command-line command
+ * @cmdtp:	Command data struct pointer
+ * @flag:	Command flag
+ * @argc:	Command-line argument count
+ * @argv:	Array of command-line arguments
+ *
+ * Modify memory.
+ *
+ * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
+ * on error.
  *
  * Syntax:
  *	i2c mm{.b, .w, .l} {i2c_chip} {addr}{.0, .1, .2}
  *	i2c nm{.b, .w, .l} {i2c_chip} {addr}{.0, .1, .2}
  */
-
 static int
 mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const argv[])
 {
@@ -603,7 +678,16 @@
 	return 0;
 }
 
-/*
+/**
+ * do_i2c_probe() - Handle the "i2c probe" command-line command
+ * @cmdtp:	Command data struct pointer
+ * @flag:	Command flag
+ * @argc:	Command-line argument count
+ * @argv:	Array of command-line arguments
+ *
+ * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
+ * on error.
+ *
  * Syntax:
  *	i2c probe {addr}
  *
@@ -657,7 +741,16 @@
 	return (0 == found);
 }
 
-/*
+/**
+ * do_i2c_loop() - Handle the "i2c loop" command-line command
+ * @cmdtp:	Command data struct pointer
+ * @flag:	Command flag
+ * @argc:	Command-line argument count
+ * @argv:	Array of command-line arguments
+ *
+ * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
+ * on error.
+ *
  * Syntax:
  *	i2c loop {i2c_chip} {addr}{.0, .1, .2} [{length}] [{delay}]
  *	{length} - Number of bytes to read
@@ -718,6 +811,8 @@
 /*
  * The SDRAM command is separately configured because many
  * (most?) embedded boards don't use SDRAM DIMMs.
+ *
+ * FIXME: Document and probably move elsewhere!
  */
 #if defined(CONFIG_CMD_SDRAM)
 static void print_ddr2_tcyc (u_char const b)
@@ -1246,7 +1341,48 @@
 }
 #endif
 
+/*
+ * Syntax:
+ *	i2c edid {i2c_chip}
+ */
+#if defined(CONFIG_I2C_EDID)
+int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+	u_char chip;
+	struct edid1_info edid;
+
+	if (argc < 2) {
+		cmd_usage(cmdtp);
+		return 1;
+	}
+
+	chip = simple_strtoul(argv[1], NULL, 16);
+	if (i2c_read(chip, 0, 1, (uchar *)&edid, sizeof(edid)) != 0) {
+		puts("Error reading EDID content.\n");
+		return 1;
+	}
+
+	if (edid_check_info(&edid)) {
+		puts("Content isn't valid EDID.\n");
+		return 1;
+	}
+
+	edid_print_info(&edid);
+	return 0;
+
+}
+#endif /* CONFIG_I2C_EDID */
+
 #if defined(CONFIG_I2C_MUX)
+/**
+ * do_i2c_add_bus() - Handle the "i2c bus" command-line command
+ * @cmdtp:	Command data struct pointer
+ * @flag:	Command flag
+ * @argc:	Command-line argument count
+ * @argv:	Array of command-line arguments
+ *
+ * Returns zero always.
+ */
 static int do_i2c_add_bus(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 {
 	int ret=0;
@@ -1276,6 +1412,16 @@
 #endif  /* CONFIG_I2C_MUX */
 
 #if defined(CONFIG_I2C_MULTI_BUS)
+/**
+ * do_i2c_bus_num() - Handle the "i2c dev" command-line command
+ * @cmdtp:	Command data struct pointer
+ * @flag:	Command flag
+ * @argc:	Command-line argument count
+ * @argv:	Array of command-line arguments
+ *
+ * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
+ * on error.
+ */
 static int do_i2c_bus_num(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 {
 	int bus_idx, ret=0;
@@ -1294,6 +1440,16 @@
 }
 #endif  /* CONFIG_I2C_MULTI_BUS */
 
+/**
+ * do_i2c_bus_speed() - Handle the "i2c speed" command-line command
+ * @cmdtp:	Command data struct pointer
+ * @flag:	Command flag
+ * @argc:	Command-line argument count
+ * @argv:	Array of command-line arguments
+ *
+ * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
+ * on error.
+ */
 static int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 {
 	int speed, ret=0;
@@ -1311,16 +1467,45 @@
 	return ret;
 }
 
+/**
+ * do_i2c_mm() - Handle the "i2c mm" command-line command
+ * @cmdtp:	Command data struct pointer
+ * @flag:	Command flag
+ * @argc:	Command-line argument count
+ * @argv:	Array of command-line arguments
+ *
+ * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
+ * on error.
+ */
 static int do_i2c_mm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 {
 	return mod_i2c_mem (cmdtp, 1, flag, argc, argv);
 }
 
+/**
+ * do_i2c_nm() - Handle the "i2c nm" command-line command
+ * @cmdtp:	Command data struct pointer
+ * @flag:	Command flag
+ * @argc:	Command-line argument count
+ * @argv:	Array of command-line arguments
+ *
+ * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
+ * on error.
+ */
 static int do_i2c_nm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 {
 	return mod_i2c_mem (cmdtp, 0, flag, argc, argv);
 }
 
+/**
+ * do_i2c_reset() - Handle the "i2c reset" command-line command
+ * @cmdtp:	Command data struct pointer
+ * @flag:	Command flag
+ * @argc:	Command-line argument count
+ * @argv:	Array of command-line arguments
+ *
+ * Returns zero always.
+ */
 static int do_i2c_reset(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 {
 	i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
@@ -1335,6 +1520,9 @@
 #if defined(CONFIG_I2C_MULTI_BUS)
 	U_BOOT_CMD_MKENT(dev, 1, 1, do_i2c_bus_num, "", ""),
 #endif  /* CONFIG_I2C_MULTI_BUS */
+#if defined(CONFIG_I2C_EDID)
+	U_BOOT_CMD_MKENT(edid, 1, 1, do_edid, "", ""),
+#endif  /* CONFIG_I2C_EDID */
 	U_BOOT_CMD_MKENT(loop, 3, 1, do_i2c_loop, "", ""),
 	U_BOOT_CMD_MKENT(md, 3, 1, do_i2c_md, "", ""),
 	U_BOOT_CMD_MKENT(mm, 2, 1, do_i2c_mm, "", ""),
@@ -1356,6 +1544,16 @@
 }
 #endif
 
+/**
+ * do_i2c() - Handle the "i2c" command-line command
+ * @cmdtp:	Command data struct pointer
+ * @flag:	Command flag
+ * @argc:	Command-line argument count
+ * @argv:	Array of command-line arguments
+ *
+ * Returns zero on success, CMD_RET_USAGE in case of misuse and negative
+ * on error.
+ */
 static int do_i2c(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 {
 	cmd_tbl_t *c;
@@ -1385,6 +1583,9 @@
 #if defined(CONFIG_I2C_MULTI_BUS)
 	"i2c dev [dev] - show or set current I2C bus\n"
 #endif  /* CONFIG_I2C_MULTI_BUS */
+#if defined(CONFIG_I2C_EDID)
+	"i2c edid chip - print EDID configuration information\n"
+#endif  /* CONFIG_I2C_EDID */
 	"i2c loop chip address[.0, .1, .2] [# of objects] - looping read of device\n"
 	"i2c md chip address[.0, .1, .2] [# of objects] - read from I2C device\n"
 	"i2c mm chip address[.0, .1, .2] - write to I2C device (auto-incrementing)\n"
diff --git a/common/cmd_io.c b/common/cmd_io.c
new file mode 100644
index 0000000..6450cb5
--- /dev/null
+++ b/common/cmd_io.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2012 The Chromium OS Authors.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * IO space access commands.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+
+/*
+ * IO Display
+ *
+ * Syntax:
+ *	iod{.b, .w, .l} {addr}
+ */
+int do_io_iod(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+	ulong addr;
+	int size;
+
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	size = cmd_get_data_size(argv[0], 4);
+	if (size < 0)
+		return 1;
+
+	addr = simple_strtoul(argv[1], NULL, 16);
+
+	printf("%04x: ", (u16) addr);
+
+	if (size == 4)
+		printf("%08x\n", inl(addr));
+	else if (size == 2)
+		printf("%04x\n", inw(addr));
+	else
+		printf("%02x\n", inb(addr));
+
+	return 0;
+}
+
+int do_io_iow(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+	ulong addr, size, val;
+
+	if (argc != 3)
+		return CMD_RET_USAGE;
+
+	size = cmd_get_data_size(argv[0], 4);
+	if (size < 0)
+		return 1;
+
+	addr = simple_strtoul(argv[1], NULL, 16);
+	val = simple_strtoul(argv[2], NULL, 16);
+
+	if (size == 4)
+		outl((u32) val, addr);
+	else if (size == 2)
+		outw((u16) val, addr);
+	else
+		outb((u8) val, addr);
+
+	return 0;
+}
+
+/**************************************************/
+U_BOOT_CMD(iod, 2, 0, do_io_iod,
+	   "IO space display", "[.b, .w, .l] address [# of objects]");
+
+U_BOOT_CMD(iow, 3, 0, do_io_iow,
+	   "IO space modify (auto-incrementing address)",
+	   "[.b, .w, .l] address");
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 006131f..7633f0c 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -47,12 +47,8 @@
 #include <errno.h>
 #include <malloc.h>
 #include <watchdog.h>
-#include <serial.h>
 #include <linux/stddef.h>
 #include <asm/byteorder.h>
-#if defined(CONFIG_CMD_NET)
-#include <net.h>
-#endif
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -76,16 +72,6 @@
  */
 #define	MAX_ENV_SIZE	(1 << 20)	/* 1 MiB */
 
-ulong load_addr = CONFIG_SYS_LOAD_ADDR;	/* Default Load Address */
-ulong save_addr;			/* Default Save Address */
-ulong save_size;			/* Default Save Size (in bytes) */
-
-/*
- * Table with supported baudrates (defined in config_xyz.h)
- */
-static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
-#define	N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0]))
-
 /*
  * This variable is incremented on each do_env_set(), so it can
  * be used via get_env_id() as an indication, if the environment
@@ -106,7 +92,7 @@
  *
  * Returns 0 in case of error, or length of printed string
  */
-static int env_print(char *name)
+static int env_print(char *name, int flag)
 {
 	char *res = NULL;
 	size_t len;
@@ -116,7 +102,7 @@
 
 		e.key = name;
 		e.data = NULL;
-		hsearch_r(e, FIND, &ep, &env_htab);
+		hsearch_r(e, FIND, &ep, &env_htab, flag);
 		if (ep == NULL)
 			return 0;
 		len = printf("%s=%s\n", ep->key, ep->data);
@@ -124,7 +110,7 @@
 	}
 
 	/* print whole list */
-	len = hexport_r(&env_htab, '\n', &res, 0, 0, NULL);
+	len = hexport_r(&env_htab, '\n', flag, &res, 0, 0, NULL);
 
 	if (len > 0) {
 		puts(res);
@@ -141,10 +127,17 @@
 {
 	int i;
 	int rcode = 0;
+	int env_flag = H_HIDE_DOT;
+
+	if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'a') {
+		argc--;
+		argv++;
+		env_flag &= ~H_HIDE_DOT;
+	}
 
 	if (argc == 1) {
 		/* print all env vars */
-		rcode = env_print(NULL);
+		rcode = env_print(NULL, env_flag);
 		if (!rcode)
 			return 1;
 		printf("\nEnvironment size: %d/%ld bytes\n",
@@ -153,8 +146,9 @@
 	}
 
 	/* print selected env vars */
+	env_flag &= ~H_HIDE_DOT;
 	for (i = 1; i < argc; ++i) {
-		int rc = env_print(argv[i]);
+		int rc = env_print(argv[i], env_flag);
 		if (!rc) {
 			printf("## Error: \"%s\" not defined\n", argv[i]);
 			++rcode;
@@ -198,137 +192,32 @@
 #endif /* CONFIG_SPL_BUILD */
 
 /*
- * Perform consistency checking before setting, replacing, or deleting an
- * environment variable, then (if successful) apply the changes to internals so
- * to make them effective.  Code for this function was taken out of
- * _do_env_set(), which now calls it instead.
- * Also called as a callback function by himport_r().
- * Returns 0 in case of success, 1 in case of failure.
- * When (flag & H_FORCE) is set, do not print out any error message and force
- * overwriting of write-once variables.
- */
-
-int env_check_apply(const char *name, const char *oldval,
-			const char *newval, int flag)
-{
-	int   console = -1;
-
-	/* Default value for NULL to protect string-manipulating functions */
-	newval = newval ? : "";
-
-	/* Check for console redirection */
-	if (strcmp(name, "stdin") == 0)
-		console = stdin;
-	else if (strcmp(name, "stdout") == 0)
-		console = stdout;
-	else if (strcmp(name, "stderr") == 0)
-		console = stderr;
-
-	if (console != -1) {
-		if ((newval == NULL) || (*newval == '\0')) {
-			/* We cannot delete stdin/stdout/stderr */
-			if ((flag & H_FORCE) == 0)
-				printf("Can't delete \"%s\"\n", name);
-			return 1;
-		}
-
-#ifdef CONFIG_CONSOLE_MUX
-		if (iomux_doenv(console, newval))
-			return 1;
-#else
-		/* Try assigning specified device */
-		if (console_assign(console, newval) < 0)
-			return 1;
-#endif /* CONFIG_CONSOLE_MUX */
-	}
-
-	/*
-	 * Some variables like "ethaddr" and "serial#" can be set only once and
-	 * cannot be deleted, unless CONFIG_ENV_OVERWRITE is defined.
-	 */
-#ifndef CONFIG_ENV_OVERWRITE
-	if (oldval != NULL &&			/* variable exists */
-		(flag & H_FORCE) == 0) {	/* and we are not forced */
-		if (strcmp(name, "serial#") == 0 ||
-		    (strcmp(name, "ethaddr") == 0
-#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)
-		     && strcmp(oldval, __stringify(CONFIG_ETHADDR)) != 0
-#endif	/* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */
-			)) {
-			printf("Can't overwrite \"%s\"\n", name);
-			return 1;
-		}
-	}
-#endif
-	/*
-	 * When we change baudrate, or we are doing an env default -a
-	 * (which will erase all variables prior to calling this),
-	 * we want the baudrate to actually change - for real.
-	 */
-	if (oldval != NULL ||			/* variable exists */
-		(flag & H_NOCLEAR) == 0) {	/* or env is clear */
-		/*
-		 * Switch to new baudrate if new baudrate is supported
-		 */
-		if (strcmp(name, "baudrate") == 0) {
-			int baudrate = simple_strtoul(newval, NULL, 10);
-			int i;
-			for (i = 0; i < N_BAUDRATES; ++i) {
-				if (baudrate == baudrate_table[i])
-					break;
-			}
-			if (i == N_BAUDRATES) {
-				if ((flag & H_FORCE) == 0)
-					printf("## Baudrate %d bps not "
-						"supported\n", baudrate);
-				return 1;
-			}
-			if (gd->baudrate == baudrate) {
-				/* If unchanged, we just say it's OK */
-				return 0;
-			}
-			printf("## Switch baudrate to %d bps and"
-				"press ENTER ...\n", baudrate);
-			udelay(50000);
-			gd->baudrate = baudrate;
-#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2)
-			gd->bd->bi_baudrate = baudrate;
-#endif
-
-			serial_setbrg();
-			udelay(50000);
-			while (getc() != '\r')
-				;
-		}
-	}
-
-	/*
-	 * Some variables should be updated when the corresponding
-	 * entry in the environment is changed
-	 */
-	if (strcmp(name, "loadaddr") == 0) {
-		load_addr = simple_strtoul(newval, NULL, 16);
-		return 0;
-	}
-#if defined(CONFIG_CMD_NET)
-	else if (strcmp(name, "bootfile") == 0) {
-		copy_filename(BootFile, newval, sizeof(BootFile));
-		return 0;
-	}
-#endif
-	return 0;
-}
-
-/*
  * Set a new environment variable,
  * or replace or delete an existing one.
-*/
+ */
 static int _do_env_set(int flag, int argc, char * const argv[])
 {
 	int   i, len;
 	char  *name, *value, *s;
 	ENTRY e, *ep;
+	int env_flag = H_INTERACTIVE;
 
+	debug("Initial value for argc=%d\n", argc);
+	while (argc > 1 && **(argv + 1) == '-') {
+		char *arg = *++argv;
+
+		--argc;
+		while (*++arg) {
+			switch (*arg) {
+			case 'f':		/* force */
+				env_flag |= H_FORCE;
+				break;
+			default:
+				return CMD_RET_USAGE;
+			}
+		}
+	}
+	debug("Final value for argc=%d\n", argc);
 	name = argv[1];
 	value = argv[2];
 
@@ -339,25 +228,10 @@
 	}
 
 	env_id++;
-	/*
-	 * search if variable with this name already exists
-	 */
-	e.key = name;
-	e.data = NULL;
-	hsearch_r(e, FIND, &ep, &env_htab);
-
-	/*
-	 * Perform requested checks. Notice how since we are overwriting
-	 * a single variable, we need to set H_NOCLEAR
-	 */
-	if (env_check_apply(name, ep ? ep->data : NULL, value, H_NOCLEAR)) {
-		debug("check function did not approve, refusing\n");
-		return 1;
-	}
 
 	/* Delete only ? */
 	if (argc < 3 || argv[2] == NULL) {
-		int rc = hdelete_r(name, &env_htab, 0);
+		int rc = hdelete_r(name, &env_htab, env_flag);
 		return !rc;
 	}
 
@@ -384,7 +258,7 @@
 
 	e.key	= name;
 	e.data	= value;
-	hsearch_r(e, ENTER, &ep, &env_htab);
+	hsearch_r(e, ENTER, &ep, &env_htab, env_flag);
 	free(value);
 	if (!ep) {
 		printf("## Error inserting \"%s\" variable, errno=%d\n",
@@ -511,6 +385,153 @@
 }
 #endif
 
+#if defined(CONFIG_CMD_ENV_CALLBACK)
+static int print_static_binding(const char *var_name, const char *callback_name)
+{
+	printf("\t%-20s %-20s\n", var_name, callback_name);
+
+	return 0;
+}
+
+static int print_active_callback(ENTRY *entry)
+{
+	struct env_clbk_tbl *clbkp;
+	int i;
+	int num_callbacks;
+
+	if (entry->callback == NULL)
+		return 0;
+
+	/* look up the callback in the linker-list */
+	num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
+	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
+	     i < num_callbacks;
+	     i++, clbkp++) {
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+		if (entry->callback == clbkp->callback + gd->reloc_off)
+#else
+		if (entry->callback == clbkp->callback)
+#endif
+			break;
+	}
+
+	if (i == num_callbacks)
+		/* this should probably never happen, but just in case... */
+		printf("\t%-20s %p\n", entry->key, entry->callback);
+	else
+		printf("\t%-20s %-20s\n", entry->key, clbkp->name);
+
+	return 0;
+}
+
+/*
+ * Print the callbacks available and what they are bound to
+ */
+int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	struct env_clbk_tbl *clbkp;
+	int i;
+	int num_callbacks;
+
+	/* Print the available callbacks */
+	puts("Available callbacks:\n");
+	puts("\tCallback Name\n");
+	puts("\t-------------\n");
+	num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
+	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
+	     i < num_callbacks;
+	     i++, clbkp++)
+		printf("\t%s\n", clbkp->name);
+	puts("\n");
+
+	/* Print the static bindings that may exist */
+	puts("Static callback bindings:\n");
+	printf("\t%-20s %-20s\n", "Variable Name", "Callback Name");
+	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	env_attr_walk(ENV_CALLBACK_LIST_STATIC, print_static_binding);
+	puts("\n");
+
+	/* walk through each variable and print the callback if it has one */
+	puts("Active callback bindings:\n");
+	printf("\t%-20s %-20s\n", "Variable Name", "Callback Name");
+	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	hwalk_r(&env_htab, print_active_callback);
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_CMD_ENV_FLAGS)
+static int print_static_flags(const char *var_name, const char *flags)
+{
+	enum env_flags_vartype type = env_flags_parse_vartype(flags);
+	enum env_flags_varaccess access = env_flags_parse_varaccess(flags);
+
+	printf("\t%-20s %-20s %-20s\n", var_name,
+		env_flags_get_vartype_name(type),
+		env_flags_get_varaccess_name(access));
+
+	return 0;
+}
+
+static int print_active_flags(ENTRY *entry)
+{
+	enum env_flags_vartype type;
+	enum env_flags_varaccess access;
+
+	if (entry->flags == 0)
+		return 0;
+
+	type = (enum env_flags_vartype)
+		(entry->flags & ENV_FLAGS_VARTYPE_BIN_MASK);
+	access = env_flags_parse_varaccess_from_binflags(entry->flags);
+	printf("\t%-20s %-20s %-20s\n", entry->key,
+		env_flags_get_vartype_name(type),
+		env_flags_get_varaccess_name(access));
+
+	return 0;
+}
+
+/*
+ * Print the flags available and what variables have flags
+ */
+int do_env_flags(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	/* Print the available variable types */
+	printf("Available variable type flags (position %d):\n",
+		ENV_FLAGS_VARTYPE_LOC);
+	puts("\tFlag\tVariable Type Name\n");
+	puts("\t----\t------------------\n");
+	env_flags_print_vartypes();
+	puts("\n");
+
+	/* Print the available variable access types */
+	printf("Available variable access flags (position %d):\n",
+		ENV_FLAGS_VARACCESS_LOC);
+	puts("\tFlag\tVariable Access Name\n");
+	puts("\t----\t--------------------\n");
+	env_flags_print_varaccess();
+	puts("\n");
+
+	/* Print the static flags that may exist */
+	puts("Static flags:\n");
+	printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type",
+		"Variable Access");
+	printf("\t%-20s %-20s %-20s\n", "-------------", "-------------",
+		"---------------");
+	env_attr_walk(ENV_FLAGS_LIST_STATIC, print_static_flags);
+	puts("\n");
+
+	/* walk through each variable and print the flags if non-default */
+	puts("Active flags:\n");
+	printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type",
+		"Variable Access");
+	printf("\t%-20s %-20s %-20s\n", "-------------", "-------------",
+		"---------------");
+	hwalk_r(&env_htab, print_active_flags);
+	return 0;
+}
+#endif
+
 /*
  * Interactively edit an environment variable
  */
@@ -552,7 +573,7 @@
 
 		e.key	= name;
 		e.data	= NULL;
-		hsearch_r(e, FIND, &ep, &env_htab);
+		hsearch_r(e, FIND, &ep, &env_htab, 0);
 
 		return ep ? ep->data : NULL;
 	}
@@ -704,8 +725,36 @@
 static int do_env_delete(cmd_tbl_t *cmdtp, int flag,
 			 int argc, char * const argv[])
 {
-	printf("Not implemented yet\n");
-	return 0;
+	int env_flag = H_INTERACTIVE;
+	int ret = 0;
+
+	debug("Initial value for argc=%d\n", argc);
+	while (argc > 1 && **(argv + 1) == '-') {
+		char *arg = *++argv;
+
+		--argc;
+		while (*++arg) {
+			switch (*arg) {
+			case 'f':		/* force */
+				env_flag |= H_FORCE;
+				break;
+			default:
+				return CMD_RET_USAGE;
+			}
+		}
+	}
+	debug("Final value for argc=%d\n", argc);
+
+	env_id++;
+
+	while (--argc > 0) {
+		char *name = *++argv;
+
+		if (!hdelete_r(name, &env_htab, env_flag))
+			ret = 1;
+	}
+
+	return ret;
 }
 
 #ifdef CONFIG_CMD_EXPORTENV
@@ -812,7 +861,7 @@
 	argv++;
 
 	if (sep) {		/* export as text file */
-		len = hexport_r(&env_htab, sep, &addr, size, argc, argv);
+		len = hexport_r(&env_htab, sep, 0, &addr, size, argc, argv);
 		if (len < 0) {
 			error("Cannot export environment: errno = %d\n", errno);
 			return 1;
@@ -830,7 +879,7 @@
 	else			/* export as raw binary data */
 		res = addr;
 
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, argc, argv);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, argc, argv);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
@@ -951,7 +1000,7 @@
 	}
 
 	if (himport_r(&env_htab, addr, size, sep, del ? 0 : H_NOCLEAR,
-			0, NULL, 0 /* do_apply */) == 0) {
+			0, NULL) == 0) {
 		error("Environment import failed: errno = %d\n", errno);
 		return 1;
 	}
@@ -974,10 +1023,16 @@
 	U_BOOT_CMD_MKENT(ask, CONFIG_SYS_MAXARGS, 1, do_env_ask, "", ""),
 #endif
 	U_BOOT_CMD_MKENT(default, 1, 0, do_env_default, "", ""),
-	U_BOOT_CMD_MKENT(delete, 2, 0, do_env_delete, "", ""),
+	U_BOOT_CMD_MKENT(delete, CONFIG_SYS_MAXARGS, 0, do_env_delete, "", ""),
 #if defined(CONFIG_CMD_EDITENV)
 	U_BOOT_CMD_MKENT(edit, 2, 0, do_env_edit, "", ""),
 #endif
+#if defined(CONFIG_CMD_ENV_CALLBACK)
+	U_BOOT_CMD_MKENT(callbacks, 1, 0, do_env_callback, "", ""),
+#endif
+#if defined(CONFIG_CMD_ENV_FLAGS)
+	U_BOOT_CMD_MKENT(flags, 1, 0, do_env_flags, "", ""),
+#endif
 #if defined(CONFIG_CMD_EXPORTENV)
 	U_BOOT_CMD_MKENT(export, 4, 0, do_env_export, "", ""),
 #endif
@@ -1028,21 +1083,28 @@
 #if defined(CONFIG_CMD_ASKENV)
 	"ask name [message] [size] - ask for environment variable\nenv "
 #endif
+#if defined(CONFIG_CMD_ENV_CALLBACK)
+	"callbacks - print callbacks and their associated variables\nenv "
+#endif
 	"default [-f] -a - [forcibly] reset default environment\n"
 	"env default [-f] var [...] - [forcibly] reset variable(s) to their default values\n"
+	"env delete [-f] var [...] - [forcibly] delete variable(s)\n"
 #if defined(CONFIG_CMD_EDITENV)
 	"env edit name - edit environment variable\n"
 #endif
 #if defined(CONFIG_CMD_EXPORTENV)
 	"env export [-t | -b | -c] [-s size] addr [var ...] - export environment\n"
 #endif
+#if defined(CONFIG_CMD_ENV_FLAGS)
+	"env flags - print variables that have non-default flags\n"
+#endif
 #if defined(CONFIG_CMD_GREPENV)
 	"env grep string [...] - search environment\n"
 #endif
 #if defined(CONFIG_CMD_IMPORTENV)
 	"env import [-d] [-t | -b | -c] addr [size] - import environment\n"
 #endif
-	"env print [name ...] - print environment\n"
+	"env print [-a | name ...] - print environment\n"
 #if defined(CONFIG_CMD_RUN)
 	"env run var [...] - run commands in an environment variable\n"
 #endif
@@ -1074,7 +1136,7 @@
 U_BOOT_CMD_COMPLETE(
 	printenv, CONFIG_SYS_MAXARGS, 1,	do_env_print,
 	"print environment variables",
-	"\n    - print values of all environment variables\n"
+	"[-a]\n    - print [all] values of all environment variables\n"
 	"printenv name ...\n"
 	"    - print value of environment variable 'name'",
 	var_complete
@@ -1093,10 +1155,10 @@
 U_BOOT_CMD_COMPLETE(
 	setenv, CONFIG_SYS_MAXARGS, 0,	do_env_set,
 	"set environment variables",
-	"name value ...\n"
-	"    - set environment variable 'name' to 'value ...'\n"
-	"setenv name\n"
-	"    - delete environment variable 'name'",
+	"[-f] name value ...\n"
+	"    - [forcibly] set environment variable 'name' to 'value ...'\n"
+	"setenv [-f] name\n"
+	"    - [forcibly] delete environment variable 'name'",
 	var_complete
 );
 
diff --git a/common/cmd_read.c b/common/cmd_read.c
new file mode 100644
index 0000000..f0fc9bf
--- /dev/null
+++ b/common/cmd_read.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <part.h>
+
+int do_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	char *ep;
+	block_dev_desc_t *dev_desc = NULL;
+	int dev;
+	int part = 0;
+	disk_partition_t part_info;
+	ulong offset = 0u;
+	ulong limit = 0u;
+	void *addr;
+	uint blk;
+	uint cnt;
+
+	if (argc != 6) {
+		cmd_usage(cmdtp);
+		return 1;
+	}
+
+	dev = (int)simple_strtoul(argv[2], &ep, 16);
+	if (*ep) {
+		if (*ep != ':') {
+			printf("Invalid block device %s\n", argv[2]);
+			return 1;
+		}
+		part = (int)simple_strtoul(++ep, NULL, 16);
+	}
+
+	dev_desc = get_dev(argv[1], dev);
+	if (dev_desc == NULL) {
+		printf("Block device %s %d not supported\n", argv[1], dev);
+		return 1;
+	}
+
+	addr = (void *)simple_strtoul(argv[3], NULL, 16);
+	blk = simple_strtoul(argv[4], NULL, 16);
+	cnt = simple_strtoul(argv[5], NULL, 16);
+
+	if (part != 0) {
+		if (get_partition_info(dev_desc, part, &part_info)) {
+			printf("Cannot find partition %d\n", part);
+			return 1;
+		}
+		offset = part_info.start;
+		limit = part_info.size;
+	} else {
+		/* Largest address not available in block_dev_desc_t. */
+		limit = ~0;
+	}
+
+	if (cnt + blk > limit) {
+		printf("Read out of range\n");
+		return 1;
+	}
+
+	if (dev_desc->block_read(dev, offset + blk, cnt, addr) < 0) {
+		printf("Error reading blocks\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	read,	6,	0,	do_read,
+	"Load binary data from a partition",
+	"<interface> <dev[:part]> addr blk# cnt"
+);
diff --git a/common/cmd_sha1sum.c b/common/cmd_sha1sum.c
index 8db5456..fe927ab 100644
--- a/common/cmd_sha1sum.c
+++ b/common/cmd_sha1sum.c
@@ -26,73 +26,11 @@
 
 #include <common.h>
 #include <command.h>
+#include <hash.h>
 #include <sha1.h>
 
-/*
- * Store the resulting sum to an address or variable
- */
-static void store_result(const u8 *sum, const char *dest)
-{
-	unsigned int i;
-
-	if (*dest == '*') {
-		u8 *ptr;
-
-		ptr = (u8 *)simple_strtoul(dest + 1, NULL, 16);
-		for (i = 0; i < 20; i++)
-			*ptr++ = sum[i];
-	} else {
-		char str_output[41];
-		char *str_ptr = str_output;
-
-		for (i = 0; i < 20; i++) {
-			sprintf(str_ptr, "%02x", sum[i]);
-			str_ptr += 2;
-		}
-		str_ptr = '\0';
-		setenv(dest, str_output);
-	}
-}
-
-#ifdef CONFIG_SHA1SUM_VERIFY
-static int parse_verify_sum(char *verify_str, u8 *vsum)
-{
-	if (*verify_str == '*') {
-		u8 *ptr;
-
-		ptr = (u8 *)simple_strtoul(verify_str + 1, NULL, 16);
-		memcpy(vsum, ptr, 20);
-	} else {
-		unsigned int i;
-		char *vsum_str;
-
-		if (strlen(verify_str) == 40)
-			vsum_str = verify_str;
-		else {
-			vsum_str = getenv(verify_str);
-			if (vsum_str == NULL || strlen(vsum_str) != 40)
-				return 1;
-		}
-
-		for (i = 0; i < 20; i++) {
-			char *nullp = vsum_str + (i + 1) * 2;
-			char end = *nullp;
-
-			*nullp = '\0';
-			*(u8 *)(vsum + i) =
-				simple_strtoul(vsum_str + (i * 2), NULL, 16);
-			*nullp = end;
-		}
-	}
-	return 0;
-}
-
 int do_sha1sum(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-	ulong addr, len;
-	unsigned int i;
-	u8 output[20];
-	u8 vsum[20];
 	int verify = 0;
 	int ac;
 	char * const *av;
@@ -102,76 +40,17 @@
 
 	av = argv + 1;
 	ac = argc - 1;
+#ifdef CONFIG_SHA1SUM_VERIFY
 	if (strcmp(*av, "-v") == 0) {
 		verify = 1;
 		av++;
 		ac--;
-		if (ac < 3)
-			return CMD_RET_USAGE;
 	}
-
-	addr = simple_strtoul(*av++, NULL, 16);
-	len = simple_strtoul(*av++, NULL, 16);
-
-	sha1_csum_wd((unsigned char *) addr, len, output, CHUNKSZ_SHA1);
-
-	if (!verify) {
-		printf("SHA1 for %08lx ... %08lx ==> ", addr, addr + len - 1);
-		for (i = 0; i < 20; i++)
-			printf("%02x", output[i]);
-		printf("\n");
-
-		if (ac > 2)
-			store_result(output, *av);
-	} else {
-		char *verify_str = *av++;
-
-		if (parse_verify_sum(verify_str, vsum)) {
-			printf("ERROR: %s does not contain a valid SHA1 sum\n",
-				verify_str);
-			return 1;
-		}
-		if (memcmp(output, vsum, 20) != 0) {
-			printf("SHA1 for %08lx ... %08lx ==> ", addr,
-				addr + len - 1);
-			for (i = 0; i < 20; i++)
-				printf("%02x", output[i]);
-			printf(" != ");
-			for (i = 0; i < 20; i++)
-				printf("%02x", vsum[i]);
-			printf(" ** ERROR **\n");
-			return 1;
-		}
-	}
-
-	return 0;
-}
-#else
-static int do_sha1sum(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
-{
-	unsigned long addr, len;
-	unsigned int i;
-	u8 output[20];
-
-	if (argc < 3)
-		return CMD_RET_USAGE;
-
-	addr = simple_strtoul(argv[1], NULL, 16);
-	len = simple_strtoul(argv[2], NULL, 16);
-
-	sha1_csum_wd((unsigned char *) addr, len, output, CHUNKSZ_SHA1);
-	printf("SHA1 for %08lx ... %08lx ==> ", addr, addr + len - 1);
-	for (i = 0; i < 20; i++)
-		printf("%02x", output[i]);
-	printf("\n");
-
-	if (argc > 3)
-		store_result(output, argv[3]);
-
-	return 0;
-}
 #endif
 
+	return hash_command("sha1", verify, cmdtp, flag, ac, av);
+}
+
 #ifdef CONFIG_SHA1SUM_VERIFY
 U_BOOT_CMD(
 	sha1sum,	5,	1,	do_sha1sum,
diff --git a/common/cmd_spl.c b/common/cmd_spl.c
index 9ec054a..e3c543b 100644
--- a/common/cmd_spl.c
+++ b/common/cmd_spl.c
@@ -130,10 +130,12 @@
 		if (call_bootm(argc, argv, subcmd_list[(int)c->cmd]))
 			return -1;
 		switch ((int)c->cmd) {
+#ifdef CONFIG_OF_LIBFDT
 		case SPL_EXPORT_FDT:
 			printf("Argument image is now in RAM: 0x%p\n",
 				(void *)images.ft_addr);
 			break;
+#endif
 		case SPL_EXPORT_ATAGS:
 			printf("Argument image is now in RAM at: 0x%p\n",
 				(void *)gd->bd->bi_boot_params);
diff --git a/common/cmd_tpm.c b/common/cmd_tpm.c
index 6f5cd48..0970a6f 100644
--- a/common/cmd_tpm.c
+++ b/common/cmd_tpm.c
@@ -63,19 +63,68 @@
 	return rv;
 }
 
-static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+#define CHECK(exp) do {							\
+		int _rv = exp;						\
+		if (_rv) {						\
+			printf("CHECK: %s %d %x\n", #exp, __LINE__, _rv);\
+		}							\
+	} while (0)
+
+static int tpm_process_stress(int repeat_count)
+{
+	int i;
+	int rv = 0;
+	u8 request[] = {0x0, 0xc1,
+			0x0, 0x0, 0x0, 0x16,
+			0x0, 0x0, 0x0, 0x65,
+			0x0, 0x0, 0x0, 0x4,
+			0x0, 0x0, 0x0, 0x4,
+			0x0, 0x0, 0x1, 0x9};
+	u8 response[MAX_TRANSACTION_SIZE];
+	u32 rlength = MAX_TRANSACTION_SIZE;
+
+	CHECK(tis_init());
+
+	for (i = 0; i < repeat_count; i++) {
+		CHECK(tis_open());
+		rv = tis_sendrecv(request, sizeof(request), response, &rlength);
+		if (rv) {
+			printf("tpm test failed at step %d with 0x%x\n", i, rv);
+			CHECK(tis_close());
+			break;
+		}
+		CHECK(tis_close());
+		if ((response[6] || response[7] || response[8] || response[9])
+		    && response[9] != 0x26) {
+			/* Ignore postinit errors */
+			printf("tpm command failed at step %d\n"
+			       "tpm error code: %02x%02x%02x%02x\n", i,
+			       response[6], response[7],
+			       response[8], response[9]);
+			rv = -1;
+			break;
+		}
+	}
+	return rv;
+}
+
+
+static int do_tpm_many(cmd_tbl_t *cmdtp, int flag,
+		       int argc, char * const argv[], int repeat_count)
+
 {
 	int rv = 0;
 
-	/*
-	 * Verify that in case it is present, the first argument, it is
-	 * exactly one character in size.
-	 */
-	if (argc < 7) {
+	if (argc < 7 && repeat_count == 0) {
 		puts("command should be at least six bytes in size\n");
 		return -1;
 	}
 
+	if (repeat_count > 0) {
+		rv = tpm_process_stress(repeat_count);
+		return rv;
+	}
+
 	if (tis_init()) {
 		puts("tis_init() failed!\n");
 		return -1;
@@ -96,8 +145,40 @@
 	return rv;
 }
 
+
+static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	return do_tpm_many(cmdtp, flag, argc, argv, 0);
+}
+
+
 U_BOOT_CMD(tpm, MAX_TRANSACTION_SIZE, 1, do_tpm,
 	   "<byte> [<byte> ...]   - write data and read response",
 	   "send arbitrary data (at least 6 bytes) to the TPM "
 	   "device and read the response"
 );
+
+static int do_tpm_stress(cmd_tbl_t *cmdtp, int flag,
+			 int argc, char * const argv[])
+{
+	long unsigned int n;
+	int rv;
+
+	if (argc != 2) {
+		puts("usage: tpm_stress <count>\n");
+		return -1;
+	}
+
+	rv = strict_strtoul(argv[1], 10, &n);
+	if (rv) {
+		puts("tpm_stress: bad count");
+		return -1;
+	}
+
+	return do_tpm_many(cmdtp, flag, argc, argv, n);
+}
+
+U_BOOT_CMD(tpm_stress, 2, 1, do_tpm_stress,
+	   "<n>   - stress-test communication with TPM",
+	   "Repeat a TPM transaction (request-response) N times"
+);
diff --git a/common/console.c b/common/console.c
index 1177f7d..bf73178 100644
--- a/common/console.c
+++ b/common/console.c
@@ -24,11 +24,78 @@
 #include <common.h>
 #include <stdarg.h>
 #include <malloc.h>
+#include <serial.h>
 #include <stdio_dev.h>
 #include <exports.h>
+#include <environment.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
+static int on_console(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	int console = -1;
+
+	/* Check for console redirection */
+	if (strcmp(name, "stdin") == 0)
+		console = stdin;
+	else if (strcmp(name, "stdout") == 0)
+		console = stdout;
+	else if (strcmp(name, "stderr") == 0)
+		console = stderr;
+
+	/* if not actually setting a console variable, we don't care */
+	if (console == -1 || (gd->flags & GD_FLG_DEVINIT) == 0)
+		return 0;
+
+	switch (op) {
+	case env_op_create:
+	case env_op_overwrite:
+
+#ifdef CONFIG_CONSOLE_MUX
+		if (iomux_doenv(console, value))
+			return 1;
+#else
+		/* Try assigning specified device */
+		if (console_assign(console, value) < 0)
+			return 1;
+#endif /* CONFIG_CONSOLE_MUX */
+		return 0;
+
+	case env_op_delete:
+		if ((flags & H_FORCE) == 0)
+			printf("Can't delete \"%s\"\n", name);
+		return 1;
+
+	default:
+		return 0;
+	}
+}
+U_BOOT_ENV_CALLBACK(console, on_console);
+
+#ifdef CONFIG_SILENT_CONSOLE
+static int on_silent(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+#ifndef CONFIG_SILENT_CONSOLE_UPDATE_ON_SET
+	if (flags & H_INTERACTIVE)
+		return 0;
+#endif
+#ifndef CONFIG_SILENT_CONSOLE_UPDATE_ON_RELOC
+	if ((flags & H_INTERACTIVE) == 0)
+		return 0;
+#endif
+
+	if (value != NULL)
+		gd->flags |= GD_FLG_SILENT;
+	else
+		gd->flags &= ~GD_FLG_SILENT;
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(silent, on_silent);
+#endif
+
 #ifdef CONFIG_SYS_CONSOLE_IS_IN_ENV
 /*
  * if overwrite_console returns 1, the stdin, stderr and stdout
@@ -591,7 +658,6 @@
 
 void stdio_print_current_devices(void)
 {
-#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET
 	/* Print information */
 	puts("In:    ");
 	if (stdio_devices[stdin] == NULL) {
@@ -613,7 +679,6 @@
 	} else {
 		printf ("%s\n", stdio_devices[stderr]->name);
 	}
-#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */
 }
 
 #ifdef CONFIG_SYS_CONSOLE_IS_IN_ENV
@@ -683,9 +748,9 @@
 done:
 #endif
 
-	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */
-
+#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET
 	stdio_print_current_devices();
+#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */
 
 #ifdef CONFIG_SYS_CONSOLE_ENV_OVERWRITE
 	/* set the environment variables (will overwrite previous env settings) */
@@ -694,6 +759,8 @@
 	}
 #endif /* CONFIG_SYS_CONSOLE_ENV_OVERWRITE */
 
+	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */
+
 #if 0
 	/* If nothing usable installed, use only the initial console */
 	if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
@@ -758,15 +825,17 @@
 #endif
 	}
 
-	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */
-
+#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET
 	stdio_print_current_devices();
+#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */
 
 	/* Setting environment variables */
 	for (i = 0; i < 3; i++) {
 		setenv(stdio_names[i], stdio_devices[i]->name);
 	}
 
+	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */
+
 #if 0
 	/* If nothing usable installed, use only the initial console */
 	if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
diff --git a/common/edid.c b/common/edid.c
new file mode 100644
index 0000000..c82c298
--- /dev/null
+++ b/common/edid.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2012 The Chromium OS Authors.
+ *
+ * (C) Copyright 2010
+ * Petr Stetiar <ynezz@true.cz>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Contains stolen code from ddcprobe project which is:
+ * Copyright (C) Nalin Dahyabhai <bigfun@pobox.com>
+ *
+ */
+
+#include <common.h>
+#include <edid.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+
+int edid_check_info(struct edid1_info *edid_info)
+{
+	if ((edid_info == NULL) || (edid_info->version == 0))
+		return -1;
+
+	if (memcmp(edid_info->header, "\x0\xff\xff\xff\xff\xff\xff\x0", 8))
+		return -1;
+
+	if (edid_info->version == 0xff && edid_info->revision == 0xff)
+		return -1;
+
+	return 0;
+}
+
+int edid_get_ranges(struct edid1_info *edid, unsigned int *hmin,
+		    unsigned int *hmax, unsigned int *vmin,
+		    unsigned int *vmax)
+{
+	int i;
+	struct edid_monitor_descriptor *monitor;
+
+	*hmin = *hmax = *vmin = *vmax = 0;
+	if (edid_check_info(edid))
+		return -1;
+
+	for (i = 0; i < ARRAY_SIZE(edid->monitor_details.descriptor); i++) {
+		monitor = &edid->monitor_details.descriptor[i];
+		if (monitor->type == EDID_MONITOR_DESCRIPTOR_RANGE) {
+			*hmin = monitor->data.range_data.horizontal_min;
+			*hmax = monitor->data.range_data.horizontal_max;
+			*vmin = monitor->data.range_data.vertical_min;
+			*vmax = monitor->data.range_data.vertical_max;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+/**
+ * Snip the tailing whitespace/return of a string.
+ *
+ * @param string	The string to be snipped
+ * @return the snipped string
+ */
+static char *snip(char *string)
+{
+	char *s;
+
+	/*
+	 * This is always a 13 character buffer
+	 * and it's not always terminated.
+	 */
+	string[12] = '\0';
+	s = &string[strlen(string) - 1];
+
+	while (s >= string && (isspace(*s) || *s == '\n' || *s == '\r' ||
+			*s == '\0'))
+		*(s--) = '\0';
+
+	return string;
+}
+
+/**
+ * Print an EDID monitor descriptor block
+ *
+ * @param monitor	The EDID monitor descriptor block
+ * @have_timing		Modifies to 1 if the desciptor contains timing info
+ */
+static void edid_print_dtd(struct edid_monitor_descriptor *monitor,
+			   unsigned int *have_timing)
+{
+	unsigned char *bytes = (unsigned char *)monitor;
+	struct edid_detailed_timing *timing =
+			(struct edid_detailed_timing *)monitor;
+
+	if (bytes[0] == 0 && bytes[1] == 0) {
+		if (monitor->type == EDID_MONITOR_DESCRIPTOR_SERIAL)
+			printf("Monitor serial number: %s\n",
+			       snip(monitor->data.string));
+		else if (monitor->type == EDID_MONITOR_DESCRIPTOR_ASCII)
+			printf("Monitor ID: %s\n",
+			       snip(monitor->data.string));
+		else if (monitor->type == EDID_MONITOR_DESCRIPTOR_NAME)
+			printf("Monitor name: %s\n",
+			       snip(monitor->data.string));
+		else if (monitor->type == EDID_MONITOR_DESCRIPTOR_RANGE)
+			printf("Monitor range limits, horizontal sync: "
+			       "%d-%d kHz, vertical refresh: "
+			       "%d-%d Hz, max pixel clock: "
+			       "%d MHz\n",
+			       monitor->data.range_data.horizontal_min,
+			       monitor->data.range_data.horizontal_max,
+			       monitor->data.range_data.vertical_min,
+			       monitor->data.range_data.vertical_max,
+			       monitor->data.range_data.pixel_clock_max * 10);
+	} else {
+		uint32_t pixclock, h_active, h_blanking, v_active, v_blanking;
+		uint32_t h_total, v_total, vfreq;
+
+		pixclock = EDID_DETAILED_TIMING_PIXEL_CLOCK(*timing);
+		h_active = EDID_DETAILED_TIMING_HORIZONTAL_ACTIVE(*timing);
+		h_blanking = EDID_DETAILED_TIMING_HORIZONTAL_BLANKING(*timing);
+		v_active = EDID_DETAILED_TIMING_VERTICAL_ACTIVE(*timing);
+		v_blanking = EDID_DETAILED_TIMING_VERTICAL_BLANKING(*timing);
+
+		h_total = h_active + h_blanking;
+		v_total = v_active + v_blanking;
+		if (v_total * h_total)
+			vfreq = pixclock / (v_total * h_total);
+		else
+			vfreq = 1; /* Error case */
+		printf("\t%dx%d\%c\t%d Hz (detailed)\n", h_active,
+		       v_active, h_active > 1000 ? ' ' : '\t', vfreq);
+		*have_timing = 1;
+	}
+}
+
+/**
+ * Get the manufacturer name from an EDID info.
+ *
+ * @param edid_info     The EDID info to be printed
+ * @param name		Returns the string of the manufacturer name
+ */
+static void edid_get_manufacturer_name(struct edid1_info *edid, char *name)
+{
+	name[0] = EDID1_INFO_MANUFACTURER_NAME_CHAR1(*edid) + 'A' - 1;
+	name[1] = EDID1_INFO_MANUFACTURER_NAME_CHAR2(*edid) + 'A' - 1;
+	name[2] = EDID1_INFO_MANUFACTURER_NAME_CHAR3(*edid) + 'A' - 1;
+	name[3] = '\0';
+}
+
+void edid_print_info(struct edid1_info *edid_info)
+{
+	int i;
+	char manufacturer[4];
+	unsigned int have_timing = 0;
+	uint32_t serial_number;
+
+	if (edid_check_info(edid_info)) {
+		printf("Not a valid EDID\n");
+		return;
+	}
+
+	printf("EDID version: %d.%d\n",
+	       edid_info->version, edid_info->revision);
+
+	printf("Product ID code: %04x\n", EDID1_INFO_PRODUCT_CODE(*edid_info));
+
+	edid_get_manufacturer_name(edid_info, manufacturer);
+	printf("Manufacturer: %s\n", manufacturer);
+
+	serial_number = EDID1_INFO_SERIAL_NUMBER(*edid_info);
+	if (serial_number != 0xffffffff) {
+		if (strcmp(manufacturer, "MAG") == 0)
+			serial_number -= 0x7000000;
+		if (strcmp(manufacturer, "OQI") == 0)
+			serial_number -= 456150000;
+		if (strcmp(manufacturer, "VSC") == 0)
+			serial_number -= 640000000;
+	}
+	printf("Serial number: %08x\n", serial_number);
+	printf("Manufactured in week: %d year: %d\n",
+	       edid_info->week, edid_info->year + 1990);
+
+	printf("Video input definition: %svoltage level %d%s%s%s%s%s\n",
+	       EDID1_INFO_VIDEO_INPUT_DIGITAL(*edid_info) ?
+	       "digital signal, " : "analog signal, ",
+	       EDID1_INFO_VIDEO_INPUT_VOLTAGE_LEVEL(*edid_info),
+	       EDID1_INFO_VIDEO_INPUT_BLANK_TO_BLACK(*edid_info) ?
+	       ", blank to black" : "",
+	       EDID1_INFO_VIDEO_INPUT_SEPARATE_SYNC(*edid_info) ?
+	       ", separate sync" : "",
+	       EDID1_INFO_VIDEO_INPUT_COMPOSITE_SYNC(*edid_info) ?
+	       ", composite sync" : "",
+	       EDID1_INFO_VIDEO_INPUT_SYNC_ON_GREEN(*edid_info) ?
+	       ", sync on green" : "",
+	       EDID1_INFO_VIDEO_INPUT_SERRATION_V(*edid_info) ?
+	       ", serration v" : "");
+
+	printf("Monitor is %s\n",
+	       EDID1_INFO_FEATURE_RGB(*edid_info) ? "RGB" : "non-RGB");
+
+	printf("Maximum visible display size: %d cm x %d cm\n",
+	       edid_info->max_size_horizontal,
+	       edid_info->max_size_vertical);
+
+	printf("Power management features: %s%s, %s%s, %s%s\n",
+	       EDID1_INFO_FEATURE_ACTIVE_OFF(*edid_info) ?
+	       "" : "no ", "active off",
+	       EDID1_INFO_FEATURE_SUSPEND(*edid_info) ? "" : "no ", "suspend",
+	       EDID1_INFO_FEATURE_STANDBY(*edid_info) ? "" : "no ", "standby");
+
+	printf("Estabilished timings:\n");
+	if (EDID1_INFO_ESTABLISHED_TIMING_720X400_70(*edid_info))
+		printf("\t720x400\t\t70 Hz (VGA 640x400, IBM)\n");
+	if (EDID1_INFO_ESTABLISHED_TIMING_720X400_88(*edid_info))
+		printf("\t720x400\t\t88 Hz (XGA2)\n");
+	if (EDID1_INFO_ESTABLISHED_TIMING_640X480_60(*edid_info))
+		printf("\t640x480\t\t60 Hz (VGA)\n");
+	if (EDID1_INFO_ESTABLISHED_TIMING_640X480_67(*edid_info))
+		printf("\t640x480\t\t67 Hz (Mac II, Apple)\n");
+	if (EDID1_INFO_ESTABLISHED_TIMING_640X480_72(*edid_info))
+		printf("\t640x480\t\t72 Hz (VESA)\n");
+	if (EDID1_INFO_ESTABLISHED_TIMING_640X480_75(*edid_info))
+		printf("\t640x480\t\t75 Hz (VESA)\n");
+	if (EDID1_INFO_ESTABLISHED_TIMING_800X600_56(*edid_info))
+		printf("\t800x600\t\t56 Hz (VESA)\n");
+	if (EDID1_INFO_ESTABLISHED_TIMING_800X600_60(*edid_info))
+		printf("\t800x600\t\t60 Hz (VESA)\n");
+	if (EDID1_INFO_ESTABLISHED_TIMING_800X600_72(*edid_info))
+		printf("\t800x600\t\t72 Hz (VESA)\n");
+	if (EDID1_INFO_ESTABLISHED_TIMING_800X600_75(*edid_info))
+		printf("\t800x600\t\t75 Hz (VESA)\n");
+	if (EDID1_INFO_ESTABLISHED_TIMING_832X624_75(*edid_info))
+		printf("\t832x624\t\t75 Hz (Mac II)\n");
+	if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_87I(*edid_info))
+		printf("\t1024x768\t87 Hz Interlaced (8514A)\n");
+	if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_60(*edid_info))
+		printf("\t1024x768\t60 Hz (VESA)\n");
+	if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_70(*edid_info))
+		printf("\t1024x768\t70 Hz (VESA)\n");
+	if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_75(*edid_info))
+		printf("\t1024x768\t75 Hz (VESA)\n");
+	if (EDID1_INFO_ESTABLISHED_TIMING_1280X1024_75(*edid_info))
+		printf("\t1280x1024\t75 (VESA)\n");
+	if (EDID1_INFO_ESTABLISHED_TIMING_1152X870_75(*edid_info))
+		printf("\t1152x870\t75 (Mac II)\n");
+
+	/* Standard timings. */
+	printf("Standard timings:\n");
+	for (i = 0; i < ARRAY_SIZE(edid_info->standard_timings); i++) {
+		unsigned int aspect = 10000;
+		unsigned int x, y;
+		unsigned char xres, vfreq;
+
+		xres = EDID1_INFO_STANDARD_TIMING_XRESOLUTION(*edid_info, i);
+		vfreq = EDID1_INFO_STANDARD_TIMING_VFREQ(*edid_info, i);
+		if ((xres != vfreq) ||
+		    ((xres != 0) && (xres != 1)) ||
+		    ((vfreq != 0) && (vfreq != 1))) {
+			switch (EDID1_INFO_STANDARD_TIMING_ASPECT(*edid_info,
+					i)) {
+			case ASPECT_625:
+				aspect = 6250;
+				break;
+			case ASPECT_75:
+				aspect = 7500;
+				break;
+			case ASPECT_8:
+				aspect = 8000;
+				break;
+			case ASPECT_5625:
+				aspect = 5625;
+				break;
+			}
+			x = (xres + 31) * 8;
+			y = x * aspect / 10000;
+			printf("\t%dx%d%c\t%d Hz\n", x, y,
+			       x > 1000 ? ' ' : '\t', (vfreq & 0x3f) + 60);
+			have_timing = 1;
+		}
+	}
+
+	/* Detailed timing information. */
+	for (i = 0; i < ARRAY_SIZE(edid_info->monitor_details.descriptor);
+			i++) {
+		edid_print_dtd(&edid_info->monitor_details.descriptor[i],
+			       &have_timing);
+	}
+
+	if (!have_timing)
+		printf("\tNone\n");
+}
diff --git a/common/env_attr.c b/common/env_attr.c
new file mode 100644
index 0000000..210c98d
--- /dev/null
+++ b/common/env_attr.c
@@ -0,0 +1,229 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger@ni.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */
+#include <stdint.h>
+#include <stdio.h>
+#include <linux/linux_string.h>
+#else
+#include <common.h>
+#endif
+
+#include <env_attr.h>
+#include <errno.h>
+#include <linux/string.h>
+#include <malloc.h>
+
+/*
+ * Iterate through the whole list calling the callback for each found element.
+ * "attr_list" takes the form:
+ *	attributes = [^,:\s]*
+ *	entry = name[:attributes]
+ *	list = entry[,list]
+ */
+int env_attr_walk(const char *attr_list,
+	int (*callback)(const char *name, const char *attributes))
+{
+	const char *entry, *entry_end;
+	char *name, *attributes;
+
+	if (!attr_list)
+		/* list not found */
+		return 1;
+
+	entry = attr_list;
+	do {
+		char *entry_cpy = NULL;
+
+		entry_end = strchr(entry, ENV_ATTR_LIST_DELIM);
+		/* check if this is the last entry in the list */
+		if (entry_end == NULL) {
+			int entry_len = strlen(entry);
+
+			if (entry_len) {
+				/*
+				 * allocate memory to copy the entry into since
+				 * we will need to inject '\0' chars and squash
+				 * white-space before calling the callback
+				 */
+				entry_cpy = malloc(entry_len + 1);
+				if (entry_cpy)
+					/* copy the rest of the list */
+					strcpy(entry_cpy, entry);
+				else
+					return -ENOMEM;
+			}
+		} else {
+			int entry_len = entry_end - entry;
+
+			if (entry_len) {
+				/*
+				 * allocate memory to copy the entry into since
+				 * we will need to inject '\0' chars and squash
+				 * white-space before calling the callback
+				 */
+				entry_cpy = malloc(entry_len + 1);
+				if (entry_cpy) {
+					/* copy just this entry and null term */
+					strncpy(entry_cpy, entry, entry_len);
+					entry_cpy[entry_len] = '\0';
+				} else
+					return -ENOMEM;
+			}
+		}
+
+		/* check if there is anything to process (e.g. not ",,,") */
+		if (entry_cpy != NULL) {
+			attributes = strchr(entry_cpy, ENV_ATTR_SEP);
+			/* check if there is a ':' */
+			if (attributes != NULL) {
+				/* replace the ':' with '\0' to term name */
+				*attributes++ = '\0';
+				/* remove white-space from attributes */
+				attributes = strim(attributes);
+			}
+			/* remove white-space from name */
+			name = strim(entry_cpy);
+
+			/* only call the callback if there is a name */
+			if (strlen(name) != 0) {
+				int retval = 0;
+
+				retval = callback(name, attributes);
+				if (retval) {
+					free(entry_cpy);
+					return retval;
+				}
+			}
+		}
+
+		free(entry_cpy);
+		entry = entry_end + 1;
+	} while (entry_end != NULL);
+
+	return 0;
+}
+
+/*
+ * Search for the last matching string in another string with the option to
+ * start looking at a certain point (i.e. ignore anything beyond that point).
+ */
+static char *reverse_strstr(const char *searched, const char *search_for,
+	const char *searched_start)
+{
+	char *result = NULL;
+
+	if (*search_for == '\0')
+		return (char *)searched;
+
+	for (;;) {
+		char *match = strstr(searched, search_for);
+
+		/*
+		 * Stop looking if no new match is found or looking past the
+		 * searched_start pointer
+		 */
+		if (match == NULL || (searched_start != NULL &&
+		    match + strlen(search_for) > searched_start))
+			break;
+
+		result = match;
+		searched = match + 1;
+	}
+
+	return result;
+}
+
+/*
+ * Retrieve the attributes string associated with a single name in the list
+ * There is no protection on attributes being too small for the value
+ */
+int env_attr_lookup(const char *attr_list, const char *name, char *attributes)
+{
+	const char *entry = NULL;
+
+	if (!attributes)
+		/* bad parameter */
+		return -1;
+	if (!attr_list)
+		/* list not found */
+		return 1;
+
+	entry = reverse_strstr(attr_list, name, NULL);
+	while (entry != NULL) {
+		const char *prevch = entry - 1;
+		const char *nextch = entry + strlen(name);
+
+		/* Skip spaces */
+		while (*prevch == ' ')
+			prevch--;
+		while (*nextch == ' ')
+			nextch++;
+
+		/* check for an exact match */
+		if ((entry == attr_list ||
+		     *prevch == ENV_ATTR_LIST_DELIM) &&
+		    (*nextch == ENV_ATTR_SEP ||
+		     *nextch == ENV_ATTR_LIST_DELIM ||
+		     *nextch == '\0'))
+			break;
+
+		entry = reverse_strstr(attr_list, name, entry);
+	}
+	if (entry != NULL) {
+		int len;
+
+		/* skip the name */
+		entry += strlen(name);
+		/* skip spaces */
+		while (*entry == ' ')
+			entry++;
+		if (*entry != ENV_ATTR_SEP)
+			len = 0;
+		else {
+			const char *delim;
+			static const char delims[] = {
+				ENV_ATTR_LIST_DELIM, ' ', '\0'};
+
+			/* skip the attr sep */
+			entry += 1;
+			/* skip spaces */
+			while (*entry == ' ')
+				entry++;
+
+			delim = strpbrk(entry, delims);
+			if (delim == NULL)
+				len = strlen(entry);
+			else
+				len = delim - entry;
+			memcpy(attributes, entry, len);
+		}
+		attributes[len] = '\0';
+
+		/* success */
+		return 0;
+	}
+
+	/* not found in list */
+	return 2;
+}
diff --git a/common/env_callback.c b/common/env_callback.c
new file mode 100644
index 0000000..78ca367
--- /dev/null
+++ b/common/env_callback.c
@@ -0,0 +1,144 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger@ni.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <environment.h>
+
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+/*
+ * Look up a callback function pointer by name
+ */
+struct env_clbk_tbl *find_env_callback(const char *name)
+{
+	struct env_clbk_tbl *clbkp;
+	int i;
+	int num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
+
+	if (name == NULL)
+		return NULL;
+
+	/* look up the callback in the linker-list */
+	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
+	     i < num_callbacks;
+	     i++, clbkp++) {
+		if (strcmp(name, clbkp->name) == 0)
+			return clbkp;
+	}
+
+	return NULL;
+}
+
+/*
+ * Look for a possible callback for a newly added variable
+ * This is called specifically when the variable did not exist in the hash
+ * previously, so the blanket update did not find this variable.
+ */
+void env_callback_init(ENTRY *var_entry)
+{
+	const char *var_name = var_entry->key;
+	const char *callback_list = getenv(ENV_CALLBACK_VAR);
+	char callback_name[256] = "";
+	struct env_clbk_tbl *clbkp;
+	int ret = 1;
+
+	/* look in the ".callbacks" var for a reference to this variable */
+	if (callback_list != NULL)
+		ret = env_attr_lookup(callback_list, var_name, callback_name);
+
+	/* only if not found there, look in the static list */
+	if (ret)
+		ret = env_attr_lookup(ENV_CALLBACK_LIST_STATIC, var_name,
+			callback_name);
+
+	/* if an association was found, set the callback pointer */
+	if (!ret && strlen(callback_name)) {
+		clbkp = find_env_callback(callback_name);
+		if (clbkp != NULL)
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+			var_entry->callback = clbkp->callback + gd->reloc_off;
+#else
+			var_entry->callback = clbkp->callback;
+#endif
+	}
+}
+
+/*
+ * Called on each existing env var prior to the blanket update since removing
+ * a callback association should remove its callback.
+ */
+static int clear_callback(ENTRY *entry)
+{
+	entry->callback = NULL;
+
+	return 0;
+}
+
+/*
+ * Call for each element in the list that associates variables to callbacks
+ */
+static int set_callback(const char *name, const char *value)
+{
+	ENTRY e, *ep;
+	struct env_clbk_tbl *clbkp;
+
+	e.key	= name;
+	e.data	= NULL;
+	hsearch_r(e, FIND, &ep, &env_htab, 0);
+
+	/* does the env variable actually exist? */
+	if (ep != NULL) {
+		/* the assocaition delares no callback, so remove the pointer */
+		if (value == NULL || strlen(value) == 0)
+			ep->callback = NULL;
+		else {
+			/* assign the requested callback */
+			clbkp = find_env_callback(value);
+			if (clbkp != NULL)
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+				ep->callback = clbkp->callback + gd->reloc_off;
+#else
+				ep->callback = clbkp->callback;
+#endif
+		}
+	}
+
+	return 0;
+}
+
+static int on_callbacks(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	/* remove all callbacks */
+	hwalk_r(&env_htab, clear_callback);
+
+	/* configure any static callback bindings */
+	env_attr_walk(ENV_CALLBACK_LIST_STATIC, set_callback);
+	/* configure any dynamic callback bindings */
+	env_attr_walk(value, set_callback);
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(callbacks, on_callbacks);
diff --git a/common/env_common.c b/common/env_common.c
index 3d3cb70..906b41f 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -40,7 +40,7 @@
 #include <env_default.h>
 
 struct hsearch_data env_htab = {
-	.apply = env_check_apply,
+	.change_ok = env_flags_validate,
 };
 
 static uchar __env_get_char_spec(int index)
@@ -81,13 +81,42 @@
 		return &default_environment[index];
 }
 
+/*
+ * Read an environment variable as a boolean
+ * Return -1 if variable does not exist (default to true)
+ */
+int getenv_yesno(const char *var)
+{
+	char *s = getenv(var);
+
+	if (s == NULL)
+		return -1;
+	return (*s == '1' || *s == 'y' || *s == 'Y' || *s == 't' || *s == 'T') ?
+		1 : 0;
+}
+
+/*
+ * Look up the variable from the default environment
+ */
+char *getenv_default(const char *name)
+{
+	char *ret_val;
+	unsigned long really_valid = gd->env_valid;
+	unsigned long real_gd_flags = gd->flags;
+
+	/* Pretend that the image is bad. */
+	gd->flags &= ~GD_FLG_ENV_READY;
+	gd->env_valid = 0;
+	ret_val = getenv(name);
+	gd->env_valid = really_valid;
+	gd->flags = real_gd_flags;
+	return ret_val;
+}
+
 void set_default_env(const char *s)
 {
-	/*
-	 * By default, do not apply changes as they will eventually
-	 * be applied by someone else
-	 */
-	int do_apply = 0;
+	int flags = 0;
+
 	if (sizeof(default_environment) > ENV_SIZE) {
 		puts("*** Error - default environment is too large\n\n");
 		return;
@@ -99,14 +128,7 @@
 				"using default environment\n\n",
 				s + 1);
 		} else {
-			/*
-			 * This set_to_default was explicitly asked for
-			 * by the user, as opposed to being a recovery
-			 * mechanism.  Therefore we check every single
-			 * variable and apply changes to the system
-			 * right away (e.g. baudrate, console).
-			 */
-			do_apply = 1;
+			flags = H_INTERACTIVE;
 			puts(s);
 		}
 	} else {
@@ -114,8 +136,8 @@
 	}
 
 	if (himport_r(&env_htab, (char *)default_environment,
-			sizeof(default_environment), '\0', 0,
-			0, NULL, do_apply) == 0)
+			sizeof(default_environment), '\0', flags,
+			0, NULL) == 0)
 		error("Environment import failed: errno = %d\n", errno);
 
 	gd->flags |= GD_FLG_ENV_READY;
@@ -130,8 +152,8 @@
 	 * (and use \0 as a separator)
 	 */
 	return himport_r(&env_htab, (const char *)default_environment,
-				sizeof(default_environment), '\0', H_NOCLEAR,
-				nvars, vars, 1 /* do_apply */);
+				sizeof(default_environment), '\0',
+				H_NOCLEAR | H_INTERACTIVE, nvars, vars);
 }
 
 #ifndef CONFIG_SPL_BUILD
@@ -155,7 +177,7 @@
 	}
 
 	if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0,
-			0, NULL, 0 /* do_apply */)) {
+			0, NULL)) {
 		gd->flags |= GD_FLG_ENV_READY;
 		return 1;
 	}
@@ -172,6 +194,7 @@
 {
 #if defined(CONFIG_NEEDS_MANUAL_RELOC)
 	env_reloc();
+	env_htab.change_ok += gd->reloc_off;
 #endif
 	if (gd->env_valid == 0) {
 #if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD)
diff --git a/common/env_dataflash.c b/common/env_dataflash.c
index 3c5af37..38c9615 100644
--- a/common/env_dataflash.c
+++ b/common/env_dataflash.c
@@ -60,7 +60,7 @@
 	char	*res;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_eeprom.c b/common/env_eeprom.c
index b66bba2..45c935b 100644
--- a/common/env_eeprom.c
+++ b/common/env_eeprom.c
@@ -139,7 +139,7 @@
 	BUG_ON(env_ptr != NULL);
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_fat.c b/common/env_fat.c
index 6ef5318..c0f18ab 100644
--- a/common/env_fat.c
+++ b/common/env_fat.c
@@ -61,7 +61,7 @@
 	int err;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_flags.c b/common/env_flags.c
new file mode 100644
index 0000000..336cae4
--- /dev/null
+++ b/common/env_flags.c
@@ -0,0 +1,560 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger@ni.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <linux/string.h>
+#include <linux/ctype.h>
+
+#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */
+#include <stdint.h>
+#include <stdio.h>
+#include "fw_env.h"
+#include <env_attr.h>
+#include <env_flags.h>
+#define getenv fw_getenv
+#else
+#include <common.h>
+#include <environment.h>
+#endif
+
+#ifdef CONFIG_CMD_NET
+#define ENV_FLAGS_NET_VARTYPE_REPS "im"
+#else
+#define ENV_FLAGS_NET_VARTYPE_REPS ""
+#endif
+
+static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS;
+static const char env_flags_varaccess_rep[] = "aroc";
+static const int env_flags_varaccess_mask[] = {
+	0,
+	ENV_FLAGS_VARACCESS_PREVENT_DELETE |
+		ENV_FLAGS_VARACCESS_PREVENT_CREATE |
+		ENV_FLAGS_VARACCESS_PREVENT_OVERWR,
+	ENV_FLAGS_VARACCESS_PREVENT_DELETE |
+		ENV_FLAGS_VARACCESS_PREVENT_OVERWR,
+	ENV_FLAGS_VARACCESS_PREVENT_DELETE |
+		ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR};
+
+#ifdef CONFIG_CMD_ENV_FLAGS
+static const char * const env_flags_vartype_names[] = {
+	"string",
+	"decimal",
+	"hexadecimal",
+	"boolean",
+#ifdef CONFIG_CMD_NET
+	"IP address",
+	"MAC address",
+#endif
+};
+static const char * const env_flags_varaccess_names[] = {
+	"any",
+	"read-only",
+	"write-once",
+	"change-default",
+};
+
+/*
+ * Print the whole list of available type flags.
+ */
+void env_flags_print_vartypes(void)
+{
+	enum env_flags_vartype curtype = (enum env_flags_vartype)0;
+
+	while (curtype != env_flags_vartype_end) {
+		printf("\t%c   -\t%s\n", env_flags_vartype_rep[curtype],
+			env_flags_vartype_names[curtype]);
+		curtype++;
+	}
+}
+
+/*
+ * Print the whole list of available access flags.
+ */
+void env_flags_print_varaccess(void)
+{
+	enum env_flags_varaccess curaccess = (enum env_flags_varaccess)0;
+
+	while (curaccess != env_flags_varaccess_end) {
+		printf("\t%c   -\t%s\n", env_flags_varaccess_rep[curaccess],
+			env_flags_varaccess_names[curaccess]);
+		curaccess++;
+	}
+}
+
+/*
+ * Return the name of the type.
+ */
+const char *env_flags_get_vartype_name(enum env_flags_vartype type)
+{
+	return env_flags_vartype_names[type];
+}
+
+/*
+ * Return the name of the access.
+ */
+const char *env_flags_get_varaccess_name(enum env_flags_varaccess access)
+{
+	return env_flags_varaccess_names[access];
+}
+#endif /* CONFIG_CMD_ENV_FLAGS */
+
+/*
+ * Parse the flags string from a .flags attribute list into the vartype enum.
+ */
+enum env_flags_vartype env_flags_parse_vartype(const char *flags)
+{
+	char *type;
+
+	if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC)
+		return env_flags_vartype_string;
+
+	type = strchr(env_flags_vartype_rep,
+		flags[ENV_FLAGS_VARTYPE_LOC]);
+
+	if (type != NULL)
+		return (enum env_flags_vartype)
+			(type - &env_flags_vartype_rep[0]);
+
+	printf("## Warning: Unknown environment variable type '%c'\n",
+		flags[ENV_FLAGS_VARTYPE_LOC]);
+	return env_flags_vartype_string;
+}
+
+/*
+ * Parse the flags string from a .flags attribute list into the varaccess enum.
+ */
+enum env_flags_varaccess env_flags_parse_varaccess(const char *flags)
+{
+	char *access;
+
+	if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC)
+		return env_flags_varaccess_any;
+
+	access = strchr(env_flags_varaccess_rep,
+		flags[ENV_FLAGS_VARACCESS_LOC]);
+
+	if (access != NULL)
+		return (enum env_flags_varaccess)
+			(access - &env_flags_varaccess_rep[0]);
+
+	printf("## Warning: Unknown environment variable access method '%c'\n",
+		flags[ENV_FLAGS_VARACCESS_LOC]);
+	return env_flags_varaccess_any;
+}
+
+/*
+ * Parse the binary flags from a hash table entry into the varaccess enum.
+ */
+enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags)
+{
+	int i;
+
+	for (i = 0; i < sizeof(env_flags_varaccess_mask); i++)
+		if (env_flags_varaccess_mask[i] ==
+		    (binflags & ENV_FLAGS_VARACCESS_BIN_MASK))
+			return (enum env_flags_varaccess)i;
+
+	printf("Warning: Non-standard access flags. (0x%x)\n",
+		binflags & ENV_FLAGS_VARACCESS_BIN_MASK);
+
+	return env_flags_varaccess_any;
+}
+
+static inline int is_hex_prefix(const char *value)
+{
+	return value[0] == '0' && (value[1] == 'x' || value[1] == 'X');
+}
+
+static void skip_num(int hex, const char *value, const char **end,
+	int max_digits)
+{
+	int i;
+
+	if (hex && is_hex_prefix(value))
+		value += 2;
+
+	for (i = max_digits; i != 0; i--) {
+		if (hex && !isxdigit(*value))
+			break;
+		if (!hex && !isdigit(*value))
+			break;
+		value++;
+	}
+	if (end != NULL)
+		*end = value;
+}
+
+/*
+ * Based on the declared type enum, validate that the value string complies
+ * with that format
+ */
+static int _env_flags_validate_type(const char *value,
+	enum env_flags_vartype type)
+{
+	const char *end;
+#ifdef CONFIG_CMD_NET
+	const char *cur;
+	int i;
+#endif
+
+	switch (type) {
+	case env_flags_vartype_string:
+		break;
+	case env_flags_vartype_decimal:
+		skip_num(0, value, &end, -1);
+		if (*end != '\0')
+			return -1;
+		break;
+	case env_flags_vartype_hex:
+		skip_num(1, value, &end, -1);
+		if (*end != '\0')
+			return -1;
+		if (value + 2 == end && is_hex_prefix(value))
+			return -1;
+		break;
+	case env_flags_vartype_bool:
+		if (value[0] != '1' && value[0] != 'y' && value[0] != 't' &&
+		    value[0] != 'Y' && value[0] != 'T' &&
+		    value[0] != '0' && value[0] != 'n' && value[0] != 'f' &&
+		    value[0] != 'N' && value[0] != 'F')
+			return -1;
+		if (value[1] != '\0')
+			return -1;
+		break;
+#ifdef CONFIG_CMD_NET
+	case env_flags_vartype_ipaddr:
+		cur = value;
+		for (i = 0; i < 4; i++) {
+			skip_num(0, cur, &end, 3);
+			if (cur == end)
+				return -1;
+			if (i != 3 && *end != '.')
+				return -1;
+			if (i == 3 && *end != '\0')
+				return -1;
+			cur = end + 1;
+		}
+		break;
+	case env_flags_vartype_macaddr:
+		cur = value;
+		for (i = 0; i < 6; i++) {
+			skip_num(1, cur, &end, 2);
+			if (cur == end)
+				return -1;
+			if (cur + 2 == end && is_hex_prefix(cur))
+				return -1;
+			if (i != 5 && *end != ':')
+				return -1;
+			if (i == 5 && *end != '\0')
+				return -1;
+			cur = end + 1;
+		}
+		break;
+#endif
+	case env_flags_vartype_end:
+		return -1;
+	}
+
+	/* OK */
+	return 0;
+}
+
+/*
+ * Look for flags in a provided list and failing that the static list
+ */
+static inline int env_flags_lookup(const char *flags_list, const char *name,
+	char *flags)
+{
+	int ret = 1;
+
+	if (!flags)
+		/* bad parameter */
+		return -1;
+
+	/* try the env first */
+	if (flags_list)
+		ret = env_attr_lookup(flags_list, name, flags);
+
+	if (ret != 0)
+		/* if not found in the env, look in the static list */
+		ret = env_attr_lookup(ENV_FLAGS_LIST_STATIC, name, flags);
+
+	return ret;
+}
+
+#ifdef USE_HOSTCC /* Functions only used from tools/env */
+/*
+ * Look up any flags directly from the .flags variable and the static list
+ * and convert them to the vartype enum.
+ */
+enum env_flags_vartype env_flags_get_type(const char *name)
+{
+	const char *flags_list = getenv(ENV_FLAGS_VAR);
+	char flags[ENV_FLAGS_ATTR_MAX_LEN + 1];
+
+	if (env_flags_lookup(flags_list, name, flags))
+		return env_flags_vartype_string;
+
+	if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC)
+		return env_flags_vartype_string;
+
+	return env_flags_parse_vartype(flags);
+}
+
+/*
+ * Look up the access of a variable directly from the .flags var.
+ */
+enum env_flags_varaccess env_flags_get_varaccess(const char *name)
+{
+	const char *flags_list = getenv(ENV_FLAGS_VAR);
+	char flags[ENV_FLAGS_ATTR_MAX_LEN + 1];
+
+	if (env_flags_lookup(flags_list, name, flags))
+		return env_flags_varaccess_any;
+
+	if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC)
+		return env_flags_varaccess_any;
+
+	return env_flags_parse_varaccess(flags);
+}
+
+/*
+ * Validate that the proposed new value for "name" is valid according to the
+ * defined flags for that variable, if any.
+ */
+int env_flags_validate_type(const char *name, const char *value)
+{
+	enum env_flags_vartype type;
+
+	if (value == NULL)
+		return 0;
+	type = env_flags_get_type(name);
+	if (_env_flags_validate_type(value, type) < 0) {
+		printf("## Error: flags type check failure for "
+			"\"%s\" <= \"%s\" (type: %c)\n",
+			name, value, env_flags_vartype_rep[type]);
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * Validate that the proposed access to variable "name" is valid according to
+ * the defined flags for that variable, if any.
+ */
+int env_flags_validate_varaccess(const char *name, int check_mask)
+{
+	enum env_flags_varaccess access;
+	int access_mask;
+
+	access = env_flags_get_varaccess(name);
+	access_mask = env_flags_varaccess_mask[access];
+
+	return (check_mask & access_mask) != 0;
+}
+
+/*
+ * Validate the parameters to "env set" directly
+ */
+int env_flags_validate_env_set_params(int argc, char * const argv[])
+{
+	if ((argc >= 3) && argv[2] != NULL) {
+		enum env_flags_vartype type = env_flags_get_type(argv[1]);
+
+		/*
+		 * we don't currently check types that need more than
+		 * one argument
+		 */
+		if (type != env_flags_vartype_string && argc > 3) {
+			printf("## Error: too many parameters for setting "
+				"\"%s\"\n", argv[1]);
+			return -1;
+		}
+		return env_flags_validate_type(argv[1], argv[2]);
+	}
+	/* ok */
+	return 0;
+}
+
+#else /* !USE_HOSTCC - Functions only used from lib/hashtable.c */
+
+/*
+ * Parse the flag charachters from the .flags attribute list into the binary
+ * form to be stored in the environment entry->flags field.
+ */
+static int env_parse_flags_to_bin(const char *flags)
+{
+	int binflags;
+
+	binflags = env_flags_parse_vartype(flags) & ENV_FLAGS_VARTYPE_BIN_MASK;
+	binflags |= env_flags_varaccess_mask[env_flags_parse_varaccess(flags)];
+
+	return binflags;
+}
+
+/*
+ * Look for possible flags for a newly added variable
+ * This is called specifically when the variable did not exist in the hash
+ * previously, so the blanket update did not find this variable.
+ */
+void env_flags_init(ENTRY *var_entry)
+{
+	const char *var_name = var_entry->key;
+	const char *flags_list = getenv(ENV_FLAGS_VAR);
+	char flags[ENV_FLAGS_ATTR_MAX_LEN + 1] = "";
+	int ret = 1;
+
+	/* look in the ".flags" and static for a reference to this variable */
+	ret = env_flags_lookup(flags_list, var_name, flags);
+
+	/* if any flags were found, set the binary form to the entry */
+	if (!ret && strlen(flags))
+		var_entry->flags = env_parse_flags_to_bin(flags);
+}
+
+/*
+ * Called on each existing env var prior to the blanket update since removing
+ * a flag in the flag list should remove its flags.
+ */
+static int clear_flags(ENTRY *entry)
+{
+	entry->flags = 0;
+
+	return 0;
+}
+
+/*
+ * Call for each element in the list that defines flags for a variable
+ */
+static int set_flags(const char *name, const char *value)
+{
+	ENTRY e, *ep;
+
+	e.key	= name;
+	e.data	= NULL;
+	hsearch_r(e, FIND, &ep, &env_htab, 0);
+
+	/* does the env variable actually exist? */
+	if (ep != NULL) {
+		/* the flag list is empty, so clear the flags */
+		if (value == NULL || strlen(value) == 0)
+			ep->flags = 0;
+		else
+			/* assign the requested flags */
+			ep->flags = env_parse_flags_to_bin(value);
+	}
+
+	return 0;
+}
+
+static int on_flags(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	/* remove all flags */
+	hwalk_r(&env_htab, clear_flags);
+
+	/* configure any static flags */
+	env_attr_walk(ENV_FLAGS_LIST_STATIC, set_flags);
+	/* configure any dynamic flags */
+	env_attr_walk(value, set_flags);
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(flags, on_flags);
+
+/*
+ * Perform consistency checking before creating, overwriting, or deleting an
+ * environment variable. Called as a callback function by hsearch_r() and
+ * hdelete_r(). Returns 0 in case of success, 1 in case of failure.
+ * When (flag & H_FORCE) is set, do not print out any error message and force
+ * overwriting of write-once variables.
+ */
+
+int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
+	int flag)
+{
+	const char *name;
+	const char *oldval = NULL;
+
+	if (op != env_op_create)
+		oldval = item->data;
+
+	name = item->key;
+
+	/* Default value for NULL to protect string-manipulating functions */
+	newval = newval ? : "";
+
+	/* validate the value to match the variable type */
+	if (op != env_op_delete) {
+		enum env_flags_vartype type = (enum env_flags_vartype)
+			(ENV_FLAGS_VARTYPE_BIN_MASK & item->flags);
+
+		if (_env_flags_validate_type(newval, type) < 0) {
+			printf("## Error: flags type check failure for "
+				"\"%s\" <= \"%s\" (type: %c)\n",
+				name, newval, env_flags_vartype_rep[type]);
+			return -1;
+		}
+	}
+
+	/* check for access permission */
+#ifndef CONFIG_ENV_ACCESS_IGNORE_FORCE
+	if (flag & H_FORCE)
+		return 0;
+#endif
+	switch (op) {
+	case env_op_delete:
+		if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_DELETE) {
+			printf("## Error: Can't delete \"%s\"\n", name);
+			return 1;
+		}
+		break;
+	case env_op_overwrite:
+		if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_OVERWR) {
+			printf("## Error: Can't overwrite \"%s\"\n", name);
+			return 1;
+		} else if (item->flags &
+		    ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR) {
+			const char *defval = getenv_default(name);
+
+			if (defval == NULL)
+				defval = "";
+			printf("oldval: %s  defval: %s\n", oldval, defval);
+			if (strcmp(oldval, defval) != 0) {
+				printf("## Error: Can't overwrite \"%s\"\n",
+					name);
+				return 1;
+			}
+		}
+		break;
+	case env_op_create:
+		if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_CREATE) {
+			printf("## Error: Can't create \"%s\"\n", name);
+			return 1;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+#endif
diff --git a/common/env_flash.c b/common/env_flash.c
index aa970d4..e07d336 100644
--- a/common/env_flash.c
+++ b/common/env_flash.c
@@ -142,7 +142,7 @@
 		goto done;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		goto done;
@@ -275,7 +275,7 @@
 		goto done;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		goto done;
diff --git a/common/env_mmc.c b/common/env_mmc.c
index a2ff90b..ce21671 100644
--- a/common/env_mmc.c
+++ b/common/env_mmc.c
@@ -130,7 +130,7 @@
 	}
 
 	res = (char *)&env_new->data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		ret = 1;
diff --git a/common/env_nand.c b/common/env_nand.c
index 79e8033..22e72a2 100644
--- a/common/env_nand.c
+++ b/common/env_nand.c
@@ -186,7 +186,7 @@
 		return 1;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
@@ -239,7 +239,7 @@
 		return 1;
 
 	res = (char *)&env_new->data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_nvram.c b/common/env_nvram.c
index 6483db3..eab0e7b 100644
--- a/common/env_nvram.c
+++ b/common/env_nvram.c
@@ -90,7 +90,7 @@
 	int	rcode = 0;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_onenand.c b/common/env_onenand.c
index da35071..faa903d 100644
--- a/common/env_onenand.c
+++ b/common/env_onenand.c
@@ -95,7 +95,7 @@
 	};
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_sf.c b/common/env_sf.c
index bbd472f..d9e9085 100644
--- a/common/env_sf.c
+++ b/common/env_sf.c
@@ -79,7 +79,7 @@
 	}
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
@@ -277,7 +277,7 @@
 	}
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		goto done;
diff --git a/common/fdt_support.c b/common/fdt_support.c
index 963ea90..6b9fa05 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -1315,7 +1315,7 @@
 	return fdt_set_node_status(fdt, offset, status, error_code);
 }
 
-#if defined(CONFIG_VIDEO)
+#if defined(CONFIG_VIDEO) || defined(CONFIG_LCD)
 int fdt_add_edid(void *blob, const char *compat, unsigned char *edid_buf)
 {
 	int noff;
diff --git a/common/hash.c b/common/hash.c
new file mode 100644
index 0000000..e3a6e43
--- /dev/null
+++ b/common/hash.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2012 The Chromium OS Authors.
+ *
+ * (C) Copyright 2011
+ * Joe Hershberger, National Instruments, joe.hershberger@ni.com
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <hash.h>
+#include <sha1.h>
+#include <sha256.h>
+
+/*
+ * These are the hash algorithms we support. Chips which support accelerated
+ * crypto could perhaps add named version of these algorithms here.
+ */
+static struct hash_algo hash_algo[] = {
+#ifdef CONFIG_SHA1
+	{
+		"SHA1",
+		SHA1_SUM_LEN,
+		sha1_csum_wd,
+		CHUNKSZ_SHA1,
+	},
+#endif
+#ifdef CONFIG_SHA256
+	{
+		"SHA256",
+		SHA256_SUM_LEN,
+		sha256_csum_wd,
+		CHUNKSZ_SHA256,
+	},
+#endif
+};
+
+/**
+ * store_result: Store the resulting sum to an address or variable
+ *
+ * @algo:		Hash algorithm being used
+ * @sum:		Hash digest (algo->digest_size bytes)
+ * @dest:		Destination, interpreted as a hex address if it starts
+ *			with * or otherwise as an environment variable.
+ */
+static void store_result(struct hash_algo *algo, const u8 *sum,
+			 const char *dest)
+{
+	unsigned int i;
+
+	if (*dest == '*') {
+		u8 *ptr;
+
+		ptr = (u8 *)simple_strtoul(dest + 1, NULL, 16);
+		memcpy(ptr, sum, algo->digest_size);
+	} else {
+		char str_output[HASH_MAX_DIGEST_SIZE * 2 + 1];
+		char *str_ptr = str_output;
+
+		for (i = 0; i < algo->digest_size; i++) {
+			sprintf(str_ptr, "%02x", sum[i]);
+			str_ptr += 2;
+		}
+		str_ptr = '\0';
+		setenv(dest, str_output);
+	}
+}
+
+/**
+ * parse_verify_sum: Parse a hash verification parameter
+ *
+ * @algo:		Hash algorithm being used
+ * @verify_str:		Argument to parse. If it starts with * then it is
+ *			interpreted as a hex address containing the hash.
+ *			If the length is exactly the right number of hex digits
+ *			for the digest size, then we assume it is a hex digest.
+ *			Otherwise we assume it is an environment variable, and
+ *			look up its value (it must contain a hex digest).
+ * @vsum:		Returns binary digest value (algo->digest_size bytes)
+ * @return 0 if ok, non-zero on error
+ */
+static int parse_verify_sum(struct hash_algo *algo, char *verify_str, u8 *vsum)
+{
+	if (*verify_str == '*') {
+		u8 *ptr;
+
+		ptr = (u8 *)simple_strtoul(verify_str + 1, NULL, 16);
+		memcpy(vsum, ptr, algo->digest_size);
+	} else {
+		unsigned int i;
+		char *vsum_str;
+		int digits = algo->digest_size * 2;
+
+		/*
+		 * As with the original code from sha1sum.c, we assume that a
+		 * string which matches the digest size exactly is a hex
+		 * string and not an environment variable.
+		 */
+		if (strlen(verify_str) == digits)
+			vsum_str = verify_str;
+		else {
+			vsum_str = getenv(verify_str);
+			if (vsum_str == NULL || strlen(vsum_str) != digits) {
+				printf("Expected %d hex digits in env var\n",
+				       digits);
+				return 1;
+			}
+		}
+
+		for (i = 0; i < algo->digest_size; i++) {
+			char *nullp = vsum_str + (i + 1) * 2;
+			char end = *nullp;
+
+			*nullp = '\0';
+			vsum[i] = simple_strtoul(vsum_str + (i * 2), NULL, 16);
+			*nullp = end;
+		}
+	}
+	return 0;
+}
+
+static struct hash_algo *find_hash_algo(const char *name)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hash_algo); i++) {
+		if (!strcasecmp(name, hash_algo[i].name))
+			return &hash_algo[i];
+	}
+
+	return NULL;
+}
+
+static void show_hash(struct hash_algo *algo, ulong addr, ulong len,
+		      u8 *output)
+{
+	int i;
+
+	printf("%s for %08lx ... %08lx ==> ", algo->name, addr, addr + len - 1);
+	for (i = 0; i < algo->digest_size; i++)
+		printf("%02x", output[i]);
+}
+
+int hash_command(const char *algo_name, int verify, cmd_tbl_t *cmdtp, int flag,
+		 int argc, char * const argv[])
+{
+	struct hash_algo *algo;
+	ulong addr, len;
+	u8 output[HASH_MAX_DIGEST_SIZE];
+	u8 vsum[HASH_MAX_DIGEST_SIZE];
+
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	algo = find_hash_algo(algo_name);
+	if (!algo) {
+		printf("Unknown hash algorithm '%s'\n", algo_name);
+		return CMD_RET_USAGE;
+	}
+	addr = simple_strtoul(*argv++, NULL, 16);
+	len = simple_strtoul(*argv++, NULL, 16);
+	argc -= 2;
+
+	if (algo->digest_size > HASH_MAX_DIGEST_SIZE) {
+		puts("HASH_MAX_DIGEST_SIZE exceeded\n");
+		return 1;
+	}
+
+	algo->hash_func_ws((const unsigned char *)addr, len, output,
+			   algo->chunk_size);
+
+	/* Try to avoid code bloat when verify is not needed */
+#ifdef CONFIG_HASH_VERIFY
+	if (verify) {
+#else
+	if (0) {
+#endif
+		if (!argc)
+			return CMD_RET_USAGE;
+		if (parse_verify_sum(algo, *argv, vsum)) {
+			printf("ERROR: %s does not contain a valid %s sum\n",
+				*argv, algo->name);
+			return 1;
+		}
+		if (memcmp(output, vsum, algo->digest_size) != 0) {
+			int i;
+
+			show_hash(algo, addr, len, output);
+			printf(" != ");
+			for (i = 0; i < algo->digest_size; i++)
+				printf("%02x", vsum[i]);
+			puts(" ** ERROR **\n");
+			return 1;
+		}
+	} else {
+		show_hash(algo, addr, len, output);
+		printf("\n");
+
+		if (argc)
+			store_result(algo, output, *argv);
+	}
+
+	return 0;
+}
diff --git a/common/image.c b/common/image.c
index e93b6e8..95498e6 100644
--- a/common/image.c
+++ b/common/image.c
@@ -43,6 +43,7 @@
 #include <rtc.h>
 #endif
 
+#include <environment.h>
 #include <image.h>
 
 #if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT)
@@ -416,11 +417,25 @@
 /* Shared dual-format routines */
 /*****************************************************************************/
 #ifndef USE_HOSTCC
-int getenv_yesno(char *var)
+ulong load_addr = CONFIG_SYS_LOAD_ADDR;	/* Default Load Address */
+ulong save_addr;			/* Default Save Address */
+ulong save_size;			/* Default Save Size (in bytes) */
+
+static int on_loadaddr(const char *name, const char *value, enum env_op op,
+	int flags)
 {
-	char *s = getenv(var);
-	return (s && (*s == 'n')) ? 0 : 1;
+	switch (op) {
+	case env_op_create:
+	case env_op_overwrite:
+		load_addr = simple_strtoul(value, NULL, 16);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
 }
+U_BOOT_ENV_CALLBACK(loadaddr, on_loadaddr);
 
 ulong getenv_bootm_low(void)
 {
diff --git a/common/main.c b/common/main.c
index 5362781..b145f85 100644
--- a/common/main.c
+++ b/common/main.c
@@ -376,6 +376,8 @@
 	char bcs_set[16];
 #endif /* CONFIG_BOOTCOUNT_LIMIT */
 
+	bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");
+
 #ifdef CONFIG_BOOTCOUNT_LIMIT
 	bootcount = bootcount_load();
 	bootcount++;
diff --git a/common/stdio.c b/common/stdio.c
index 9f48e5f..97ff9cf 100644
--- a/common/stdio.c
+++ b/common/stdio.c
@@ -135,7 +135,6 @@
 		return NULL;
 
 	memcpy(_dev, dev, sizeof(struct stdio_dev));
-	strncpy(_dev->name, dev->name, 16);
 
 	return _dev;
 }
diff --git a/disk/part_efi.c b/disk/part_efi.c
index a3873ce..7665017 100644
--- a/disk/part_efi.c
+++ b/disk/part_efi.c
@@ -34,9 +34,11 @@
 #include <command.h>
 #include <ide.h>
 #include <malloc.h>
-#include "part_efi.h"
+#include <part_efi.h>
 #include <linux/ctype.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 #if defined(CONFIG_CMD_IDE) || \
     defined(CONFIG_CMD_SATA) || \
     defined(CONFIG_CMD_SCSI) || \
@@ -44,34 +46,6 @@
     defined(CONFIG_MMC) || \
     defined(CONFIG_SYSTEMACE)
 
-/* Convert char[2] in little endian format to the host format integer
- */
-static inline unsigned short le16_to_int(unsigned char *le16)
-{
-	return ((le16[1] << 8) + le16[0]);
-}
-
-/* Convert char[4] in little endian format to the host format integer
- */
-static inline unsigned long le32_to_int(unsigned char *le32)
-{
-	return ((le32[3] << 24) + (le32[2] << 16) + (le32[1] << 8) + le32[0]);
-}
-
-/* Convert char[8] in little endian format to the host format integer
- */
-static inline unsigned long long le64_to_int(unsigned char *le64)
-{
-	return (((unsigned long long)le64[7] << 56) +
-		((unsigned long long)le64[6] << 48) +
-		((unsigned long long)le64[5] << 40) +
-		((unsigned long long)le64[4] << 32) +
-		((unsigned long long)le64[3] << 24) +
-		((unsigned long long)le64[2] << 16) +
-		((unsigned long long)le64[1] << 8) +
-		(unsigned long long)le64[0]);
-}
-
 /**
  * efi_crc32() - EFI version of crc32 function
  * @buf: buffer to calculate crc32 of
@@ -79,7 +53,7 @@
  *
  * Description: Returns EFI-style CRC32 value for @buf
  */
-static inline unsigned long efi_crc32(const void *buf, unsigned long len)
+static inline u32 efi_crc32(const void *buf, u32 len)
 {
 	return crc32(0, buf, len);
 }
@@ -90,13 +64,10 @@
 
 static int pmbr_part_valid(struct partition *part);
 static int is_pmbr_valid(legacy_mbr * mbr);
-
 static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba,
 				gpt_header * pgpt_head, gpt_entry ** pgpt_pte);
-
 static gpt_entry *alloc_read_gpt_entries(block_dev_desc_t * dev_desc,
 				gpt_header * pgpt_head);
-
 static int is_pte_valid(gpt_entry * pte);
 
 static char *print_efiname(gpt_entry *pte)
@@ -142,6 +113,7 @@
 			sizeof(efi_guid_t));
 }
 
+#ifdef CONFIG_EFI_PARTITION
 /*
  * Public Functions (include/part.h)
  */
@@ -171,14 +143,14 @@
 	printf("\tType UUID\n");
 	printf("\tPartition UUID\n");
 
-	for (i = 0; i < le32_to_int(gpt_head->num_partition_entries); i++) {
+	for (i = 0; i < le32_to_cpu(gpt_head->num_partition_entries); i++) {
 		/* Stop at the first non valid PTE */
 		if (!is_pte_valid(&gpt_pte[i]))
 			break;
 
 		printf("%3d\t0x%08llx\t0x%08llx\t\"%s\"\n", (i + 1),
-			le64_to_int(gpt_pte[i].starting_lba),
-			le64_to_int(gpt_pte[i].ending_lba),
+			le64_to_cpu(gpt_pte[i].starting_lba),
+			le64_to_cpu(gpt_pte[i].ending_lba),
 			print_efiname(&gpt_pte[i]));
 		printf("\tattrs:\t0x%016llx\n", gpt_pte[i].attributes.raw);
 		uuid_string(gpt_pte[i].partition_type_guid.b, uuid);
@@ -211,7 +183,7 @@
 		return -1;
 	}
 
-	if (part > le32_to_int(gpt_head->num_partition_entries) ||
+	if (part > le32_to_cpu(gpt_head->num_partition_entries) ||
 	    !is_pte_valid(&gpt_pte[part - 1])) {
 		printf("%s: *** ERROR: Invalid partition number %d ***\n",
 			__func__, part);
@@ -219,9 +191,9 @@
 	}
 
 	/* The ulong casting limits the maximum disk size to 2 TB */
-	info->start = (ulong) le64_to_int(gpt_pte[part - 1].starting_lba);
+	info->start = (u64)le64_to_cpu(gpt_pte[part - 1].starting_lba);
 	/* The ending LBA is inclusive, to calculate size, add 1 to it */
-	info->size = ((ulong)le64_to_int(gpt_pte[part - 1].ending_lba) + 1)
+	info->size = ((u64)le64_to_cpu(gpt_pte[part - 1].ending_lba) + 1)
 		     - info->start;
 	info->blksz = GPT_BLOCK_SIZE;
 
@@ -253,6 +225,281 @@
 	return 0;
 }
 
+/**
+ * set_protective_mbr(): Set the EFI protective MBR
+ * @param dev_desc - block device descriptor
+ *
+ * @return - zero on success, otherwise error
+ */
+static int set_protective_mbr(block_dev_desc_t *dev_desc)
+{
+	legacy_mbr *p_mbr;
+
+	/* Setup the Protective MBR */
+	p_mbr = calloc(1, sizeof(p_mbr));
+	if (p_mbr == NULL) {
+		printf("%s: calloc failed!\n", __func__);
+		return -1;
+	}
+	/* Append signature */
+	p_mbr->signature = MSDOS_MBR_SIGNATURE;
+	p_mbr->partition_record[0].sys_ind = EFI_PMBR_OSTYPE_EFI_GPT;
+	p_mbr->partition_record[0].start_sect = 1;
+	p_mbr->partition_record[0].nr_sects = (u32) dev_desc->lba;
+
+	/* Write MBR sector to the MMC device */
+	if (dev_desc->block_write(dev_desc->dev, 0, 1, p_mbr) != 1) {
+		printf("** Can't write to device %d **\n",
+			dev_desc->dev);
+		free(p_mbr);
+		return -1;
+	}
+
+	free(p_mbr);
+	return 0;
+}
+
+/**
+ * string_uuid(); Convert UUID stored as string to bytes
+ *
+ * @param uuid - UUID represented as string
+ * @param dst - GUID buffer
+ *
+ * @return return 0 on successful conversion
+ */
+static int string_uuid(char *uuid, u8 *dst)
+{
+	efi_guid_t guid;
+	u16 b, c, d;
+	u64 e;
+	u32 a;
+	u8 *p;
+	u8 i;
+
+	const u8 uuid_str_len = 36;
+
+	/* The UUID is written in text: */
+	/* 1        9    14   19   24 */
+	/* xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx */
+
+	debug("%s: uuid: %s\n", __func__, uuid);
+
+	if (strlen(uuid) != uuid_str_len)
+		return -1;
+
+	for (i = 0; i < uuid_str_len; i++) {
+		if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
+			if (uuid[i] != '-')
+				return -1;
+		} else {
+			if (!isxdigit(uuid[i]))
+				return -1;
+		}
+	}
+
+	a = (u32)simple_strtoul(uuid, NULL, 16);
+	b = (u16)simple_strtoul(uuid + 9, NULL, 16);
+	c = (u16)simple_strtoul(uuid + 14, NULL, 16);
+	d = (u16)simple_strtoul(uuid + 19, NULL, 16);
+	e = (u64)simple_strtoull(uuid + 24, NULL, 16);
+
+	p = (u8 *) &e;
+	guid = EFI_GUID(a, b, c, d >> 8, d & 0xFF,
+			*(p + 5), *(p + 4), *(p + 3),
+			*(p + 2), *(p + 1) , *p);
+
+	memcpy(dst, guid.b, sizeof(efi_guid_t));
+
+	return 0;
+}
+
+int write_gpt_table(block_dev_desc_t *dev_desc,
+		gpt_header *gpt_h, gpt_entry *gpt_e)
+{
+	const int pte_blk_num = (gpt_h->num_partition_entries
+		* sizeof(gpt_entry)) / dev_desc->blksz;
+
+	u32 calc_crc32;
+	u64 val;
+
+	debug("max lba: %x\n", (u32) dev_desc->lba);
+	/* Setup the Protective MBR */
+	if (set_protective_mbr(dev_desc) < 0)
+		goto err;
+
+	/* Generate CRC for the Primary GPT Header */
+	calc_crc32 = efi_crc32((const unsigned char *)gpt_e,
+			      le32_to_cpu(gpt_h->num_partition_entries) *
+			      le32_to_cpu(gpt_h->sizeof_partition_entry));
+	gpt_h->partition_entry_array_crc32 = cpu_to_le32(calc_crc32);
+
+	calc_crc32 = efi_crc32((const unsigned char *)gpt_h,
+			      le32_to_cpu(gpt_h->header_size));
+	gpt_h->header_crc32 = cpu_to_le32(calc_crc32);
+
+	/* Write the First GPT to the block right after the Legacy MBR */
+	if (dev_desc->block_write(dev_desc->dev, 1, 1, gpt_h) != 1)
+		goto err;
+
+	if (dev_desc->block_write(dev_desc->dev, 2, pte_blk_num, gpt_e)
+	    != pte_blk_num)
+		goto err;
+
+	/* recalculate the values for the Second GPT Header */
+	val = le64_to_cpu(gpt_h->my_lba);
+	gpt_h->my_lba = gpt_h->alternate_lba;
+	gpt_h->alternate_lba = cpu_to_le64(val);
+	gpt_h->header_crc32 = 0;
+
+	calc_crc32 = efi_crc32((const unsigned char *)gpt_h,
+			      le32_to_cpu(gpt_h->header_size));
+	gpt_h->header_crc32 = cpu_to_le32(calc_crc32);
+
+	if (dev_desc->block_write(dev_desc->dev,
+				  le32_to_cpu(gpt_h->last_usable_lba + 1),
+				  pte_blk_num, gpt_e) != pte_blk_num)
+		goto err;
+
+	if (dev_desc->block_write(dev_desc->dev,
+				  le32_to_cpu(gpt_h->my_lba), 1, gpt_h) != 1)
+		goto err;
+
+	debug("GPT successfully written to block device!\n");
+	return 0;
+
+ err:
+	printf("** Can't write to device %d **\n", dev_desc->dev);
+	return -1;
+}
+
+int gpt_fill_pte(gpt_header *gpt_h, gpt_entry *gpt_e,
+		disk_partition_t *partitions, int parts)
+{
+	u32 offset = (u32)le32_to_cpu(gpt_h->first_usable_lba);
+	ulong start;
+	int i, k;
+	size_t name_len;
+#ifdef CONFIG_PARTITION_UUIDS
+	char *str_uuid;
+#endif
+
+	for (i = 0; i < parts; i++) {
+		/* partition starting lba */
+		start = partitions[i].start;
+		if (start && (start < offset)) {
+			printf("Partition overlap\n");
+			return -1;
+		}
+		if (start) {
+			gpt_e[i].starting_lba = cpu_to_le64(start);
+			offset = start + partitions[i].size;
+		} else {
+			gpt_e[i].starting_lba = cpu_to_le64(offset);
+			offset += partitions[i].size;
+		}
+		if (offset >= gpt_h->last_usable_lba) {
+			printf("Partitions layout exceds disk size\n");
+			return -1;
+		}
+		/* partition ending lba */
+		if ((i == parts - 1) && (partitions[i].size == 0))
+			/* extend the last partition to maximuim */
+			gpt_e[i].ending_lba = gpt_h->last_usable_lba;
+		else
+			gpt_e[i].ending_lba = cpu_to_le64(offset - 1);
+
+		/* partition type GUID */
+		memcpy(gpt_e[i].partition_type_guid.b,
+			&PARTITION_BASIC_DATA_GUID, 16);
+
+#ifdef CONFIG_PARTITION_UUIDS
+		str_uuid = partitions[i].uuid;
+		if (string_uuid(str_uuid, gpt_e[i].unique_partition_guid.b)) {
+			printf("Partition no. %d: invalid guid: %s\n",
+				i, str_uuid);
+			return -1;
+		}
+#endif
+
+		/* partition attributes */
+		memset(&gpt_e[i].attributes, 0,
+		       sizeof(gpt_entry_attributes));
+
+		/* partition name */
+		name_len = sizeof(gpt_e[i].partition_name)
+			/ sizeof(efi_char16_t);
+		for (k = 0; k < name_len; k++)
+			gpt_e[i].partition_name[k] =
+				(efi_char16_t)(partitions[i].name[k]);
+
+		debug("%s: name: %s offset[%d]: 0x%x size[%d]: 0x%lx\n",
+		      __func__, partitions[i].name, i,
+		      offset, i, partitions[i].size);
+	}
+
+	return 0;
+}
+
+int gpt_fill_header(block_dev_desc_t *dev_desc, gpt_header *gpt_h,
+		char *str_guid, int parts_count)
+{
+	gpt_h->signature = cpu_to_le64(GPT_HEADER_SIGNATURE);
+	gpt_h->revision = cpu_to_le32(GPT_HEADER_REVISION_V1);
+	gpt_h->header_size = cpu_to_le32(sizeof(gpt_header));
+	gpt_h->my_lba = cpu_to_le64(1);
+	gpt_h->alternate_lba = cpu_to_le64(dev_desc->lba - 1);
+	gpt_h->first_usable_lba = cpu_to_le64(34);
+	gpt_h->last_usable_lba = cpu_to_le64(dev_desc->lba - 34);
+	gpt_h->partition_entry_lba = cpu_to_le64(2);
+	gpt_h->num_partition_entries = cpu_to_le32(GPT_ENTRY_NUMBERS);
+	gpt_h->sizeof_partition_entry = cpu_to_le32(sizeof(gpt_entry));
+	gpt_h->header_crc32 = 0;
+	gpt_h->partition_entry_array_crc32 = 0;
+
+	if (string_uuid(str_guid, gpt_h->disk_guid.b))
+		return -1;
+
+	return 0;
+}
+
+int gpt_restore(block_dev_desc_t *dev_desc, char *str_disk_guid,
+		disk_partition_t *partitions, int parts_count)
+{
+	int ret;
+
+	gpt_header *gpt_h = calloc(1, sizeof(gpt_header));
+	if (gpt_h == NULL) {
+		printf("%s: calloc failed!\n", __func__);
+		return -1;
+	}
+
+	gpt_entry *gpt_e = calloc(GPT_ENTRY_NUMBERS, sizeof(gpt_entry));
+	if (gpt_e == NULL) {
+		printf("%s: calloc failed!\n", __func__);
+		free(gpt_h);
+		return -1;
+	}
+
+	/* Generate Primary GPT header (LBA1) */
+	ret = gpt_fill_header(dev_desc, gpt_h, str_disk_guid, parts_count);
+	if (ret)
+		goto err;
+
+	/* Generate partition entries */
+	ret = gpt_fill_pte(gpt_h, gpt_e, partitions, parts_count);
+	if (ret)
+		goto err;
+
+	/* Write GPT partition table */
+	ret = write_gpt_table(dev_desc, gpt_h, gpt_e);
+
+err:
+	free(gpt_e);
+	free(gpt_h);
+	return ret;
+}
+#endif
+
 /*
  * Private functions
  */
@@ -264,7 +511,7 @@
 static int pmbr_part_valid(struct partition *part)
 {
 	if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT &&
-		le32_to_int(part->start_sect) == 1UL) {
+		le32_to_cpu(part->start_sect) == 1UL) {
 		return 1;
 	}
 
@@ -283,9 +530,8 @@
 {
 	int i = 0;
 
-	if (!mbr || le16_to_int(mbr->signature) != MSDOS_MBR_SIGNATURE) {
+	if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
 		return 0;
-	}
 
 	for (i = 0; i < 4; i++) {
 		if (pmbr_part_valid(&mbr->partition_record[i])) {
@@ -308,8 +554,8 @@
 static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba,
 			gpt_header * pgpt_head, gpt_entry ** pgpt_pte)
 {
-	unsigned char crc32_backup[4] = { 0 };
-	unsigned long calc_crc32;
+	u32 crc32_backup = 0;
+	u32 calc_crc32;
 	unsigned long long lastlba;
 
 	if (!dev_desc || !pgpt_head) {
@@ -324,54 +570,54 @@
 	}
 
 	/* Check the GPT header signature */
-	if (le64_to_int(pgpt_head->signature) != GPT_HEADER_SIGNATURE) {
+	if (le64_to_cpu(pgpt_head->signature) != GPT_HEADER_SIGNATURE) {
 		printf("GUID Partition Table Header signature is wrong:"
 			"0x%llX != 0x%llX\n",
-			(unsigned long long)le64_to_int(pgpt_head->signature),
-			(unsigned long long)GPT_HEADER_SIGNATURE);
+			le64_to_cpu(pgpt_head->signature),
+			GPT_HEADER_SIGNATURE);
 		return 0;
 	}
 
 	/* Check the GUID Partition Table CRC */
-	memcpy(crc32_backup, pgpt_head->header_crc32, sizeof(crc32_backup));
-	memset(pgpt_head->header_crc32, 0, sizeof(pgpt_head->header_crc32));
+	memcpy(&crc32_backup, &pgpt_head->header_crc32, sizeof(crc32_backup));
+	memset(&pgpt_head->header_crc32, 0, sizeof(pgpt_head->header_crc32));
 
 	calc_crc32 = efi_crc32((const unsigned char *)pgpt_head,
-		le32_to_int(pgpt_head->header_size));
+		le32_to_cpu(pgpt_head->header_size));
 
-	memcpy(pgpt_head->header_crc32, crc32_backup, sizeof(crc32_backup));
+	memcpy(&pgpt_head->header_crc32, &crc32_backup, sizeof(crc32_backup));
 
-	if (calc_crc32 != le32_to_int(crc32_backup)) {
+	if (calc_crc32 != le32_to_cpu(crc32_backup)) {
 		printf("GUID Partition Table Header CRC is wrong:"
-			"0x%08lX != 0x%08lX\n",
-			le32_to_int(crc32_backup), calc_crc32);
+			"0x%x != 0x%x\n",
+		       le32_to_cpu(crc32_backup), calc_crc32);
 		return 0;
 	}
 
 	/* Check that the my_lba entry points to the LBA that contains the GPT */
-	if (le64_to_int(pgpt_head->my_lba) != lba) {
+	if (le64_to_cpu(pgpt_head->my_lba) != lba) {
 		printf("GPT: my_lba incorrect: %llX != %llX\n",
-			(unsigned long long)le64_to_int(pgpt_head->my_lba),
-			(unsigned long long)lba);
+			le64_to_cpu(pgpt_head->my_lba),
+			lba);
 		return 0;
 	}
 
 	/* Check the first_usable_lba and last_usable_lba are within the disk. */
 	lastlba = (unsigned long long)dev_desc->lba;
-	if (le64_to_int(pgpt_head->first_usable_lba) > lastlba) {
+	if (le64_to_cpu(pgpt_head->first_usable_lba) > lastlba) {
 		printf("GPT: first_usable_lba incorrect: %llX > %llX\n",
-			le64_to_int(pgpt_head->first_usable_lba), lastlba);
+			le64_to_cpu(pgpt_head->first_usable_lba), lastlba);
 		return 0;
 	}
-	if (le64_to_int(pgpt_head->last_usable_lba) > lastlba) {
+	if (le64_to_cpu(pgpt_head->last_usable_lba) > lastlba) {
 		printf("GPT: last_usable_lba incorrect: %llX > %llX\n",
-			le64_to_int(pgpt_head->last_usable_lba), lastlba);
+			(u64) le64_to_cpu(pgpt_head->last_usable_lba), lastlba);
 		return 0;
 	}
 
 	debug("GPT: first_usable_lba: %llX last_usable_lba %llX last lba %llX\n",
-		le64_to_int(pgpt_head->first_usable_lba),
-		le64_to_int(pgpt_head->last_usable_lba), lastlba);
+		le64_to_cpu(pgpt_head->first_usable_lba),
+		le64_to_cpu(pgpt_head->last_usable_lba), lastlba);
 
 	/* Read and allocate Partition Table Entries */
 	*pgpt_pte = alloc_read_gpt_entries(dev_desc, pgpt_head);
@@ -382,13 +628,13 @@
 
 	/* Check the GUID Partition Table Entry Array CRC */
 	calc_crc32 = efi_crc32((const unsigned char *)*pgpt_pte,
-		le32_to_int(pgpt_head->num_partition_entries) *
-		le32_to_int(pgpt_head->sizeof_partition_entry));
+		le32_to_cpu(pgpt_head->num_partition_entries) *
+		le32_to_cpu(pgpt_head->sizeof_partition_entry));
 
-	if (calc_crc32 != le32_to_int(pgpt_head->partition_entry_array_crc32)) {
+	if (calc_crc32 != le32_to_cpu(pgpt_head->partition_entry_array_crc32)) {
 		printf("GUID Partition Table Entry Array CRC is wrong:"
-			"0x%08lX != 0x%08lX\n",
-			le32_to_int(pgpt_head->partition_entry_array_crc32),
+			"0x%x != 0x%x\n",
+			le32_to_cpu(pgpt_head->partition_entry_array_crc32),
 			calc_crc32);
 
 		free(*pgpt_pte);
@@ -419,12 +665,12 @@
 		return NULL;
 	}
 
-	count = le32_to_int(pgpt_head->num_partition_entries) *
-		le32_to_int(pgpt_head->sizeof_partition_entry);
+	count = le32_to_cpu(pgpt_head->num_partition_entries) *
+		le32_to_cpu(pgpt_head->sizeof_partition_entry);
 
-	debug("%s: count = %lu * %lu = %zu\n", __func__,
-		le32_to_int(pgpt_head->num_partition_entries),
-		le32_to_int(pgpt_head->sizeof_partition_entry), count);
+	debug("%s: count = %u * %u = %zu\n", __func__,
+	      (u32) le32_to_cpu(pgpt_head->num_partition_entries),
+	      (u32) le32_to_cpu(pgpt_head->sizeof_partition_entry), count);
 
 	/* Allocate memory for PTE, remember to FREE */
 	if (count != 0) {
@@ -440,7 +686,7 @@
 
 	/* Read GPT Entries from device */
 	if (dev_desc->block_read (dev_desc->dev,
-		(unsigned long)le64_to_int(pgpt_head->partition_entry_lba),
+		le64_to_cpu(pgpt_head->partition_entry_lba),
 		(lbaint_t) (count / GPT_BLOCK_SIZE), pte)
 		!= (count / GPT_BLOCK_SIZE)) {
 
diff --git a/doc/README.gpt b/doc/README.gpt
new file mode 100644
index 0000000..a9c58b4
--- /dev/null
+++ b/doc/README.gpt
@@ -0,0 +1,201 @@
+#
+#  Copyright (C) 2012 Samsung Electronics
+#
+#  Lukasz Majewski <l.majewski@samsung.com>
+#
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+
+
+Glossary:
+========
+- UUID -(Universally Unique Identifier)
+- GUID - (Globally Unique ID)
+- EFI - (Extensible Firmware Interface)
+- UEFI - (Unified EFI) - EFI evolution
+- GPT (GUID Partition Table) - it is the EFI standard part
+- partitions - lists of available partitions (defined at u-boot):
+  ./include/configs/{target}.h
+
+Introduction:
+=============
+This document describes the GPT partition table format and usage of
+the gpt command in u-boot.
+
+
+UUID introduction:
+====================
+
+GPT for marking disks/partitions is using the UUID. It is supposed to be a
+globally unique value. A UUID is a 16-byte (128-bit) number. The number of
+theoretically possible UUIDs is therefore about 3 x 10^38.
+More often UUID is displayed as 32 hexadecimal digits, in 5 groups,
+separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters
+(32 digits and 4 hyphens)
+
+For instance, GUID of Linux data partition: EBD0A0A2-B9E5-4433-87C0-68B6B72699C7
+
+Historically there are 5 methods to generate this number. The oldest one is
+combining machine's MAC address and timer (epoch) value.
+
+Successive versions are using MD5 hash, random numbers and SHA-1 hash. All major
+OSes and programming languages are providing libraries to compute UUID (e.g.
+uuid command line tool).
+
+GPT brief explanation:
+======================
+
+	Layout:
+	-------
+
+	--------------------------------------------------
+	LBA 0          |Protective MBR                   |
+	----------------------------------------------------------
+	LBA 1          |Primary GPT Header               | Primary
+	-------------------------------------------------- GPT
+	LBA 2          |Entry 1|Entry 2| Entry 3| Entry 4|
+	--------------------------------------------------
+	LBA 3          |Entries 5 - 128                  |
+		       |                                 |
+		       |                                 |
+	----------------------------------------------------------
+	LBA 34         |Partition 1                      |
+		       |                                 |
+		       -----------------------------------
+		       |Partition 2                      |
+		       |                                 |
+		       -----------------------------------
+		       |Partition n                      |
+		       |                                 |
+	----------------------------------------------------------
+	LBA -34        |Entry 1|Entry 2| Entry 3| Entry 4| Secondary
+	-------------------------------------------------- (bkp)
+	LBA -33        |Entries 5 - 128                  | GPT
+		       |                                 |
+		       |                                 |
+	LBA -2         |                                 |
+	--------------------------------------------------
+	LBA -1         |Secondary GPT Header             |
+	----------------------------------------------------------
+
+
+For a legacy reasons, GPT's LBA 0 sector has a MBR structure. It is called
+"protective MBR".
+Its first partition entry ID has 0xEE value, and disk software, which is not
+handling the GPT sees it as a storage device without free space.
+
+It is possible to define 128 linearly placed partition entries.
+
+"LBA -1" means the last addressable block (in the mmc subsystem:
+"dev_desc->lba - 1")
+
+Primary/Secondary GPT header:
+----------------------------
+Offset  Size    Description
+
+0       8 B     Signature ("EFI PART", 45 46 49 20 50 41 52 54)
+8       4 B     Revision (For version 1.0, the value is 00 00 01 00)
+12      4 B     Header size (in bytes, usually 5C 00 00 00 meaning 92 bytes)
+16      4 B     CRC32 of header (0 to header size), with this field zeroed
+		during calculation
+20      4 B     Reserved (ZERO);
+24      8 B     Current LBA (location of this header copy)
+32      8 B     Backup LBA (location of the other header copy)
+40      8 B     First usable LBA for partitions (primary partition table last
+		LBA + 1)
+48      8 B     Last usable LBA (secondary partition table first LBA - 1)
+56      16 B    Disk GUID (also referred as UUID on UNIXes)
+72      8 B     Partition entries starting LBA (always 2 in primary copy)
+80      4 B     Number of partition entries
+84      4 B     Size of a partition entry (usually 128)
+88      4 B     CRC32 of partition array
+92      *       Reserved; must be ZERO (420 bytes for a 512-byte LBA)
+
+TOTAL: 512 B
+
+
+
+IMPORTANT:
+
+GPT headers and partition entries are protected by CRC32 (the POSIX CRC32).
+
+Primary GPT header and Secondary GPT header have swapped values of "Current LBA"
+and "Backup LBA" and therefore different CRC32 check-sum.
+
+CRC32 for GPT headers (field "CRC of header") are calculated up till
+"Header size" (92), NOT 512 bytes.
+
+CRC32 for partition entries (field "CRC32 of partition array") is calculated for
+the whole array entry ( Number_of_partition_entries *
+sizeof(partition_entry_size (usually 128)))
+
+Observe, how Secondary GPT is placed in the memory. It is NOT a mirror reflect
+of the Primary.
+
+
+	   Partition Entry Format:
+	   ----------------------
+	   Offset  Size    Description
+
+	   0       16 B    Partition type GUID
+	   16      16 B    Unique partition GUID
+	   32      8  B    First LBA (Little Endian)
+	   40      8  B    Last LBA (inclusive)
+	   48      8  B    Attribute flags [+]
+	   56      72 B    Partition name (text)
+
+	   Attribute flags:
+	   Bit 0  - System partition
+	   Bit 60 - Read-only
+	   Bit 62 - Hidden
+	   Bit 63 - Not mount
+
+
+Creating GPT partitions in U-Boot:
+==============
+
+To restore GUID partition table one needs to:
+1. Define partition layout in the environment.
+   Format of partitions layout:
+     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+	name=kernel,size=60MiB,uuid=...;"
+     or
+     "partitions=uuid_disk=${uuid_gpt_disk};name=${uboot_name},
+	size=${uboot_size},uuid=${uboot_uuid};"
+
+   Fields 'name', 'size' and 'uuid' are mandatory for every partition.
+   The field 'start' is optional.
+
+2. Define 'CONFIG_EFI_PARTITION' and 'CONFIG_CMD_GPT'
+
+2. From u-boot prompt type:
+   gpt write mmc 0 $partitions
+
+
+Useful info:
+============
+
+Two programs, namely: 'fdisk' and 'parted' are recommended to work with GPT
+recovery. Parted is able to handle GUID partitions. Unfortunately the 'fdisk'
+hasn't got such ability.
+Please, pay attention at -l switch for parted.
+
+"uuid" program is recommended to generate UUID string. Moreover it can decode
+(-d switch) passed in UUID string. It can be used to generate partitions UUID
+passed to u-boot environment variables.
diff --git a/doc/README.silent b/doc/README.silent
index a26e3df..70202ce 100644
--- a/doc/README.silent
+++ b/doc/README.silent
@@ -1,9 +1,15 @@
 The config option CONFIG_SILENT_CONSOLE can be used to quiet messages
 on the console.  If the option has been enabled, the output can be
-silenced by setting the environment variable "silent".  The variable
-is latched into the global data at an early stage in the boot process
-so deleting it with "setenv" will not take effect until the system is
-restarted.
+silenced by setting the environment variable "silent".
+
+- CONFIG_SILENT_CONSOLE_UPDATE_ON_SET
+	When the "silent" variable is changed with env set, the change
+	will take effect immediately.
+
+- CONFIG_SILENT_CONSOLE_UPDATE_ON_RELOC
+	Some environments are not available until relocation (e.g. NAND)
+	so this will make the value in the flash env take effect at
+	relocation.
 
 The following actions are taken if "silent" is set at boot time:
 
diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c
index bf64a2a..6653870 100644
--- a/drivers/i2c/designware_i2c.c
+++ b/drivers/i2c/designware_i2c.c
@@ -26,7 +26,12 @@
 #include <asm/arch/hardware.h>
 #include "designware_i2c.h"
 
-static struct i2c_regs *const i2c_regs_p =
+#ifdef CONFIG_I2C_MULTI_BUS
+static unsigned int bus_initialized[CONFIG_SYS_I2C_BUS_MAX];
+static unsigned int current_bus = 0;
+#endif
+
+static struct i2c_regs *i2c_regs_p =
     (struct i2c_regs *)CONFIG_SYS_I2C_BASE;
 
 /*
@@ -39,7 +44,6 @@
 {
 	unsigned int cntl;
 	unsigned int hcnt, lcnt;
-	unsigned int high, low;
 	unsigned int enbl;
 
 	/* to set speed cltr must be disabled */
@@ -47,39 +51,38 @@
 	enbl &= ~IC_ENABLE_0B;
 	writel(enbl, &i2c_regs_p->ic_enable);
 
-
 	cntl = (readl(&i2c_regs_p->ic_con) & (~IC_CON_SPD_MSK));
 
 	switch (i2c_spd) {
 	case IC_SPEED_MODE_MAX:
 		cntl |= IC_CON_SPD_HS;
-		high = MIN_HS_SCL_HIGHTIME;
-		low = MIN_HS_SCL_LOWTIME;
+		hcnt = (IC_CLK * MIN_HS_SCL_HIGHTIME) / NANO_TO_MICRO;
+		writel(hcnt, &i2c_regs_p->ic_hs_scl_hcnt);
+		lcnt = (IC_CLK * MIN_HS_SCL_LOWTIME) / NANO_TO_MICRO;
+		writel(lcnt, &i2c_regs_p->ic_hs_scl_lcnt);
 		break;
 
 	case IC_SPEED_MODE_STANDARD:
 		cntl |= IC_CON_SPD_SS;
-		high = MIN_SS_SCL_HIGHTIME;
-		low = MIN_SS_SCL_LOWTIME;
+		hcnt = (IC_CLK * MIN_SS_SCL_HIGHTIME) / NANO_TO_MICRO;
+		writel(hcnt, &i2c_regs_p->ic_ss_scl_hcnt);
+		lcnt = (IC_CLK * MIN_SS_SCL_LOWTIME) / NANO_TO_MICRO;
+		writel(lcnt, &i2c_regs_p->ic_ss_scl_lcnt);
 		break;
 
 	case IC_SPEED_MODE_FAST:
 	default:
 		cntl |= IC_CON_SPD_FS;
-		high = MIN_FS_SCL_HIGHTIME;
-		low = MIN_FS_SCL_LOWTIME;
+		hcnt = (IC_CLK * MIN_FS_SCL_HIGHTIME) / NANO_TO_MICRO;
+		writel(hcnt, &i2c_regs_p->ic_fs_scl_hcnt);
+		lcnt = (IC_CLK * MIN_FS_SCL_LOWTIME) / NANO_TO_MICRO;
+		writel(lcnt, &i2c_regs_p->ic_fs_scl_lcnt);
 		break;
 	}
 
 	writel(cntl, &i2c_regs_p->ic_con);
 
-	hcnt = (IC_CLK * high) / NANO_TO_MICRO;
-	writel(hcnt, &i2c_regs_p->ic_fs_scl_hcnt);
-
-	lcnt = (IC_CLK * low) / NANO_TO_MICRO;
-	writel(lcnt, &i2c_regs_p->ic_fs_scl_lcnt);
-
-	/* re-enable i2c ctrl back now that speed is set */
+	/* Enable back i2c now speed set */
 	enbl |= IC_ENABLE_0B;
 	writel(enbl, &i2c_regs_p->ic_enable);
 }
@@ -150,6 +153,10 @@
 	enbl = readl(&i2c_regs_p->ic_enable);
 	enbl |= IC_ENABLE_0B;
 	writel(enbl, &i2c_regs_p->ic_enable);
+
+#ifdef CONFIG_I2C_MULTI_BUS
+	bus_initialized[current_bus] = 1;
+#endif
 }
 
 /*
@@ -274,7 +281,10 @@
 
 	start_time_rx = get_timer(0);
 	while (len) {
-		writel(IC_CMD, &i2c_regs_p->ic_cmd_data);
+		if (len == 1)
+			writel(IC_CMD | IC_STOP, &i2c_regs_p->ic_cmd_data);
+		else
+			writel(IC_CMD, &i2c_regs_p->ic_cmd_data);
 
 		if (readl(&i2c_regs_p->ic_status) & IC_STATUS_RFNE) {
 			*buffer++ = (uchar)readl(&i2c_regs_p->ic_cmd_data);
@@ -313,9 +323,11 @@
 	start_time_tx = get_timer(0);
 	while (len) {
 		if (readl(&i2c_regs_p->ic_status) & IC_STATUS_TFNF) {
-			writel(*buffer, &i2c_regs_p->ic_cmd_data);
+			if (--len == 0)
+				writel(*buffer | IC_STOP, &i2c_regs_p->ic_cmd_data);
+			else
+				writel(*buffer, &i2c_regs_p->ic_cmd_data);
 			buffer++;
-			len--;
 			start_time_tx = get_timer(0);
 
 		} else if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) {
@@ -344,3 +356,74 @@
 
 	return ret;
 }
+
+#ifdef CONFIG_I2C_MULTI_BUS
+int i2c_set_bus_num(unsigned int bus)
+{
+	switch (bus) {
+	case 0:
+		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE;
+		break;
+#ifdef CONFIG_SYS_I2C_BASE1
+	case 1:
+		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE1;
+		break;
+#endif
+#ifdef CONFIG_SYS_I2C_BASE2
+	case 2:
+		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE2;
+		break;
+#endif
+#ifdef CONFIG_SYS_I2C_BASE3
+	case 3:
+		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE3;
+		break;
+#endif
+#ifdef CONFIG_SYS_I2C_BASE4
+	case 4:
+		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE4;
+		break;
+#endif
+#ifdef CONFIG_SYS_I2C_BASE5
+	case 5:
+		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE5;
+		break;
+#endif
+#ifdef CONFIG_SYS_I2C_BASE6
+	case 6:
+		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE6;
+		break;
+#endif
+#ifdef CONFIG_SYS_I2C_BASE7
+	case 7:
+		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE7;
+		break;
+#endif
+#ifdef CONFIG_SYS_I2C_BASE8
+	case 8:
+		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE8;
+		break;
+#endif
+#ifdef CONFIG_SYS_I2C_BASE9
+	case 9:
+		i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE9;
+		break;
+#endif
+	default:
+		printf("Bad bus: %d\n", bus);
+		return -1;
+	}
+
+	current_bus = bus;
+
+	if (!bus_initialized[current_bus])
+		i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+	return 0;
+}
+
+int i2c_get_bus_num(void)
+{
+	return current_bus;
+}
+#endif
diff --git a/drivers/i2c/designware_i2c.h b/drivers/i2c/designware_i2c.h
index 03b520e..2faf4a8 100644
--- a/drivers/i2c/designware_i2c.h
+++ b/drivers/i2c/designware_i2c.h
@@ -60,14 +60,16 @@
 	u32 ic_tx_abrt_source;
 };
 
+#if !defined(IC_CLK)
 #define IC_CLK			166
+#endif
 #define NANO_TO_MICRO		1000
 
 /* High and low times in different speed modes (in ns) */
 #define MIN_SS_SCL_HIGHTIME	4000
-#define MIN_SS_SCL_LOWTIME	5000
-#define MIN_FS_SCL_HIGHTIME	800
-#define MIN_FS_SCL_LOWTIME	1700
+#define MIN_SS_SCL_LOWTIME	4700
+#define MIN_FS_SCL_HIGHTIME	600
+#define MIN_FS_SCL_LOWTIME	1300
 #define MIN_HS_SCL_HIGHTIME	60
 #define MIN_HS_SCL_LOWTIME	160
 
@@ -95,6 +97,7 @@
 
 /* i2c data buffer and command register definitions */
 #define IC_CMD			0x0100
+#define IC_STOP			0x0200
 
 /* i2c interrupt status register definitions */
 #define IC_GEN_CALL		0x0800
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c
index 18270b9..a73b10b 100644
--- a/drivers/i2c/mxc_i2c.c
+++ b/drivers/i2c/mxc_i2c.c
@@ -115,7 +115,7 @@
 /*
  * Set I2C Bus speed
  */
-int bus_i2c_set_bus_speed(void *base, int speed)
+static int bus_i2c_set_bus_speed(void *base, int speed)
 {
 	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base;
 	u8 clk_idx = i2c_imx_get_clk(speed);
@@ -133,7 +133,7 @@
 /*
  * Get I2C Speed
  */
-unsigned int bus_i2c_get_bus_speed(void *base)
+static unsigned int bus_i2c_get_bus_speed(void *base)
 {
 	struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base;
 	u8 clk_idx = readb(&i2c_regs->ifdr);
diff --git a/drivers/i2c/mxs_i2c.c b/drivers/i2c/mxs_i2c.c
index 2a193c2..b907f7b 100644
--- a/drivers/i2c/mxs_i2c.c
+++ b/drivers/i2c/mxs_i2c.c
@@ -28,6 +28,7 @@
 
 #include <common.h>
 #include <malloc.h>
+#include <i2c.h>
 #include <asm/errno.h>
 #include <asm/io.h>
 #include <asm/arch/clock.h>
@@ -40,6 +41,7 @@
 {
 	struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE;
 	int ret;
+	int speed = i2c_get_bus_speed();
 
 	ret = mxs_reset_block(&i2c_regs->hw_i2c_ctrl0_reg);
 	if (ret) {
@@ -53,6 +55,8 @@
 		&i2c_regs->hw_i2c_ctrl1_clr);
 
 	writel(I2C_QUEUECTRL_PIO_QUEUE_MODE, &i2c_regs->hw_i2c_queuectrl_set);
+
+	i2c_set_bus_speed(speed);
 }
 
 void mxs_i2c_setup_read(uint8_t chip, int len)
@@ -210,37 +214,65 @@
 	return ret;
 }
 
-void i2c_init(int speed, int slaveadd)
+int i2c_set_bus_speed(unsigned int speed)
 {
 	struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE;
+	/*
+	 * The timing derivation algorithm. There is no documentation for this
+	 * algorithm available, it was derived by using the scope and fiddling
+	 * with constants until the result observed on the scope was good enough
+	 * for 20kHz, 50kHz, 100kHz, 200kHz, 300kHz and 400kHz. It should be
+	 * possible to assume the algorithm works for other frequencies as well.
+	 *
+	 * Note it was necessary to cap the frequency on both ends as it's not
+	 * possible to configure completely arbitrary frequency for the I2C bus
+	 * clock.
+	 */
+	uint32_t clk = mxc_get_clock(MXC_XTAL_CLK);
+	uint32_t base = ((clk / speed) - 38) / 2;
+	uint16_t high_count = base + 3;
+	uint16_t low_count = base - 3;
+	uint16_t rcv_count = (high_count * 3) / 4;
+	uint16_t xmit_count = low_count / 4;
 
-	mxs_i2c_reset();
-
-	switch (speed) {
-	case 100000:
-		writel((0x0078 << I2C_TIMING0_HIGH_COUNT_OFFSET) |
-			(0x0030 << I2C_TIMING0_RCV_COUNT_OFFSET),
-			&i2c_regs->hw_i2c_timing0);
-		writel((0x0080 << I2C_TIMING1_LOW_COUNT_OFFSET) |
-			(0x0030 << I2C_TIMING1_XMIT_COUNT_OFFSET),
-			&i2c_regs->hw_i2c_timing1);
-		break;
-	case 400000:
-		writel((0x000f << I2C_TIMING0_HIGH_COUNT_OFFSET) |
-			(0x0007 << I2C_TIMING0_RCV_COUNT_OFFSET),
-			&i2c_regs->hw_i2c_timing0);
-		writel((0x001f << I2C_TIMING1_LOW_COUNT_OFFSET) |
-			(0x000f << I2C_TIMING1_XMIT_COUNT_OFFSET),
-			&i2c_regs->hw_i2c_timing1);
-		break;
-	default:
-		printf("MXS I2C: Invalid speed selected (%d Hz)\n", speed);
-		return;
+	if (speed > 540000) {
+		printf("MXS I2C: Speed too high (%d Hz)\n", speed);
+		return -EINVAL;
 	}
 
-	writel((0x0015 << I2C_TIMING2_BUS_FREE_OFFSET) |
-		(0x000d << I2C_TIMING2_LEADIN_COUNT_OFFSET),
+	if (speed < 12000) {
+		printf("MXS I2C: Speed too low (%d Hz)\n", speed);
+		return -EINVAL;
+	}
+
+	writel((high_count << 16) | rcv_count, &i2c_regs->hw_i2c_timing0);
+	writel((low_count << 16) | xmit_count, &i2c_regs->hw_i2c_timing1);
+
+	writel((0x0030 << I2C_TIMING2_BUS_FREE_OFFSET) |
+		(0x0030 << I2C_TIMING2_LEADIN_COUNT_OFFSET),
 		&i2c_regs->hw_i2c_timing2);
 
+	return 0;
+}
+
+unsigned int i2c_get_bus_speed(void)
+{
+	struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE;
+	uint32_t clk = mxc_get_clock(MXC_XTAL_CLK);
+	uint32_t timing0;
+
+	timing0 = readl(&i2c_regs->hw_i2c_timing0);
+	/*
+	 * This is a reverse version of the algorithm presented in
+	 * i2c_set_bus_speed(). Please refer there for details.
+	 */
+	return clk / ((((timing0 >> 16) - 3) * 2) + 38);
+}
+
+void i2c_init(int speed, int slaveadd)
+{
+	mxs_i2c_reset();
+	i2c_set_bus_speed(speed);
+
 	return;
 }
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
index 094305f..af454f9 100644
--- a/drivers/i2c/omap24xx_i2c.c
+++ b/drivers/i2c/omap24xx_i2c.c
@@ -179,7 +179,8 @@
 		if (status & I2C_STAT_XRDY) {
 			w = tmpbuf[i++];
 #if !(defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
-	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX))
+	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
+	defined(CONFIG_OMAP54XX))
 			w |= tmpbuf[i++] << 8;
 #endif
 			writew(w, &i2c_base->data);
@@ -209,7 +210,8 @@
 		}
 		if (status & I2C_STAT_RRDY) {
 #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
-	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX)
+	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
+	defined(CONFIG_OMAP54XX)
 			*value = readb(&i2c_base->data);
 #else
 			*value = readw(&i2c_base->data);
@@ -239,7 +241,8 @@
 		stat = readw(&i2c_base->stat);
 		if (stat == I2C_STAT_RRDY) {
 #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
-	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX)
+	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
+	defined(CONFIG_OMAP54XX)
 			readb(&i2c_base->data);
 #else
 			readw(&i2c_base->data);
@@ -289,7 +292,8 @@
 		if (status & I2C_STAT_RRDY) {
 			res = 0;
 #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
-    defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX)
+	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
+	defined(CONFIG_OMAP54XX)
 			readb(&i2c_base->data);
 #else
 			readw(&i2c_base->data);
@@ -376,7 +380,8 @@
 		if (status & I2C_STAT_XRDY) {
 			w = (i < 0) ? tmpbuf[2+i] : buffer[i];
 #if !(defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
-	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX))
+	defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
+	defined(CONFIG_OMAP54XX))
 			w |= ((++i < 0) ? tmpbuf[2+i] : buffer[i]) << 8;
 #endif
 			writew(w, &i2c_base->data);
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c
index 9bc4c7f..90d297a 100644
--- a/drivers/i2c/s3c24x0_i2c.c
+++ b/drivers/i2c/s3c24x0_i2c.c
@@ -27,7 +27,7 @@
  */
 
 #include <common.h>
-#ifdef CONFIG_EXYNOS5
+#if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
 #include <asm/arch/clk.h>
 #include <asm/arch/cpu.h>
 #else
@@ -62,7 +62,7 @@
 
 static unsigned int g_current_bus;	/* Stores Current I2C Bus */
 
-#ifndef CONFIG_EXYNOS5
+#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
 static int GetI2CSDA(void)
 {
 	struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
@@ -121,7 +121,12 @@
 
 static struct s3c24x0_i2c *get_base_i2c(void)
 {
-#ifdef CONFIG_EXYNOS5
+#ifdef CONFIG_EXYNOS4
+	struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)(samsung_get_base_i2c()
+							+ (EXYNOS4_I2C_SPACING
+							* g_current_bus));
+	return i2c;
+#elif defined CONFIG_EXYNOS5
 	struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)(samsung_get_base_i2c()
 							+ (EXYNOS5_I2C_SPACING
 							* g_current_bus));
@@ -134,7 +139,7 @@
 static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)
 {
 	ulong freq, pres = 16, div;
-#ifdef CONFIG_EXYNOS5
+#if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
 	freq = get_i2c_clk();
 #else
 	freq = get_PCLK();
@@ -188,7 +193,7 @@
 void i2c_init(int speed, int slaveadd)
 {
 	struct s3c24x0_i2c *i2c;
-#ifndef CONFIG_EXYNOS5
+#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
 	struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
 #endif
 	int i;
@@ -204,7 +209,7 @@
 		i--;
 	}
 
-#ifndef CONFIG_EXYNOS5
+#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
 	if ((readl(&i2c->iicstat) & I2CSTAT_BSY) || GetI2CSDA() == 0) {
 #ifdef CONFIG_S3C2410
 		ulong old_gpecon = readl(&gpio->gpecon);
@@ -248,7 +253,7 @@
 		writel(old_gpecon, &gpio->pgcon);
 #endif
 	}
-#endif /* #ifndef CONFIG_EXYNOS5 */
+#endif /* #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) */
 	i2c_ch_init(i2c, speed, slaveadd);
 }
 
diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c
index 1595c07..ae3c573 100644
--- a/drivers/i2c/soft_i2c.c
+++ b/drivers/i2c/soft_i2c.c
@@ -30,6 +30,9 @@
 #include <ioports.h>
 #include <asm/io.h>
 #endif
+#if defined(CONFIG_AVR32)
+#include <asm/arch/portmux.h>
+#endif
 #if defined(CONFIG_AT91FAMILY)
 #include <asm/io.h>
 #include <asm/arch/hardware.h>
diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
index f5f43a6..1f8955a 100644
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -22,6 +22,7 @@
  */
 
 #include <common.h>
+#include <environment.h>
 #include <serial.h>
 #include <stdio_dev.h>
 #include <post.h>
@@ -32,6 +33,11 @@
 
 static struct serial_device *serial_devices;
 static struct serial_device *serial_current;
+/*
+ * Table with supported baudrates (defined in config_xyz.h)
+ */
+static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
+#define	N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0]))
 
 /**
  * serial_null() - Void registration routine of a serial driver
@@ -46,6 +52,70 @@
 }
 
 /**
+ * on_baudrate() - Update the actual baudrate when the env var changes
+ *
+ * This will check for a valid baudrate and only apply it if valid.
+ */
+static int on_baudrate(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	int i;
+	int baudrate;
+
+	switch (op) {
+	case env_op_create:
+	case env_op_overwrite:
+		/*
+		 * Switch to new baudrate if new baudrate is supported
+		 */
+		baudrate = simple_strtoul(value, NULL, 10);
+
+		/* Not actually changing */
+		if (gd->baudrate == baudrate)
+			return 0;
+
+		for (i = 0; i < N_BAUDRATES; ++i) {
+			if (baudrate == baudrate_table[i])
+				break;
+		}
+		if (i == N_BAUDRATES) {
+			if ((flags & H_FORCE) == 0)
+				printf("## Baudrate %d bps not supported\n",
+					baudrate);
+			return 1;
+		}
+		if ((flags & H_INTERACTIVE) != 0) {
+			printf("## Switch baudrate to %d"
+				" bps and press ENTER ...\n", baudrate);
+			udelay(50000);
+		}
+
+		gd->baudrate = baudrate;
+#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2)
+		gd->bd->bi_baudrate = baudrate;
+#endif
+
+		serial_setbrg();
+
+		udelay(50000);
+
+		if ((flags & H_INTERACTIVE) != 0)
+			while (1) {
+				if (getc() == '\r')
+					break;
+			}
+
+		return 0;
+	case env_op_delete:
+		printf("## Baudrate may not be deleted\n");
+		return 1;
+	default:
+		return 0;
+	}
+}
+U_BOOT_ENV_CALLBACK(baudrate, on_baudrate);
+
+/**
  * serial_initfunc() - Forward declare of driver registration routine
  * @name:	Name of the real driver registration routine.
  *
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 23c9649..bfedbe4 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -42,10 +42,11 @@
  */
 
 /**
- * Request ownership of a GPIO.
+ * Request a gpio. This should be called before any of the other functions
+ * are used on this gpio.
  *
- * @param gpio	GPIO number
- * @param label	Name given to the GPIO
+ * @param gp	GPIO number
+ * @param label	User label for this GPIO
  * @return 0 if ok, -1 on error
  */
 int gpio_request(unsigned gpio, const char *label);
@@ -93,14 +94,4 @@
  * @return 0 if ok, -1 on error
  */
 int gpio_set_value(unsigned gpio, int value);
-
-/**
- * Request a gpio. This should be called before any of the other functions
- * are used on this gpio.
- *
- * @param gp	GPIO number
- * @param label	User label for this GPIO
- * @return 0 if ok, -1 on error
- */
-int gpio_request(unsigned gpio, const char *label);
 #endif	/* _ASM_GENERIC_GPIO_H_ */
diff --git a/include/command.h b/include/command.h
index 10bc260..476e7cf 100644
--- a/include/command.h
+++ b/include/command.h
@@ -89,10 +89,10 @@
  */
 
 #if defined(CONFIG_CMD_MEMORY)		\
-    || defined(CONFIG_CMD_I2C)		\
-    || defined(CONFIG_CMD_ITEST)	\
-    || defined(CONFIG_CMD_PCI)		\
-    || defined(CONFIG_CMD_PORTIO)
+	|| defined(CONFIG_CMD_I2C)	\
+	|| defined(CONFIG_CMD_ITEST)	\
+	|| defined(CONFIG_CMD_PCI)	\
+	|| defined(CONFIG_CMD_PORTIO)
 #define CMD_DATA_SIZE
 extern int cmd_get_data_size(char* arg, int default_size);
 #endif
diff --git a/include/common.h b/include/common.h
index 5e3c5ee..d0bf1e8 100644
--- a/include/common.h
+++ b/include/common.h
@@ -340,6 +340,11 @@
 char	*getenv	     (const char *);
 int	getenv_f     (const char *name, char *buf, unsigned len);
 ulong getenv_ulong(const char *name, int base, ulong default_val);
+/*
+ * Read an environment variable as a boolean
+ * Return -1 if variable does not exist (default to true)
+ */
+int getenv_yesno(const char *var);
 int	saveenv	     (void);
 int	setenv	     (const char *, const char *);
 int setenv_ulong(const char *varname, ulong value);
diff --git a/include/config_cmd_all.h b/include/config_cmd_all.h
index f434cd0..e82f642 100644
--- a/include/config_cmd_all.h
+++ b/include/config_cmd_all.h
@@ -40,12 +40,15 @@
 #define CONFIG_CMD_FDOS		/* Floppy DOS support		*/
 #define CONFIG_CMD_FLASH	/* flinfo, erase, protect	*/
 #define CONFIG_CMD_FPGA		/* FPGA configuration Support	*/
+#define CONFIG_CMD_GETTIME	/* Get time since boot         */
+#define CONFIG_CMD_HASH		/* calculate hash / digest	*/
 #define CONFIG_CMD_HWFLOW	/* RTS/CTS hw flow control	*/
 #define CONFIG_CMD_I2C		/* I2C serial bus support	*/
 #define CONFIG_CMD_IDE		/* IDE harddisk support		*/
 #define CONFIG_CMD_IMI		/* iminfo			*/
 #define CONFIG_CMD_IMLS		/* List all found images	*/
 #define CONFIG_CMD_IMMAP	/* IMMR dump support		*/
+#define CONFIG_CMD_IO		/* Access to X86 IO space	*/
 #define CONFIG_CMD_IRQ		/* irqinfo			*/
 #define CONFIG_CMD_ITEST	/* Integer (and string) test	*/
 #define CONFIG_CMD_JFFS2	/* JFFS2 Support		*/
@@ -70,6 +73,7 @@
 #define CONFIG_CMD_REGINFO	/* Register dump		*/
 #define CONFIG_CMD_REISER	/* Reiserfs support		*/
 #define CONFIG_CMD_RARP		/* rarpboot support		*/
+#define CONFIG_CMD_READ		/* Read data from partition	*/
 #define CONFIG_CMD_RUN		/* run command in env variable	*/
 #define CONFIG_CMD_SAVEENV	/* saveenv			*/
 #define CONFIG_CMD_SAVES	/* save S record dump		*/
diff --git a/include/configs/omap3_evm.h b/include/configs/omap3_evm.h
index b4d925e..fc6e782 100644
--- a/include/configs/omap3_evm.h
+++ b/include/configs/omap3_evm.h
@@ -95,10 +95,7 @@
 #define CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME	"u-boot.img"
 
 /* Partition tables */
-/* Only need DOS partition support for SPL, currently */
-#ifndef CONFIG_SPL_BUILD
 #define CONFIG_EFI_PARTITION
-#endif
 #define CONFIG_DOS_PARTITION
 
 /* USB
diff --git a/include/configs/smdk5250.h b/include/configs/smdk5250.h
index c0f8622..39a347a 100644
--- a/include/configs/smdk5250.h
+++ b/include/configs/smdk5250.h
@@ -203,6 +203,7 @@
 #define CONFIG_I2C_MULTI_BUS
 #define CONFIG_MAX_I2C_NUM	8
 #define CONFIG_SYS_I2C_SLAVE    0x0
+#define CONFIG_I2C_EDID
 
 /* Ethernet Controllor Driver */
 #ifdef CONFIG_CMD_NET
@@ -215,4 +216,10 @@
 /* Enable devicetree support */
 #define CONFIG_OF_LIBFDT
 
+/* SHA hashing */
+#define CONFIG_CMD_HASH
+#define CONFIG_HASH_VERIFY
+#define CONFIG_SHA1
+#define CONFIG_SHA256
+
 #endif	/* __CONFIG_H */
diff --git a/include/configs/trats.h b/include/configs/trats.h
index 355029e..94ba55e 100644
--- a/include/configs/trats.h
+++ b/include/configs/trats.h
@@ -98,6 +98,7 @@
 #undef CONFIG_CMD_MTDPARTS
 #define CONFIG_CMD_MMC
 #define CONFIG_CMD_DFU
+#define CONFIG_CMD_GPT
 
 /* FAT */
 #define CONFIG_CMD_FAT
@@ -122,6 +123,26 @@
 #define CONFIG_BOOTBLOCK		"10"
 #define CONFIG_ENV_COMMON_BOOT		"${console} ${meminfo}"
 
+/* Tizen - partitions definitions */
+#define PARTS_CSA		"csa-mmc"
+#define PARTS_BOOTLOADER	"u-boot"
+#define PARTS_BOOT		"boot"
+#define PARTS_ROOT		"platform"
+#define PARTS_DATA		"data"
+#define PARTS_CSC		"csc"
+#define PARTS_UMS		"ums"
+
+#define PARTS_DEFAULT \
+	"uuid_disk=${uuid_gpt_disk};" \
+	"name="PARTS_CSA",size=8MiB,uuid=${uuid_gpt_"PARTS_CSA"};" \
+	"name="PARTS_BOOTLOADER",size=60MiB," \
+		"uuid=${uuid_gpt_"PARTS_BOOTLOADER"};" \
+	"name="PARTS_BOOT",size=100MiB,uuid=${uuid_gpt_"PARTS_BOOT"};" \
+	"name="PARTS_ROOT",size=1GiB,uuid=${uuid_gpt_"PARTS_ROOT"};" \
+	"name="PARTS_DATA",size=3GiB,uuid=${uuid_gpt_"PARTS_DATA"};" \
+	"name="PARTS_CSC",size=150MiB,uuid=${uuid_gpt_"PARTS_CSC"};" \
+	"name="PARTS_UMS",size=-,uuid=${uuid_gpt_"PARTS_UMS"}\0" \
+
 #define CONFIG_DFU_ALT \
 	"dfu_alt_info=" \
 	"u-boot mmc 80 400;" \
@@ -171,7 +192,8 @@
 	"mmcbootpart=2\0" \
 	"mmcrootpart=3\0" \
 	"opts=always_resume=1\0" \
-	CONFIG_DFU_ALT
+	"partitions=" PARTS_DEFAULT \
+	CONFIG_DFU_ALT \
 
 /* Miscellaneous configurable options */
 #define CONFIG_SYS_LONGHELP		/* undef to save memory */
@@ -208,6 +230,10 @@
 
 #define CONFIG_DOS_PARTITION
 
+/* GPT */
+#define CONFIG_EFI_PARTITION
+#define CONFIG_PARTITION_UUIDS
+
 #define CONFIG_SYS_INIT_SP_ADDR	(CONFIG_SYS_LOAD_ADDR - GENERATED_GBL_DATA_SIZE)
 #define CONFIG_SYS_CACHELINE_SIZE       32
 
diff --git a/include/edid.h b/include/edid.h
new file mode 100644
index 0000000..4788de9
--- /dev/null
+++ b/include/edid.h
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2012 The Chromium OS Authors.
+ *
+ * (C) Copyright 2010
+ * Petr Stetiar <ynezz@true.cz>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Contains stolen code from ddcprobe project which is:
+ * Copyright (C) Nalin Dahyabhai <bigfun@pobox.com>
+ *
+ */
+
+#ifndef __EDID_H_
+#define __EDID_H_
+
+#include <linux/types.h>
+
+#define GET_BIT(_x, _pos) \
+	(((_x) >> (_pos)) & 1)
+#define GET_BITS(_x, _pos_msb, _pos_lsb) \
+	(((_x) >> (_pos_lsb)) & ((1 << ((_pos_msb) - (_pos_lsb) + 1)) - 1))
+
+/* Aspect ratios used in EDID info. */
+enum edid_aspect {
+	ASPECT_625 = 0,
+	ASPECT_75,
+	ASPECT_8,
+	ASPECT_5625,
+};
+
+/* Detailed timing information used in EDID v1.x */
+struct edid_detailed_timing {
+	unsigned char pixel_clock[2];
+#define EDID_DETAILED_TIMING_PIXEL_CLOCK(_x) \
+	(((((uint32_t)(_x).pixel_clock[1]) << 8) + \
+	 (_x).pixel_clock[0]) * 10000)
+	unsigned char horizontal_active;
+	unsigned char horizontal_blanking;
+	unsigned char horizontal_active_blanking_hi;
+#define EDID_DETAILED_TIMING_HORIZONTAL_ACTIVE(_x) \
+	((GET_BITS((_x).horizontal_active_blanking_hi, 7, 4) << 8) + \
+	 (_x).horizontal_active)
+#define EDID_DETAILED_TIMING_HORIZONTAL_BLANKING(_x) \
+	((GET_BITS((_x).horizontal_active_blanking_hi, 3, 0) << 8) + \
+	 (_x).horizontal_blanking)
+	unsigned char vertical_active;
+	unsigned char vertical_blanking;
+	unsigned char vertical_active_blanking_hi;
+#define EDID_DETAILED_TIMING_VERTICAL_ACTIVE(_x) \
+	((GET_BITS((_x).vertical_active_blanking_hi, 7, 4) << 8) + \
+	 (_x).vertical_active)
+#define EDID_DETAILED_TIMING_VERTICAL_BLANKING(_x) \
+	((GET_BITS((_x).vertical_active_blanking_hi, 3, 0) << 8) + \
+	 (_x).vertical_blanking)
+	unsigned char hsync_offset;
+	unsigned char hsync_pulse_width;
+	unsigned char sync_offset_pulse_width;
+	unsigned char hsync_vsync_offset_pulse_width_hi;
+#define EDID_DETAILED_TIMING_HSYNC_OFFSET(_x) \
+	((GET_BITS((_x).hsync_vsync_offset_pulse_width_hi, 7, 6) << 8) + \
+	 (_x).hsync_offset)
+#define EDID_DETAILED_TIMING_HSYNC_PULSE_WIDTH(_x) \
+	((GET_BITS((_x).hsync_vsync_offset_pulse_width_hi, 5, 4) << 8) + \
+	 (_x).hsync_pulse_width)
+#define EDID_DETAILED_TIMING_VSYNC_OFFSET(_x) \
+	((GET_BITS((_x).hsync_vsync_offset_pulse_width_hi, 3, 2) << 4) + \
+	 GET_BITS((_x).vsync_offset_pulse_width, 7, 4))
+#define EDID_DETAILED_TIMING_VSYNC_PULSE_WIDTH(_x) \
+	((GET_BITS((_x).hsync_vsync_offset_pulse_width_hi, 1, 0) << 4) + \
+	 GET_BITS((_x).vsync_offset_pulse_width, 3, 0))
+	unsigned char himage_size;
+	unsigned char vimage_size;
+	unsigned char himage_vimage_size_hi;
+#define EDID_DETAILED_TIMING_HIMAGE_SIZE(_x) \
+	((GET_BITS((_x).himage_vimage_size_hi, 7, 4) << 8) + (_x).himage_size)
+#define EDID_DETAILED_TIMING_VIMAGE_SIZE(_x) \
+	((GET_BITS((_x).himage_vimage_size_hi, 3, 0) << 8) + (_x).vimage_size)
+	unsigned char hborder;
+	unsigned char vborder;
+	unsigned char flags;
+#define EDID_DETAILED_TIMING_FLAG_INTERLACED(_x) \
+	GET_BIT((_x).flags, 7)
+#define EDID_DETAILED_TIMING_FLAG_STEREO(_x) \
+	GET_BITS((_x).flags, 6, 5)
+#define EDID_DETAILED_TIMING_FLAG_DIGITAL_COMPOSITE(_x) \
+	GET_BITS((_x).flags, 4, 3)
+#define EDID_DETAILED_TIMING_FLAG_POLARITY(_x) \
+	GET_BITS((_x).flags, 2, 1)
+#define EDID_DETAILED_TIMING_FLAG_INTERLEAVED(_x) \
+	GET_BIT((_x).flags, 0)
+} __attribute__ ((__packed__));
+
+enum edid_monitor_descriptor_types {
+	EDID_MONITOR_DESCRIPTOR_SERIAL = 0xff,
+	EDID_MONITOR_DESCRIPTOR_ASCII = 0xfe,
+	EDID_MONITOR_DESCRIPTOR_RANGE = 0xfd,
+	EDID_MONITOR_DESCRIPTOR_NAME = 0xfc,
+};
+
+struct edid_monitor_descriptor {
+	uint16_t zero_flag_1;
+	unsigned char zero_flag_2;
+	unsigned char type;
+	unsigned char zero_flag_3;
+	union {
+		char string[13];
+		struct {
+			unsigned char vertical_min;
+			unsigned char vertical_max;
+			unsigned char horizontal_min;
+			unsigned char horizontal_max;
+			unsigned char pixel_clock_max;
+			unsigned char gtf_data[8];
+		} range_data;
+	} data;
+} __attribute__ ((__packed__));
+
+struct edid1_info {
+	unsigned char header[8];
+	unsigned char manufacturer_name[2];
+#define EDID1_INFO_MANUFACTURER_NAME_ZERO(_x) \
+	GET_BIT(((_x).manufacturer_name[0]), 7)
+#define EDID1_INFO_MANUFACTURER_NAME_CHAR1(_x) \
+	GET_BITS(((_x).manufacturer_name[0]), 6, 2)
+#define EDID1_INFO_MANUFACTURER_NAME_CHAR2(_x) \
+	((GET_BITS(((_x).manufacturer_name[0]), 1, 0) << 3) + \
+	 GET_BITS(((_x).manufacturer_name[1]), 7, 5))
+#define EDID1_INFO_MANUFACTURER_NAME_CHAR3(_x) \
+	GET_BITS(((_x).manufacturer_name[1]), 4, 0)
+	unsigned char product_code[2];
+#define EDID1_INFO_PRODUCT_CODE(_x) \
+	(((uint16_t)(_x).product_code[1] << 8) + (_x).product_code[0])
+	unsigned char serial_number[4];
+#define EDID1_INFO_SERIAL_NUMBER(_x) \
+	(((uint32_t)(_x).serial_number[3] << 24) + \
+	 ((_x).serial_number[2] << 16) + ((_x).serial_number[1] << 8) + \
+	 (_x).serial_number[0])
+	unsigned char week;
+	unsigned char year;
+	unsigned char version;
+	unsigned char revision;
+	unsigned char video_input_definition;
+#define EDID1_INFO_VIDEO_INPUT_DIGITAL(_x) \
+	GET_BIT(((_x).video_input_definition), 7)
+#define EDID1_INFO_VIDEO_INPUT_VOLTAGE_LEVEL(_x) \
+	GET_BITS(((_x).video_input_definition), 6, 5)
+#define EDID1_INFO_VIDEO_INPUT_BLANK_TO_BLACK(_x) \
+	GET_BIT(((_x).video_input_definition), 4)
+#define EDID1_INFO_VIDEO_INPUT_SEPARATE_SYNC(_x) \
+	GET_BIT(((_x).video_input_definition), 3)
+#define EDID1_INFO_VIDEO_INPUT_COMPOSITE_SYNC(_x) \
+	GET_BIT(((_x).video_input_definition), 2)
+#define EDID1_INFO_VIDEO_INPUT_SYNC_ON_GREEN(_x) \
+	GET_BIT(((_x).video_input_definition), 1)
+#define EDID1_INFO_VIDEO_INPUT_SERRATION_V(_x) \
+	GET_BIT(((_x).video_input_definition), 0)
+	unsigned char max_size_horizontal;
+	unsigned char max_size_vertical;
+	unsigned char gamma;
+	unsigned char feature_support;
+#define EDID1_INFO_FEATURE_STANDBY(_x) \
+	GET_BIT(((_x).feature_support), 7)
+#define EDID1_INFO_FEATURE_SUSPEND(_x) \
+	GET_BIT(((_x).feature_support), 6)
+#define EDID1_INFO_FEATURE_ACTIVE_OFF(_x) \
+	GET_BIT(((_x).feature_support), 5)
+#define EDID1_INFO_FEATURE_DISPLAY_TYPE(_x) \
+	GET_BITS(((_x).feature_support), 4, 3)
+#define EDID1_INFO_FEATURE_RGB(_x) \
+	GET_BIT(((_x).feature_support), 2)
+#define EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(_x) \
+	GET_BIT(((_x).feature_support), 1)
+#define EDID1_INFO_FEATURE_DEFAULT_GTF_SUPPORT(_x) \
+	GET_BIT(((_x).feature_support), 0)
+	unsigned char color_characteristics[10];
+	unsigned char established_timings[3];
+#define EDID1_INFO_ESTABLISHED_TIMING_720X400_70(_x) \
+	GET_BIT(((_x).established_timings[0]), 7)
+#define EDID1_INFO_ESTABLISHED_TIMING_720X400_88(_x) \
+	GET_BIT(((_x).established_timings[0]), 6)
+#define EDID1_INFO_ESTABLISHED_TIMING_640X480_60(_x) \
+	GET_BIT(((_x).established_timings[0]), 5)
+#define EDID1_INFO_ESTABLISHED_TIMING_640X480_67(_x) \
+	GET_BIT(((_x).established_timings[0]), 4)
+#define EDID1_INFO_ESTABLISHED_TIMING_640X480_72(_x) \
+	GET_BIT(((_x).established_timings[0]), 3)
+#define EDID1_INFO_ESTABLISHED_TIMING_640X480_75(_x) \
+	GET_BIT(((_x).established_timings[0]), 2)
+#define EDID1_INFO_ESTABLISHED_TIMING_800X600_56(_x) \
+	GET_BIT(((_x).established_timings[0]), 1)
+#define EDID1_INFO_ESTABLISHED_TIMING_800X600_60(_x) \
+	GET_BIT(((_x).established_timings[0]), 0)
+#define EDID1_INFO_ESTABLISHED_TIMING_800X600_72(_x) \
+	GET_BIT(((_x).established_timings[1]), 7)
+#define EDID1_INFO_ESTABLISHED_TIMING_800X600_75(_x) \
+	GET_BIT(((_x).established_timings[1]), 6)
+#define EDID1_INFO_ESTABLISHED_TIMING_832X624_75(_x) \
+	GET_BIT(((_x).established_timings[1]), 5)
+#define EDID1_INFO_ESTABLISHED_TIMING_1024X768_87I(_x) \
+	GET_BIT(((_x).established_timings[1]), 4)
+#define EDID1_INFO_ESTABLISHED_TIMING_1024X768_60(_x) \
+	GET_BIT(((_x).established_timings[1]), 3)
+#define EDID1_INFO_ESTABLISHED_TIMING_1024X768_70(_x) \
+	GET_BIT(((_x).established_timings[1]), 2)
+#define EDID1_INFO_ESTABLISHED_TIMING_1024X768_75(_x) \
+	GET_BIT(((_x).established_timings[1]), 1)
+#define EDID1_INFO_ESTABLISHED_TIMING_1280X1024_75(_x) \
+	GET_BIT(((_x).established_timings[1]), 0)
+#define EDID1_INFO_ESTABLISHED_TIMING_1152X870_75(_x) \
+	GET_BIT(((_x).established_timings[2]), 7)
+	struct {
+		unsigned char xresolution;
+		unsigned char aspect_vfreq;
+	} __attribute__((__packed__)) standard_timings[8];
+#define EDID1_INFO_STANDARD_TIMING_XRESOLUTION(_x, _i) \
+	(((_x).standard_timings[_i]).xresolution)
+#define EDID1_INFO_STANDARD_TIMING_ASPECT(_x, _i) \
+	GET_BITS(((_x).standard_timings[_i].aspect_vfreq), 7, 6)
+#define EDID1_INFO_STANDARD_TIMING_VFREQ(_x, _i) \
+	GET_BITS(((_x).standard_timings[_i].aspect_vfreq), 5, 0)
+	union {
+		unsigned char timing[72];
+		struct edid_monitor_descriptor descriptor[4];
+	} monitor_details;
+	unsigned char extension_flag;
+	unsigned char checksum;
+} __attribute__ ((__packed__));
+
+/**
+ * Print the EDID info.
+ *
+ * @param edid_info	The EDID info to be printed
+ */
+void edid_print_info(struct edid1_info *edid_info);
+
+/**
+ * Check the EDID info.
+ *
+ * @param info  The EDID info to be checked
+ * @return 0 on valid, or -1 on invalid
+ */
+int edid_check_info(struct edid1_info *info);
+
+/**
+ * Get the horizontal and vertical rate ranges of the monitor.
+ *
+ * @param edid	The EDID info
+ * @param hmin	Returns the minimum horizontal rate
+ * @param hmax	Returns the maxium horizontal rate
+ * @param vmin	Returns the minimum vertical rate
+ * @param vmax	Returns the maxium vertical rate
+ * @return 0 on success, or -1 on error
+ */
+int edid_get_ranges(struct edid1_info *edid, unsigned int *hmin,
+		    unsigned int *hmax, unsigned int *vmin,
+		    unsigned int *vmax);
+
+#endif /* __EDID_H_ */
diff --git a/include/env_attr.h b/include/env_attr.h
new file mode 100644
index 0000000..6ef114f
--- /dev/null
+++ b/include/env_attr.h
@@ -0,0 +1,55 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger@ni.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __ENV_ATTR_H__
+#define __ENV_ATTR_H__
+
+#define ENV_ATTR_LIST_DELIM	','
+#define ENV_ATTR_SEP		':'
+
+/*
+ * env_attr_walk takes as input an "attr_list" that takes the form:
+ *	attributes = [^,:\s]*
+ *	entry = name[:attributes]
+ *	list = entry[,list]
+ * It will call the "callback" function with the "name" and attribute as "value"
+ * The callback may return a non-0 to abort the list walk.
+ * This return value will be passed through to the caller.
+ * 0 is returned on success.
+ */
+extern int env_attr_walk(const char *attr_list,
+	int (*callback)(const char *name, const char *value));
+
+/*
+ * env_attr_lookup takes as input an "attr_list" with the same form as above.
+ * It also takes as input a "name" to look for.
+ * If the name is found in the list, it's value is copied into "attributes".
+ * There is no protection on attributes being too small for the value.
+ * It returns -1 if attributes is NULL, 1 if "name" is not found, 2 if
+ * "attr_list" is NULL.
+ * Returns 0 on success.
+ */
+extern int env_attr_lookup(const char *attr_list, const char *name,
+	char *attributes);
+
+#endif /* __ENV_ATTR_H__ */
diff --git a/include/env_callback.h b/include/env_callback.h
new file mode 100644
index 0000000..47fdc6f
--- /dev/null
+++ b/include/env_callback.h
@@ -0,0 +1,75 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger@ni.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __ENV_CALLBACK_H__
+#define __ENV_CALLBACK_H__
+
+#include <env_flags.h>
+#include <linker_lists.h>
+#include <search.h>
+
+#define ENV_CALLBACK_VAR ".callbacks"
+
+/* Board configs can define additional static callback bindings */
+#ifndef CONFIG_ENV_CALLBACK_LIST_STATIC
+#define CONFIG_ENV_CALLBACK_LIST_STATIC
+#endif
+
+#ifdef CONFIG_SILENT_CONSOLE
+#define SILENT_CALLBACK "silent:silent,"
+#else
+#define SILENT_CALLBACK
+#endif
+
+/*
+ * This list of callback bindings is static, but may be overridden by defining
+ * a new association in the ".callbacks" environment variable.
+ */
+#define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \
+	ENV_FLAGS_VAR ":flags," \
+	"baudrate:baudrate," \
+	"bootfile:bootfile," \
+	"loadaddr:loadaddr," \
+	SILENT_CALLBACK \
+	"stdin:console,stdout:console,stderr:console," \
+	CONFIG_ENV_CALLBACK_LIST_STATIC
+
+struct env_clbk_tbl {
+	const char *name;		/* Callback name */
+	int (*callback)(const char *name, const char *value, enum env_op op,
+		int flags);
+};
+
+struct env_clbk_tbl *find_env_callback(const char *);
+void env_callback_init(ENTRY *var_entry);
+
+/*
+ * Define a callback that can be associated with variables.
+ * when associated through the ".callbacks" environment variable, the callback
+ * will be executed any time the variable is inserted, overwritten, or deleted.
+ */
+#define U_BOOT_ENV_CALLBACK(name, callback) \
+	ll_entry_declare(struct env_clbk_tbl, name, env_clbk, env_clbk) = \
+	{#name, callback}
+
+#endif /* __ENV_CALLBACK_H__ */
diff --git a/include/env_default.h b/include/env_default.h
index a1db73a..39c5b7c 100644
--- a/include/env_default.h
+++ b/include/env_default.h
@@ -24,6 +24,8 @@
  * MA 02111-1307 USA
  */
 
+#include <env_callback.h>
+
 #ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
 env_t environment __PPCENV__ = {
 	ENV_CRC,	/* CRC Sum */
@@ -36,6 +38,12 @@
 #else
 const uchar default_environment[] = {
 #endif
+#ifdef	CONFIG_ENV_CALLBACK_LIST_DEFAULT
+	ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"
+#endif
+#ifdef	CONFIG_ENV_FLAGS_LIST_DEFAULT
+	ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0"
+#endif
 #ifdef	CONFIG_BOOTARGS
 	"bootargs="	CONFIG_BOOTARGS			"\0"
 #endif
diff --git a/include/env_flags.h b/include/env_flags.h
new file mode 100644
index 0000000..d1aa144
--- /dev/null
+++ b/include/env_flags.h
@@ -0,0 +1,172 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger@ni.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __ENV_FLAGS_H__
+#define __ENV_FLAGS_H__
+
+enum env_flags_vartype {
+	env_flags_vartype_string,
+	env_flags_vartype_decimal,
+	env_flags_vartype_hex,
+	env_flags_vartype_bool,
+#ifdef CONFIG_CMD_NET
+	env_flags_vartype_ipaddr,
+	env_flags_vartype_macaddr,
+#endif
+	env_flags_vartype_end
+};
+
+enum env_flags_varaccess {
+	env_flags_varaccess_any,
+	env_flags_varaccess_readonly,
+	env_flags_varaccess_writeonce,
+	env_flags_varaccess_changedefault,
+	env_flags_varaccess_end
+};
+
+#define ENV_FLAGS_VAR ".flags"
+#define ENV_FLAGS_ATTR_MAX_LEN 2
+#define ENV_FLAGS_VARTYPE_LOC 0
+#define ENV_FLAGS_VARACCESS_LOC 1
+
+#ifndef CONFIG_ENV_FLAGS_LIST_STATIC
+#define CONFIG_ENV_FLAGS_LIST_STATIC ""
+#endif
+
+#ifdef CONFIG_CMD_NET
+#ifdef CONFIG_ENV_OVERWRITE
+#define ETHADDR_FLAGS "ethaddr:ma,"
+#else
+#ifdef CONFIG_OVERWRITE_ETHADDR_ONCE
+#define ETHADDR_FLAGS "ethaddr:mc,"
+#else
+#define ETHADDR_FLAGS "ethaddr:mo,"
+#endif
+#endif
+#else
+#define ETHADDR_FLAGS ""
+#endif
+
+#ifndef CONFIG_ENV_OVERWRITE
+#define SERIAL_FLAGS "serial#:so,"
+#else
+#define SERIAL_FLAGS ""
+#endif
+
+#define ENV_FLAGS_LIST_STATIC \
+	ETHADDR_FLAGS \
+	SERIAL_FLAGS \
+	CONFIG_ENV_FLAGS_LIST_STATIC
+
+#ifdef CONFIG_CMD_ENV_FLAGS
+/*
+ * Print the whole list of available type flags.
+ */
+void env_flags_print_vartypes(void);
+/*
+ * Print the whole list of available access flags.
+ */
+void env_flags_print_varaccess(void);
+/*
+ * Return the name of the type.
+ */
+const char *env_flags_get_vartype_name(enum env_flags_vartype type);
+/*
+ * Return the name of the access.
+ */
+const char *env_flags_get_varaccess_name(enum env_flags_varaccess access);
+#endif
+
+/*
+ * Parse the flags string from a .flags attribute list into the vartype enum.
+ */
+enum env_flags_vartype env_flags_parse_vartype(const char *flags);
+/*
+ * Parse the flags string from a .flags attribute list into the varaccess enum.
+ */
+enum env_flags_varaccess env_flags_parse_varaccess(const char *flags);
+/*
+ * Parse the binary flags from a hash table entry into the varaccess enum.
+ */
+enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags);
+
+#ifdef USE_HOSTCC
+/*
+ * Look up the type of a variable directly from the .flags var.
+ */
+enum env_flags_vartype env_flags_get_type(const char *name);
+/*
+ * Look up the access of a variable directly from the .flags var.
+ */
+enum env_flags_varaccess env_flags_get_access(const char *name);
+/*
+ * Validate the newval for its type to conform with the requirements defined by
+ * its flags (directly looked at the .flags var).
+ */
+int env_flags_validate_type(const char *name, const char *newval);
+/*
+ * Validate the newval for its access to conform with the requirements defined
+ * by its flags (directly looked at the .flags var).
+ */
+int env_flags_validate_access(const char *name, int check_mask);
+/*
+ * Validate that the proposed access to variable "name" is valid according to
+ * the defined flags for that variable, if any.
+ */
+int env_flags_validate_varaccess(const char *name, int check_mask);
+/*
+ * Validate the parameters passed to "env set" for type compliance
+ */
+int env_flags_validate_env_set_params(int argc, char * const argv[]);
+
+#else /* !USE_HOSTCC */
+
+#include <search.h>
+
+/*
+ * When adding a variable to the environment, initialize the flags for that
+ * variable.
+ */
+void env_flags_init(ENTRY *var_entry);
+
+/*
+ * Validate the newval for to conform with the requirements defined by its flags
+ */
+int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
+	int flag);
+
+#endif /* USE_HOSTCC */
+
+/*
+ * These are the binary flags used in the environment entry->flags variable to
+ * decribe properties of veriables in the table
+ */
+#define ENV_FLAGS_VARTYPE_BIN_MASK			0x00000007
+/* The actual variable type values use the enum value (within the mask) */
+#define ENV_FLAGS_VARACCESS_PREVENT_DELETE		0x00000008
+#define ENV_FLAGS_VARACCESS_PREVENT_CREATE		0x00000010
+#define ENV_FLAGS_VARACCESS_PREVENT_OVERWR		0x00000020
+#define ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR	0x00000040
+#define ENV_FLAGS_VARACCESS_BIN_MASK			0x00000078
+
+#endif /* __ENV_FLAGS_H__ */
diff --git a/include/environment.h b/include/environment.h
index e8ab703..e64b43d 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -164,6 +164,9 @@
 
 #ifndef DO_DEPS_ONLY
 
+#include <env_attr.h>
+#include <env_callback.h>
+#include <env_flags.h>
 #include <search.h>
 
 extern struct hsearch_data env_htab;
@@ -178,6 +181,9 @@
 /* Function that updates CRC of the enironment */
 void env_crc_update(void);
 
+/* Look up the variable from the default environment */
+char *getenv_default(const char *name);
+
 /* [re]set to the default environment */
 void set_default_env(const char *s);
 
@@ -187,15 +193,6 @@
 /* Import from binary representation into hash table */
 int env_import(const char *buf, int check);
 
-/*
- * Check if variable "name" can be changed from oldval to newval,
- * and if so, apply the changes (e.g. baudrate).
- * When (flag & H_FORCE) is set, it does not print out any error
- * message and forces overwriting of write-once variables.
- */
-int env_check_apply(const char *name, const char *oldval,
-			const char *newval, int flag);
-
 #endif /* DO_DEPS_ONLY */
 
 #endif /* _ENVIRONMENT_H_ */
diff --git a/include/exports.h b/include/exports.h
index 63aa4b2..6cf31aa 100644
--- a/include/exports.h
+++ b/include/exports.h
@@ -23,7 +23,7 @@
 int setenv (const char *varname, const char *varvalue);
 long simple_strtol(const char *cp,char **endp,unsigned int base);
 int strcmp(const char * cs,const char * ct);
-int ustrtoul(const char *cp, char **endp, unsigned int base);
+unsigned long ustrtoul(const char *cp, char **endp, unsigned int base);
 #if defined(CONFIG_CMD_I2C)
 int i2c_write (uchar, uint, int , uchar* , int);
 int i2c_read (uchar, uint, int , uchar* , int);
diff --git a/include/hash.h b/include/hash.h
new file mode 100644
index 0000000..34ba558
--- /dev/null
+++ b/include/hash.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2012 The Chromium OS Authors.
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _HASH_H
+#define _HASH_H
+
+#ifdef CONFIG_SHA1SUM_VERIFY
+#define CONFIG_HASH_VERIFY
+#endif
+
+struct hash_algo {
+	const char *name;			/* Name of algorithm */
+	int digest_size;			/* Length of digest */
+	/**
+	 * hash_func_ws: Generic hashing function
+	 *
+	 * This is the generic prototype for a hashing function. We only
+	 * have the watchdog version at present.
+	 *
+	 * @input:	Input buffer
+	 * @ilen:	Input buffer length
+	 * @output:	Checksum result (length depends on algorithm)
+	 * @chunk_sz:	Trigger watchdog after processing this many bytes
+	 */
+	void (*hash_func_ws)(const unsigned char *input, unsigned int ilen,
+		unsigned char *output, unsigned int chunk_sz);
+	int chunk_size;				/* Watchdog chunk size */
+};
+
+/*
+ * Maximum digest size for all algorithms we support. Having this value
+ * avoids a malloc() or C99 local declaration in common/cmd_hash.c.
+ */
+#define HASH_MAX_DIGEST_SIZE	32
+
+/**
+ * hash_command: Process a hash command for a particular algorithm
+ *
+ * This common function is used to implement specific hash commands.
+ *
+ * @algo_name:		Hash algorithm being used
+ * @verify:		Non-zero to enable verify mode
+ * @cmdtp:		Pointer to command table entry
+ * @flag:		Some flags normally 0 (see CMD_FLAG_.. above)
+ * @argc:		Number of arguments (arg 0 must be the command text)
+ * @argv:		Arguments
+ */
+int hash_command(const char *algo_name, int verify, cmd_tbl_t *cmdtp, int flag,
+		 int argc, char * const argv[]);
+
+#endif
diff --git a/include/image.h b/include/image.h
index f54d983..b958b18 100644
--- a/include/image.h
+++ b/include/image.h
@@ -460,7 +460,6 @@
 int image_check_hcrc(const image_header_t *hdr);
 int image_check_dcrc(const image_header_t *hdr);
 #ifndef USE_HOSTCC
-int getenv_yesno(char *var);
 ulong getenv_bootm_low(void);
 phys_size_t getenv_bootm_size(void);
 phys_size_t getenv_bootm_mapsize(void);
diff --git a/include/linux/linux_string.h b/include/linux/linux_string.h
new file mode 100644
index 0000000..192b4c9
--- /dev/null
+++ b/include/linux/linux_string.h
@@ -0,0 +1,8 @@
+#ifndef _LINUX_LINUX_STRING_H_
+#define _LINUX_LINUX_STRING_H_
+
+extern char * skip_spaces(const char *);
+
+extern char *strim(char *);
+
+#endif
diff --git a/include/linux/string.h b/include/linux/string.h
index 9a8cbc2..e9b134d 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -38,8 +38,11 @@
 #ifndef __HAVE_ARCH_STRNCMP
 extern int strncmp(const char *,const char *,__kernel_size_t);
 #endif
-#if 0 /* not used - was: #ifndef __HAVE_ARCH_STRNICMP */
-extern int strnicmp(const char *, const char *, __kernel_size_t);
+#ifndef __HAVE_ARCH_STRCASECMP
+int strcasecmp(const char *s1, const char *s2);
+#endif
+#ifndef __HAVE_ARCH_STRNCASECMP
+extern int strncasecmp(const char *s1, const char *s2, __kernel_size_t len);
 #endif
 #ifndef __HAVE_ARCH_STRCHR
 extern char * strchr(const char *,int);
@@ -47,10 +50,7 @@
 #ifndef __HAVE_ARCH_STRRCHR
 extern char * strrchr(const char *,int);
 #endif
-extern char * skip_spaces(const char *);
-
-extern char *strim(char *);
-
+#include <linux/linux_string.h>
 #ifndef __HAVE_ARCH_STRSTR
 extern char * strstr(const char *,const char *);
 #endif
diff --git a/include/part.h b/include/part.h
index 27ea283..c58a734 100644
--- a/include/part.h
+++ b/include/part.h
@@ -176,10 +176,62 @@
 #endif
 
 #ifdef CONFIG_EFI_PARTITION
+#include <part_efi.h>
 /* disk/part_efi.c */
 int get_partition_info_efi (block_dev_desc_t * dev_desc, int part, disk_partition_t *info);
 void print_part_efi (block_dev_desc_t *dev_desc);
 int   test_part_efi (block_dev_desc_t *dev_desc);
+
+/**
+ * write_gpt_table() - Write the GUID Partition Table to disk
+ *
+ * @param dev_desc - block device descriptor
+ * @param gpt_h - pointer to GPT header representation
+ * @param gpt_e - pointer to GPT partition table entries
+ *
+ * @return - zero on success, otherwise error
+ */
+int write_gpt_table(block_dev_desc_t *dev_desc,
+		  gpt_header *gpt_h, gpt_entry *gpt_e);
+
+/**
+ * gpt_fill_pte(): Fill the GPT partition table entry
+ *
+ * @param gpt_h - GPT header representation
+ * @param gpt_e - GPT partition table entries
+ * @param partitions - list of partitions
+ * @param parts - number of partitions
+ *
+ * @return zero on success
+ */
+int gpt_fill_pte(gpt_header *gpt_h, gpt_entry *gpt_e,
+		disk_partition_t *partitions, int parts);
+
+/**
+ * gpt_fill_header(): Fill the GPT header
+ *
+ * @param dev_desc - block device descriptor
+ * @param gpt_h - GPT header representation
+ * @param str_guid - disk guid string representation
+ * @param parts_count - number of partitions
+ *
+ * @return - error on str_guid conversion error
+ */
+int gpt_fill_header(block_dev_desc_t *dev_desc, gpt_header *gpt_h,
+		char *str_guid, int parts_count);
+
+/**
+ * gpt_restore(): Restore GPT partition table
+ *
+ * @param dev_desc - block device descriptor
+ * @param str_disk_guid - disk GUID
+ * @param partitions - list of partitions
+ * @param parts - number of partitions
+ *
+ * @return zero on success
+ */
+int gpt_restore(block_dev_desc_t *dev_desc, char *str_disk_guid,
+		disk_partition_t *partitions, const int parts_count);
 #endif
 
 #endif /* _PART_H */
diff --git a/disk/part_efi.h b/include/part_efi.h
similarity index 65%
rename from disk/part_efi.h
rename to include/part_efi.h
index 4e28d1d..6de0a32 100644
--- a/disk/part_efi.h
+++ b/include/part_efi.h
@@ -29,6 +29,8 @@
  * http://developer.intel.com/technology/efi/efi.htm
 */
 
+#include <linux/compiler.h>
+
 #ifndef _DISK_PART_EFI_H
 #define _DISK_PART_EFI_H
 
@@ -41,6 +43,8 @@
 #define GPT_HEADER_REVISION_V1 0x00010000
 #define GPT_PRIMARY_PARTITION_TABLE_LBA 1ULL
 #define GPT_ENTRY_NAME "gpt"
+#define GPT_ENTRY_NUMBERS		128
+#define GPT_ENTRY_SIZE			128
 
 #define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \
 	((efi_guid_t) \
@@ -72,73 +76,72 @@
 		0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28)
 
 /* linux/include/efi.h */
-typedef unsigned short efi_char16_t;
+typedef u16 efi_char16_t;
 
 typedef struct {
-	unsigned char b[16];
+	u8 b[16];
 } efi_guid_t;
 
 /* based on linux/include/genhd.h */
 struct partition {
-	unsigned char boot_ind;		/* 0x80 - active */
-	unsigned char head;		/* starting head */
-	unsigned char sector;		/* starting sector */
-	unsigned char cyl;		/* starting cylinder */
-	unsigned char sys_ind;		/* What partition type */
-	unsigned char end_head;		/* end head */
-	unsigned char end_sector;	/* end sector */
-	unsigned char end_cyl;		/* end cylinder */
-	unsigned char start_sect[4];	/* starting sector counting from 0 */
-	unsigned char nr_sects[4];	/* nr of sectors in partition */
-} __attribute__ ((packed));
+	u8 boot_ind;		/* 0x80 - active */
+	u8 head;		/* starting head */
+	u8 sector;		/* starting sector */
+	u8 cyl;			/* starting cylinder */
+	u8 sys_ind;		/* What partition type */
+	u8 end_head;		/* end head */
+	u8 end_sector;		/* end sector */
+	u8 end_cyl;		/* end cylinder */
+	__le32 start_sect;	/* starting sector counting from 0 */
+	__le32 nr_sects;	/* nr of sectors in partition */
+} __packed;
 
 /* based on linux/fs/partitions/efi.h */
 typedef struct _gpt_header {
-	unsigned char signature[8];
-	unsigned char revision[4];
-	unsigned char header_size[4];
-	unsigned char header_crc32[4];
-	unsigned char reserved1[4];
-	unsigned char my_lba[8];
-	unsigned char alternate_lba[8];
-	unsigned char first_usable_lba[8];
-	unsigned char last_usable_lba[8];
+	__le64 signature;
+	__le32 revision;
+	__le32 header_size;
+	__le32 header_crc32;
+	__le32 reserved1;
+	__le64 my_lba;
+	__le64 alternate_lba;
+	__le64 first_usable_lba;
+	__le64 last_usable_lba;
 	efi_guid_t disk_guid;
-	unsigned char partition_entry_lba[8];
-	unsigned char num_partition_entries[4];
-	unsigned char sizeof_partition_entry[4];
-	unsigned char partition_entry_array_crc32[4];
-	unsigned char reserved2[GPT_BLOCK_SIZE - 92];
-} __attribute__ ((packed)) gpt_header;
+	__le64 partition_entry_lba;
+	__le32 num_partition_entries;
+	__le32 sizeof_partition_entry;
+	__le32 partition_entry_array_crc32;
+	u8 reserved2[GPT_BLOCK_SIZE - 92];
+} __packed gpt_header;
 
 typedef union _gpt_entry_attributes {
 	struct {
-		unsigned long long required_to_function:1;
-		unsigned long long no_block_io_protocol:1;
-		unsigned long long legacy_bios_bootable:1;
-		unsigned long long reserved:45;
-		unsigned long long type_guid_specific:16;
+		u64 required_to_function:1;
+		u64 no_block_io_protocol:1;
+		u64 legacy_bios_bootable:1;
+		u64 reserved:45;
+		u64 type_guid_specific:16;
 	} fields;
 	unsigned long long raw;
-} __attribute__ ((packed)) gpt_entry_attributes;
+} __packed gpt_entry_attributes;
 
 #define PARTNAME_SZ	(72 / sizeof(efi_char16_t))
 typedef struct _gpt_entry {
 	efi_guid_t partition_type_guid;
 	efi_guid_t unique_partition_guid;
-	unsigned char starting_lba[8];
-	unsigned char ending_lba[8];
+	__le64 starting_lba;
+	__le64 ending_lba;
 	gpt_entry_attributes attributes;
 	efi_char16_t partition_name[PARTNAME_SZ];
-}
-__attribute__ ((packed)) gpt_entry;
+} __packed gpt_entry;
 
 typedef struct _legacy_mbr {
-	unsigned char boot_code[440];
-	unsigned char unique_mbr_signature[4];
-	unsigned char unknown[2];
+	u8 boot_code[440];
+	__le32 unique_mbr_signature;
+	__le16 unknown;
 	struct partition partition_record[4];
-	unsigned char signature[2];
-} __attribute__ ((packed)) legacy_mbr;
+	__le16 signature;
+} __packed legacy_mbr;
 
 #endif	/* _DISK_PART_EFI_H */
diff --git a/include/search.h b/include/search.h
index 93e1cbc..13d3be6 100644
--- a/include/search.h
+++ b/include/search.h
@@ -32,6 +32,12 @@
 
 #define __set_errno(val) do { errno = val; } while (0)
 
+enum env_op {
+	env_op_create,
+	env_op_delete,
+	env_op_overwrite,
+};
+
 /* Action which shall be performed in the call the hsearch.  */
 typedef enum {
 	FIND,
@@ -41,6 +47,9 @@
 typedef struct entry {
 	const char *key;
 	char *data;
+	int (*callback)(const char *name, const char *value, enum env_op op,
+		int flags);
+	int flags;
 } ENTRY;
 
 /* Opaque type for internal use.  */
@@ -59,21 +68,20 @@
 	unsigned int filled;
 /*
  * Callback function which will check whether the given change for variable
- * "name" from "oldval" to "newval" may be applied or not, and possibly apply
- * such change.
+ * "item" to "newval" may be applied or not, and possibly apply such change.
  * When (flag & H_FORCE) is set, it shall not print out any error message and
  * shall force overwriting of write-once variables.
 .* Must return 0 for approval, 1 for denial.
  */
-	int (*apply)(const char *name, const char *oldval,
-			const char *newval, int flag);
+	int (*change_ok)(const ENTRY *__item, const char *newval, enum env_op,
+		int flag);
 };
 
 /* Create a new hashing table which will at most contain NEL elements.  */
 extern int hcreate_r(size_t __nel, struct hsearch_data *__htab);
 
 /* Destroy current internal hashing table.  */
-extern void hdestroy_r(struct hsearch_data *__htab, int do_apply);
+extern void hdestroy_r(struct hsearch_data *__htab);
 
 /*
  * Search for entry matching ITEM.key in internal hash table.  If
@@ -82,7 +90,7 @@
  * ITEM.data.
  * */
 extern int hsearch_r(ENTRY __item, ACTION __action, ENTRY ** __retval,
-		     struct hsearch_data *__htab);
+		     struct hsearch_data *__htab, int __flag);
 
 /*
  * Search for an entry matching `MATCH'.  Otherwise, Same semantics
@@ -99,10 +107,10 @@
 
 /* Search and delete entry matching ITEM.key in internal hash table. */
 extern int hdelete_r(const char *__key, struct hsearch_data *__htab,
-			int do_apply);
+		     int __flag);
 
 extern ssize_t hexport_r(struct hsearch_data *__htab,
-		     const char __sep, char **__resp, size_t __size,
+		     const char __sep, int __flag, char **__resp, size_t __size,
 		     int argc, char * const argv[]);
 
 /*
@@ -113,10 +121,15 @@
  */
 extern int himport_r(struct hsearch_data *__htab,
 		     const char *__env, size_t __size, const char __sep,
-		     int __flag, int nvars, char * const vars[], int do_apply);
+		     int __flag, int nvars, char * const vars[]);
 
-/* Flags for himport_r() */
-#define	H_NOCLEAR	(1 << 0) /* do not clear hash table before importing */
-#define	H_FORCE		(1 << 1) /* overwrite read-only/write-once variables */
+/* Walk the whole table calling the callback on each element */
+extern int hwalk_r(struct hsearch_data *__htab, int (*callback)(ENTRY *));
+
+/* Flags for himport_r(), hexport_r(), hdelete_r(), and hsearch_r() */
+#define H_NOCLEAR	(1 << 0) /* do not clear hash table before importing */
+#define H_FORCE		(1 << 1) /* overwrite read-only/write-once variables */
+#define H_INTERACTIVE	(1 << 2) /* indicate that an import is user directed */
+#define H_HIDE_DOT	(1 << 3) /* don't print env vars that begin with '.' */
 
 #endif /* search.h */
diff --git a/include/sha1.h b/include/sha1.h
index 734d1fb..da09dab 100644
--- a/include/sha1.h
+++ b/include/sha1.h
@@ -59,7 +59,8 @@
  * \param input    buffer holding the  data
  * \param ilen	   length of the input data
  */
-void sha1_update( sha1_context *ctx, unsigned char *input, int ilen );
+void sha1_update(sha1_context *ctx, const unsigned char *input,
+		 unsigned int ilen);
 
 /**
  * \brief	   SHA-1 final digest
@@ -76,8 +77,8 @@
  * \param ilen	   length of the input data
  * \param output   SHA-1 checksum result
  */
-void sha1_csum( unsigned char *input, int ilen,
-		unsigned char output[20] );
+void sha1_csum(const unsigned char *input, unsigned int ilen,
+		unsigned char *output);
 
 /**
  * \brief	   Output = SHA-1( input buffer ), with watchdog triggering
@@ -87,17 +88,8 @@
  * \param output   SHA-1 checksum result
  * \param chunk_sz watchdog triggering period (in bytes of input processed)
  */
-void sha1_csum_wd (unsigned char *input, int ilen,
-		unsigned char output[20], unsigned int chunk_sz);
-
-/**
- * \brief	   Output = SHA-1( file contents )
- *
- * \param path	   input file name
- * \param output   SHA-1 checksum result
- * \return	   0 if successful, or 1 if fopen failed
- */
-int sha1_file( char *path, unsigned char output[20] );
+void sha1_csum_wd(const unsigned char *input, unsigned int ilen,
+		unsigned char *output, unsigned int chunk_sz);
 
 /**
  * \brief	   Output = HMAC-SHA-1( input buffer, hmac key )
@@ -108,9 +100,9 @@
  * \param ilen	   length of the input data
  * \param output   HMAC-SHA-1 result
  */
-void sha1_hmac( unsigned char *key, int keylen,
-		unsigned char *input, int ilen,
-		unsigned char output[20] );
+void sha1_hmac(const unsigned char *key, int keylen,
+		const unsigned char *input, unsigned int ilen,
+		unsigned char *output);
 
 /**
  * \brief	   Checkup routine
diff --git a/include/sha256.h b/include/sha256.h
index e38ea89..beadab3 100644
--- a/include/sha256.h
+++ b/include/sha256.h
@@ -3,6 +3,9 @@
 
 #define SHA256_SUM_LEN	32
 
+/* Reset watchdog each time we process this many bytes */
+#define CHUNKSZ_SHA256	(64 * 1024)
+
 typedef struct {
 	uint32_t total[2];
 	uint32_t state[8];
@@ -10,7 +13,10 @@
 } sha256_context;
 
 void sha256_starts(sha256_context * ctx);
-void sha256_update(sha256_context * ctx, uint8_t * input, uint32_t length);
+void sha256_update(sha256_context *ctx, const uint8_t *input, uint32_t length);
 void sha256_finish(sha256_context * ctx, uint8_t digest[SHA256_SUM_LEN]);
 
+void sha256_csum_wd(const unsigned char *input, unsigned int ilen,
+		unsigned char *output, unsigned int chunk_sz);
+
 #endif /* _SHA256_H */
diff --git a/lib/Makefile b/lib/Makefile
index f83f6e8..86ca1a6 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -69,6 +69,7 @@
 COBJS-y += crc32.o
 COBJS-y += ctype.o
 COBJS-y += div64.o
+COBJS-y += linux_string.o
 COBJS-y += string.o
 COBJS-y += time.o
 COBJS-$(CONFIG_BOOTP_PXE) += uuid.o
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 94a7b61..07ebfb2 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -54,7 +54,9 @@
 #define	CONFIG_ENV_MAX_ENTRIES 512
 #endif
 
-#include "search.h"
+#include <env_callback.h>
+#include <env_flags.h>
+#include <search.h>
 
 /*
  * [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
@@ -66,12 +68,16 @@
  * Instead the interface of all functions is extended to take an argument
  * which describes the current status.
  */
+
 typedef struct _ENTRY {
 	int used;
 	ENTRY entry;
 } _ENTRY;
 
 
+static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep,
+	int idx);
+
 /*
  * hcreate()
  */
@@ -142,7 +148,7 @@
  * be freed and the local static variable can be marked as not used.
  */
 
-void hdestroy_r(struct hsearch_data *htab, int do_apply)
+void hdestroy_r(struct hsearch_data *htab)
 {
 	int i;
 
@@ -156,10 +162,7 @@
 	for (i = 1; i <= htab->size; ++i) {
 		if (htab->table[i].used > 0) {
 			ENTRY *ep = &htab->table[i].entry;
-			if (do_apply && htab->apply != NULL) {
-				/* deletion is always forced */
-				htab->apply(ep->key, ep->data, NULL, H_FORCE);
-			}
+
 			free((void *)ep->key);
 			free(ep->data);
 		}
@@ -250,14 +253,65 @@
 	return 0;
 }
 
+/*
+ * Compare an existing entry with the desired key, and overwrite if the action
+ * is ENTER.  This is simply a helper function for hsearch_r().
+ */
+static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action,
+	ENTRY **retval, struct hsearch_data *htab, int flag,
+	unsigned int hval, unsigned int idx)
+{
+	if (htab->table[idx].used == hval
+	    && strcmp(item.key, htab->table[idx].entry.key) == 0) {
+		/* Overwrite existing value? */
+		if ((action == ENTER) && (item.data != NULL)) {
+			/* check for permission */
+			if (htab->change_ok != NULL && htab->change_ok(
+			    &htab->table[idx].entry, item.data,
+			    env_op_overwrite, flag)) {
+				debug("change_ok() rejected setting variable "
+					"%s, skipping it!\n", item.key);
+				__set_errno(EPERM);
+				*retval = NULL;
+				return 0;
+			}
+
+			/* If there is a callback, call it */
+			if (htab->table[idx].entry.callback &&
+			    htab->table[idx].entry.callback(item.key,
+			    item.data, env_op_overwrite, flag)) {
+				debug("callback() rejected setting variable "
+					"%s, skipping it!\n", item.key);
+				__set_errno(EINVAL);
+				*retval = NULL;
+				return 0;
+			}
+
+			free(htab->table[idx].entry.data);
+			htab->table[idx].entry.data = strdup(item.data);
+			if (!htab->table[idx].entry.data) {
+				__set_errno(ENOMEM);
+				*retval = NULL;
+				return 0;
+			}
+		}
+		/* return found entry */
+		*retval = &htab->table[idx].entry;
+		return idx;
+	}
+	/* keep searching */
+	return -1;
+}
+
 int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
-	      struct hsearch_data *htab)
+	      struct hsearch_data *htab, int flag)
 {
 	unsigned int hval;
 	unsigned int count;
 	unsigned int len = strlen(item.key);
 	unsigned int idx;
 	unsigned int first_deleted = 0;
+	int ret;
 
 	/* Compute an value for the given string. Perhaps use a better method. */
 	hval = len;
@@ -289,23 +343,10 @@
 		    && !first_deleted)
 			first_deleted = idx;
 
-		if (htab->table[idx].used == hval
-		    && strcmp(item.key, htab->table[idx].entry.key) == 0) {
-			/* Overwrite existing value? */
-			if ((action == ENTER) && (item.data != NULL)) {
-				free(htab->table[idx].entry.data);
-				htab->table[idx].entry.data =
-					strdup(item.data);
-				if (!htab->table[idx].entry.data) {
-					__set_errno(ENOMEM);
-					*retval = NULL;
-					return 0;
-				}
-			}
-			/* return found entry */
-			*retval = &htab->table[idx].entry;
-			return idx;
-		}
+		ret = _compare_and_overwrite_entry(item, action, retval, htab,
+			flag, hval, idx);
+		if (ret != -1)
+			return ret;
 
 		/*
 		 * Second hash function:
@@ -331,23 +372,10 @@
 				break;
 
 			/* If entry is found use it. */
-			if ((htab->table[idx].used == hval)
-			    && strcmp(item.key, htab->table[idx].entry.key) == 0) {
-				/* Overwrite existing value? */
-				if ((action == ENTER) && (item.data != NULL)) {
-					free(htab->table[idx].entry.data);
-					htab->table[idx].entry.data =
-						strdup(item.data);
-					if (!htab->table[idx].entry.data) {
-						__set_errno(ENOMEM);
-						*retval = NULL;
-						return 0;
-					}
-				}
-				/* return found entry */
-				*retval = &htab->table[idx].entry;
-				return idx;
-			}
+			ret = _compare_and_overwrite_entry(item, action, retval,
+				htab, flag, hval, idx);
+			if (ret != -1)
+				return ret;
 		}
 		while (htab->table[idx].used);
 	}
@@ -383,6 +411,34 @@
 
 		++htab->filled;
 
+		/* This is a new entry, so look up a possible callback */
+		env_callback_init(&htab->table[idx].entry);
+		/* Also look for flags */
+		env_flags_init(&htab->table[idx].entry);
+
+		/* check for permission */
+		if (htab->change_ok != NULL && htab->change_ok(
+		    &htab->table[idx].entry, item.data, env_op_create, flag)) {
+			debug("change_ok() rejected setting variable "
+				"%s, skipping it!\n", item.key);
+			_hdelete(item.key, htab, &htab->table[idx].entry, idx);
+			__set_errno(EPERM);
+			*retval = NULL;
+			return 0;
+		}
+
+		/* If there is a callback, call it */
+		if (htab->table[idx].entry.callback &&
+		    htab->table[idx].entry.callback(item.key, item.data,
+		    env_op_create, flag)) {
+			debug("callback() rejected setting variable "
+				"%s, skipping it!\n", item.key);
+			_hdelete(item.key, htab, &htab->table[idx].entry, idx);
+			__set_errno(EINVAL);
+			*retval = NULL;
+			return 0;
+		}
+
 		/* return new entry */
 		*retval = &htab->table[idx].entry;
 		return 1;
@@ -404,7 +460,21 @@
  * do that.
  */
 
-int hdelete_r(const char *key, struct hsearch_data *htab, int do_apply)
+static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep,
+	int idx)
+{
+	/* free used ENTRY */
+	debug("hdelete: DELETING key \"%s\"\n", key);
+	free((void *)ep->key);
+	free(ep->data);
+	ep->callback = NULL;
+	ep->flags = 0;
+	htab->table[idx].used = -1;
+
+	--htab->filled;
+}
+
+int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
 {
 	ENTRY e, *ep;
 	int idx;
@@ -413,20 +483,31 @@
 
 	e.key = (char *)key;
 
-	if ((idx = hsearch_r(e, FIND, &ep, htab)) == 0) {
+	idx = hsearch_r(e, FIND, &ep, htab, 0);
+	if (idx == 0) {
 		__set_errno(ESRCH);
 		return 0;	/* not found */
 	}
 
-	/* free used ENTRY */
-	debug("hdelete: DELETING key \"%s\"\n", key);
-	if (do_apply && htab->apply != NULL)
-		htab->apply(ep->key, ep->data, NULL, H_FORCE);
-	free((void *)ep->key);
-	free(ep->data);
-	htab->table[idx].used = -1;
+	/* Check for permission */
+	if (htab->change_ok != NULL &&
+	    htab->change_ok(ep, NULL, env_op_delete, flag)) {
+		debug("change_ok() rejected deleting variable "
+			"%s, skipping it!\n", key);
+		__set_errno(EPERM);
+		return 0;
+	}
 
-	--htab->filled;
+	/* If there is a callback, call it */
+	if (htab->table[idx].entry.callback &&
+	    htab->table[idx].entry.callback(key, NULL, env_op_delete, flag)) {
+		debug("callback() rejected deleting variable "
+			"%s, skipping it!\n", key);
+		__set_errno(EINVAL);
+		return 0;
+	}
+
+	_hdelete(key, htab, ep, idx);
 
 	return 1;
 }
@@ -482,7 +563,7 @@
 	return (strcmp(e1->key, e2->key));
 }
 
-ssize_t hexport_r(struct hsearch_data *htab, const char sep,
+ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag,
 		 char **resp, size_t size,
 		 int argc, char * const argv[])
 {
@@ -519,6 +600,9 @@
 			if ((argc > 0) && (found == 0))
 				continue;
 
+			if ((flag & H_HIDE_DOT) && ep->key[0] == '.')
+				continue;
+
 			list[n++] = ep;
 
 			totlen += strlen(ep->key) + 2;
@@ -674,7 +758,7 @@
 
 int himport_r(struct hsearch_data *htab,
 		const char *env, size_t size, const char sep, int flag,
-		int nvars, char * const vars[], int do_apply)
+		int nvars, char * const vars[])
 {
 	char *data, *sp, *dp, *name, *value;
 	char *localvars[nvars];
@@ -704,7 +788,7 @@
 		debug("Destroy Hash Table: %p table = %p\n", htab,
 		       htab->table);
 		if (htab->table)
-			hdestroy_r(htab, do_apply);
+			hdestroy_r(htab);
 	}
 
 	/*
@@ -770,7 +854,7 @@
 			if (!drop_var_from_set(name, nvars, localvars))
 				continue;
 
-			if (hdelete_r(name, htab, do_apply) == 0)
+			if (hdelete_r(name, htab, flag) == 0)
 				debug("DELETE ERROR ##############################\n");
 
 			continue;
@@ -794,30 +878,10 @@
 		e.key = name;
 		e.data = value;
 
-		/* if there is an apply function, check what it has to say */
-		if (do_apply && htab->apply != NULL) {
-			debug("searching before calling cb function"
-				" for  %s\n", name);
-			/*
-			 * Search for variable in existing env, so to pass
-			 * its previous value to the apply callback
-			 */
-			hsearch_r(e, FIND, &rv, htab);
-			debug("previous value was %s\n", rv ? rv->data : "");
-			if (htab->apply(name, rv ? rv->data : NULL,
-				value, flag)) {
-				debug("callback function refused to set"
-					" variable %s, skipping it!\n", name);
-				continue;
-			}
-		}
-
-		hsearch_r(e, ENTER, &rv, htab);
-		if (rv == NULL) {
+		hsearch_r(e, ENTER, &rv, htab, flag);
+		if (rv == NULL)
 			printf("himport_r: can't insert \"%s=%s\" into hash table\n",
 				name, value);
-			return 0;
-		}
 
 		debug("INSERT: table %p, filled %d/%d rv %p ==> name=\"%s\" value=\"%s\"\n",
 			htab, htab->filled, htab->size,
@@ -839,7 +903,7 @@
 		 * b) if the variable was not present in current env, we notify
 		 *    it might be a typo
 		 */
-		if (hdelete_r(localvars[i], htab, do_apply) == 0)
+		if (hdelete_r(localvars[i], htab, flag) == 0)
 			printf("WARNING: '%s' neither in running nor in imported env!\n", localvars[i]);
 		else
 			printf("WARNING: '%s' not in imported env, deleting it!\n", localvars[i]);
@@ -848,3 +912,27 @@
 	debug("INSERT: done\n");
 	return 1;		/* everything OK */
 }
+
+/*
+ * hwalk_r()
+ */
+
+/*
+ * Walk all of the entries in the hash, calling the callback for each one.
+ * this allows some generic operation to be performed on each element.
+ */
+int hwalk_r(struct hsearch_data *htab, int (*callback)(ENTRY *))
+{
+	int i;
+	int retval;
+
+	for (i = 1; i <= htab->size; ++i) {
+		if (htab->table[i].used > 0) {
+			retval = callback(&htab->table[i].entry);
+			if (retval)
+				return retval;
+		}
+	}
+
+	return 0;
+}
diff --git a/lib/linux_string.c b/lib/linux_string.c
new file mode 100644
index 0000000..d5a5e08
--- /dev/null
+++ b/lib/linux_string.c
@@ -0,0 +1,51 @@
+/*
+ *  linux/lib/string.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+#ifdef USE_HOSTCC
+#include <stdio.h>
+#endif
+
+#include <linux/ctype.h>
+#include <linux/string.h>
+
+/**
+ * skip_spaces - Removes leading whitespace from @str.
+ * @str: The string to be stripped.
+ *
+ * Returns a pointer to the first non-whitespace character in @str.
+ */
+char *skip_spaces(const char *str)
+{
+	while (isspace(*str))
+		++str;
+	return (char *)str;
+}
+
+/**
+ * strim - Removes leading and trailing whitespace from @s.
+ * @s: The string to be stripped.
+ *
+ * Note that the first trailing whitespace is replaced with a %NUL-terminator
+ * in the given string @s. Returns a pointer to the first non-whitespace
+ * character in @s.
+ */
+char *strim(char *s)
+{
+	size_t size;
+	char *end;
+
+	s = skip_spaces(s);
+	size = strlen(s);
+	if (!size)
+		return s;
+
+	end = s + size - 1;
+	while (end >= s && isspace(*end))
+		end--;
+	*(end + 1) = '\0';
+
+	return s;
+}
diff --git a/lib/sha1.c b/lib/sha1.c
index da5bc16..a121224 100644
--- a/lib/sha1.c
+++ b/lib/sha1.c
@@ -73,7 +73,7 @@
 	ctx->state[4] = 0xC3D2E1F0;
 }
 
-static void sha1_process (sha1_context * ctx, unsigned char data[64])
+static void sha1_process(sha1_context *ctx, const unsigned char data[64])
 {
 	unsigned long temp, W[16], A, B, C, D, E;
 
@@ -230,7 +230,8 @@
 /*
  * SHA-1 process buffer
  */
-void sha1_update (sha1_context * ctx, unsigned char *input, int ilen)
+void sha1_update(sha1_context *ctx, const unsigned char *input,
+		 unsigned int ilen)
 {
 	int fill;
 	unsigned long left;
@@ -305,7 +306,8 @@
 /*
  * Output = SHA-1( input buffer )
  */
-void sha1_csum (unsigned char *input, int ilen, unsigned char output[20])
+void sha1_csum(const unsigned char *input, unsigned int ilen,
+	       unsigned char *output)
 {
 	sha1_context ctx;
 
@@ -318,12 +320,12 @@
  * Output = SHA-1( input buffer ). Trigger the watchdog every 'chunk_sz'
  * bytes of input processed.
  */
-void sha1_csum_wd (unsigned char *input, int ilen, unsigned char output[20],
-			unsigned int chunk_sz)
+void sha1_csum_wd(const unsigned char *input, unsigned int ilen,
+		  unsigned char *output, unsigned int chunk_sz)
 {
 	sha1_context ctx;
 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
-	unsigned char *end, *curr;
+	const unsigned char *end, *curr;
 	int chunk;
 #endif
 
@@ -350,8 +352,9 @@
 /*
  * Output = HMAC-SHA-1( input buffer, hmac key )
  */
-void sha1_hmac (unsigned char *key, int keylen,
-		unsigned char *input, int ilen, unsigned char output[20])
+void sha1_hmac(const unsigned char *key, int keylen,
+	       const unsigned char *input, unsigned int ilen,
+	       unsigned char *output)
 {
 	int i;
 	sha1_context ctx;
diff --git a/lib/sha256.c b/lib/sha256.c
index deb63a4..ab2db48 100644
--- a/lib/sha256.c
+++ b/lib/sha256.c
@@ -60,7 +60,7 @@
 	ctx->state[7] = 0x5BE0CD19;
 }
 
-void sha256_process(sha256_context * ctx, uint8_t data[64])
+static void sha256_process(sha256_context *ctx, const uint8_t data[64])
 {
 	uint32_t temp1, temp2;
 	uint32_t W[64];
@@ -191,7 +191,7 @@
 	ctx->state[7] += H;
 }
 
-void sha256_update(sha256_context * ctx, uint8_t * input, uint32_t length)
+void sha256_update(sha256_context *ctx, const uint8_t *input, uint32_t length)
 {
 	uint32_t left, fill;
 
@@ -260,3 +260,36 @@
 	PUT_UINT32_BE(ctx->state[6], digest, 24);
 	PUT_UINT32_BE(ctx->state[7], digest, 28);
 }
+
+/*
+ * Output = SHA-256( input buffer ). Trigger the watchdog every 'chunk_sz'
+ * bytes of input processed.
+ */
+void sha256_csum_wd(const unsigned char *input, unsigned int ilen,
+		unsigned char *output, unsigned int chunk_sz)
+{
+	sha256_context ctx;
+#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
+	unsigned char *end, *curr;
+	int chunk;
+#endif
+
+	sha256_starts(&ctx);
+
+#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
+	curr = input;
+	end = input + ilen;
+	while (curr < end) {
+		chunk = end - curr;
+		if (chunk > chunk_sz)
+			chunk = chunk_sz;
+		sha256_update(&ctx, curr, chunk);
+		curr += chunk;
+		WATCHDOG_RESET();
+	}
+#else
+	sha256_update(&ctx, input, ilen);
+#endif
+
+	sha256_finish(&ctx, output);
+}
diff --git a/lib/string.c b/lib/string.c
index c3ad055..09dfae0 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -21,14 +21,13 @@
 #include <malloc.h>
 
 
-#if 0 /* not used - was: #ifndef __HAVE_ARCH_STRNICMP */
 /**
- * strnicmp - Case insensitive, length-limited string comparison
+ * strncasecmp - Case insensitive, length-limited string comparison
  * @s1: One string
  * @s2: The other string
  * @len: the maximum number of characters to compare
  */
-int strnicmp(const char *s1, const char *s2, size_t len)
+int strncasecmp(const char *s1, const char *s2, size_t len)
 {
 	/* Yes, Virginia, it had better be unsigned */
 	unsigned char c1, c2;
@@ -52,7 +51,16 @@
 	}
 	return (int)c1 - (int)c2;
 }
-#endif
+
+/**
+ * strcasecmp - Case insensitive string comparison
+ * @s1: One string
+ * @s2: The other string
+ */
+int strcasecmp(const char *s1, const char *s2)
+{
+	return strncasecmp(s1, s2, -1U);
+}
 
 char * ___strtok;
 
@@ -214,45 +222,6 @@
 }
 #endif
 
-
-/**
- * skip_spaces - Removes leading whitespace from @str.
- * @str: The string to be stripped.
- *
- * Returns a pointer to the first non-whitespace character in @str.
- */
-char *skip_spaces(const char *str)
-{
-	while (isspace(*str))
-		++str;
-	return (char *)str;
-}
-
-/**
- * strim - Removes leading and trailing whitespace from @s.
- * @s: The string to be stripped.
- *
- * Note that the first trailing whitespace is replaced with a %NUL-terminator
- * in the given string @s. Returns a pointer to the first non-whitespace
- * character in @s.
- */
-char *strim(char *s)
-{
-	size_t size;
-	char *end;
-
-	s = skip_spaces(s);
-	size = strlen(s);
-	if (!size)
-		return s;
-
-	end = s + size - 1;
-	while (end >= s && isspace(*end))
-		end--;
-	*(end + 1) = '\0';
-
-	return s;
-}
 #ifndef __HAVE_ARCH_STRLEN
 /**
  * strlen - Find the length of a string
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index b7a79c0..3c432f8 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -103,7 +103,7 @@
 	return simple_strtoul(cp, endp, base);
 }
 
-int ustrtoul(const char *cp, char **endp, unsigned int base)
+unsigned long ustrtoul(const char *cp, char **endp, unsigned int base)
 {
 	unsigned long result = simple_strtoul(cp, endp, base);
 	switch (**endp) {
diff --git a/net/net.c b/net/net.c
index 82c4cc9..a40cde1 100644
--- a/net/net.c
+++ b/net/net.c
@@ -82,6 +82,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <environment.h>
 #include <net.h>
 #if defined(CONFIG_STATUS_LED)
 #include <miiphy.h>
@@ -208,32 +209,46 @@
 
 /**********************************************************************/
 
+static int on_bootfile(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	switch (op) {
+	case env_op_create:
+	case env_op_overwrite:
+		copy_filename(BootFile, value, sizeof(BootFile));
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(bootfile, on_bootfile);
+
 /*
  * Check if autoload is enabled. If so, use either NFS or TFTP to download
  * the boot file.
  */
 void net_auto_load(void)
 {
+#if defined(CONFIG_CMD_NFS)
 	const char *s = getenv("autoload");
 
-	if (s != NULL) {
-		if (*s == 'n') {
-			/*
-			 * Just use BOOTP/RARP to configure system;
-			 * Do not use TFTP to load the bootfile.
-			 */
-			net_set_state(NETLOOP_SUCCESS);
-			return;
-		}
-#if defined(CONFIG_CMD_NFS)
-		if (strcmp(s, "NFS") == 0) {
-			/*
-			 * Use NFS to load the bootfile.
-			 */
-			NfsStart();
-			return;
-		}
+	if (s != NULL && strcmp(s, "NFS") == 0) {
+		/*
+		 * Use NFS to load the bootfile.
+		 */
+		NfsStart();
+		return;
+	}
 #endif
+	if (getenv_yesno("autoload") == 0) {
+		/*
+		 * Just use BOOTP/RARP to configure system;
+		 * Do not use TFTP to load the bootfile.
+		 */
+		net_set_state(NETLOOP_SUCCESS);
+		return;
 	}
 	TftpStart(TFTPGET);
 }
diff --git a/tools/env/Makefile b/tools/env/Makefile
index ab73c8c..0e798e0 100644
--- a/tools/env/Makefile
+++ b/tools/env/Makefile
@@ -24,12 +24,15 @@
 include $(TOPDIR)/config.mk
 
 HOSTSRCS := $(SRCTREE)/lib/crc32.c  fw_env.c  fw_env_main.c
+HOSTSRCS += $(SRCTREE)/lib/ctype.c $(SRCTREE)/lib/linux_string.c
+HOSTSRCS += $(SRCTREE)/common/env_attr.c $(SRCTREE)/common/env_flags.c
 HEADERS	:= fw_env.h $(OBJTREE)/include/config.h
 
 # Compile for a hosted environment on the target
 HOSTCPPFLAGS  = -idirafter $(SRCTREE)/include \
 		-idirafter $(OBJTREE)/include2 \
 		-idirafter $(OBJTREE)/include \
+		-idirafter $(SRCTREE)/tools/env \
 		-DUSE_HOSTCC \
 		-DTEXT_BASE=$(TEXT_BASE)
 
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index 9b023e8..90c7a5d 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -25,6 +25,7 @@
  */
 
 #include <errno.h>
+#include <env_flags.h>
 #include <fcntl.h>
 #include <linux/stringify.h>
 #include <stdio.h>
@@ -181,6 +182,32 @@
 }
 
 /*
+ * Search the default environment for a variable.
+ * Return the value, if found, or NULL, if not found.
+ */
+char *fw_getdefenv(char *name)
+{
+	char *env, *nxt;
+
+	for (env = default_environment; *env; env = nxt + 1) {
+		char *val;
+
+		for (nxt = env; *nxt; ++nxt) {
+			if (nxt >= &default_environment[ENV_SIZE]) {
+				fprintf(stderr, "## Error: "
+					"default environment not terminated\n");
+				return NULL;
+			}
+		}
+		val = envmatch(name, env);
+		if (!val)
+			continue;
+		return val;
+	}
+	return NULL;
+}
+
+/*
  * Print the current definition of one, or more, or all
  * environment variables
  */
@@ -281,6 +308,7 @@
 	int len;
 	char *env, *nxt;
 	char *oldval = NULL;
+	int deleting, creating, overwriting;
 
 	/*
 	 * search if variable with this name already exists
@@ -298,27 +326,49 @@
 			break;
 	}
 
-	/*
-	 * Delete any existing definition
-	 */
-	if (oldval) {
-#ifndef CONFIG_ENV_OVERWRITE
-		/*
-		 * Ethernet Address and serial# can be set only once
-		 */
-		if (
-		    (strcmp(name, "serial#") == 0) ||
-		    ((strcmp(name, "ethaddr") == 0)
-#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)
-		    && (strcmp(oldval, __stringify(CONFIG_ETHADDR)) != 0)
-#endif /* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */
-		   ) ) {
-			fprintf (stderr, "Can't overwrite \"%s\"\n", name);
+	deleting = (oldval && !(value && strlen(value)));
+	creating = (!oldval && (value && strlen(value)));
+	overwriting = (oldval && (value && strlen(value)));
+
+	/* check for permission */
+	if (deleting) {
+		if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_DELETE)) {
+			printf("Can't delete \"%s\"\n", name);
 			errno = EROFS;
 			return -1;
 		}
-#endif /* CONFIG_ENV_OVERWRITE */
+	} else if (overwriting) {
+		if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_OVERWR)) {
+			printf("Can't overwrite \"%s\"\n", name);
+			errno = EROFS;
+			return -1;
+		} else if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR)) {
+			const char *defval = fw_getdefenv(name);
 
+			if (defval == NULL)
+				defval = "";
+			if (strcmp(oldval, defval)
+			    != 0) {
+				printf("Can't overwrite \"%s\"\n", name);
+				errno = EROFS;
+				return -1;
+			}
+		}
+	} else if (creating) {
+		if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_CREATE)) {
+			printf("Can't create \"%s\"\n", name);
+			errno = EROFS;
+			return -1;
+		}
+	} else
+		/* Nothing to do */
+		return 0;
+
+	if (deleting || overwriting) {
 		if (*++nxt == '\0') {
 			*env = '\0';
 		} else {
@@ -395,6 +445,9 @@
 
 	name = argv[1];
 
+	if (env_flags_validate_env_set_params(argc, argv) < 0)
+		return 1;
+
 	len = 0;
 	for (i = 2; i < argc; ++i) {
 		char *val = argv[i];
@@ -516,6 +569,11 @@
 			name, val ? val : " removed");
 #endif
 
+		if (env_flags_validate_type(name, val) < 0) {
+			ret = -1;
+			break;
+		}
+
 		/*
 		 * If there is an error setting a variable,
 		 * try to save the environment and returns an error
diff --git a/tools/fit_image.c b/tools/fit_image.c
index ef9ffee..76bbba1 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -80,7 +80,7 @@
 	}
 	sprintf (tmpfile, "%s%s", params->imagefile, MKIMAGE_TMPFILE_SUFFIX);
 
-	/* dtc -I dts -O -p 200 datafile > tmpfile */
+	/* dtc -I dts -O dtb -p 500 datafile > tmpfile */
 	sprintf (cmd, "%s %s %s > %s",
 		MKIMAGE_DTC, params->dtc, params->datafile, tmpfile);
 	debug ("Trying to execute \"%s\"\n", cmd);