Merge branch 'master' of git://www.denx.de/git/u-boot-avr32
diff --git a/board/cm5200/cm5200.c b/board/cm5200/cm5200.c
index 4a86d3c..79fb71d 100644
--- a/board/cm5200/cm5200.c
+++ b/board/cm5200/cm5200.c
@@ -263,7 +263,6 @@
 {
 	int len, ret, nodeoffset = 0;
 	char module_name[MODULE_NAME_MAXLEN] = {0};
-	ulong memory_data[2] = {0};
 
 	compose_module_name(hw_id, module_name);
 	len = strlen(module_name) + 1;
@@ -273,22 +272,12 @@
 	printf("ft_blob_update(): cannot set /model property err:%s\n",
 		fdt_strerror(ret));
 
-	memory_data[0] = cpu_to_be32(bd->bi_memstart);
-	memory_data[1] = cpu_to_be32(bd->bi_memsize);
+	ret = fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
 
-	nodeoffset = fdt_path_offset (blob, "/memory");
-	if (nodeoffset >= 0) {
-		ret = fdt_setprop(blob, nodeoffset, "reg", memory_data,
-					sizeof(memory_data));
-	if (ret < 0)
+	if (ret < 0) {
 		printf("ft_blob_update): cannot set /memory/reg "
 			"property err:%s\n", fdt_strerror(ret));
 	}
-	else {
-		/* memory node is required in dts */
-		printf("ft_blob_update(): cannot find /memory node "
-		"err:%s\n", fdt_strerror(nodeoffset));
-	}
 }
 #endif /* defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT) */
 
diff --git a/board/ids8247/ids8247.c b/board/ids8247/ids8247.c
index b05424d..7176770 100644
--- a/board/ids8247/ids8247.c
+++ b/board/ids8247/ids8247.c
@@ -329,25 +329,14 @@
  */
 void ft_blob_update(void *blob, bd_t *bd)
 {
-	int ret, nodeoffset = 0;
-	ulong memory_data[2] = {0};
+	int ret;
 
-	memory_data[0] = cpu_to_be32(bd->bi_memstart);
-	memory_data[1] = cpu_to_be32(bd->bi_memsize);
+	ret = fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
 
-	nodeoffset = fdt_find_node_by_path (blob, "/memory");
-	if (nodeoffset >= 0) {
-		ret = fdt_setprop(blob, nodeoffset, "reg", memory_data,
-					sizeof(memory_data));
-	if (ret < 0)
+	if (ret < 0) {
 		printf("ft_blob_update): cannot set /memory/reg "
 			"property err:%s\n", fdt_strerror(ret));
 	}
-	else {
-		/* memory node is required in dts */
-		printf("ft_blob_update(): cannot find /memory node "
-		"err:%s\n", fdt_strerror(nodeoffset));
-	}
 }
 
 void ft_board_setup(void *blob, bd_t *bd)
diff --git a/common/Makefile b/common/Makefile
index ace8cc7..7be89a4 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -55,7 +55,7 @@
 COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o
 COBJS-$(CONFIG_CMD_FAT) += cmd_fat.o
 COBJS-y += cmd_fdc.o
-COBJS-$(CONFIG_OF_LIBFDT) += cmd_fdt.o
+COBJS-$(CONFIG_OF_LIBFDT) += cmd_fdt.o fdt_support.o
 COBJS-$(CONFIG_CMD_FDOS) += cmd_fdos.o
 COBJS-$(CONFIG_CMD_FLASH) += cmd_flash.o
 ifdef CONFIG_FPGA
@@ -105,7 +105,6 @@
 COBJS-y += env_nvram.o
 COBJS-y += env_nowhere.o
 COBJS-y += exports.o
-COBJS-y += fdt_support.o
 COBJS-y += flash.o
 COBJS-y += fpga.o
 COBJS-y += ft_build.o
diff --git a/common/cmd_fdt.c b/common/cmd_fdt.c
index 629c9b4..4639126 100644
--- a/common/cmd_fdt.c
+++ b/common/cmd_fdt.c
@@ -588,7 +588,7 @@
 			printf("%s %s\n", pathp, prop);
 			return 0;
 		} else if (len > 0) {
-			printf("%s=", prop);
+			printf("%s = ", prop);
 			print_data (nodep, len);
 			printf("\n");
 			return 0;
@@ -649,7 +649,7 @@
 						pathp);
 			} else {
 				if (level <= depth) {
-					printf("%s%s=",
+					printf("%s%s = ",
 						&tabs[MAX_LEVEL - level],
 						pathp);
 					print_data (nodep, len);
diff --git a/common/fdt_support.c b/common/fdt_support.c
index c67bb3d..b5ee6e9 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -24,13 +24,11 @@
 #include <common.h>
 #include <linux/ctype.h>
 #include <linux/types.h>
-
-#ifdef CONFIG_OF_LIBFDT
-
 #include <asm/global_data.h>
 #include <fdt.h>
 #include <libfdt.h>
 #include <fdt_support.h>
+#include <exports.h>
 
 /*
  * Global data (for the gd->bd)
@@ -70,6 +68,43 @@
 	return fdt_setprop(fdt, nodeoff, prop, val, len);
 }
 
+#ifdef CONFIG_OF_STDOUT_VIA_ALIAS
+static int fdt_fixup_stdout(void *fdt, int choosenoff)
+{
+	int err = 0;
+#ifdef CONFIG_CONS_INDEX
+	int node;
+	char sername[9] = { 0 };
+	const char *path;
+
+	sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1);
+
+	err = node = fdt_path_offset(fdt, "/aliases");
+	if (node >= 0) {
+		int len;
+		path = fdt_getprop(fdt, node, sername, &len);
+		if (path) {
+			char *p = malloc(len);
+			err = -FDT_ERR_NOSPACE;
+			if (p) {
+				memcpy(p, path, len);
+				err = fdt_setprop(fdt, choosenoff,
+					"linux,stdout-path", p, len);
+				free(p);
+			}
+		} else {
+			err = len;
+		}
+	}
+#endif
+	if (err < 0)
+		printf("WARNING: could not set linux,stdout-path %s.\n",
+				fdt_strerror(err));
+
+	return err;
+}
+#endif
+
 int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force)
 {
 	int   nodeoffset;
@@ -160,6 +195,11 @@
 			printf("WARNING: could not set linux,initrd-end %s.\n",
 				fdt_strerror(err));
 	}
+
+#ifdef CONFIG_OF_STDOUT_VIA_ALIAS
+	err = fdt_fixup_stdout(fdt, nodeoffset);
+#endif
+
 #ifdef OF_STDOUT_PATH
 	err = fdt_setprop(fdt, nodeoffset,
 		"linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1);
@@ -441,6 +481,87 @@
 	do_fixup_by_compat(fdt, compat, prop, &val, 4, create);
 }
 
+int fdt_fixup_memory(void *blob, u64 start, u64 size)
+{
+	int err, nodeoffset, len = 0;
+	u8 tmp[16];
+	const u32 *addrcell, *sizecell;
+
+	err = fdt_check_header(blob);
+	if (err < 0) {
+		printf("%s: %s\n", __FUNCTION__, fdt_strerror(err));
+		return err;
+	}
+
+	/* update, or add and update /memory node */
+	nodeoffset = fdt_path_offset(blob, "/memory");
+	if (nodeoffset < 0) {
+		nodeoffset = fdt_add_subnode(blob, 0, "memory");
+		if (nodeoffset < 0)
+			printf("WARNING: could not create /memory: %s.\n",
+					fdt_strerror(nodeoffset));
+		return nodeoffset;
+	}
+	err = fdt_setprop(blob, nodeoffset, "device_type", "memory",
+			sizeof("memory"));
+	if (err < 0) {
+		printf("WARNING: could not set %s %s.\n", "device_type",
+				fdt_strerror(err));
+		return err;
+	}
+
+	addrcell = fdt_getprop(blob, 0, "#address-cells", NULL);
+	/* use shifts and mask to ensure endianness */
+	if ((addrcell) && (*addrcell == 2)) {
+		tmp[0] = (start >> 56) & 0xff;
+		tmp[1] = (start >> 48) & 0xff;
+		tmp[2] = (start >> 40) & 0xff;
+		tmp[3] = (start >> 32) & 0xff;
+		tmp[4] = (start >> 24) & 0xff;
+		tmp[5] = (start >> 16) & 0xff;
+		tmp[6] = (start >>  8) & 0xff;
+		tmp[7] = (start      ) & 0xff;
+		len = 8;
+	} else {
+		tmp[0] = (start >> 24) & 0xff;
+		tmp[1] = (start >> 16) & 0xff;
+		tmp[2] = (start >>  8) & 0xff;
+		tmp[3] = (start      ) & 0xff;
+		len = 4;
+	}
+
+	sizecell = fdt_getprop(blob, 0, "#size-cells", NULL);
+	/* use shifts and mask to ensure endianness */
+	if ((sizecell) && (*sizecell == 2)) {
+		tmp[0+len] = (size >> 56) & 0xff;
+		tmp[1+len] = (size >> 48) & 0xff;
+		tmp[2+len] = (size >> 40) & 0xff;
+		tmp[3+len] = (size >> 32) & 0xff;
+		tmp[4+len] = (size >> 24) & 0xff;
+		tmp[5+len] = (size >> 16) & 0xff;
+		tmp[6+len] = (size >>  8) & 0xff;
+		tmp[7+len] = (size      ) & 0xff;
+		len += 8;
+	} else {
+		tmp[0+len] = (size >> 24) & 0xff;
+		tmp[1+len] = (size >> 16) & 0xff;
+		tmp[2+len] = (size >>  8) & 0xff;
+		tmp[3+len] = (size      ) & 0xff;
+		len += 4;
+	}
+
+	err = fdt_setprop(blob, nodeoffset, "reg", tmp, len);
+	if (err < 0) {
+		printf("WARNING: could not set %s %s.\n",
+				"reg", fdt_strerror(err));
+		return err;
+	}
+	return 0;
+}
+
+#if defined(CONFIG_HAS_ETH0) || defined(CONFIG_HAS_ETH1) ||\
+    defined(CONFIG_HAS_ETH2) || defined(CONFIG_HAS_ETH3)
+
 void fdt_fixup_ethernet(void *fdt, bd_t *bd)
 {
 	int node;
@@ -486,5 +607,4 @@
 #endif
 	}
 }
-
-#endif /* CONFIG_OF_LIBFDT */
+#endif
diff --git a/cpu/mpc83xx/cpu.c b/cpu/mpc83xx/cpu.c
index b2c35d3..f1ea17d 100644
--- a/cpu/mpc83xx/cpu.c
+++ b/cpu/mpc83xx/cpu.c
@@ -35,6 +35,7 @@
 #include <ft_build.h>
 #elif defined(CONFIG_OF_LIBFDT)
 #include <libfdt.h>
+#include <fdt_support.h>
 #endif
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -526,7 +527,6 @@
 	int nodeoffset;
 	int err;
 	int j;
-	int tmp[2];
 
 	for (j = 0; j < (sizeof(fixup_props) / sizeof(fixup_props[0])); j++) {
 		nodeoffset = fdt_path_offset(blob, fixup_props[j].node);
@@ -543,21 +543,7 @@
 		}
 	}
 
-	/* update, or add and update /memory node */
-	nodeoffset = fdt_path_offset(blob, "/memory");
-	if (nodeoffset < 0) {
-		nodeoffset = fdt_add_subnode(blob, 0, "memory");
-		if (nodeoffset < 0)
-			debug("failed to add /memory node: %s\n",
-			      fdt_strerror(nodeoffset));
-	}
-	if (nodeoffset >= 0) {
-		fdt_setprop(blob, nodeoffset, "device_type",
-			    "memory", sizeof("memory"));
-		tmp[0] = cpu_to_be32(bd->bi_memstart);
-		tmp[1] = cpu_to_be32(bd->bi_memsize);
-		fdt_setprop(blob, nodeoffset, "reg", tmp, sizeof(tmp));
-	}
+	fdt_fixup_memory(blob, (u64)bd->bi_memstart, (u64)bd->bi_memsize);
 }
 #elif defined(CONFIG_OF_FLAT_TREE)
 void
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 95c5e02..952e919 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -29,6 +29,7 @@
 COBJS-y += cfi_flash.o
 COBJS-y += dataflash.o
 COBJS-y += mw_eeprom.o
+COBJS-$(CONFIG_FLASH_CFI_LEGACY) += jedec_flash.o
 
 COBJS	:= $(COBJS-y)
 SRCS 	:= $(COBJS:.o=.c)
diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index 5579a1e..f370e4f 100644
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -42,9 +42,12 @@
 #ifdef	CFG_FLASH_CFI_DRIVER
 
 /*
- * This file implements a Common Flash Interface (CFI) driver for U-Boot.
- * The width of the port and the width of the chips are determined at initialization.
- * These widths are used to calculate the address for access CFI data structures.
+ * This file implements a Common Flash Interface (CFI) driver for
+ * U-Boot.
+ *
+ * The width of the port and the width of the chips are determined at
+ * initialization.  These widths are used to calculate the address for
+ * access CFI data structures.
  *
  * References
  * JEDEC Standard JESD68 - Common Flash Interface (CFI)
@@ -55,7 +58,7 @@
  * AMD/Spansion Application Note: Migration from Single-byte to Three-byte
  *   Device IDs, Publication Number 25538 Revision A, November 8, 2001
  *
- * define CFG_WRITE_SWAPPED_DATA, if you have to swap the Bytes between
+ * Define CFG_WRITE_SWAPPED_DATA, if you have to swap the Bytes between
  * reading and writing ... (yes there is such a Hardware).
  */
 
@@ -98,10 +101,6 @@
 #define AMD_STATUS_TOGGLE		0x40
 #define AMD_STATUS_ERROR		0x20
 
-#define AMD_ADDR_ERASE_START	((info->portwidth == FLASH_CFI_8BIT) ? 0xAAA : 0x555)
-#define AMD_ADDR_START		((info->portwidth == FLASH_CFI_8BIT) ? 0xAAA : 0x555)
-#define AMD_ADDR_ACK		((info->portwidth == FLASH_CFI_8BIT) ? 0x555 : 0x2AA)
-
 #define FLASH_OFFSET_MANUFACTURER_ID	0x00
 #define FLASH_OFFSET_DEVICE_ID		0x01
 #define FLASH_OFFSET_DEVICE_ID2		0x0E
@@ -110,7 +109,8 @@
 #define FLASH_OFFSET_CFI_ALT		0x555
 #define FLASH_OFFSET_CFI_RESP		0x10
 #define FLASH_OFFSET_PRIMARY_VENDOR	0x13
-#define FLASH_OFFSET_EXT_QUERY_T_P_ADDR	0x15	/* extended query table primary addr */
+/* extended query table primary address */
+#define FLASH_OFFSET_EXT_QUERY_T_P_ADDR	0x15
 #define FLASH_OFFSET_WTOUT		0x1F
 #define FLASH_OFFSET_WBTOUT		0x20
 #define FLASH_OFFSET_ETOUT		0x21
@@ -149,16 +149,9 @@
 	unsigned long long ll;
 } cfiword_t;
 
-typedef union {
-	volatile unsigned char *cp;
-	volatile unsigned short *wp;
-	volatile unsigned long *lp;
-	volatile unsigned long long *llp;
-} cfiptr_t;
-
 #define NUM_ERASE_REGIONS	4 /* max. number of erase regions */
 
-static uint flash_offset_cfi[2]={FLASH_OFFSET_CFI,FLASH_OFFSET_CFI_ALT};
+static uint flash_offset_cfi[2] = { FLASH_OFFSET_CFI, FLASH_OFFSET_CFI_ALT };
 
 /* use CFG_MAX_FLASH_BANKS_DETECT if defined */
 #ifdef CFG_MAX_FLASH_BANKS_DETECT
@@ -176,250 +169,80 @@
 #define CFG_FLASH_CFI_WIDTH	FLASH_CFI_8BIT
 #endif
 
-
-/*-----------------------------------------------------------------------
- * Functions
- */
-
 typedef unsigned long flash_sect_t;
 
-static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c);
-static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf);
-static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd);
-static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect);
-static int flash_isequal (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd);
-static int flash_isset (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd);
-static int flash_toggle (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd);
-static void flash_read_jedec_ids (flash_info_t * info);
-static int flash_detect_cfi (flash_info_t * info);
-static int flash_write_cfiword (flash_info_t * info, ulong dest, cfiword_t cword);
-static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
-				    ulong tout, char *prompt);
-ulong flash_get_size (ulong base, int banknum);
-#if defined(CFG_ENV_IS_IN_FLASH) || defined(CFG_ENV_ADDR_REDUND) || (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
-static flash_info_t *flash_get_info(ulong base);
-#endif
-#ifdef CFG_FLASH_USE_BUFFER_WRITE
-static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp, int len);
-#endif
+/* CFI standard query structure */
+struct cfi_qry {
+	u8	qry[3];
+	u16	p_id;
+	u16	p_adr;
+	u16	a_id;
+	u16	a_adr;
+	u8	vcc_min;
+	u8	vcc_max;
+	u8	vpp_min;
+	u8	vpp_max;
+	u8	word_write_timeout_typ;
+	u8	buf_write_timeout_typ;
+	u8	block_erase_timeout_typ;
+	u8	chip_erase_timeout_typ;
+	u8	word_write_timeout_max;
+	u8	buf_write_timeout_max;
+	u8	block_erase_timeout_max;
+	u8	chip_erase_timeout_max;
+	u8	dev_size;
+	u16	interface_desc;
+	u16	max_buf_write_size;
+	u8	num_erase_regions;
+	u32	erase_region_info[NUM_ERASE_REGIONS];
+} __attribute__((packed));
 
-/*-----------------------------------------------------------------------
- * create an address based on the offset and the port width
- */
-inline uchar *flash_make_addr (flash_info_t * info, flash_sect_t sect, uint offset)
+struct cfi_pri_hdr {
+	u8	pri[3];
+	u8	major_version;
+	u8	minor_version;
+} __attribute__((packed));
+
+static void flash_write8(u8 value, void *addr)
 {
-	return ((uchar *) (info->start[sect] + (offset * info->portwidth)));
+	__raw_writeb(value, addr);
 }
 
-#ifdef DEBUG
-/*-----------------------------------------------------------------------
- * Debug support
- */
-void print_longlong (char *str, unsigned long long data)
+static void flash_write16(u16 value, void *addr)
 {
-	int i;
-	char *cp;
-
-	cp = (unsigned char *) &data;
-	for (i = 0; i < 8; i++)
-		sprintf (&str[i * 2], "%2.2x", *cp++);
-}
-static void flash_printqry (flash_info_t * info, flash_sect_t sect)
-{
-	cfiptr_t cptr;
-	int x, y;
-
-	for (x = 0; x < 0x40; x += 16U / info->portwidth) {
-		cptr.cp =
-			flash_make_addr (info, sect,
-					 x + FLASH_OFFSET_CFI_RESP);
-		debug ("%p : ", cptr.cp);
-		for (y = 0; y < 16; y++) {
-			debug ("%2.2x ", cptr.cp[y]);
-		}
-		debug (" ");
-		for (y = 0; y < 16; y++) {
-			if (cptr.cp[y] >= 0x20 && cptr.cp[y] <= 0x7e) {
-				debug ("%c", cptr.cp[y]);
-			} else {
-				debug (".");
-			}
-		}
-		debug ("\n");
-	}
-}
-#endif
-
-
-/*-----------------------------------------------------------------------
- * read a character at a port width address
- */
-inline uchar flash_read_uchar (flash_info_t * info, uint offset)
-{
-	uchar *cp;
-
-	cp = flash_make_addr (info, 0, offset);
-#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
-	return (cp[0]);
-#else
-	return (cp[info->portwidth - 1]);
-#endif
+	__raw_writew(value, addr);
 }
 
-/*-----------------------------------------------------------------------
- * read a short word by swapping for ppc format.
- */
-ushort flash_read_ushort (flash_info_t * info, flash_sect_t sect, uint offset)
+static void flash_write32(u32 value, void *addr)
 {
-	uchar *addr;
-	ushort retval;
-
-#ifdef DEBUG
-	int x;
-#endif
-	addr = flash_make_addr (info, sect, offset);
-
-#ifdef DEBUG
-	debug ("ushort addr is at %p info->portwidth = %d\n", addr,
-	       info->portwidth);
-	for (x = 0; x < 2 * info->portwidth; x++) {
-		debug ("addr[%x] = 0x%x\n", x, addr[x]);
-	}
-#endif
-#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
-	retval = ((addr[(info->portwidth)] << 8) | addr[0]);
-#else
-	retval = ((addr[(2 * info->portwidth) - 1] << 8) |
-		  addr[info->portwidth - 1]);
-#endif
-
-	debug ("retval = 0x%x\n", retval);
-	return retval;
+	__raw_writel(value, addr);
 }
 
-/*-----------------------------------------------------------------------
- * read a long word by picking the least significant byte of each maximum
- * port size word. Swap for ppc format.
- */
-ulong flash_read_long (flash_info_t * info, flash_sect_t sect, uint offset)
+static void flash_write64(u64 value, void *addr)
 {
-	uchar *addr;
-	ulong retval;
-
-#ifdef DEBUG
-	int x;
-#endif
-	addr = flash_make_addr (info, sect, offset);
-
-#ifdef DEBUG
-	debug ("long addr is at %p info->portwidth = %d\n", addr,
-	       info->portwidth);
-	for (x = 0; x < 4 * info->portwidth; x++) {
-		debug ("addr[%x] = 0x%x\n", x, addr[x]);
-	}
-#endif
-#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
-	retval = (addr[0] << 16) | (addr[(info->portwidth)] << 24) |
-		(addr[(2 * info->portwidth)]) | (addr[(3 * info->portwidth)] << 8);
-#else
-	retval = (addr[(2 * info->portwidth) - 1] << 24) |
-		(addr[(info->portwidth) - 1] << 16) |
-		(addr[(4 * info->portwidth) - 1] << 8) |
-		addr[(3 * info->portwidth) - 1];
-#endif
-	return retval;
+	/* No architectures currently implement __raw_writeq() */
+	*(volatile u64 *)addr = value;
 }
 
-
-/*-----------------------------------------------------------------------
- */
-unsigned long flash_init (void)
+static u8 flash_read8(void *addr)
 {
-	unsigned long size = 0;
-	int i;
+	return __raw_readb(addr);
+}
 
-#ifdef CFG_FLASH_PROTECTION
-	char *s = getenv("unlock");
-#endif
+static u16 flash_read16(void *addr)
+{
+	return __raw_readw(addr);
+}
 
-	/* Init: no FLASHes known */
-	for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
-		flash_info[i].flash_id = FLASH_UNKNOWN;
-		size += flash_info[i].size = flash_get_size (bank_base[i], i);
-		if (flash_info[i].flash_id == FLASH_UNKNOWN) {
-#ifndef CFG_FLASH_QUIET_TEST
-			printf ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n",
-				i+1, flash_info[i].size, flash_info[i].size << 20);
-#endif /* CFG_FLASH_QUIET_TEST */
-		}
-#ifdef CFG_FLASH_PROTECTION
-		else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
-			/*
-			 * Only the U-Boot image and it's environment is protected,
-			 * all other sectors are unprotected (unlocked) if flash
-			 * hardware protection is used (CFG_FLASH_PROTECTION) and
-			 * the environment variable "unlock" is set to "yes".
-			 */
-			if (flash_info[i].legacy_unlock) {
-				int k;
+static u32 flash_read32(void *addr)
+{
+	return __raw_readl(addr);
+}
 
-				/*
-				 * Disable legacy_unlock temporarily, since
-				 * flash_real_protect would relock all other sectors
-				 * again otherwise.
-				 */
-				flash_info[i].legacy_unlock = 0;
-
-				/*
-				 * Legacy unlocking (e.g. Intel J3) -> unlock only one
-				 * sector. This will unlock all sectors.
-				 */
-				flash_real_protect (&flash_info[i], 0, 0);
-
-				flash_info[i].legacy_unlock = 1;
-
-				/*
-				 * Manually mark other sectors as unlocked (unprotected)
-				 */
-				for (k = 1; k < flash_info[i].sector_count; k++)
-					flash_info[i].protect[k] = 0;
-			} else {
-				/*
-				 * No legancy unlocking -> unlock all sectors
-				 */
-				flash_protect (FLAG_PROTECT_CLEAR,
-					       flash_info[i].start[0],
-					       flash_info[i].start[0] + flash_info[i].size - 1,
-					       &flash_info[i]);
-			}
-		}
-#endif /* CFG_FLASH_PROTECTION */
-	}
-
-	/* Monitor protection ON by default */
-#if (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
-	flash_protect (FLAG_PROTECT_SET,
-		       CFG_MONITOR_BASE,
-		       CFG_MONITOR_BASE + monitor_flash_len  - 1,
-		       flash_get_info(CFG_MONITOR_BASE));
-#endif
-
-	/* Environment protection ON by default */
-#ifdef CFG_ENV_IS_IN_FLASH
-	flash_protect (FLAG_PROTECT_SET,
-		       CFG_ENV_ADDR,
-		       CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
-		       flash_get_info(CFG_ENV_ADDR));
-#endif
-
-	/* Redundant environment protection ON by default */
-#ifdef CFG_ENV_ADDR_REDUND
-	flash_protect (FLAG_PROTECT_SET,
-		       CFG_ENV_ADDR_REDUND,
-		       CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1,
-		       flash_get_info(CFG_ENV_ADDR_REDUND));
-#endif
-	return (size);
+static u64 flash_read64(void *addr)
+{
+	/* No architectures currently implement __raw_readq() */
+	return *(volatile u64 *)addr;
 }
 
 /*-----------------------------------------------------------------------
@@ -430,7 +253,7 @@
 	int i;
 	flash_info_t * info = 0;
 
-	for (i = 0; i < CFG_MAX_FLASH_BANKS; i ++) {
+	for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {
 		info = & flash_info[i];
 		if (info->size && info->start[0] <= base &&
 		    base <= info->start[0] + info->size - 1)
@@ -441,330 +264,325 @@
 }
 #endif
 
-/*-----------------------------------------------------------------------
- */
-int flash_erase (flash_info_t * info, int s_first, int s_last)
+unsigned long flash_sector_size(flash_info_t *info, flash_sect_t sect)
 {
-	int rcode = 0;
-	int prot;
-	flash_sect_t sect;
-
-	if (info->flash_id != FLASH_MAN_CFI) {
-		puts ("Can't erase unknown flash type - aborted\n");
-		return 1;
-	}
-	if ((s_first < 0) || (s_first > s_last)) {
-		puts ("- no sectors to erase\n");
-		return 1;
-	}
-
-	prot = 0;
-	for (sect = s_first; sect <= s_last; ++sect) {
-		if (info->protect[sect]) {
-			prot++;
-		}
-	}
-	if (prot) {
-		printf ("- Warning: %d protected sectors will not be erased!\n", prot);
-	} else {
-		putc ('\n');
-	}
-
-
-	for (sect = s_first; sect <= s_last; sect++) {
-		if (info->protect[sect] == 0) { /* not protected */
-			switch (info->vendor) {
-			case CFI_CMDSET_INTEL_STANDARD:
-			case CFI_CMDSET_INTEL_EXTENDED:
-				flash_write_cmd (info, sect, 0, FLASH_CMD_CLEAR_STATUS);
-				flash_write_cmd (info, sect, 0, FLASH_CMD_BLOCK_ERASE);
-				flash_write_cmd (info, sect, 0, FLASH_CMD_ERASE_CONFIRM);
-				break;
-			case CFI_CMDSET_AMD_STANDARD:
-			case CFI_CMDSET_AMD_EXTENDED:
-				flash_unlock_seq (info, sect);
-				flash_write_cmd (info, sect, AMD_ADDR_ERASE_START,
-							AMD_CMD_ERASE_START);
-				flash_unlock_seq (info, sect);
-				flash_write_cmd (info, sect, 0, AMD_CMD_ERASE_SECTOR);
-				break;
-			default:
-				debug ("Unkown flash vendor %d\n",
-				       info->vendor);
-				break;
-			}
-
-			if (flash_full_status_check
-			    (info, sect, info->erase_blk_tout, "erase")) {
-				rcode = 1;
-			} else
-				putc ('.');
-		}
-	}
-	puts (" done\n");
-	return rcode;
+	if (sect != (info->sector_count - 1))
+		return info->start[sect + 1] - info->start[sect];
+	else
+		return info->start[0] + info->size - info->start[sect];
 }
 
 /*-----------------------------------------------------------------------
+ * create an address based on the offset and the port width
  */
-void flash_print_info (flash_info_t * info)
+static inline void *
+flash_map (flash_info_t * info, flash_sect_t sect, uint offset)
+{
+	unsigned int byte_offset = offset * info->portwidth;
+
+	return map_physmem(info->start[sect] + byte_offset,
+			flash_sector_size(info, sect) - byte_offset,
+			MAP_NOCACHE);
+}
+
+static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
+		unsigned int offset, void *addr)
+{
+	unsigned int byte_offset = offset * info->portwidth;
+
+	unmap_physmem(addr, flash_sector_size(info, sect) - byte_offset);
+}
+
+/*-----------------------------------------------------------------------
+ * make a proper sized command based on the port and chip widths
+ */
+static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf)
 {
 	int i;
+	uchar *cp = (uchar *) cmdbuf;
 
-	if (info->flash_id != FLASH_MAN_CFI) {
-		puts ("missing or unknown FLASH type\n");
-		return;
-	}
-
-	printf ("CFI conformant FLASH (%d x %d)",
-		(info->portwidth << 3), (info->chipwidth << 3));
-	printf ("  Size: %ld MB in %d Sectors\n",
-		info->size >> 20, info->sector_count);
-	printf ("  ");
-	switch (info->vendor) {
-		case CFI_CMDSET_INTEL_STANDARD:
-			printf ("Intel Standard");
-			break;
-		case CFI_CMDSET_INTEL_EXTENDED:
-			printf ("Intel Extended");
-			break;
-		case CFI_CMDSET_AMD_STANDARD:
-			printf ("AMD Standard");
-			break;
-		case CFI_CMDSET_AMD_EXTENDED:
-			printf ("AMD Extended");
-			break;
-		default:
-			printf ("Unknown (%d)", info->vendor);
-			break;
-	}
-	printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X",
-		info->manufacturer_id, info->device_id);
-	if (info->device_id == 0x7E) {
-		printf("%04X", info->device_id2);
-	}
-	printf ("\n  Erase timeout: %ld ms, write timeout: %ld ms\n",
-		info->erase_blk_tout,
-		info->write_tout);
-	if (info->buffer_size > 1) {
-		printf ("  Buffer write timeout: %ld ms, buffer size: %d bytes\n",
-		info->buffer_write_tout,
-		info->buffer_size);
-	}
-
-	puts ("\n  Sector Start Addresses:");
-	for (i = 0; i < info->sector_count; ++i) {
-		if ((i % 5) == 0)
-			printf ("\n");
-#ifdef CFG_FLASH_EMPTY_INFO
-		int k;
-		int size;
-		int erased;
-		volatile unsigned long *flash;
-
-		/*
-		 * Check if whole sector is erased
-		 */
-		if (i != (info->sector_count - 1))
-			size = info->start[i + 1] - info->start[i];
-		else
-			size = info->start[0] + info->size - info->start[i];
-		erased = 1;
-		flash = (volatile unsigned long *) info->start[i];
-		size = size >> 2;	/* divide by 4 for longword access */
-		for (k = 0; k < size; k++) {
-			if (*flash++ != 0xffffffff) {
-				erased = 0;
-				break;
-			}
-		}
-
-		/* print empty and read-only info */
-		printf ("  %08lX %c %s ",
-			info->start[i],
-			erased ? 'E' : ' ',
-			info->protect[i] ? "RO" : "  ");
-#else	/* ! CFG_FLASH_EMPTY_INFO */
-		printf ("  %08lX   %s ",
-			info->start[i],
-			info->protect[i] ? "RO" : "  ");
-#endif
-	}
-	putc ('\n');
-	return;
-}
-
-/*-----------------------------------------------------------------------
- * Copy memory to flash, returns:
- * 0 - OK
- * 1 - write timeout
- * 2 - Flash not erased
- */
-int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
-{
-	ulong wp;
-	ulong cp;
-	int aln;
-	cfiword_t cword;
-	int i, rc;
-
-#ifdef CFG_FLASH_USE_BUFFER_WRITE
-	int buffered_size;
-#endif
-	/* get lower aligned address */
-	/* get lower aligned address */
-	wp = (addr & ~(info->portwidth - 1));
-
-	/* handle unaligned start */
-	if ((aln = addr - wp) != 0) {
-		cword.l = 0;
-		cp = wp;
-		for (i = 0; i < aln; ++i, ++cp)
-			flash_add_byte (info, &cword, (*(uchar *) cp));
-
-		for (; (i < info->portwidth) && (cnt > 0); i++) {
-			flash_add_byte (info, &cword, *src++);
-			cnt--;
-			cp++;
-		}
-		for (; (cnt == 0) && (i < info->portwidth); ++i, ++cp)
-			flash_add_byte (info, &cword, (*(uchar *) cp));
-		if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
-			return rc;
-		wp = cp;
-	}
-
-	/* handle the aligned part */
-#ifdef CFG_FLASH_USE_BUFFER_WRITE
-	buffered_size = (info->portwidth / info->chipwidth);
-	buffered_size *= info->buffer_size;
-	while (cnt >= info->portwidth) {
-		/* prohibit buffer write when buffer_size is 1 */
-		if (info->buffer_size == 1) {
-			cword.l = 0;
-			for (i = 0; i < info->portwidth; i++)
-				flash_add_byte (info, &cword, *src++);
-			if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
-				return rc;
-			wp += info->portwidth;
-			cnt -= info->portwidth;
-			continue;
-		}
-
-		/* write buffer until next buffered_size aligned boundary */
-		i = buffered_size - (wp % buffered_size);
-		if (i > cnt)
-			i = cnt;
-		if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
-			return rc;
-		i -= i & (info->portwidth - 1);
-		wp += i;
-		src += i;
-		cnt -= i;
-	}
+#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
+	for (i = info->portwidth; i > 0; i--)
 #else
-	while (cnt >= info->portwidth) {
-		cword.l = 0;
-		for (i = 0; i < info->portwidth; i++) {
-			flash_add_byte (info, &cword, *src++);
+	for (i = 1; i <= info->portwidth; i++)
+#endif
+		*cp++ = (i & (info->chipwidth - 1)) ? '\0' : cmd;
+}
+
+#ifdef DEBUG
+/*-----------------------------------------------------------------------
+ * Debug support
+ */
+static void print_longlong (char *str, unsigned long long data)
+{
+	int i;
+	char *cp;
+
+	cp = (unsigned char *) &data;
+	for (i = 0; i < 8; i++)
+		sprintf (&str[i * 2], "%2.2x", *cp++);
+}
+
+static void flash_printqry (struct cfi_qry *qry)
+{
+	u8 *p = (u8 *)qry;
+	int x, y;
+
+	for (x = 0; x < sizeof(struct cfi_qry); x += 16) {
+		debug("%02x : ", x);
+		for (y = 0; y < 16; y++)
+			debug("%2.2x ", p[x + y]);
+		debug(" ");
+		for (y = 0; y < 16; y++) {
+			unsigned char c = p[x + y];
+			if (c >= 0x20 && c <= 0x7e)
+				debug("%c", c);
+			else
+				debug(".");
 		}
-		if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
-			return rc;
-		wp += info->portwidth;
-		cnt -= info->portwidth;
+		debug("\n");
 	}
-#endif /* CFG_FLASH_USE_BUFFER_WRITE */
-	if (cnt == 0) {
-		return (0);
-	}
+}
+#endif
 
-	/*
-	 * handle unaligned tail bytes
-	 */
-	cword.l = 0;
-	for (i = 0, cp = wp; (i < info->portwidth) && (cnt > 0); ++i, ++cp) {
-		flash_add_byte (info, &cword, *src++);
-		--cnt;
-	}
-	for (; i < info->portwidth; ++i, ++cp) {
-		flash_add_byte (info, &cword, (*(uchar *) cp));
-	}
 
-	return flash_write_cfiword (info, wp, cword);
+/*-----------------------------------------------------------------------
+ * read a character at a port width address
+ */
+static inline uchar flash_read_uchar (flash_info_t * info, uint offset)
+{
+	uchar *cp;
+	uchar retval;
+
+	cp = flash_map (info, 0, offset);
+#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
+	retval = flash_read8(cp);
+#else
+	retval = flash_read8(cp + info->portwidth - 1);
+#endif
+	flash_unmap (info, 0, offset, cp);
+	return retval;
 }
 
 /*-----------------------------------------------------------------------
+ * read a long word by picking the least significant byte of each maximum
+ * port size word. Swap for ppc format.
  */
-#ifdef CFG_FLASH_PROTECTION
-
-int flash_real_protect (flash_info_t * info, long sector, int prot)
+static ulong flash_read_long (flash_info_t * info, flash_sect_t sect,
+			      uint offset)
 {
-	int retcode = 0;
+	uchar *addr;
+	ulong retval;
 
-	flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
-	flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
-	if (prot)
-		flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
-	else
-		flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
+#ifdef DEBUG
+	int x;
+#endif
+	addr = flash_map (info, sect, offset);
 
-	if ((retcode =
-	     flash_full_status_check (info, sector, info->erase_blk_tout,
-				      prot ? "protect" : "unprotect")) == 0) {
-
-		info->protect[sector] = prot;
-
-		/*
-		 * On some of Intel's flash chips (marked via legacy_unlock)
-		 * unprotect unprotects all locking.
-		 */
-		if ((prot == 0) && (info->legacy_unlock)) {
-			flash_sect_t i;
-
-			for (i = 0; i < info->sector_count; i++) {
-				if (info->protect[i])
-					flash_real_protect (info, i, 1);
-			}
-		}
+#ifdef DEBUG
+	debug ("long addr is at %p info->portwidth = %d\n", addr,
+	       info->portwidth);
+	for (x = 0; x < 4 * info->portwidth; x++) {
+		debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
 	}
-	return retcode;
-}
+#endif
+#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
+	retval = ((flash_read8(addr) << 16) |
+		  (flash_read8(addr + info->portwidth) << 24) |
+		  (flash_read8(addr + 2 * info->portwidth)) |
+		  (flash_read8(addr + 3 * info->portwidth) << 8));
+#else
+	retval = ((flash_read8(addr + 2 * info->portwidth - 1) << 24) |
+		  (flash_read8(addr + info->portwidth - 1) << 16) |
+		  (flash_read8(addr + 4 * info->portwidth - 1) << 8) |
+		  (flash_read8(addr + 3 * info->portwidth - 1)));
+#endif
+	flash_unmap(info, sect, offset, addr);
 
-/*-----------------------------------------------------------------------
- * flash_read_user_serial - read the OneTimeProgramming cells
- */
-void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
-			     int len)
-{
-	uchar *src;
-	uchar *dst;
-
-	dst = buffer;
-	src = flash_make_addr (info, 0, FLASH_OFFSET_USER_PROTECTION);
-	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
-	memcpy (dst, src + offset, len);
-	flash_write_cmd (info, 0, 0, info->cmd_reset);
+	return retval;
 }
 
 /*
- * flash_read_factory_serial - read the device Id from the protection area
+ * Write a proper sized command to the correct address
  */
-void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
-				int len)
+static void flash_write_cmd (flash_info_t * info, flash_sect_t sect,
+			     uint offset, uchar cmd)
 {
-	uchar *src;
 
-	src = flash_make_addr (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
-	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
-	memcpy (buffer, src + offset, len);
-	flash_write_cmd (info, 0, 0, info->cmd_reset);
+	void *addr;
+	cfiword_t cword;
+
+	addr = flash_map (info, sect, offset);
+	flash_make_cmd (info, cmd, &cword);
+	switch (info->portwidth) {
+	case FLASH_CFI_8BIT:
+		debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr, cmd,
+		       cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
+		flash_write8(cword.c, addr);
+		break;
+	case FLASH_CFI_16BIT:
+		debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr,
+		       cmd, cword.w,
+		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
+		flash_write16(cword.w, addr);
+		break;
+	case FLASH_CFI_32BIT:
+		debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr,
+		       cmd, cword.l,
+		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
+		flash_write32(cword.l, addr);
+		break;
+	case FLASH_CFI_64BIT:
+#ifdef DEBUG
+		{
+			char str[20];
+
+			print_longlong (str, cword.ll);
+
+			debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
+			       addr, cmd, str,
+			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
+		}
+#endif
+		flash_write64(cword.ll, addr);
+		break;
+	}
+
+	/* Ensure all the instructions are fully finished */
+	sync();
+
+	flash_unmap(info, sect, offset, addr);
 }
 
-#endif /* CFG_FLASH_PROTECTION */
+static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
+{
+	flash_write_cmd (info, sect, info->addr_unlock1, AMD_CMD_UNLOCK_START);
+	flash_write_cmd (info, sect, info->addr_unlock2, AMD_CMD_UNLOCK_ACK);
+}
+
+/*-----------------------------------------------------------------------
+ */
+static int flash_isequal (flash_info_t * info, flash_sect_t sect,
+			  uint offset, uchar cmd)
+{
+	void *addr;
+	cfiword_t cword;
+	int retval;
+
+	addr = flash_map (info, sect, offset);
+	flash_make_cmd (info, cmd, &cword);
+
+	debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
+	switch (info->portwidth) {
+	case FLASH_CFI_8BIT:
+		debug ("is= %x %x\n", flash_read8(addr), cword.c);
+		retval = (flash_read8(addr) == cword.c);
+		break;
+	case FLASH_CFI_16BIT:
+		debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w);
+		retval = (flash_read16(addr) == cword.w);
+		break;
+	case FLASH_CFI_32BIT:
+		debug ("is= %8.8lx %8.8lx\n", flash_read32(addr), cword.l);
+		retval = (flash_read32(addr) == cword.l);
+		break;
+	case FLASH_CFI_64BIT:
+#ifdef DEBUG
+		{
+			char str1[20];
+			char str2[20];
+
+			print_longlong (str1, flash_read64(addr));
+			print_longlong (str2, cword.ll);
+			debug ("is= %s %s\n", str1, str2);
+		}
+#endif
+		retval = (flash_read64(addr) == cword.ll);
+		break;
+	default:
+		retval = 0;
+		break;
+	}
+	flash_unmap(info, sect, offset, addr);
+
+	return retval;
+}
+
+/*-----------------------------------------------------------------------
+ */
+static int flash_isset (flash_info_t * info, flash_sect_t sect,
+			uint offset, uchar cmd)
+{
+	void *addr;
+	cfiword_t cword;
+	int retval;
+
+	addr = flash_map (info, sect, offset);
+	flash_make_cmd (info, cmd, &cword);
+	switch (info->portwidth) {
+	case FLASH_CFI_8BIT:
+		retval = ((flash_read8(addr) & cword.c) == cword.c);
+		break;
+	case FLASH_CFI_16BIT:
+		retval = ((flash_read16(addr) & cword.w) == cword.w);
+		break;
+	case FLASH_CFI_32BIT:
+		retval = ((flash_read16(addr) & cword.l) == cword.l);
+		break;
+	case FLASH_CFI_64BIT:
+		retval = ((flash_read64(addr) & cword.ll) == cword.ll);
+		break;
+	default:
+		retval = 0;
+		break;
+	}
+	flash_unmap(info, sect, offset, addr);
+
+	return retval;
+}
+
+/*-----------------------------------------------------------------------
+ */
+static int flash_toggle (flash_info_t * info, flash_sect_t sect,
+			 uint offset, uchar cmd)
+{
+	void *addr;
+	cfiword_t cword;
+	int retval;
+
+	addr = flash_map (info, sect, offset);
+	flash_make_cmd (info, cmd, &cword);
+	switch (info->portwidth) {
+	case FLASH_CFI_8BIT:
+		retval = ((flash_read8(addr) & cword.c) !=
+			  (flash_read8(addr) & cword.c));
+		break;
+	case FLASH_CFI_16BIT:
+		retval = ((flash_read16(addr) & cword.w) !=
+			  (flash_read16(addr) & cword.w));
+		break;
+	case FLASH_CFI_32BIT:
+		retval = ((flash_read32(addr) & cword.l) !=
+			  (flash_read32(addr) & cword.l));
+		break;
+	case FLASH_CFI_64BIT:
+		retval = ((flash_read64(addr) & cword.ll) !=
+			  (flash_read64(addr) & cword.ll));
+		break;
+	default:
+		retval = 0;
+		break;
+	}
+	flash_unmap(info, sect, offset, addr);
+
+	return retval;
+}
 
 /*
  * flash_is_busy - check to see if the flash is busy
- * This routine checks the status of the chip and returns true if the chip is busy
+ *
+ * This routine checks the status of the chip and returns true if the
+ * chip is busy.
  */
 static int flash_is_busy (flash_info_t * info, flash_sect_t sect)
 {
@@ -777,6 +595,9 @@
 		break;
 	case CFI_CMDSET_AMD_STANDARD:
 	case CFI_CMDSET_AMD_EXTENDED:
+#ifdef CONFIG_FLASH_CFI_LEGACY
+	case CFI_CMDSET_AMD_LEGACY:
+#endif
 		retval = flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE);
 		break;
 	default:
@@ -815,7 +636,9 @@
 }
 
 /*-----------------------------------------------------------------------
- * Wait for XSR.7 to be set, if it times out print an error, otherwise do a full status check.
+ * Wait for XSR.7 to be set, if it times out print an error, otherwise
+ * do a full status check.
+ *
  * This routine sets the flash to read-array mode.
  */
 static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
@@ -832,12 +655,15 @@
 			retcode = ERR_INVAL;
 			printf ("Flash %s error at address %lx\n", prompt,
 				info->start[sector]);
-			if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS | FLASH_STATUS_PSLBS)) {
+			if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS |
+					 FLASH_STATUS_PSLBS)) {
 				puts ("Command Sequence Error.\n");
-			} else if (flash_isset (info, sector, 0, FLASH_STATUS_ECLBS)) {
+			} else if (flash_isset (info, sector, 0,
+						FLASH_STATUS_ECLBS)) {
 				puts ("Block Erase Error.\n");
 				retcode = ERR_NOT_ERASED;
-			} else if (flash_isset (info, sector, 0, FLASH_STATUS_PSLBS)) {
+			} else if (flash_isset (info, sector, 0,
+						FLASH_STATUS_PSLBS)) {
 				puts ("Locking Error\n");
 			}
 			if (flash_isset (info, sector, 0, FLASH_STATUS_DPS)) {
@@ -899,182 +725,598 @@
 	}
 }
 
+/* loop through the sectors from the highest address when the passed
+ * address is greater or equal to the sector address we have a match
+ */
+static flash_sect_t find_sector (flash_info_t * info, ulong addr)
+{
+	flash_sect_t sector;
+
+	for (sector = info->sector_count - 1; sector >= 0; sector--) {
+		if (addr >= info->start[sector])
+			break;
+	}
+	return sector;
+}
 
 /*-----------------------------------------------------------------------
- * make a proper sized command based on the port and chip widths
  */
-static void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf)
+static int flash_write_cfiword (flash_info_t * info, ulong dest,
+				cfiword_t cword)
+{
+	void *dstaddr;
+	int flag;
+
+	dstaddr = map_physmem(dest, info->portwidth, MAP_NOCACHE);
+
+	/* Check if Flash is (sufficiently) erased */
+	switch (info->portwidth) {
+	case FLASH_CFI_8BIT:
+		flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
+		break;
+	case FLASH_CFI_16BIT:
+		flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
+		break;
+	case FLASH_CFI_32BIT:
+		flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
+		break;
+	case FLASH_CFI_64BIT:
+		flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
+		break;
+	default:
+		flag = 0;
+		break;
+	}
+	if (!flag) {
+		unmap_physmem(dstaddr, info->portwidth);
+		return 2;
+	}
+
+	/* Disable interrupts which might cause a timeout here */
+	flag = disable_interrupts ();
+
+	switch (info->vendor) {
+	case CFI_CMDSET_INTEL_EXTENDED:
+	case CFI_CMDSET_INTEL_STANDARD:
+		flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
+		flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
+		break;
+	case CFI_CMDSET_AMD_EXTENDED:
+	case CFI_CMDSET_AMD_STANDARD:
+#ifdef CONFIG_FLASH_CFI_LEGACY
+	case CFI_CMDSET_AMD_LEGACY:
+#endif
+		flash_unlock_seq (info, 0);
+		flash_write_cmd (info, 0, info->addr_unlock1, AMD_CMD_WRITE);
+		break;
+	}
+
+	switch (info->portwidth) {
+	case FLASH_CFI_8BIT:
+		flash_write8(cword.c, dstaddr);
+		break;
+	case FLASH_CFI_16BIT:
+		flash_write16(cword.w, dstaddr);
+		break;
+	case FLASH_CFI_32BIT:
+		flash_write32(cword.l, dstaddr);
+		break;
+	case FLASH_CFI_64BIT:
+		flash_write64(cword.ll, dstaddr);
+		break;
+	}
+
+	/* re-enable interrupts if necessary */
+	if (flag)
+		enable_interrupts ();
+
+	unmap_physmem(dstaddr, info->portwidth);
+
+	return flash_full_status_check (info, find_sector (info, dest),
+					info->write_tout, "write");
+}
+
+#ifdef CFG_FLASH_USE_BUFFER_WRITE
+
+static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
+				  int len)
+{
+	flash_sect_t sector;
+	int cnt;
+	int retcode;
+	void *src = cp;
+	void *dst = map_physmem(dest, len, MAP_NOCACHE);
+
+	sector = find_sector (info, dest);
+
+	switch (info->vendor) {
+	case CFI_CMDSET_INTEL_STANDARD:
+	case CFI_CMDSET_INTEL_EXTENDED:
+		flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
+		flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER);
+		retcode = flash_status_check (info, sector,
+					      info->buffer_write_tout,
+					      "write to buffer");
+		if (retcode == ERR_OK) {
+			/* reduce the number of loops by the width of
+			 * the port */
+			switch (info->portwidth) {
+			case FLASH_CFI_8BIT:
+				cnt = len;
+				break;
+			case FLASH_CFI_16BIT:
+				cnt = len >> 1;
+				break;
+			case FLASH_CFI_32BIT:
+				cnt = len >> 2;
+				break;
+			case FLASH_CFI_64BIT:
+				cnt = len >> 3;
+				break;
+			default:
+				retcode = ERR_INVAL;
+				goto out_unmap;
+			}
+			flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
+			while (cnt-- > 0) {
+				switch (info->portwidth) {
+				case FLASH_CFI_8BIT:
+					flash_write8(flash_read8(src), dst);
+					src += 1, dst += 1;
+					break;
+				case FLASH_CFI_16BIT:
+					flash_write16(flash_read16(src), dst);
+					src += 2, dst += 2;
+					break;
+				case FLASH_CFI_32BIT:
+					flash_write32(flash_read32(src), dst);
+					src += 4, dst += 4;
+					break;
+				case FLASH_CFI_64BIT:
+					flash_write64(flash_read64(src), dst);
+					src += 8, dst += 8;
+					break;
+				default:
+					retcode = ERR_INVAL;
+					goto out_unmap;
+				}
+			}
+			flash_write_cmd (info, sector, 0,
+					 FLASH_CMD_WRITE_BUFFER_CONFIRM);
+			retcode = flash_full_status_check (
+				info, sector, info->buffer_write_tout,
+				"buffer write");
+		}
+
+		break;
+
+	case CFI_CMDSET_AMD_STANDARD:
+	case CFI_CMDSET_AMD_EXTENDED:
+		flash_unlock_seq(info,0);
+		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_TO_BUFFER);
+
+		switch (info->portwidth) {
+		case FLASH_CFI_8BIT:
+			cnt = len;
+			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
+			while (cnt-- > 0) {
+				flash_write8(flash_read8(src), dst);
+				src += 1, dst += 1;
+			}
+			break;
+		case FLASH_CFI_16BIT:
+			cnt = len >> 1;
+			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
+			while (cnt-- > 0) {
+				flash_write16(flash_read16(src), dst);
+				src += 2, dst += 2;
+			}
+			break;
+		case FLASH_CFI_32BIT:
+			cnt = len >> 2;
+			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
+			while (cnt-- > 0) {
+				flash_write32(flash_read32(src), dst);
+				src += 4, dst += 4;
+			}
+			break;
+		case FLASH_CFI_64BIT:
+			cnt = len >> 3;
+			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
+			while (cnt-- > 0) {
+				flash_write64(flash_read64(src), dst);
+				src += 8, dst += 8;
+			}
+			break;
+		default:
+			retcode = ERR_INVAL;
+			goto out_unmap;
+		}
+
+		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
+		retcode = flash_full_status_check (info, sector,
+						   info->buffer_write_tout,
+						   "buffer write");
+		break;
+
+	default:
+		debug ("Unknown Command Set\n");
+		retcode = ERR_INVAL;
+		break;
+	}
+
+out_unmap:
+	unmap_physmem(dst, len);
+	return retcode;
+}
+#endif /* CFG_FLASH_USE_BUFFER_WRITE */
+
+
+/*-----------------------------------------------------------------------
+ */
+int flash_erase (flash_info_t * info, int s_first, int s_last)
+{
+	int rcode = 0;
+	int prot;
+	flash_sect_t sect;
+
+	if (info->flash_id != FLASH_MAN_CFI) {
+		puts ("Can't erase unknown flash type - aborted\n");
+		return 1;
+	}
+	if ((s_first < 0) || (s_first > s_last)) {
+		puts ("- no sectors to erase\n");
+		return 1;
+	}
+
+	prot = 0;
+	for (sect = s_first; sect <= s_last; ++sect) {
+		if (info->protect[sect]) {
+			prot++;
+		}
+	}
+	if (prot) {
+		printf ("- Warning: %d protected sectors will not be erased!\n",
+			prot);
+	} else {
+		putc ('\n');
+	}
+
+
+	for (sect = s_first; sect <= s_last; sect++) {
+		if (info->protect[sect] == 0) { /* not protected */
+			switch (info->vendor) {
+			case CFI_CMDSET_INTEL_STANDARD:
+			case CFI_CMDSET_INTEL_EXTENDED:
+				flash_write_cmd (info, sect, 0,
+						 FLASH_CMD_CLEAR_STATUS);
+				flash_write_cmd (info, sect, 0,
+						 FLASH_CMD_BLOCK_ERASE);
+				flash_write_cmd (info, sect, 0,
+						 FLASH_CMD_ERASE_CONFIRM);
+				break;
+			case CFI_CMDSET_AMD_STANDARD:
+			case CFI_CMDSET_AMD_EXTENDED:
+				flash_unlock_seq (info, sect);
+				flash_write_cmd (info, sect,
+						info->addr_unlock1,
+						AMD_CMD_ERASE_START);
+				flash_unlock_seq (info, sect);
+				flash_write_cmd (info, sect, 0,
+						 AMD_CMD_ERASE_SECTOR);
+				break;
+#ifdef CONFIG_FLASH_CFI_LEGACY
+			case CFI_CMDSET_AMD_LEGACY:
+				flash_unlock_seq (info, 0);
+				flash_write_cmd (info, 0, info->addr_unlock1,
+						AMD_CMD_ERASE_START);
+				flash_unlock_seq (info, 0);
+				flash_write_cmd (info, sect, 0,
+						AMD_CMD_ERASE_SECTOR);
+				break;
+#endif
+			default:
+				debug ("Unkown flash vendor %d\n",
+				       info->vendor);
+				break;
+			}
+
+			if (flash_full_status_check
+			    (info, sect, info->erase_blk_tout, "erase")) {
+				rcode = 1;
+			} else
+				putc ('.');
+		}
+	}
+	puts (" done\n");
+	return rcode;
+}
+
+/*-----------------------------------------------------------------------
+ */
+void flash_print_info (flash_info_t * info)
 {
 	int i;
-	uchar *cp = (uchar *) cmdbuf;
 
-#if defined(__LITTLE_ENDIAN) || defined(CFG_WRITE_SWAPPED_DATA)
-	for (i = info->portwidth; i > 0; i--)
-#else
-	for (i = 1; i <= info->portwidth; i++)
+	if (info->flash_id != FLASH_MAN_CFI) {
+		puts ("missing or unknown FLASH type\n");
+		return;
+	}
+
+	printf ("%s FLASH (%d x %d)",
+		info->name,
+		(info->portwidth << 3), (info->chipwidth << 3));
+	if (info->size < 1024*1024)
+		printf ("  Size: %ld kB in %d Sectors\n",
+			info->size >> 10, info->sector_count);
+	else
+		printf ("  Size: %ld MB in %d Sectors\n",
+			info->size >> 20, info->sector_count);
+	printf ("  ");
+	switch (info->vendor) {
+		case CFI_CMDSET_INTEL_STANDARD:
+			printf ("Intel Standard");
+			break;
+		case CFI_CMDSET_INTEL_EXTENDED:
+			printf ("Intel Extended");
+			break;
+		case CFI_CMDSET_AMD_STANDARD:
+			printf ("AMD Standard");
+			break;
+		case CFI_CMDSET_AMD_EXTENDED:
+			printf ("AMD Extended");
+			break;
+#ifdef CONFIG_FLASH_CFI_LEGACY
+		case CFI_CMDSET_AMD_LEGACY:
+			printf ("AMD Legacy");
+			break;
 #endif
-		*cp++ = (i & (info->chipwidth - 1)) ? '\0' : cmd;
+		default:
+			printf ("Unknown (%d)", info->vendor);
+			break;
+	}
+	printf (" command set, Manufacturer ID: 0x%02X, Device ID: 0x%02X",
+		info->manufacturer_id, info->device_id);
+	if (info->device_id == 0x7E) {
+		printf("%04X", info->device_id2);
+	}
+	printf ("\n  Erase timeout: %ld ms, write timeout: %ld ms\n",
+		info->erase_blk_tout,
+		info->write_tout);
+	if (info->buffer_size > 1) {
+		printf ("  Buffer write timeout: %ld ms, "
+			"buffer size: %d bytes\n",
+		info->buffer_write_tout,
+		info->buffer_size);
+	}
+
+	puts ("\n  Sector Start Addresses:");
+	for (i = 0; i < info->sector_count; ++i) {
+		if ((i % 5) == 0)
+			printf ("\n");
+#ifdef CFG_FLASH_EMPTY_INFO
+		int k;
+		int size;
+		int erased;
+		volatile unsigned long *flash;
+
+		/*
+		 * Check if whole sector is erased
+		 */
+		size = flash_sector_size(info, i);
+		erased = 1;
+		flash = (volatile unsigned long *) info->start[i];
+		size = size >> 2;	/* divide by 4 for longword access */
+		for (k = 0; k < size; k++) {
+			if (*flash++ != 0xffffffff) {
+				erased = 0;
+				break;
+			}
+		}
+
+		/* print empty and read-only info */
+		printf ("  %08lX %c %s ",
+			info->start[i],
+			erased ? 'E' : ' ',
+			info->protect[i] ? "RO" : "  ");
+#else	/* ! CFG_FLASH_EMPTY_INFO */
+		printf ("  %08lX   %s ",
+			info->start[i],
+			info->protect[i] ? "RO" : "  ");
+#endif
+	}
+	putc ('\n');
+	return;
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
+{
+	ulong wp;
+	uchar *p;
+	int aln;
+	cfiword_t cword;
+	int i, rc;
+
+#ifdef CFG_FLASH_USE_BUFFER_WRITE
+	int buffered_size;
+#endif
+	/* get lower aligned address */
+	wp = (addr & ~(info->portwidth - 1));
+
+	/* handle unaligned start */
+	if ((aln = addr - wp) != 0) {
+		cword.l = 0;
+		p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
+		for (i = 0; i < aln; ++i)
+			flash_add_byte (info, &cword, flash_read8(p + i));
+
+		for (; (i < info->portwidth) && (cnt > 0); i++) {
+			flash_add_byte (info, &cword, *src++);
+			cnt--;
+		}
+		for (; (cnt == 0) && (i < info->portwidth); ++i)
+			flash_add_byte (info, &cword, flash_read8(p + i));
+
+		rc = flash_write_cfiword (info, wp, cword);
+		unmap_physmem(p, info->portwidth);
+		if (rc != 0)
+			return rc;
+
+		wp += i;
+	}
+
+	/* handle the aligned part */
+#ifdef CFG_FLASH_USE_BUFFER_WRITE
+	buffered_size = (info->portwidth / info->chipwidth);
+	buffered_size *= info->buffer_size;
+	while (cnt >= info->portwidth) {
+		/* prohibit buffer write when buffer_size is 1 */
+		if (info->buffer_size == 1) {
+			cword.l = 0;
+			for (i = 0; i < info->portwidth; i++)
+				flash_add_byte (info, &cword, *src++);
+			if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
+				return rc;
+			wp += info->portwidth;
+			cnt -= info->portwidth;
+			continue;
+		}
+
+		/* write buffer until next buffered_size aligned boundary */
+		i = buffered_size - (wp % buffered_size);
+		if (i > cnt)
+			i = cnt;
+		if ((rc = flash_write_cfibuffer (info, wp, src, i)) != ERR_OK)
+			return rc;
+		i -= i & (info->portwidth - 1);
+		wp += i;
+		src += i;
+		cnt -= i;
+	}
+#else
+	while (cnt >= info->portwidth) {
+		cword.l = 0;
+		for (i = 0; i < info->portwidth; i++) {
+			flash_add_byte (info, &cword, *src++);
+		}
+		if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
+			return rc;
+		wp += info->portwidth;
+		cnt -= info->portwidth;
+	}
+#endif /* CFG_FLASH_USE_BUFFER_WRITE */
+	if (cnt == 0) {
+		return (0);
+	}
+
+	/*
+	 * handle unaligned tail bytes
+	 */
+	cword.l = 0;
+	p = map_physmem(wp, info->portwidth, MAP_NOCACHE);
+	for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
+		flash_add_byte (info, &cword, *src++);
+		--cnt;
+	}
+	for (; i < info->portwidth; ++i)
+		flash_add_byte (info, &cword, flash_read8(p + i));
+	unmap_physmem(p, info->portwidth);
+
+	return flash_write_cfiword (info, wp, cword);
+}
+
+/*-----------------------------------------------------------------------
+ */
+#ifdef CFG_FLASH_PROTECTION
+
+int flash_real_protect (flash_info_t * info, long sector, int prot)
+{
+	int retcode = 0;
+
+	flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
+	flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT);
+	if (prot)
+		flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_SET);
+	else
+		flash_write_cmd (info, sector, 0, FLASH_CMD_PROTECT_CLEAR);
+
+	if ((retcode =
+	     flash_full_status_check (info, sector, info->erase_blk_tout,
+				      prot ? "protect" : "unprotect")) == 0) {
+
+		info->protect[sector] = prot;
+
+		/*
+		 * On some of Intel's flash chips (marked via legacy_unlock)
+		 * unprotect unprotects all locking.
+		 */
+		if ((prot == 0) && (info->legacy_unlock)) {
+			flash_sect_t i;
+
+			for (i = 0; i < info->sector_count; i++) {
+				if (info->protect[i])
+					flash_real_protect (info, i, 1);
+			}
+		}
+	}
+	return retcode;
+}
+
+/*-----------------------------------------------------------------------
+ * flash_read_user_serial - read the OneTimeProgramming cells
+ */
+void flash_read_user_serial (flash_info_t * info, void *buffer, int offset,
+			     int len)
+{
+	uchar *src;
+	uchar *dst;
+
+	dst = buffer;
+	src = flash_map (info, 0, FLASH_OFFSET_USER_PROTECTION);
+	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
+	memcpy (dst, src + offset, len);
+	flash_write_cmd (info, 0, 0, info->cmd_reset);
+	flash_unmap(info, 0, FLASH_OFFSET_USER_PROTECTION, src);
 }
 
 /*
- * Write a proper sized command to the correct address
+ * flash_read_factory_serial - read the device Id from the protection area
  */
-static void flash_write_cmd (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
+void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset,
+				int len)
 {
+	uchar *src;
 
-	volatile cfiptr_t addr;
-	cfiword_t cword;
-
-	addr.cp = flash_make_addr (info, sect, offset);
-	flash_make_cmd (info, cmd, &cword);
-	switch (info->portwidth) {
-	case FLASH_CFI_8BIT:
-		debug ("fwc addr %p cmd %x %x 8bit x %d bit\n", addr.cp, cmd,
-		       cword.c, info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
-		*addr.cp = cword.c;
-		break;
-	case FLASH_CFI_16BIT:
-		debug ("fwc addr %p cmd %x %4.4x 16bit x %d bit\n", addr.wp,
-		       cmd, cword.w,
-		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
-		*addr.wp = cword.w;
-		break;
-	case FLASH_CFI_32BIT:
-		debug ("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n", addr.lp,
-		       cmd, cword.l,
-		       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
-		*addr.lp = cword.l;
-		break;
-	case FLASH_CFI_64BIT:
-#ifdef DEBUG
-		{
-			char str[20];
-
-			print_longlong (str, cword.ll);
-
-			debug ("fwrite addr %p cmd %x %s 64 bit x %d bit\n",
-			       addr.llp, cmd, str,
-			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
-		}
-#endif
-		*addr.llp = cword.ll;
-		break;
-	}
-
-	/* Ensure all the instructions are fully finished */
-	sync();
+	src = flash_map (info, 0, FLASH_OFFSET_INTEL_PROTECTION);
+	flash_write_cmd (info, 0, 0, FLASH_CMD_READ_ID);
+	memcpy (buffer, src + offset, len);
+	flash_write_cmd (info, 0, 0, info->cmd_reset);
+	flash_unmap(info, 0, FLASH_OFFSET_INTEL_PROTECTION, src);
 }
 
-static void flash_unlock_seq (flash_info_t * info, flash_sect_t sect)
-{
-	flash_write_cmd (info, sect, AMD_ADDR_START, AMD_CMD_UNLOCK_START);
-	flash_write_cmd (info, sect, AMD_ADDR_ACK, AMD_CMD_UNLOCK_ACK);
-}
+#endif /* CFG_FLASH_PROTECTION */
 
 /*-----------------------------------------------------------------------
+ * Reverse the order of the erase regions in the CFI QRY structure.
+ * This is needed for chips that are either a) correctly detected as
+ * top-boot, or b) buggy.
  */
-static int flash_isequal (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
+static void cfi_reverse_geometry(struct cfi_qry *qry)
 {
-	cfiptr_t cptr;
-	cfiword_t cword;
-	int retval;
+	unsigned int i, j;
+	u32 tmp;
 
-	cptr.cp = flash_make_addr (info, sect, offset);
-	flash_make_cmd (info, cmd, &cword);
-
-	debug ("is= cmd %x(%c) addr %p ", cmd, cmd, cptr.cp);
-	switch (info->portwidth) {
-	case FLASH_CFI_8BIT:
-		debug ("is= %x %x\n", cptr.cp[0], cword.c);
-		retval = (cptr.cp[0] == cword.c);
-		break;
-	case FLASH_CFI_16BIT:
-		debug ("is= %4.4x %4.4x\n", cptr.wp[0], cword.w);
-		retval = (cptr.wp[0] == cword.w);
-		break;
-	case FLASH_CFI_32BIT:
-		debug ("is= %8.8lx %8.8lx\n", cptr.lp[0], cword.l);
-		retval = (cptr.lp[0] == cword.l);
-		break;
-	case FLASH_CFI_64BIT:
-#ifdef DEBUG
-		{
-			char str1[20];
-			char str2[20];
-
-			print_longlong (str1, cptr.llp[0]);
-			print_longlong (str2, cword.ll);
-			debug ("is= %s %s\n", str1, str2);
-		}
-#endif
-		retval = (cptr.llp[0] == cword.ll);
-		break;
-	default:
-		retval = 0;
-		break;
+	for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) {
+		tmp = qry->erase_region_info[i];
+		qry->erase_region_info[i] = qry->erase_region_info[j];
+		qry->erase_region_info[j] = tmp;
 	}
-	return retval;
-}
-
-/*-----------------------------------------------------------------------
- */
-static int flash_isset (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
-{
-	cfiptr_t cptr;
-	cfiword_t cword;
-	int retval;
-
-	cptr.cp = flash_make_addr (info, sect, offset);
-	flash_make_cmd (info, cmd, &cword);
-	switch (info->portwidth) {
-	case FLASH_CFI_8BIT:
-		retval = ((cptr.cp[0] & cword.c) == cword.c);
-		break;
-	case FLASH_CFI_16BIT:
-		retval = ((cptr.wp[0] & cword.w) == cword.w);
-		break;
-	case FLASH_CFI_32BIT:
-		retval = ((cptr.lp[0] & cword.l) == cword.l);
-		break;
-	case FLASH_CFI_64BIT:
-		retval = ((cptr.llp[0] & cword.ll) == cword.ll);
-		break;
-	default:
-		retval = 0;
-		break;
-	}
-	return retval;
-}
-
-/*-----------------------------------------------------------------------
- */
-static int flash_toggle (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
-{
-	cfiptr_t cptr;
-	cfiword_t cword;
-	int retval;
-
-	cptr.cp = flash_make_addr (info, sect, offset);
-	flash_make_cmd (info, cmd, &cword);
-	switch (info->portwidth) {
-	case FLASH_CFI_8BIT:
-		retval = ((cptr.cp[0] & cword.c) != (cptr.cp[0] & cword.c));
-		break;
-	case FLASH_CFI_16BIT:
-		retval = ((cptr.wp[0] & cword.w) != (cptr.wp[0] & cword.w));
-		break;
-	case FLASH_CFI_32BIT:
-		retval = ((cptr.lp[0] & cword.l) != (cptr.lp[0] & cword.l));
-		break;
-	case FLASH_CFI_64BIT:
-		retval = ((cptr.llp[0] & cword.ll) !=
-			  (cptr.llp[0] & cword.ll));
-		break;
-	default:
-		retval = 0;
-		break;
-	}
-	return retval;
 }
 
 /*-----------------------------------------------------------------------
@@ -1082,7 +1324,69 @@
  *
  * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct
  *
-*/
+ */
+static void cmdset_intel_read_jedec_ids(flash_info_t *info)
+{
+	flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
+	flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
+	udelay(1000); /* some flash are slow to respond */
+	info->manufacturer_id = flash_read_uchar (info,
+					FLASH_OFFSET_MANUFACTURER_ID);
+	info->device_id = flash_read_uchar (info,
+					FLASH_OFFSET_DEVICE_ID);
+	flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
+}
+
+static int cmdset_intel_init(flash_info_t *info, struct cfi_qry *qry)
+{
+	info->cmd_reset = FLASH_CMD_RESET;
+
+	cmdset_intel_read_jedec_ids(info);
+	flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
+
+#ifdef CFG_FLASH_PROTECTION
+	/* read legacy lock/unlock bit from intel flash */
+	if (info->ext_addr) {
+		info->legacy_unlock = flash_read_uchar (info,
+				info->ext_addr + 5) & 0x08;
+	}
+#endif
+
+	return 0;
+}
+
+static void cmdset_amd_read_jedec_ids(flash_info_t *info)
+{
+	flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
+	flash_unlock_seq(info, 0);
+	flash_write_cmd(info, 0, info->addr_unlock1, FLASH_CMD_READ_ID);
+	udelay(1000); /* some flash are slow to respond */
+	info->manufacturer_id = flash_read_uchar (info,
+					FLASH_OFFSET_MANUFACTURER_ID);
+	info->device_id = flash_read_uchar (info,
+					FLASH_OFFSET_DEVICE_ID);
+	if (info->device_id == 0x7E) {
+		/* AMD 3-byte (expanded) device ids */
+		info->device_id2 = flash_read_uchar (info,
+					FLASH_OFFSET_DEVICE_ID2);
+		info->device_id2 <<= 8;
+		info->device_id2 |= flash_read_uchar (info,
+					FLASH_OFFSET_DEVICE_ID3);
+	}
+	flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
+}
+
+static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry)
+{
+	info->cmd_reset = AMD_CMD_RESET;
+
+	cmdset_amd_read_jedec_ids(info);
+	flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI);
+
+	return 0;
+}
+
+#ifdef CONFIG_FLASH_CFI_LEGACY
 static void flash_read_jedec_ids (flash_info_t * info)
 {
 	info->manufacturer_id = 0;
@@ -1092,34 +1396,11 @@
 	switch (info->vendor) {
 	case CFI_CMDSET_INTEL_STANDARD:
 	case CFI_CMDSET_INTEL_EXTENDED:
-		flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
-		flash_write_cmd(info, 0, 0, FLASH_CMD_READ_ID);
-		udelay(1000); /* some flash are slow to respond */
-		info->manufacturer_id = flash_read_uchar (info,
-						FLASH_OFFSET_MANUFACTURER_ID);
-		info->device_id = flash_read_uchar (info,
-						FLASH_OFFSET_DEVICE_ID);
-		flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
+		flash_read_jedec_ids_intel(info);
 		break;
 	case CFI_CMDSET_AMD_STANDARD:
 	case CFI_CMDSET_AMD_EXTENDED:
-		flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
-		flash_unlock_seq(info, 0);
-		flash_write_cmd(info, 0, AMD_ADDR_START, FLASH_CMD_READ_ID);
-		udelay(1000); /* some flash are slow to respond */
-		info->manufacturer_id = flash_read_uchar (info,
-						FLASH_OFFSET_MANUFACTURER_ID);
-		info->device_id = flash_read_uchar (info,
-						FLASH_OFFSET_DEVICE_ID);
-		if (info->device_id == 0x7E) {
-			/* AMD 3-byte (expanded) device ids */
-			info->device_id2 = flash_read_uchar (info,
-						FLASH_OFFSET_DEVICE_ID2);
-			info->device_id2 <<= 8;
-			info->device_id2 |= flash_read_uchar (info,
-						FLASH_OFFSET_DEVICE_ID3);
-		}
-		flash_write_cmd(info, 0, 0, AMD_CMD_RESET);
+		flash_read_jedec_ids_amd(info);
 		break;
 	default:
 		break;
@@ -1127,45 +1408,195 @@
 }
 
 /*-----------------------------------------------------------------------
+ * Call board code to request info about non-CFI flash.
+ * board_flash_get_legacy needs to fill in at least:
+ * info->portwidth, info->chipwidth and info->interface for Jedec probing.
+ */
+static int flash_detect_legacy(ulong base, int banknum)
+{
+	flash_info_t *info = &flash_info[banknum];
+
+	if (board_flash_get_legacy(base, banknum, info)) {
+		/* board code may have filled info completely. If not, we
+		   use JEDEC ID probing. */
+		if (!info->vendor) {
+			int modes[] = {
+				CFI_CMDSET_AMD_STANDARD,
+				CFI_CMDSET_INTEL_STANDARD
+			};
+			int i;
+
+			for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) {
+				info->vendor = modes[i];
+				info->start[0] = base;
+				if (info->portwidth == FLASH_CFI_8BIT
+					&& info->interface == FLASH_CFI_X8X16) {
+					info->addr_unlock1 = 0x2AAA;
+					info->addr_unlock2 = 0x5555;
+				} else {
+					info->addr_unlock1 = 0x5555;
+					info->addr_unlock2 = 0x2AAA;
+				}
+				flash_read_jedec_ids(info);
+				debug("JEDEC PROBE: ID %x %x %x\n",
+						info->manufacturer_id,
+						info->device_id,
+						info->device_id2);
+				if (jedec_flash_match(info, base))
+					break;
+			}
+		}
+
+		switch(info->vendor) {
+		case CFI_CMDSET_INTEL_STANDARD:
+		case CFI_CMDSET_INTEL_EXTENDED:
+			info->cmd_reset = FLASH_CMD_RESET;
+			break;
+		case CFI_CMDSET_AMD_STANDARD:
+		case CFI_CMDSET_AMD_EXTENDED:
+		case CFI_CMDSET_AMD_LEGACY:
+			info->cmd_reset = AMD_CMD_RESET;
+			break;
+		}
+		info->flash_id = FLASH_MAN_CFI;
+		return 1;
+	}
+	return 0; /* use CFI */
+}
+#else
+static inline int flash_detect_legacy(ulong base, int banknum)
+{
+	return 0; /* use CFI */
+}
+#endif
+
+/*-----------------------------------------------------------------------
  * detect if flash is compatible with the Common Flash Interface (CFI)
  * http://www.jedec.org/download/search/jesd68.pdf
- *
-*/
-static int flash_detect_cfi (flash_info_t * info)
+ */
+static void flash_read_cfi (flash_info_t *info, void *buf,
+		unsigned int start, size_t len)
+{
+	u8 *p = buf;
+	unsigned int i;
+
+	for (i = 0; i < len; i++)
+		p[i] = flash_read_uchar(info, start + i);
+}
+
+static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
 {
 	int cfi_offset;
+
+	flash_write_cmd (info, 0, 0, info->cmd_reset);
+	for (cfi_offset=0;
+	     cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint);
+	     cfi_offset++) {
+		flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset],
+				 FLASH_CMD_CFI);
+		if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
+		    && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
+		    && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
+			flash_read_cfi(info, qry, FLASH_OFFSET_CFI_RESP,
+					sizeof(struct cfi_qry));
+			info->interface	= le16_to_cpu(qry->interface_desc);
+
+			info->cfi_offset = flash_offset_cfi[cfi_offset];
+			debug ("device interface is %d\n",
+			       info->interface);
+			debug ("found port %d chip %d ",
+			       info->portwidth, info->chipwidth);
+			debug ("port %d bits chip %d bits\n",
+			       info->portwidth << CFI_FLASH_SHIFT_WIDTH,
+			       info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
+
+			/* calculate command offsets as in the Linux driver */
+			info->addr_unlock1 = 0x555;
+			info->addr_unlock2 = 0x2aa;
+
+			/*
+			 * modify the unlock address if we are
+			 * in compatibility mode
+			 */
+			if (	/* x8/x16 in x8 mode */
+				((info->chipwidth == FLASH_CFI_BY8) &&
+					(info->interface == FLASH_CFI_X8X16)) ||
+				/* x16/x32 in x16 mode */
+				((info->chipwidth == FLASH_CFI_BY16) &&
+					(info->interface == FLASH_CFI_X16X32)))
+			{
+				info->addr_unlock1 = 0xaaa;
+				info->addr_unlock2 = 0x555;
+			}
+
+			info->name = "CFI conformant";
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry)
+{
 	debug ("flash detect cfi\n");
 
 	for (info->portwidth = CFG_FLASH_CFI_WIDTH;
 	     info->portwidth <= FLASH_CFI_64BIT; info->portwidth <<= 1) {
 		for (info->chipwidth = FLASH_CFI_BY8;
 		     info->chipwidth <= info->portwidth;
-		     info->chipwidth <<= 1) {
-			flash_write_cmd (info, 0, 0, info->cmd_reset);
-			for (cfi_offset=0; cfi_offset < sizeof(flash_offset_cfi)/sizeof(uint); cfi_offset++) {
-				flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset], FLASH_CMD_CFI);
-				if (flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q')
-				 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')
-				 && flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) {
-					info->interface = flash_read_ushort (info, 0, FLASH_OFFSET_INTERFACE);
-					info->cfi_offset=flash_offset_cfi[cfi_offset];
-					debug ("device interface is %d\n",
-						info->interface);
-					debug ("found port %d chip %d ",
-						info->portwidth, info->chipwidth);
-					debug ("port %d bits chip %d bits\n",
-						info->portwidth << CFI_FLASH_SHIFT_WIDTH,
-						info->chipwidth << CFI_FLASH_SHIFT_WIDTH);
-					return 1;
-				}
-			}
-		}
+		     info->chipwidth <<= 1)
+			if (__flash_detect_cfi(info, qry))
+				return 1;
 	}
 	debug ("not found\n");
 	return 0;
 }
 
 /*
+ * Manufacturer-specific quirks. Add workarounds for geometry
+ * reversal, etc. here.
+ */
+static void flash_fixup_amd(flash_info_t *info, struct cfi_qry *qry)
+{
+	/* check if flash geometry needs reversal */
+	if (qry->num_erase_regions > 1) {
+		/* reverse geometry if top boot part */
+		if (info->cfi_version < 0x3131) {
+			/* CFI < 1.1, try to guess from device id */
+			if ((info->device_id & 0x80) != 0)
+				cfi_reverse_geometry(qry);
+		} else if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
+			/* CFI >= 1.1, deduct from top/bottom flag */
+			/* note: ext_addr is valid since cfi_version > 0 */
+			cfi_reverse_geometry(qry);
+		}
+	}
+}
+
+static void flash_fixup_atmel(flash_info_t *info, struct cfi_qry *qry)
+{
+	int reverse_geometry = 0;
+
+	/* Check the "top boot" bit in the PRI */
+	if (info->ext_addr && !(flash_read_uchar(info, info->ext_addr + 6) & 1))
+		reverse_geometry = 1;
+
+	/* AT49BV6416(T) list the erase regions in the wrong order.
+	 * However, the device ID is identical with the non-broken
+	 * AT49BV642D since u-boot only reads the low byte (they
+	 * differ in the high byte.) So leave out this fixup for now.
+	 */
+#if 0
+	if (info->device_id == 0xd6 || info->device_id == 0xd2)
+		reverse_geometry = !reverse_geometry;
+#endif
+
+	if (reverse_geometry)
+		cfi_reverse_geometry(qry);
+}
+
+/*
  * The following code cannot be run from FLASH!
  *
  */
@@ -1180,7 +1611,7 @@
 	uchar num_erase_regions;
 	int erase_region_size;
 	int erase_region_count;
-	int geometry_reversed = 0;
+	struct cfi_qry qry;
 
 	info->ext_addr = 0;
 	info->cfi_version = 0;
@@ -1190,56 +1621,50 @@
 
 	info->start[0] = base;
 
-	if (flash_detect_cfi (info)) {
-		info->vendor = flash_read_ushort (info, 0,
-					FLASH_OFFSET_PRIMARY_VENDOR);
-		flash_read_jedec_ids (info);
-		flash_write_cmd (info, 0, info->cfi_offset, FLASH_CMD_CFI);
-		num_erase_regions = flash_read_uchar (info,
-					FLASH_OFFSET_NUM_ERASE_REGIONS);
-		info->ext_addr = flash_read_ushort (info, 0,
-					FLASH_OFFSET_EXT_QUERY_T_P_ADDR);
+	if (flash_detect_cfi (info, &qry)) {
+		info->vendor = le16_to_cpu(qry.p_id);
+		info->ext_addr = le16_to_cpu(qry.p_adr);
+		num_erase_regions = qry.num_erase_regions;
+
 		if (info->ext_addr) {
 			info->cfi_version = (ushort) flash_read_uchar (info,
 						info->ext_addr + 3) << 8;
 			info->cfi_version |= (ushort) flash_read_uchar (info,
 						info->ext_addr + 4);
 		}
+
 #ifdef DEBUG
-		flash_printqry (info, 0);
+		flash_printqry (&qry);
 #endif
+
 		switch (info->vendor) {
 		case CFI_CMDSET_INTEL_STANDARD:
 		case CFI_CMDSET_INTEL_EXTENDED:
-		default:
-			info->cmd_reset = FLASH_CMD_RESET;
-#ifdef CFG_FLASH_PROTECTION
-			/* read legacy lock/unlock bit from intel flash */
-			if (info->ext_addr) {
-				info->legacy_unlock = flash_read_uchar (info,
-						info->ext_addr + 5) & 0x08;
-			}
-#endif
+			cmdset_intel_init(info, &qry);
 			break;
 		case CFI_CMDSET_AMD_STANDARD:
 		case CFI_CMDSET_AMD_EXTENDED:
-			info->cmd_reset = AMD_CMD_RESET;
-			/* check if flash geometry needs reversal */
-			if (num_erase_regions <= 1)
-				break;
-			/* reverse geometry if top boot part */
-			if (info->cfi_version < 0x3131) {
-				/* CFI < 1.1, try to guess from device id */
-				if ((info->device_id & 0x80) != 0) {
-					geometry_reversed = 1;
-				}
-				break;
-			}
-			/* CFI >= 1.1, deduct from top/bottom flag */
-			/* note: ext_addr is valid since cfi_version > 0 */
-			if (flash_read_uchar(info, info->ext_addr + 0xf) == 3) {
-				geometry_reversed = 1;
-			}
+			cmdset_amd_init(info, &qry);
+			break;
+		default:
+			printf("CFI: Unknown command set 0x%x\n",
+					info->vendor);
+			/*
+			 * Unfortunately, this means we don't know how
+			 * to get the chip back to Read mode. Might
+			 * as well try an Intel-style reset...
+			 */
+			flash_write_cmd(info, 0, 0, FLASH_CMD_RESET);
+			return 0;
+		}
+
+		/* Do manufacturer-specific fixups */
+		switch (info->manufacturer_id) {
+		case 0x0001:
+			flash_fixup_amd(info, &qry);
+			break;
+		case 0x001f:
+			flash_fixup_atmel(info, &qry);
 			break;
 		}
 
@@ -1267,26 +1692,27 @@
 					num_erase_regions, NUM_ERASE_REGIONS);
 				break;
 			}
-			if (geometry_reversed)
-				tmp = flash_read_long (info, 0,
-					       FLASH_OFFSET_ERASE_REGIONS +
-					       (num_erase_regions - 1 - i) * 4);
-			else
-				tmp = flash_read_long (info, 0,
-					       FLASH_OFFSET_ERASE_REGIONS +
-					       i * 4);
+
+			tmp = le32_to_cpu(qry.erase_region_info[i]);
+			debug("erase region %u: 0x%08lx\n", i, tmp);
+
+			erase_region_count = (tmp & 0xffff) + 1;
+			tmp >>= 16;
 			erase_region_size =
 				(tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128;
-			tmp >>= 16;
-			erase_region_count = (tmp & 0xffff) + 1;
 			debug ("erase_region_count = %d erase_region_size = %d\n",
 				erase_region_count, erase_region_size);
 			for (j = 0; j < erase_region_count; j++) {
+				if (sect_cnt >= CFG_MAX_FLASH_SECT) {
+					printf("ERROR: too many flash sectors\n");
+					break;
+				}
 				info->start[sect_cnt] = sector;
 				sector += (erase_region_size * size_ratio);
 
 				/*
-				 * Only read protection status from supported devices (intel...)
+				 * Only read protection status from
+				 * supported devices (intel...)
 				 */
 				switch (info->vendor) {
 				case CFI_CMDSET_INTEL_EXTENDED:
@@ -1297,7 +1723,8 @@
 							     FLASH_STATUS_PROTECT);
 					break;
 				default:
-					info->protect[sect_cnt] = 0; /* default: not protected */
+					/* default: not protected */
+					info->protect[sect_cnt] = 0;
 				}
 
 				sect_cnt++;
@@ -1305,20 +1732,27 @@
 		}
 
 		info->sector_count = sect_cnt;
+		info->size = 1 << qry.dev_size;
 		/* multiply the size by the number of chips */
-		info->size = (1 << flash_read_uchar (info, FLASH_OFFSET_SIZE)) * size_ratio;
-		info->buffer_size = (1 << flash_read_ushort (info, 0, FLASH_OFFSET_BUFFER_SIZE));
-		tmp = 1 << flash_read_uchar (info, FLASH_OFFSET_ETOUT);
-		info->erase_blk_tout = (tmp * (1 << flash_read_uchar (info, FLASH_OFFSET_EMAX_TOUT)));
-		tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WBTOUT)) *
-			(1 << flash_read_uchar (info, FLASH_OFFSET_WBMAX_TOUT));
-		info->buffer_write_tout = tmp / 1000 + (tmp % 1000 ? 1 : 0); /* round up when converting to ms */
-		tmp = (1 << flash_read_uchar (info, FLASH_OFFSET_WTOUT)) *
-		      (1 << flash_read_uchar (info, FLASH_OFFSET_WMAX_TOUT));
-		info->write_tout = tmp / 1000 + (tmp % 1000 ? 1 : 0); /* round up when converting to ms */
+		info->size *= size_ratio;
+		info->buffer_size = 1 << le16_to_cpu(qry.max_buf_write_size);
+		tmp = 1 << qry.block_erase_timeout_typ;
+		info->erase_blk_tout = tmp *
+			(1 << qry.block_erase_timeout_max);
+		tmp = (1 << qry.buf_write_timeout_typ) *
+			(1 << qry.buf_write_timeout_max);
+
+		/* round up when converting to ms */
+		info->buffer_write_tout = (tmp + 999) / 1000;
+		tmp = (1 << qry.word_write_timeout_typ) *
+			(1 << qry.word_write_timeout_max);
+		/* round up when converting to ms */
+		info->write_tout = (tmp + 999) / 1000;
 		info->flash_id = FLASH_MAN_CFI;
-		if ((info->interface == FLASH_CFI_X8X16) && (info->chipwidth == FLASH_CFI_BY8)) {
-			info->portwidth >>= 1;	/* XXX - Need to test on x8/x16 in parallel. */
+		if ((info->interface == FLASH_CFI_X8X16) &&
+		    (info->chipwidth == FLASH_CFI_BY8)) {
+			/* XXX - Need to test on x8/x16 in parallel. */
+			info->portwidth >>= 1;
 		}
 	}
 
@@ -1326,203 +1760,106 @@
 	return (info->size);
 }
 
-/* loop through the sectors from the highest address
- * when the passed address is greater or equal to the sector address
- * we have a match
- */
-static flash_sect_t find_sector (flash_info_t * info, ulong addr)
-{
-	flash_sect_t sector;
-
-	for (sector = info->sector_count - 1; sector >= 0; sector--) {
-		if (addr >= info->start[sector])
-			break;
-	}
-	return sector;
-}
-
 /*-----------------------------------------------------------------------
  */
-static int flash_write_cfiword (flash_info_t * info, ulong dest,
-				cfiword_t cword)
+unsigned long flash_init (void)
 {
-	cfiptr_t ctladdr;
-	cfiptr_t cptr;
-	int flag;
+	unsigned long size = 0;
+	int i;
 
-	ctladdr.cp = flash_make_addr (info, 0, 0);
-	cptr.cp = (uchar *) dest;
+#ifdef CFG_FLASH_PROTECTION
+	char *s = getenv("unlock");
+#endif
 
-	/* Check if Flash is (sufficiently) erased */
-	switch (info->portwidth) {
-	case FLASH_CFI_8BIT:
-		flag = ((cptr.cp[0] & cword.c) == cword.c);
-		break;
-	case FLASH_CFI_16BIT:
-		flag = ((cptr.wp[0] & cword.w) == cword.w);
-		break;
-	case FLASH_CFI_32BIT:
-		flag = ((cptr.lp[0] & cword.l) == cword.l);
-		break;
-	case FLASH_CFI_64BIT:
-		flag = ((cptr.llp[0] & cword.ll) == cword.ll);
-		break;
-	default:
-		return 2;
-	}
-	if (!flag)
-		return 2;
+	/* Init: no FLASHes known */
+	for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
+		flash_info[i].flash_id = FLASH_UNKNOWN;
 
-	/* Disable interrupts which might cause a timeout here */
-	flag = disable_interrupts ();
-
-	switch (info->vendor) {
-	case CFI_CMDSET_INTEL_EXTENDED:
-	case CFI_CMDSET_INTEL_STANDARD:
-		flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS);
-		flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE);
-		break;
-	case CFI_CMDSET_AMD_EXTENDED:
-	case CFI_CMDSET_AMD_STANDARD:
-		flash_unlock_seq (info, 0);
-		flash_write_cmd (info, 0, AMD_ADDR_START, AMD_CMD_WRITE);
-		break;
-	}
-
-	switch (info->portwidth) {
-	case FLASH_CFI_8BIT:
-		cptr.cp[0] = cword.c;
-		break;
-	case FLASH_CFI_16BIT:
-		cptr.wp[0] = cword.w;
-		break;
-	case FLASH_CFI_32BIT:
-		cptr.lp[0] = cword.l;
-		break;
-	case FLASH_CFI_64BIT:
-		cptr.llp[0] = cword.ll;
-		break;
-	}
-
-	/* re-enable interrupts if necessary */
-	if (flag)
-		enable_interrupts ();
-
-	return flash_full_status_check (info, find_sector (info, dest),
-					info->write_tout, "write");
-}
-
-#ifdef CFG_FLASH_USE_BUFFER_WRITE
-
-static int flash_write_cfibuffer (flash_info_t * info, ulong dest, uchar * cp,
-				  int len)
-{
-	flash_sect_t sector;
-	int cnt;
-	int retcode;
-	volatile cfiptr_t src;
-	volatile cfiptr_t dst;
-
-	switch (info->vendor) {
-	case CFI_CMDSET_INTEL_STANDARD:
-	case CFI_CMDSET_INTEL_EXTENDED:
-		src.cp = cp;
-		dst.cp = (uchar *) dest;
-		sector = find_sector (info, dest);
-		flash_write_cmd (info, sector, 0, FLASH_CMD_CLEAR_STATUS);
-		flash_write_cmd (info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER);
-		if ((retcode = flash_status_check (info, sector, info->buffer_write_tout,
-						   "write to buffer")) == ERR_OK) {
-			/* reduce the number of loops by the width of the port	*/
-			switch (info->portwidth) {
-			case FLASH_CFI_8BIT:
-				cnt = len;
-				break;
-			case FLASH_CFI_16BIT:
-				cnt = len >> 1;
-				break;
-			case FLASH_CFI_32BIT:
-				cnt = len >> 2;
-				break;
-			case FLASH_CFI_64BIT:
-				cnt = len >> 3;
-				break;
-			default:
-				return ERR_INVAL;
-				break;
-			}
-			flash_write_cmd (info, sector, 0, (uchar) cnt - 1);
-			while (cnt-- > 0) {
-				switch (info->portwidth) {
-				case FLASH_CFI_8BIT:
-					*dst.cp++ = *src.cp++;
-					break;
-				case FLASH_CFI_16BIT:
-					*dst.wp++ = *src.wp++;
-					break;
-				case FLASH_CFI_32BIT:
-					*dst.lp++ = *src.lp++;
-					break;
-				case FLASH_CFI_64BIT:
-					*dst.llp++ = *src.llp++;
-					break;
-				default:
-					return ERR_INVAL;
-					break;
-				}
-			}
-			flash_write_cmd (info, sector, 0,
-					 FLASH_CMD_WRITE_BUFFER_CONFIRM);
-			retcode = flash_full_status_check (info, sector,
-							   info->buffer_write_tout,
-							   "buffer write");
+		if (!flash_detect_legacy (bank_base[i], i))
+			flash_get_size (bank_base[i], i);
+		size += flash_info[i].size;
+		if (flash_info[i].flash_id == FLASH_UNKNOWN) {
+#ifndef CFG_FLASH_QUIET_TEST
+			printf ("## Unknown FLASH on Bank %d "
+				"- Size = 0x%08lx = %ld MB\n",
+				i+1, flash_info[i].size,
+				flash_info[i].size << 20);
+#endif /* CFG_FLASH_QUIET_TEST */
 		}
-		return retcode;
+#ifdef CFG_FLASH_PROTECTION
+		else if ((s != NULL) && (strcmp(s, "yes") == 0)) {
+			/*
+			 * Only the U-Boot image and it's environment
+			 * is protected, all other sectors are
+			 * unprotected (unlocked) if flash hardware
+			 * protection is used (CFG_FLASH_PROTECTION)
+			 * and the environment variable "unlock" is
+			 * set to "yes".
+			 */
+			if (flash_info[i].legacy_unlock) {
+				int k;
 
-	case CFI_CMDSET_AMD_STANDARD:
-	case CFI_CMDSET_AMD_EXTENDED:
-		src.cp = cp;
-		dst.cp = (uchar *) dest;
-		sector = find_sector (info, dest);
+				/*
+				 * Disable legacy_unlock temporarily,
+				 * since flash_real_protect would
+				 * relock all other sectors again
+				 * otherwise.
+				 */
+				flash_info[i].legacy_unlock = 0;
 
-		flash_unlock_seq(info,0);
-		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_TO_BUFFER);
+				/*
+				 * Legacy unlocking (e.g. Intel J3) ->
+				 * unlock only one sector. This will
+				 * unlock all sectors.
+				 */
+				flash_real_protect (&flash_info[i], 0, 0);
 
-		switch (info->portwidth) {
-		case FLASH_CFI_8BIT:
-			cnt = len;
-			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
-			while (cnt-- > 0) *dst.cp++ = *src.cp++;
-			break;
-		case FLASH_CFI_16BIT:
-			cnt = len >> 1;
-			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
-			while (cnt-- > 0) *dst.wp++ = *src.wp++;
-			break;
-		case FLASH_CFI_32BIT:
-			cnt = len >> 2;
-			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
-			while (cnt-- > 0) *dst.lp++ = *src.lp++;
-			break;
-		case FLASH_CFI_64BIT:
-			cnt = len >> 3;
-			flash_write_cmd (info, sector, 0,  (uchar) cnt - 1);
-			while (cnt-- > 0) *dst.llp++ = *src.llp++;
-			break;
-		default:
-			return ERR_INVAL;
+				flash_info[i].legacy_unlock = 1;
+
+				/*
+				 * Manually mark other sectors as
+				 * unlocked (unprotected)
+				 */
+				for (k = 1; k < flash_info[i].sector_count; k++)
+					flash_info[i].protect[k] = 0;
+			} else {
+				/*
+				 * No legancy unlocking -> unlock all sectors
+				 */
+				flash_protect (FLAG_PROTECT_CLEAR,
+					       flash_info[i].start[0],
+					       flash_info[i].start[0]
+					       + flash_info[i].size - 1,
+					       &flash_info[i]);
+			}
 		}
-
-		flash_write_cmd (info, sector, 0, AMD_CMD_WRITE_BUFFER_CONFIRM);
-		retcode = flash_full_status_check (info, sector, info->buffer_write_tout,
-						   "buffer write");
-		return retcode;
-
-	default:
-		debug ("Unknown Command Set\n");
-		return ERR_INVAL;
+#endif /* CFG_FLASH_PROTECTION */
 	}
+
+	/* Monitor protection ON by default */
+#if (CFG_MONITOR_BASE >= CFG_FLASH_BASE)
+	flash_protect (FLAG_PROTECT_SET,
+		       CFG_MONITOR_BASE,
+		       CFG_MONITOR_BASE + monitor_flash_len  - 1,
+		       flash_get_info(CFG_MONITOR_BASE));
+#endif
+
+	/* Environment protection ON by default */
+#ifdef CFG_ENV_IS_IN_FLASH
+	flash_protect (FLAG_PROTECT_SET,
+		       CFG_ENV_ADDR,
+		       CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
+		       flash_get_info(CFG_ENV_ADDR));
+#endif
+
+	/* Redundant environment protection ON by default */
+#ifdef CFG_ENV_ADDR_REDUND
+	flash_protect (FLAG_PROTECT_SET,
+		       CFG_ENV_ADDR_REDUND,
+		       CFG_ENV_ADDR_REDUND + CFG_ENV_SIZE_REDUND - 1,
+		       flash_get_info(CFG_ENV_ADDR_REDUND));
+#endif
+	return (size);
 }
-#endif /* CFG_FLASH_USE_BUFFER_WRITE */
 
 #endif /* CFG_FLASH_CFI */
diff --git a/drivers/mtd/jedec_flash.c b/drivers/mtd/jedec_flash.c
new file mode 100644
index 0000000..94e87cb
--- /dev/null
+++ b/drivers/mtd/jedec_flash.c
@@ -0,0 +1,311 @@
+/*
+ * (C) Copyright 2007
+ * Michael Schwingen, <michael@schwingen.org>
+ *
+ * based in great part on jedec_probe.c from linux kernel:
+ * (C) 2000 Red Hat. GPL'd.
+ * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot 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
+ *
+ */
+
+/* The DEBUG define must be before common to enable debugging */
+/*#define DEBUG*/
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <environment.h>
+
+#define P_ID_AMD_STD CFI_CMDSET_AMD_LEGACY
+
+/* Manufacturers */
+#define MANUFACTURER_AMD	0x0001
+#define MANUFACTURER_SST	0x00BF
+
+/* AMD */
+#define AM29DL800BB	0x22C8
+#define AM29DL800BT	0x224A
+
+#define AM29F800BB	0x2258
+#define AM29F800BT	0x22D6
+#define AM29LV400BB	0x22BA
+#define AM29LV400BT	0x22B9
+#define AM29LV800BB	0x225B
+#define AM29LV800BT	0x22DA
+#define AM29LV160DT	0x22C4
+#define AM29LV160DB	0x2249
+#define AM29F017D	0x003D
+#define AM29F016D	0x00AD
+#define AM29F080	0x00D5
+#define AM29F040	0x00A4
+#define AM29LV040B	0x004F
+#define AM29F032B	0x0041
+#define AM29F002T	0x00B0
+
+/* SST */
+#define SST39LF800	0x2781
+#define SST39LF160	0x2782
+#define SST39VF1601	0x234b
+#define SST39LF512	0x00D4
+#define SST39LF010	0x00D5
+#define SST39LF020	0x00D6
+#define SST39LF040	0x00D7
+#define SST39SF010A	0x00B5
+#define SST39SF020A	0x00B6
+
+
+/*
+ * Unlock address sets for AMD command sets.
+ * Intel command sets use the MTD_UADDR_UNNECESSARY.
+ * Each identifier, except MTD_UADDR_UNNECESSARY, and
+ * MTD_UADDR_NO_SUPPORT must be defined below in unlock_addrs[].
+ * MTD_UADDR_NOT_SUPPORTED must be 0 so that structure
+ * initialization need not require initializing all of the
+ * unlock addresses for all bit widths.
+ */
+enum uaddr {
+	MTD_UADDR_NOT_SUPPORTED = 0,	/* data width not supported */
+	MTD_UADDR_0x0555_0x02AA,
+	MTD_UADDR_0x0555_0x0AAA,
+	MTD_UADDR_0x5555_0x2AAA,
+	MTD_UADDR_0x0AAA_0x0555,
+	MTD_UADDR_DONT_CARE,		/* Requires an arbitrary address */
+	MTD_UADDR_UNNECESSARY,		/* Does not require any address */
+};
+
+
+struct unlock_addr {
+	u32 addr1;
+	u32 addr2;
+};
+
+
+/*
+ * I don't like the fact that the first entry in unlock_addrs[]
+ * exists, but is for MTD_UADDR_NOT_SUPPORTED - and, therefore,
+ * should not be used.  The  problem is that structures with
+ * initializers have extra fields initialized to 0.  It is _very_
+ * desireable to have the unlock address entries for unsupported
+ * data widths automatically initialized - that means that
+ * MTD_UADDR_NOT_SUPPORTED must be 0 and the first entry here
+ * must go unused.
+ */
+static const struct unlock_addr  unlock_addrs[] = {
+	[MTD_UADDR_NOT_SUPPORTED] = {
+		.addr1 = 0xffff,
+		.addr2 = 0xffff
+	},
+
+	[MTD_UADDR_0x0555_0x02AA] = {
+		.addr1 = 0x0555,
+		.addr2 = 0x02aa
+	},
+
+	[MTD_UADDR_0x0555_0x0AAA] = {
+		.addr1 = 0x0555,
+		.addr2 = 0x0aaa
+	},
+
+	[MTD_UADDR_0x5555_0x2AAA] = {
+		.addr1 = 0x5555,
+		.addr2 = 0x2aaa
+	},
+
+	[MTD_UADDR_0x0AAA_0x0555] = {
+		.addr1 = 0x0AAA,
+		.addr2 = 0x0555
+	},
+
+	[MTD_UADDR_DONT_CARE] = {
+		.addr1 = 0x0000,      /* Doesn't matter which address */
+		.addr2 = 0x0000       /* is used - must be last entry */
+	},
+
+	[MTD_UADDR_UNNECESSARY] = {
+		.addr1 = 0x0000,
+		.addr2 = 0x0000
+	}
+};
+
+
+struct amd_flash_info {
+	const __u16 mfr_id;
+	const __u16 dev_id;
+	const char *name;
+	const int DevSize;
+	const int NumEraseRegions;
+	const int CmdSet;
+	const __u8 uaddr[4];		/* unlock addrs for 8, 16, 32, 64 */
+	const ulong regions[6];
+};
+
+#define ERASEINFO(size,blocks) (size<<8)|(blocks-1)
+
+#define SIZE_64KiB  16
+#define SIZE_128KiB 17
+#define SIZE_256KiB 18
+#define SIZE_512KiB 19
+#define SIZE_1MiB   20
+#define SIZE_2MiB   21
+#define SIZE_4MiB   22
+#define SIZE_8MiB   23
+
+static const struct amd_flash_info jedec_table[] = {
+#ifdef CFG_FLASH_LEGACY_256Kx8
+	{
+		.mfr_id		= MANUFACTURER_SST,
+		.dev_id		= SST39LF020,
+		.name		= "SST 39LF020",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+		},
+		.DevSize	= SIZE_256KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x01000,64),
+		}
+	},
+#endif
+#ifdef CFG_FLASH_LEGACY_512Kx8
+	{
+		.mfr_id		= MANUFACTURER_AMD,
+		.dev_id		= AM29LV040B,
+		.name		= "AMD AM29LV040B",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+		},
+		.DevSize	= SIZE_512KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x10000,8),
+		}
+	},
+	{
+		.mfr_id		= MANUFACTURER_SST,
+		.dev_id		= SST39LF040,
+		.name		= "SST 39LF040",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+		},
+		.DevSize	= SIZE_512KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x01000,128),
+		}
+	},
+#endif
+};
+
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+
+static inline void fill_info(flash_info_t *info, const struct amd_flash_info *jedec_entry, ulong base)
+{
+	int i,j;
+	int sect_cnt;
+	int size_ratio;
+	int total_size;
+	enum uaddr uaddr_idx;
+
+	size_ratio = info->portwidth / info->chipwidth;
+
+	debug("Found JEDEC Flash: %s\n", jedec_entry->name);
+	info->vendor = jedec_entry->CmdSet;
+	/* Todo: do we need device-specific timeouts? */
+	info->erase_blk_tout = 30000;
+	info->buffer_write_tout = 1000;
+	info->write_tout = 100;
+	info->name = jedec_entry->name;
+
+	/* copy unlock addresses from device table to CFI info struct. This
+	   is just here because the addresses are in the table anyway - if
+	   the flash is not detected due to wrong unlock addresses,
+	   flash_detect_legacy would have to try all of them before we even
+	   get here. */
+	switch(info->chipwidth) {
+	case FLASH_CFI_8BIT:
+		uaddr_idx = jedec_entry->uaddr[0];
+		break;
+	case FLASH_CFI_16BIT:
+		uaddr_idx = jedec_entry->uaddr[1];
+		break;
+	case FLASH_CFI_32BIT:
+		uaddr_idx = jedec_entry->uaddr[2];
+		break;
+	default:
+		uaddr_idx = MTD_UADDR_NOT_SUPPORTED;
+		break;
+	}
+
+	debug("unlock address index %d\n", uaddr_idx);
+	info->addr_unlock1 = unlock_addrs[uaddr_idx].addr1;
+	info->addr_unlock2 = unlock_addrs[uaddr_idx].addr2;
+	debug("unlock addresses are 0x%x/0x%x\n", info->addr_unlock1, info->addr_unlock2);
+
+	sect_cnt = 0;
+	total_size = 0;
+	for (i = 0; i < jedec_entry->NumEraseRegions; i++) {
+		ulong erase_region_size = jedec_entry->regions[i] >> 8;
+		ulong erase_region_count = (jedec_entry->regions[i] & 0xff) + 1;
+
+		total_size += erase_region_size * erase_region_count;
+		debug ("erase_region_count = %d erase_region_size = %d\n",
+		       erase_region_count, erase_region_size);
+		for (j = 0; j < erase_region_count; j++) {
+			if (sect_cnt >= CFG_MAX_FLASH_SECT) {
+				printf("ERROR: too many flash sectors\n");
+				break;
+			}
+			info->start[sect_cnt] = base;
+			base += (erase_region_size * size_ratio);
+			sect_cnt++;
+		}
+	}
+	info->sector_count = sect_cnt;
+	info->size = total_size * size_ratio;
+}
+
+/*-----------------------------------------------------------------------
+ * match jedec ids against table. If a match is found, fill flash_info entry
+ */
+int jedec_flash_match(flash_info_t *info, ulong base)
+{
+	int ret = 0;
+	int i;
+	ulong mask = 0xFFFF;
+	if (info->chipwidth == 1)
+		mask = 0xFF;
+
+	for (i = 0; i < ARRAY_SIZE(jedec_table); i++) {
+		if ((jedec_table[i].mfr_id & mask) == (info->manufacturer_id & mask) &&
+		    (jedec_table[i].dev_id & mask) == (info->device_id & mask)) {
+			fill_info(info, &jedec_table[i], base);
+			ret = 1;
+			break;
+		}
+	}
+	return ret;
+}
diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h
index 47c18e7..029b7f9 100644
--- a/include/asm-arm/io.h
+++ b/include/asm-arm/io.h
@@ -34,6 +34,32 @@
 }
 
 /*
+ * Given a physical address and a length, return a virtual address
+ * that can be used to access the memory range with the caching
+ * properties specified by "flags".
+ */
+typedef unsigned long phys_addr_t;
+
+#define MAP_NOCACHE	(0)
+#define MAP_WRCOMBINE	(0)
+#define MAP_WRBACK	(0)
+#define MAP_WRTHROUGH	(0)
+
+static inline void *
+map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
+{
+	return (void *)paddr;
+}
+
+/*
+ * Take down a mapping set up by map_physmem().
+ */
+static inline void unmap_physmem(void *vaddr, unsigned long flags)
+{
+
+}
+
+/*
  * Generic virtual read/write.  Note that we don't support half-word
  * read/writes.  We define __arch_*[bl] here, and leave __arch_*w
  * to the architecture specific code.
diff --git a/include/asm-avr32/io.h b/include/asm-avr32/io.h
index 3c0d569..ba14674 100644
--- a/include/asm-avr32/io.h
+++ b/include/asm-avr32/io.h
@@ -93,4 +93,36 @@
 {
 }
 
+/*
+ * Given a physical address and a length, return a virtual address
+ * that can be used to access the memory range with the caching
+ * properties specified by "flags".
+ *
+ * This implementation works for memory below 512MiB (flash, etc.) as
+ * well as above 3.5GiB (internal peripherals.)
+ */
+typedef unsigned long phys_addr_t;
+
+#define MAP_NOCACHE	(0)
+#define MAP_WRCOMBINE	(1 << 7)
+#define MAP_WRBACK	(MAP_WRCOMBINE | (1 << 9))
+#define MAP_WRTHROUGH	(MAP_WRBACK | (1 << 0))
+
+static inline void *
+map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
+{
+	if (flags == MAP_WRBACK)
+		return (void *)P1SEGADDR(paddr);
+	else
+		return (void *)P2SEGADDR(paddr);
+}
+
+/*
+ * Take down a mapping set up by map_physmem().
+ */
+static inline void unmap_physmem(void *vaddr, unsigned long len)
+{
+
+}
+
 #endif /* __ASM_AVR32_IO_H */
diff --git a/include/asm-blackfin/io.h b/include/asm-blackfin/io.h
index 332d2c6..512e13d 100644
--- a/include/asm-blackfin/io.h
+++ b/include/asm-blackfin/io.h
@@ -41,6 +41,32 @@
 }
 
 /*
+ * Given a physical address and a length, return a virtual address
+ * that can be used to access the memory range with the caching
+ * properties specified by "flags".
+ */
+typedef unsigned long phys_addr_t;
+
+#define MAP_NOCACHE	(0)
+#define MAP_WRCOMBINE	(0)
+#define MAP_WRBACK	(0)
+#define MAP_WRTHROUGH	(0)
+
+static inline void *
+map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
+{
+	return (void *)paddr;
+}
+
+/*
+ * Take down a mapping set up by map_physmem().
+ */
+static inline void unmap_physmem(void *vaddr, unsigned long flags)
+{
+
+}
+
+/*
  * These are for ISA/PCI shared memory _only_ and should never be used
  * on any other type of memory, including Zorro memory. They are meant to
  * access the bus in the bus byte order which is little-endian!.
diff --git a/include/asm-i386/io.h b/include/asm-i386/io.h
index e64d788..db4f442 100644
--- a/include/asm-i386/io.h
+++ b/include/asm-i386/io.h
@@ -205,4 +205,30 @@
 {
 }
 
+/*
+ * Given a physical address and a length, return a virtual address
+ * that can be used to access the memory range with the caching
+ * properties specified by "flags".
+ */
+typedef unsigned long phys_addr_t;
+
+#define MAP_NOCACHE	(0)
+#define MAP_WRCOMBINE	(0)
+#define MAP_WRBACK	(0)
+#define MAP_WRTHROUGH	(0)
+
+static inline void *
+map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
+{
+	return (void *)paddr;
+}
+
+/*
+ * Take down a mapping set up by map_physmem().
+ */
+static inline void unmap_physmem(void *vaddr, unsigned long flags)
+{
+
+}
+
 #endif
diff --git a/include/asm-m68k/io.h b/include/asm-m68k/io.h
index e14a581..91d7592 100644
--- a/include/asm-m68k/io.h
+++ b/include/asm-m68k/io.h
@@ -28,6 +28,20 @@
 
 #include <asm/byteorder.h>
 
+/* ++roman: The assignments to temp. vars avoid that gcc sometimes generates
+ * two accesses to memory, which may be undesirable for some devices.
+ */
+#define __raw_readb(addr) \
+    ({ u8 __v = (*(volatile u8 *) (addr)); __v; })
+#define __raw_readw(addr) \
+    ({ u16 __v = (*(volatile u16 *) (addr)); __v; })
+#define __raw_readl(addr) \
+    ({ u32 __v = (*(volatile u32 *) (addr)); __v; })
+
+#define __raw_writeb(addr,b) (void)((*(volatile u8 *) (addr)) = (b))
+#define __raw_writew(addr,w) (void)((*(volatile u16 *) (addr)) = (w))
+#define __raw_writel(addr,l) (void)((*(volatile u32 *) (addr)) = (l))
+
 #define readb(addr)		in_8((volatile u8 *)(addr))
 #define writeb(b,addr)		out_8((volatile u8 *)(addr), (b))
 #if !defined(__BIG_ENDIAN)
@@ -218,4 +232,31 @@
 	 * compatibility (CFI driver)
 	 */
 }
+
+/*
+ * Given a physical address and a length, return a virtual address
+ * that can be used to access the memory range with the caching
+ * properties specified by "flags".
+ */
+typedef unsigned long phys_addr_t;
+
+#define MAP_NOCACHE	(0)
+#define MAP_WRCOMBINE	(0)
+#define MAP_WRBACK	(0)
+#define MAP_WRTHROUGH	(0)
+
+static inline void *
+map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
+{
+	return (void *)paddr;
+}
+
+/*
+ * Take down a mapping set up by map_physmem().
+ */
+static inline void unmap_physmem(void *vaddr, unsigned long flags)
+{
+
+}
+
 #endif				/* __ASM_M68K_IO_H__ */
diff --git a/include/asm-microblaze/io.h b/include/asm-microblaze/io.h
index 1c77ade..90d1842 100644
--- a/include/asm-microblaze/io.h
+++ b/include/asm-microblaze/io.h
@@ -129,4 +129,30 @@
 {
 }
 
+/*
+ * Given a physical address and a length, return a virtual address
+ * that can be used to access the memory range with the caching
+ * properties specified by "flags".
+ */
+typedef unsigned long phys_addr_t;
+
+#define MAP_NOCACHE	(0)
+#define MAP_WRCOMBINE	(0)
+#define MAP_WRBACK	(0)
+#define MAP_WRTHROUGH	(0)
+
+static inline void *
+map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
+{
+	return (void *)paddr;
+}
+
+/*
+ * Take down a mapping set up by map_physmem().
+ */
+static inline void unmap_physmem(void *vaddr, unsigned long flags)
+{
+
+}
+
 #endif /* __MICROBLAZE_IO_H__ */
diff --git a/include/asm-mips/io.h b/include/asm-mips/io.h
index 1e060f7..e27d1f1 100644
--- a/include/asm-mips/io.h
+++ b/include/asm-mips/io.h
@@ -465,4 +465,30 @@
 {
 }
 
+/*
+ * Given a physical address and a length, return a virtual address
+ * that can be used to access the memory range with the caching
+ * properties specified by "flags".
+ */
+typedef unsigned long phys_addr_t;
+
+#define MAP_NOCACHE	(0)
+#define MAP_WRCOMBINE	(0)
+#define MAP_WRBACK	(0)
+#define MAP_WRTHROUGH	(0)
+
+static inline void *
+map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
+{
+	return (void *)paddr;
+}
+
+/*
+ * Take down a mapping set up by map_physmem().
+ */
+static inline void unmap_physmem(void *vaddr, unsigned long flags)
+{
+
+}
+
 #endif /* _ASM_IO_H */
diff --git a/include/asm-nios/io.h b/include/asm-nios/io.h
index d77695a..6fc339f 100644
--- a/include/asm-nios/io.h
+++ b/include/asm-nios/io.h
@@ -23,6 +23,14 @@
 #ifndef __ASM_NIOS_IO_H_
 #define __ASM_NIOS_IO_H_
 
+#define __raw_writeb(v,a)       (*(volatile unsigned char  *)(a) = (v))
+#define __raw_writew(v,a)       (*(volatile unsigned short *)(a) = (v))
+#define __raw_writel(v,a)       (*(volatile unsigned int   *)(a) = (v))
+
+#define __raw_readb(a)          (*(volatile unsigned char  *)(a))
+#define __raw_readw(a)          (*(volatile unsigned short *)(a))
+#define __raw_readl(a)          (*(volatile unsigned int   *)(a))
+
 #define readb(addr)\
 	({unsigned char val;\
 	 asm volatile(  "	pfxio	0		\n"\
@@ -101,4 +109,30 @@
 {
 }
 
+/*
+ * Given a physical address and a length, return a virtual address
+ * that can be used to access the memory range with the caching
+ * properties specified by "flags".
+ */
+typedef unsigned long phys_addr_t;
+
+#define MAP_NOCACHE	(0)
+#define MAP_WRCOMBINE	(0)
+#define MAP_WRBACK	(0)
+#define MAP_WRTHROUGH	(0)
+
+static inline void *
+map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
+{
+	return (void *)paddr;
+}
+
+/*
+ * Take down a mapping set up by map_physmem().
+ */
+static inline void unmap_physmem(void *vaddr, unsigned long flags)
+{
+
+}
+
 #endif /* __ASM_NIOS_IO_H_ */
diff --git a/include/asm-nios2/io.h b/include/asm-nios2/io.h
index 5bb5322..a52b95c 100644
--- a/include/asm-nios2/io.h
+++ b/include/asm-nios2/io.h
@@ -29,10 +29,44 @@
 	__asm__ __volatile__ ("sync" : : : "memory");
 }
 
+/*
+ * Given a physical address and a length, return a virtual address
+ * that can be used to access the memory range with the caching
+ * properties specified by "flags".
+ */
+typedef unsigned long phys_addr_t;
+
+#define MAP_NOCACHE	(0)
+#define MAP_WRCOMBINE	(0)
+#define MAP_WRBACK	(0)
+#define MAP_WRTHROUGH	(0)
+
+static inline void *
+map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
+{
+	return (void *)paddr;
+}
+
+/*
+ * Take down a mapping set up by map_physmem().
+ */
+static inline void unmap_physmem(void *vaddr, unsigned long flags)
+{
+
+}
+
 extern unsigned char inb (unsigned char *port);
 extern unsigned short inw (unsigned short *port);
 extern unsigned inl (unsigned port);
 
+#define __raw_writeb(v,a)       (*(volatile unsigned char  *)(a) = (v))
+#define __raw_writew(v,a)       (*(volatile unsigned short *)(a) = (v))
+#define __raw_writel(v,a)       (*(volatile unsigned int   *)(a) = (v))
+
+#define __raw_readb(a)          (*(volatile unsigned char  *)(a))
+#define __raw_readw(a)          (*(volatile unsigned short *)(a))
+#define __raw_readl(a)          (*(volatile unsigned int   *)(a))
+
 #define readb(addr)\
 	({unsigned char val;\
 	 asm volatile( "ldbio %0, 0(%1)" :"=r"(val) : "r" (addr)); val;})
diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h
index 11dfa1c..91c9c1e 100644
--- a/include/asm-ppc/io.h
+++ b/include/asm-ppc/io.h
@@ -121,13 +121,43 @@
 #define iobarrier_w()  eieio()
 
 /*
+ * Non ordered and non-swapping "raw" accessors
+ */
+#define __iomem
+#define PCI_FIX_ADDR(addr)	(addr)
+
+static inline unsigned char __raw_readb(const volatile void __iomem *addr)
+{
+	return *(volatile unsigned char *)PCI_FIX_ADDR(addr);
+}
+static inline unsigned short __raw_readw(const volatile void __iomem *addr)
+{
+	return *(volatile unsigned short *)PCI_FIX_ADDR(addr);
+}
+static inline unsigned int __raw_readl(const volatile void __iomem *addr)
+{
+	return *(volatile unsigned int *)PCI_FIX_ADDR(addr);
+}
+static inline void __raw_writeb(unsigned char v, volatile void __iomem *addr)
+{
+	*(volatile unsigned char *)PCI_FIX_ADDR(addr) = v;
+}
+static inline void __raw_writew(unsigned short v, volatile void __iomem *addr)
+{
+	*(volatile unsigned short *)PCI_FIX_ADDR(addr) = v;
+}
+static inline void __raw_writel(unsigned int v, volatile void __iomem *addr)
+{
+	*(volatile unsigned int *)PCI_FIX_ADDR(addr) = v;
+}
+
+/*
  * 8, 16 and 32 bit, big and little endian I/O operations, with barrier.
  *
  * Read operations have additional twi & isync to make sure the read
  * is actually performed (i.e. the data has come back) before we start
  * executing any following instructions.
  */
-#define __iomem
 extern inline int in_8(const volatile unsigned char __iomem *addr)
 {
 	int ret;
@@ -208,4 +238,30 @@
 	__asm__ __volatile__("sync; stw%U0%X0 %1,%0" : "=m" (*addr) : "r" (val));
 }
 
+/*
+ * Given a physical address and a length, return a virtual address
+ * that can be used to access the memory range with the caching
+ * properties specified by "flags".
+ */
+typedef unsigned long phys_addr_t;
+
+#define MAP_NOCACHE	(0)
+#define MAP_WRCOMBINE	(0)
+#define MAP_WRBACK	(0)
+#define MAP_WRTHROUGH	(0)
+
+static inline void *
+map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
+{
+	return (void *)paddr;
+}
+
+/*
+ * Take down a mapping set up by map_physmem().
+ */
+static inline void unmap_physmem(void *vaddr, unsigned long flags)
+{
+
+}
+
 #endif
diff --git a/include/fdt_support.h b/include/fdt_support.h
index 8f781d4..3d6c1a8 100644
--- a/include/fdt_support.h
+++ b/include/fdt_support.h
@@ -44,6 +44,7 @@
 			const char *prop, const void *val, int len, int create);
 void do_fixup_by_compat_u32(void *fdt, const char *compat,
 			    const char *prop, u32 val, int create);
+int fdt_fixup_memory(void *blob, u64 start, u64 size);
 void fdt_fixup_ethernet(void *fdt, bd_t *bd);
 
 #ifdef CONFIG_OF_HAS_UBOOT_ENV
diff --git a/include/flash.h b/include/flash.h
index b0bf733..2ed1e20 100644
--- a/include/flash.h
+++ b/include/flash.h
@@ -52,6 +52,9 @@
 	ushort	ext_addr;		/* extended query table address		*/
 	ushort	cfi_version;		/* cfi version				*/
 	ushort	cfi_offset;		/* offset for cfi query 		*/
+	ulong   addr_unlock1;		/* unlock address 1 for AMD flash roms  */
+	ulong   addr_unlock2;		/* unlock address 2 for AMD flash roms  */
+	const char *name;		/* human-readable name 	                */
 #endif
 } flash_info_t;
 
@@ -77,6 +80,7 @@
 #define FLASH_CFI_X8		0x00
 #define FLASH_CFI_X16		0x01
 #define FLASH_CFI_X8X16		0x02
+#define FLASH_CFI_X16X32	0x05
 
 /* convert between bit value and numeric value */
 #define CFI_FLASH_SHIFT_WIDTH	3
@@ -101,6 +105,13 @@
 extern void flash_read_factory_serial(flash_info_t * info, void * buffer, int offset, int len);
 #endif	/* CFG_FLASH_PROTECTION */
 
+#ifdef CONFIG_FLASH_CFI_LEGACY
+extern ulong board_flash_get_legacy(ulong base, int banknum, flash_info_t *info);
+extern int jedec_flash_match(flash_info_t *info, ulong base);
+#define CFI_CMDSET_AMD_LEGACY		0xFFF0
+#endif
+
+
 /*-----------------------------------------------------------------------
  * return codes from flash_write():
  */