* Patch by Thomas Frieden, 13 Nov 2002:
  Add code for AmigaOne board
  (preliminary merge to U-Boot, still WIP)

* Patch by Jon Diekema, 12 Nov 2002:
  - Adding URL for IEEE OUI lookup
  - Making the autoboot #defines dependent on CONFIG_AUTOBOOT_KEYED
    being defined.
  - In the CONFIG_EXTRA_ENV_SETTINGS #define, the root-on-initrd and
    root-on-nfs macros are designed to switch how the default boot
    method gets defined.
diff --git a/tools/updater/Makefile b/tools/updater/Makefile
new file mode 100644
index 0000000..a8fb4ce
--- /dev/null
+++ b/tools/updater/Makefile
@@ -0,0 +1,86 @@
+#
+# (C) Copyright 2000
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+LOAD_ADDR = 0x40000
+
+include $(TOPDIR)/config.mk
+
+PROG    = updater
+IMAGE   = updater.image
+SRC     = update.c flash.c flash_hw.c utils.c cmd_flash.c string.c ctype.c dummy.c
+ASRC    = ppcstring.S
+OBJS	= $(SRC:.c=.o) $(ASRC:.S=.o) 
+
+LIB	= $(TOPDIR)/examples/libsyscall.a 
+LIBAOBJS= $(TOPDIR)/examples/syscall.o
+LIBCOBJS=
+LIBOBJS	= $(LIBAOBJS) $(LIBCOBJS)
+
+CPPFLAGS += -I$(TOPDIR) -I$(TOPDIR)/board/MAI/AmigaOneG3SE
+CFLAGS   += -I$(TOPDIR)/board/MAI/AmigaOneG3SE
+
+all:	.depend $(LIB) $(PROG)
+
+#########################################################################
+$(LIB): .depend $(LIBOBJS)
+	$(AR) crv $@ $(LIBOBJS)
+
+%.srec:	%.o $(LIB)
+	$(LD) -g -Ttext $(LOAD_ADDR) -o $(<:.o=) -e $(<:.o=) $< $(LIB)
+	$(OBJCOPY) -O srec $(<:.o=) $@
+
+%.o: %.c
+	$(CC) $(CPPFLAGS) -c $< 
+
+%.o: %.S
+	$(CC) $(CPPFLAGS) -c $<
+
+#########################################################################
+
+updater: $(OBJS) $(LIB) $(TOPDIR)/board/MAI/AmigaOneG3SE/memio.o 
+	$(LD) -g -Ttext $(LOAD_ADDR) -o updater -e _main $(OBJS) $(LIB)  \
+	$(TOPDIR)/board/MAI/AmigaOneG3SE/memio.o
+	$(OBJCOPY) -O binary updater updater.bin
+
+updater.image: updater $(TOPDIR)/u-boot.bin
+	cat >/tmp/tempimage updater.bin junk $(TOPDIR)/u-boot.bin
+	$(TOPDIR)/tools/mkimage -A ppc -O u-boot -T standalone -C none -a $(LOAD_ADDR) \
+	-e `ppc-elf32-nm updater | grep _main | cut --bytes=0-8` \
+	-n "Firmware Updater" -d /tmp/tempimage updater.image
+	rm /tmp/tempimage
+	cp updater.image /tftpboot
+
+updater.image2: updater $(TOPDIR)/u-boot.bin
+	cat >/tmp/tempimage updater.bin junk ../../create_image/image
+	$(TOPDIR)/tools/mkimage -A ppc -O u-boot -T standalone -C none -a $(LOAD_ADDR) \
+	-e `ppc-elf32-nm updater | grep _main | cut --bytes=0-8` \
+	-n "Firmware Updater" -d /tmp/tempimage updater.image
+	rm /tmp/tempimage
+	cp updater.image /tftpboot
+
+.depend:	Makefile $(SRC) $(ASRC) $(LIBCOBJS:.o=.c) $(LIBAOBJS:.o=.S)
+		$(CC) -M $(CFLAGS) $(SRC) $(ASRC) $(LIBCOBJS:.o=.c) $(LIBAOBJS:.o=.S) > $@
+
+sinclude .depend
+
+#########################################################################
diff --git a/tools/updater/cmd_flash.c b/tools/updater/cmd_flash.c
new file mode 100644
index 0000000..f3465f1
--- /dev/null
+++ b/tools/updater/cmd_flash.c
@@ -0,0 +1,431 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * FLASH support
+ */
+#include <common.h>
+#include <command.h>
+#include <cmd_boot.h>
+#include <flash.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_FLASH)
+
+extern flash_info_t flash_info[];	/* info for FLASH chips */
+
+/*
+ * The user interface starts numbering for Flash banks with 1
+ * for historical reasons.
+ */
+
+/*
+ * this routine looks for an abbreviated flash range specification.
+ * the syntax is B:SF[-SL], where B is the bank number, SF is the first
+ * sector to erase, and SL is the last sector to erase (defaults to SF).
+ * bank numbers start at 1 to be consistent with other specs, sector numbers
+ * start at zero.
+ *
+ * returns:	1	- correct spec; *pinfo, *psf and *psl are
+ *			  set appropriately
+ *		0	- doesn't look like an abbreviated spec
+ *		-1	- looks like an abbreviated spec, but got
+ *			  a parsing error, a number out of range,
+ *			  or an invalid flash bank.
+ */
+static int
+abbrev_spec(char *str, flash_info_t **pinfo, int *psf, int *psl)
+{
+    flash_info_t *fp;
+    int bank, first, last;
+    char *p, *ep;
+
+    if ((p = strchr(str, ':')) == NULL)
+	return 0;
+    *p++ = '\0';
+
+    bank = simple_strtoul(str, &ep, 10);
+    if (ep == str || *ep != '\0' ||
+      bank < 1 || bank > CFG_MAX_FLASH_BANKS ||
+      (fp = &flash_info[bank - 1])->flash_id == FLASH_UNKNOWN)
+	return -1;
+
+    str = p;
+    if ((p = strchr(str, '-')) != NULL)
+	*p++ = '\0';
+
+    first = simple_strtoul(str, &ep, 10);
+    if (ep == str || *ep != '\0' || first >= fp->sector_count)
+	return -1;
+
+    if (p != NULL) {
+	last = simple_strtoul(p, &ep, 10);
+	if (ep == p || *ep != '\0' ||
+	  last < first || last >= fp->sector_count)
+	    return -1;
+    }
+    else
+	last = first;
+
+    *pinfo = fp;
+    *psf = first;
+    *psl = last;
+
+    return 1;
+}
+int do_flinfo (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+	ulong bank;
+
+	if (argc == 1) {	/* print info for all FLASH banks */
+		for (bank=0; bank <CFG_MAX_FLASH_BANKS; ++bank) {
+			mon_printf ("\nBank # %ld: ", bank+1);
+
+			flash_print_info (&flash_info[bank]);
+		}
+		return 0;
+	}
+
+	bank = simple_strtoul(argv[1], NULL, 16);
+	if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
+		mon_printf ("Only FLASH Banks # 1 ... # %d supported\n",
+			CFG_MAX_FLASH_BANKS);
+		return 1;
+	}
+	mon_printf ("\nBank # %ld: ", bank);
+	flash_print_info (&flash_info[bank-1]);
+	return 0;
+}
+int do_flerase(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+	flash_info_t *info;
+	ulong bank, addr_first, addr_last;
+	int n, sect_first, sect_last;
+	int rcode = 0;
+
+	if (argc < 2) {
+		mon_printf ("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+	}
+
+	if (strcmp(argv[1], "all") == 0) {
+		for (bank=1; bank<=CFG_MAX_FLASH_BANKS; ++bank) {
+			mon_printf ("Erase Flash Bank # %ld ", bank);
+			info = &flash_info[bank-1];
+			rcode = flash_erase (info, 0, info->sector_count-1);
+		}
+		return rcode;
+	}
+
+	if ((n = abbrev_spec(argv[1], &info, &sect_first, &sect_last)) != 0) {
+		if (n < 0) {
+			mon_printf("Bad sector specification\n");
+			return 1;
+		}
+		mon_printf ("Erase Flash Sectors %d-%d in Bank # %d ",
+			sect_first, sect_last, (info-flash_info)+1);
+		rcode = flash_erase(info, sect_first, sect_last);
+		return rcode;
+	}
+
+	if (argc != 3) {
+		mon_printf ("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+	}
+
+	if (strcmp(argv[1], "bank") == 0) {
+		bank = simple_strtoul(argv[2], NULL, 16);
+		if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
+			mon_printf ("Only FLASH Banks # 1 ... # %d supported\n",
+				CFG_MAX_FLASH_BANKS);
+			return 1;
+		}
+		mon_printf ("Erase Flash Bank # %ld ", bank);
+		info = &flash_info[bank-1];
+		rcode = flash_erase (info, 0, info->sector_count-1);
+		return rcode;
+	}
+
+	addr_first = simple_strtoul(argv[1], NULL, 16);
+	addr_last  = simple_strtoul(argv[2], NULL, 16);
+
+	if (addr_first >= addr_last) {
+		mon_printf ("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+	}
+
+	mon_printf ("Erase Flash from 0x%08lx to 0x%08lx ", addr_first, addr_last);
+	rcode = flash_sect_erase(addr_first, addr_last);
+	return rcode;
+}
+
+int flash_sect_erase (ulong addr_first, ulong addr_last)
+{
+	flash_info_t *info;
+	ulong bank;
+	int s_first, s_last;
+	int erased;
+	int rcode = 0;
+
+	erased = 0;
+
+	for (bank=0,info=&flash_info[0]; bank < CFG_MAX_FLASH_BANKS; ++bank, ++info) {
+		ulong b_end;
+		int sect;
+
+		if (info->flash_id == FLASH_UNKNOWN) {
+			continue;
+		}
+
+		b_end = info->start[0] + info->size - 1; /* bank end addr */
+
+		s_first = -1;		/* first sector to erase	*/
+		s_last  = -1;		/* last  sector to erase	*/
+
+		for (sect=0; sect < info->sector_count; ++sect) {
+			ulong end;		/* last address in current sect	*/
+			short s_end;
+
+			s_end = info->sector_count - 1;
+
+			end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;
+
+			if (addr_first > end)
+				continue;
+			if (addr_last < info->start[sect])
+				continue;
+
+			if (addr_first == info->start[sect]) {
+				s_first = sect;
+			}
+			if (addr_last  == end) {
+				s_last  = sect;
+			}
+		}
+		if (s_first>=0 && s_first<=s_last) {
+			erased += s_last - s_first + 1;
+			rcode = flash_erase (info, s_first, s_last);
+		}
+	}
+	if (erased) {
+	    //	mon_printf ("Erased %d sectors\n", erased);
+	} else {
+		mon_printf ("Error: start and/or end address"
+			" not on sector boundary\n");
+		rcode = 1;
+	}
+	return rcode;
+}
+
+
+int do_protect(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+	flash_info_t *info;
+	ulong bank, addr_first, addr_last;
+	int i, p, n, sect_first, sect_last;
+	int rcode = 0;
+
+	if (argc < 3) {
+		mon_printf ("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+	}
+
+	if (strcmp(argv[1], "off") == 0)
+		p = 0;
+	else if (strcmp(argv[1], "on") == 0)
+		p = 1;
+	else {
+		mon_printf ("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+	}
+
+	if (strcmp(argv[2], "all") == 0) {
+		for (bank=1; bank<=CFG_MAX_FLASH_BANKS; ++bank) {
+			info = &flash_info[bank-1];
+			if (info->flash_id == FLASH_UNKNOWN) {
+				continue;
+			}
+			//mon_printf ("%sProtect Flash Bank # %ld\n",
+			//	p ? "" : "Un-", bank);
+
+			for (i=0; i<info->sector_count; ++i) {
+#if defined(CFG_FLASH_PROTECTION)
+				if (flash_real_protect(info, i, p))
+					rcode = 1;
+				putc ('.');
+#else
+				info->protect[i] = p;
+#endif	/* CFG_FLASH_PROTECTION */
+			}
+		}
+
+#if defined(CFG_FLASH_PROTECTION)
+		if (!rcode) puts (" done\n");
+#endif	/* CFG_FLASH_PROTECTION */
+
+		return rcode;
+	}
+
+	if ((n = abbrev_spec(argv[2], &info, &sect_first, &sect_last)) != 0) {
+		if (n < 0) {
+			mon_printf("Bad sector specification\n");
+			return 1;
+		}
+		//mon_printf("%sProtect Flash Sectors %d-%d in Bank # %d\n",
+		//	p ? "" : "Un-", sect_first, sect_last,
+		//	(info-flash_info)+1);
+		for (i = sect_first; i <= sect_last; i++) {
+#if defined(CFG_FLASH_PROTECTION)
+			if (flash_real_protect(info, i, p))
+				rcode =  1;
+			putc ('.');
+#else
+			info->protect[i] = p;
+#endif	/* CFG_FLASH_PROTECTION */
+		}
+
+#if defined(CFG_FLASH_PROTECTION)
+		if (!rcode) puts (" done\n");
+#endif	/* CFG_FLASH_PROTECTION */
+
+		return rcode;
+	}
+
+	if (argc != 4) {
+		mon_printf ("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+	}
+
+	if (strcmp(argv[2], "bank") == 0) {
+		bank = simple_strtoul(argv[3], NULL, 16);
+		if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
+			mon_printf ("Only FLASH Banks # 1 ... # %d supported\n",
+				CFG_MAX_FLASH_BANKS);
+			return 1;
+		}
+		mon_printf ("%sProtect Flash Bank # %ld\n",
+			p ? "" : "Un-", bank);
+		info = &flash_info[bank-1];
+
+		if (info->flash_id == FLASH_UNKNOWN) {
+			mon_printf ("missing or unknown FLASH type\n");
+			return 1;
+		}
+		for (i=0; i<info->sector_count; ++i) {
+#if defined(CFG_FLASH_PROTECTION)
+			if (flash_real_protect(info, i, p))
+				rcode =  1;
+			putc ('.');
+#else
+			info->protect[i] = p;
+#endif	/* CFG_FLASH_PROTECTION */
+		}
+
+#if defined(CFG_FLASH_PROTECTION)
+		if (!rcode) puts (" done\n");
+#endif	/* CFG_FLASH_PROTECTION */
+
+		return rcode;
+	}
+
+	addr_first = simple_strtoul(argv[2], NULL, 16);
+	addr_last  = simple_strtoul(argv[3], NULL, 16);
+
+	if (addr_first >= addr_last) {
+		mon_printf ("Usage:\n%s\n", cmdtp->usage);
+		return 1;
+	}
+	rcode = flash_sect_protect (p, addr_first, addr_last);
+	return rcode;
+}
+int flash_sect_protect (int p, ulong addr_first, ulong addr_last)
+{
+	flash_info_t *info;
+	ulong bank;
+	int s_first, s_last;
+	int protected, i;
+	int rcode = 0;
+
+	protected = 0;
+
+	for (bank=0,info=&flash_info[0]; bank < CFG_MAX_FLASH_BANKS; ++bank, ++info) {
+		ulong b_end;
+		int sect;
+
+		if (info->flash_id == FLASH_UNKNOWN) {
+			continue;
+		}
+
+		b_end = info->start[0] + info->size - 1; /* bank end addr */
+
+		s_first = -1;		/* first sector to erase	*/
+		s_last  = -1;		/* last  sector to erase	*/
+
+		for (sect=0; sect < info->sector_count; ++sect) {
+			ulong end;		/* last address in current sect	*/
+			short s_end;
+
+			s_end = info->sector_count - 1;
+
+			end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;
+
+			if (addr_first > end)
+				continue;
+			if (addr_last < info->start[sect])
+				continue;
+
+			if (addr_first == info->start[sect]) {
+				s_first = sect;
+			}
+			if (addr_last  == end) {
+				s_last  = sect;
+			}
+		}
+		if (s_first>=0 && s_first<=s_last) {
+			protected += s_last - s_first + 1;
+			for (i=s_first; i<=s_last; ++i) {
+#if defined(CFG_FLASH_PROTECTION)
+				if (flash_real_protect(info, i, p))
+					rcode = 1;
+				putc ('.');
+#else
+				info->protect[i] = p;
+#endif	/* CFG_FLASH_PROTECTION */
+			}
+		}
+#if defined(CFG_FLASH_PROTECTION)
+		if (!rcode) putc ('\n');
+#endif	/* CFG_FLASH_PROTECTION */
+
+	}
+	if (protected) {
+	    //	mon_printf ("%sProtected %d sectors\n",
+	    //	p ? "" : "Un-", protected);
+	} else {
+	    mon_printf ("Error: start and/or end address"
+			" not on sector boundary\n");
+		rcode = 1;
+	}
+	return rcode;
+}
+
+#endif	/* CFG_CMD_FLASH */
diff --git a/tools/updater/ctype.c b/tools/updater/ctype.c
new file mode 100644
index 0000000..6ed0468
--- /dev/null
+++ b/tools/updater/ctype.c
@@ -0,0 +1,56 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ *  linux/lib/ctype.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+#include <linux/ctype.h>
+
+unsigned char _ctype[] = {
+_C,_C,_C,_C,_C,_C,_C,_C,			/* 0-7 */
+_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,		/* 8-15 */
+_C,_C,_C,_C,_C,_C,_C,_C,			/* 16-23 */
+_C,_C,_C,_C,_C,_C,_C,_C,			/* 24-31 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,			/* 32-39 */
+_P,_P,_P,_P,_P,_P,_P,_P,			/* 40-47 */
+_D,_D,_D,_D,_D,_D,_D,_D,			/* 48-55 */
+_D,_D,_P,_P,_P,_P,_P,_P,			/* 56-63 */
+_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,	/* 64-71 */
+_U,_U,_U,_U,_U,_U,_U,_U,			/* 72-79 */
+_U,_U,_U,_U,_U,_U,_U,_U,			/* 80-87 */
+_U,_U,_U,_P,_P,_P,_P,_P,			/* 88-95 */
+_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,	/* 96-103 */
+_L,_L,_L,_L,_L,_L,_L,_L,			/* 104-111 */
+_L,_L,_L,_L,_L,_L,_L,_L,			/* 112-119 */
+_L,_L,_L,_P,_P,_P,_P,_C,			/* 120-127 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 128-143 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 144-159 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
+_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
+_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
+_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
+_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
+_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */
diff --git a/tools/updater/dummy.c b/tools/updater/dummy.c
new file mode 100644
index 0000000..9fe5ac1
--- /dev/null
+++ b/tools/updater/dummy.c
@@ -0,0 +1 @@
+volatile int __dummy = 0xDEADBEEF;
diff --git a/tools/updater/flash.c b/tools/updater/flash.c
new file mode 100644
index 0000000..d2e11d2
--- /dev/null
+++ b/tools/updater/flash.c
@@ -0,0 +1,184 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <flash.h>
+
+extern flash_info_t  flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+
+/*-----------------------------------------------------------------------
+ * Set protection status for monitor sectors
+ *
+ * The monitor is always located in the _first_ Flash bank.
+ * If necessary you have to map the second bank at lower addresses.
+ */
+void
+flash_protect (int flag, ulong from, ulong to, flash_info_t *info)
+{
+	ulong b_end = info->start[0] + info->size - 1;	/* bank end address */
+	short s_end = info->sector_count - 1;	/* index of last sector */
+	int i;
+
+	/* Do nothing if input data is bad. */
+	if (info->sector_count == 0 || info->size == 0 || to < from) {
+		return;
+	}
+
+	/* There is nothing to do if we have no data about the flash
+	 * or the protect range and flash range don't overlap.
+	 */
+	if (info->flash_id == FLASH_UNKNOWN ||
+	    to < info->start[0] || from > b_end) {
+		return;
+	}
+
+	for (i=0; i<info->sector_count; ++i) {
+		ulong end;		/* last address in current sect	*/
+
+		end = (i == s_end) ? b_end : info->start[i + 1] - 1;
+
+		/* Update protection if any part of the sector
+		 * is in the specified range.
+		 */
+		if (from <= end && to >= info->start[i]) {
+			if (flag & FLAG_PROTECT_CLEAR) {
+#if defined(CFG_FLASH_PROTECTION)
+				flash_real_protect(info, i, 0);
+#else
+				info->protect[i] = 0;
+#endif	/* CFG_FLASH_PROTECTION */
+			}
+			else if (flag & FLAG_PROTECT_SET) {
+#if defined(CFG_FLASH_PROTECTION)
+				flash_real_protect(info, i, 1);
+#else
+				info->protect[i] = 1;
+#endif	/* CFG_FLASH_PROTECTION */
+			}
+		}
+	}
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+flash_info_t *
+addr2info (ulong addr)
+{
+#ifndef CONFIG_SPD823TS
+	flash_info_t *info;
+	int i;
+
+	for (i=0, info=&flash_info[0]; i<CFG_MAX_FLASH_BANKS; ++i, ++info) {
+		if (info->flash_id != FLASH_UNKNOWN &&
+		    addr >= info->start[0] &&
+		    /* WARNING - The '- 1' is needed if the flash
+		     * is at the end of the address space, since
+		     * info->start[0] + info->size wraps back to 0.
+		     * Please don't change this unless you understand this.
+		     */
+		    addr <= info->start[0] + info->size - 1) {
+			return (info);
+		}
+	}
+#endif /* CONFIG_SPD823TS */
+
+	return (NULL);
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash.
+ * Make sure all target addresses are within Flash bounds,
+ * and no protected sectors are hit.
+ * Returns:
+ * ERR_OK          0 - OK
+ * ERR_TIMOUT      1 - write timeout
+ * ERR_NOT_ERASED  2 - Flash not erased
+ * ERR_PROTECTED   4 - target range includes protected sectors
+ * ERR_INVAL       8 - target address not in Flash memory
+ * ERR_ALIGN       16 - target address not aligned on boundary
+ *			(only some targets require alignment)
+ */
+int
+flash_write (uchar *src, ulong addr, ulong cnt)
+{
+#ifdef CONFIG_SPD823TS
+	return (ERR_TIMOUT);	/* any other error codes are possible as well */
+#else
+	int i;
+	ulong         end        = addr + cnt - 1;
+	flash_info_t *info_first = addr2info (addr);
+	flash_info_t *info_last  = addr2info (end );
+	flash_info_t *info;
+	int j;
+
+	if (cnt == 0) {
+		return (ERR_OK);
+	}
+
+	if (!info_first || !info_last) {
+		return (ERR_INVAL);
+	}
+
+	for (info = info_first; info <= info_last; ++info) {
+		ulong b_end = info->start[0] + info->size;	/* bank end addr */
+		short s_end = info->sector_count - 1;
+		for (i=0; i<info->sector_count; ++i) {
+			ulong e_addr = (i == s_end) ? b_end : info->start[i + 1];
+
+			if ((end >= info->start[i]) && (addr < e_addr) &&
+			    (info->protect[i] != 0) ) {
+				return (ERR_PROTECTED);
+			}
+		}
+	}
+
+	mon_printf("\rWriting ");
+	for (j=0; j<20; j++) mon_putc(177);
+	mon_printf("\rWriting ");
+
+	/* finally write data to flash */
+	for (info = info_first; info <= info_last && cnt>0; ++info) {
+		ulong len;
+
+		len = info->start[0] + info->size - addr;
+		if (len > cnt)
+			len = cnt;
+
+		if ((i = write_buff(info, src, addr, len)) != 0) {
+			return (i);
+		}
+		cnt  -= len;
+		addr += len;
+		src  += len;
+	}
+	return (ERR_OK);
+#endif /* CONFIG_SPD823TS */
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/tools/updater/flash_hw.c b/tools/updater/flash_hw.c
new file mode 100644
index 0000000..ec11589
--- /dev/null
+++ b/tools/updater/flash_hw.c
@@ -0,0 +1,660 @@
+/*
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <flash.h>
+#include <asm/io.h>
+#include <memio.h>
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_FLASH
+//#define DEBUG_FLASH
+
+#ifdef DEBUG_FLASH
+#define DEBUGF(fmt,args...) mon_printf(fmt ,##args)
+#else
+#define DEBUGF(fmt,args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+flash_info_t	flash_info[CFG_MAX_FLASH_BANKS];
+
+static ulong flash_get_size (ulong addr, flash_info_t *info);
+static int flash_get_offsets (ulong base, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_reset (ulong addr);
+
+int flash_xd_nest;
+
+static void flash_to_xd(void)
+{
+    unsigned char x;
+
+    flash_xd_nest ++;
+
+    if (flash_xd_nest == 1)
+    {
+	DEBUGF("Flash on XD\n");
+	x = pci_read_cfg_byte(0, 0, 0x74);
+	pci_write_cfg_byte(0, 0, 0x74, x|1);
+    }
+}
+
+static void flash_to_mem(void)
+{
+    unsigned char x;
+
+    flash_xd_nest --;
+   
+    if (flash_xd_nest == 0)
+    {
+	DEBUGF("Flash on memory bus\n");
+	x = pci_read_cfg_byte(0, 0, 0x74);
+	pci_write_cfg_byte(0, 0, 0x74, x&0xFE);
+    }
+}
+
+unsigned long flash_init_old(void)
+{
+    int i;
+
+    for (i = 0; i < CFG_MAX_FLASH_BANKS; i++)
+    {
+	flash_info[i].flash_id = FLASH_UNKNOWN;
+	flash_info[i].sector_count = 0;
+	flash_info[i].size = 0;
+    }
+
+
+    return 1;
+}
+
+unsigned long flash_init (void)
+{
+	unsigned int i;
+	unsigned long flash_size = 0;
+
+	flash_xd_nest = 0;
+
+	flash_to_xd();
+
+	/* Init: no FLASHes known */
+	for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
+		flash_info[i].flash_id = FLASH_UNKNOWN;
+		flash_info[i].sector_count = 0;
+		flash_info[i].size = 0;
+	}
+
+	DEBUGF("\n## Get flash size @ 0x%08x\n", CFG_FLASH_BASE);
+
+	flash_size = flash_get_size (CFG_FLASH_BASE, flash_info);
+
+	DEBUGF("## Flash bank size: %08lx\n", flash_size);
+
+	if (flash_size) {
+#if CFG_MONITOR_BASE >= CFG_FLASH_BASE && \
+    CFG_MONITOR_BASE < CFG_FLASH_BASE + CFG_FLASH_MAX_SIZE
+		/* monitor protection ON by default */
+		flash_protect(FLAG_PROTECT_SET,
+			      CFG_MONITOR_BASE,
+			      CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1,
+			      &flash_info[0]);
+#endif
+
+#ifdef CFG_ENV_IS_IN_FLASH
+		/* ENV protection ON by default */
+		flash_protect(FLAG_PROTECT_SET,
+			      CFG_ENV_ADDR,
+			      CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
+			      &flash_info[0]);
+#endif
+
+	} else {
+		mon_printf ("Warning: the BOOT Flash is not initialised !");
+	}
+
+	flash_to_mem();
+
+	return flash_size;
+}
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+static ulong flash_get_size (ulong addr, flash_info_t *info)
+{
+	short i;
+	uchar value;
+	uchar *x = (uchar *)addr;
+
+	flash_to_xd();
+
+	/* Write auto select command: read Manufacturer ID */
+	x[0x0555] =  0xAA;
+	__asm volatile ("sync\n eieio");
+	x[0x02AA] =  0x55;
+	__asm volatile ("sync\n eieio");
+	x[0x0555] =  0x90;
+	__asm volatile ("sync\n eieio");
+
+	value = x[0];
+	__asm volatile ("sync\n eieio");
+
+	DEBUGF("Manuf. ID @ 0x%08lx: 0x%08x\n", (ulong)addr, value);
+
+	switch (value | (value << 16)) {
+		case AMD_MANUFACT:
+			info->flash_id = FLASH_MAN_AMD;
+			break;
+
+		case FUJ_MANUFACT:
+			info->flash_id = FLASH_MAN_FUJ;
+			break;
+
+		case STM_MANUFACT:
+			info->flash_id = FLASH_MAN_STM;
+			break;
+
+		default:
+			info->flash_id = FLASH_UNKNOWN;
+			info->sector_count = 0;
+			info->size = 0;
+			flash_reset (addr);
+			return 0;
+	}
+
+	value = x[1];
+	__asm volatile ("sync\n eieio");
+
+	DEBUGF("Device ID @ 0x%08lx: 0x%08x\n", addr+1, value);
+
+	switch (value) {
+		case AMD_ID_F040B:
+			DEBUGF("Am29F040B\n");
+			info->flash_id += FLASH_AM040;
+			info->sector_count = 8;
+			info->size = 0x00080000;
+			break;			/* => 512 kB		*/
+
+		case AMD_ID_LV040B:
+			DEBUGF("Am29LV040B\n");
+			info->flash_id += FLASH_AM040;
+			info->sector_count = 8;
+			info->size = 0x00080000;
+			break;			/* => 512 kB		*/
+
+		case AMD_ID_LV400T:
+			DEBUGF("Am29LV400T\n");
+			info->flash_id += FLASH_AM400T;
+			info->sector_count = 11;
+			info->size = 0x00100000;
+			break;			/* => 1 MB		*/
+
+		case AMD_ID_LV400B:
+			DEBUGF("Am29LV400B\n");
+			info->flash_id += FLASH_AM400B;
+			info->sector_count = 11;
+			info->size = 0x00100000;
+			break;			/* => 1 MB		*/
+
+		case AMD_ID_LV800T:
+			DEBUGF("Am29LV800T\n");
+			info->flash_id += FLASH_AM800T;
+			info->sector_count = 19;
+			info->size = 0x00200000;
+			break;			/* => 2 MB		*/
+
+		case AMD_ID_LV800B:
+			DEBUGF("Am29LV400B\n");
+			info->flash_id += FLASH_AM800B;
+			info->sector_count = 19;
+			info->size = 0x00200000;
+			break;			/* => 2 MB		*/
+
+		case AMD_ID_LV160T:
+			DEBUGF("Am29LV160T\n");
+			info->flash_id += FLASH_AM160T;
+			info->sector_count = 35;
+			info->size = 0x00400000;
+			break;			/* => 4 MB		*/
+
+		case AMD_ID_LV160B:
+			DEBUGF("Am29LV160B\n");
+			info->flash_id += FLASH_AM160B;
+			info->sector_count = 35;
+			info->size = 0x00400000;
+			break;			/* => 4 MB		*/
+
+		case AMD_ID_LV320T:
+			DEBUGF("Am29LV320T\n");
+			info->flash_id += FLASH_AM320T;
+			info->sector_count = 67;
+			info->size = 0x00800000;
+			break;			/* => 8 MB		*/
+
+#if 0
+		/* Has the same ID as AMD_ID_LV320T, to be fixed */
+		case AMD_ID_LV320B:
+			DEBUGF("Am29LV320B\n");
+			info->flash_id += FLASH_AM320B;
+			info->sector_count = 67;
+			info->size = 0x00800000;
+			break;			/* => 8 MB		*/
+#endif
+
+		case AMD_ID_LV033C:
+			DEBUGF("Am29LV033C\n");
+			info->flash_id += FLASH_AM033C;
+			info->sector_count = 64;
+			info->size = 0x01000000;
+			break;			/* => 16Mb		*/
+
+		case STM_ID_F040B:
+			DEBUGF("M29F040B\n");
+			info->flash_id += FLASH_AM040;
+			info->sector_count = 8;
+			info->size = 0x00080000;
+			break;			/* => 512 kB		*/
+
+		default:
+			info->flash_id = FLASH_UNKNOWN;
+			flash_reset (addr);
+			flash_to_mem();
+			return (0);		/* => no or unknown flash */
+
+	}
+
+	if (info->sector_count > CFG_MAX_FLASH_SECT) {
+		mon_printf ("** ERROR: sector count %d > max (%d) **\n",
+			info->sector_count, CFG_MAX_FLASH_SECT);
+		info->sector_count = CFG_MAX_FLASH_SECT;
+	}
+
+	if (! flash_get_offsets (addr, info)) {
+		flash_reset (addr);
+		flash_to_mem();
+		return 0;
+	}
+
+	/* check for protected sectors */
+	for (i = 0; i < info->sector_count; i++) {
+		/* read sector protection at sector address, (A7 .. A0) = 0x02 */
+		/* D0 = 1 if protected */
+		value = in8(info->start[i] + 2);
+		iobarrier_rw();
+		info->protect[i] = (value & 1) != 0;
+	}
+
+	/*
+	 * Reset bank to read mode
+	 */
+	flash_reset (addr);
+
+	flash_to_mem();
+
+	return (info->size);
+}
+
+static int flash_get_offsets (ulong base, flash_info_t *info)
+{
+	unsigned int i;
+
+	switch (info->flash_id & FLASH_TYPEMASK) {
+		case FLASH_AM040:
+			/* set sector offsets for uniform sector type	*/
+			for (i = 0; i < info->sector_count; i++) {
+				info->start[i] = base + i * info->size /
+				                            info->sector_count;
+			}
+			break;
+		default:
+			return 0;
+	}
+
+	return 1;
+}
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+	volatile ulong addr = info->start[0];
+	int flag, prot, sect, l_sect;
+	ulong start, now, last;
+
+	flash_to_xd();
+
+	if (s_first < 0 || s_first > s_last) {
+		if (info->flash_id == FLASH_UNKNOWN) {
+			mon_printf ("- missing\n");
+		} else {
+			mon_printf ("- no sectors to erase\n");
+		}
+		flash_to_mem();
+		return 1;
+	}
+
+	if (info->flash_id == FLASH_UNKNOWN) {
+		mon_printf ("Can't erase unknown flash type %08lx - aborted\n",
+			info->flash_id);
+		flash_to_mem();
+		return 1;
+	}
+
+	prot = 0;
+	for (sect=s_first; sect<=s_last; ++sect) {
+		if (info->protect[sect]) {
+			prot++;
+		}
+	}
+
+	if (prot) {
+		mon_printf ("- Warning: %d protected sectors will not be erased!\n",
+			prot);
+	} else {
+		mon_printf ("");
+	}
+
+	l_sect = -1;
+
+	/* Disable interrupts which might cause a timeout here */
+	flag = disable_interrupts();
+
+	out8(addr + 0x555, 0xAA);
+	iobarrier_rw();
+	out8(addr + 0x2AA, 0x55);
+	iobarrier_rw();
+	out8(addr + 0x555, 0x80);
+	iobarrier_rw();
+	out8(addr + 0x555, 0xAA);
+	iobarrier_rw();
+	out8(addr + 0x2AA, 0x55);
+	iobarrier_rw();
+
+	/* Start erase on unprotected sectors */
+	for (sect = s_first; sect<=s_last; sect++) {
+		if (info->protect[sect] == 0) {	/* not protected */
+			addr = info->start[sect];
+			out8(addr, 0x30);
+			iobarrier_rw();
+			l_sect = sect;
+		}
+	}
+
+	/* re-enable interrupts if necessary */
+	if (flag)
+		enable_interrupts();
+
+	/* wait at least 80us - let's wait 1 ms */
+	mon_udelay (1000);
+
+	/*
+	 * We wait for the last triggered sector
+	 */
+	if (l_sect < 0)
+		goto DONE;
+
+	start = mon_get_timer (0);
+	last  = start;
+	addr = info->start[l_sect];
+
+	DEBUGF ("Start erase timeout: %d\n", CFG_FLASH_ERASE_TOUT);
+
+	while ((in8(addr) & 0x80) != 0x80) {
+		if ((now = mon_get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+			mon_printf ("Timeout\n");
+			flash_reset (info->start[0]);
+			flash_to_mem();
+			return 1;
+		}
+		/* show that we're waiting */
+		if ((now - last) > 1000) {	/* every second */
+			mon_putc ('.');
+			last = now;
+		}
+		iobarrier_rw();
+	}
+
+DONE:
+	/* reset to read mode */
+	flash_reset (info->start[0]);
+	flash_to_mem();
+
+	mon_printf (" done\n");
+	return 0;
+}
+
+/*
+ * 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 cp, wp, data;
+	int i, l, rc;
+	ulong out_cnt = 0;
+
+	flash_to_xd();
+
+	wp = (addr & ~3);	/* get lower word aligned address */
+
+	/*
+	 * handle unaligned start bytes
+	 */
+	if ((l = addr - wp) != 0) {
+		data = 0;
+		for (i=0, cp=wp; i<l; ++i, ++cp) {
+			data = (data << 8) | (*(uchar *)cp);
+		}
+		for (; i<4 && cnt>0; ++i) {
+			data = (data << 8) | *src++;
+			--cnt;
+			++cp;
+		}
+		for (; cnt==0 && i<4; ++i, ++cp) {
+			data = (data << 8) | (*(uchar *)cp);
+		}
+
+		if ((rc = write_word(info, wp, data)) != 0) {
+		        flash_to_mem();
+			return (rc);
+		}
+		wp += 4;
+	}
+
+	mon_putc(219);
+
+	/*
+	 * handle word aligned part
+	 */
+	while (cnt >= 4) {
+	    if (out_cnt>26214) 
+	    {
+		mon_putc(219);
+		out_cnt = 0;
+	    }
+	    data = 0;
+	    for (i=0; i<4; ++i) {
+		data = (data << 8) | *src++;
+	    }
+	    if ((rc = write_word(info, wp, data)) != 0) {
+		flash_to_mem();
+		return (rc);
+	    }
+	    wp  += 4;
+	    cnt -= 4;
+	    out_cnt += 4;
+	}
+
+	if (cnt == 0) {
+		flash_to_mem();
+		return (0);
+	}
+
+	/*
+	 * handle unaligned tail bytes
+	 */
+	data = 0;
+	for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+		data = (data << 8) | *src++;
+		--cnt;
+	}
+	for (; i<4; ++i, ++cp) {
+		data = (data << 8) | (*(uchar *)cp);
+	}
+
+	flash_to_mem();
+	return (write_word(info, wp, data));
+}
+
+/*
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+	volatile ulong addr = info->start[0];
+	ulong start;
+	int i;
+
+	flash_to_xd();
+
+	/* Check if Flash is (sufficiently) erased */
+	if ((in32(dest) & data) != data) {
+		flash_to_mem();
+		return (2);
+	}
+
+	/* write each byte out */
+	for (i = 0; i < 4; i++) {
+		char *data_ch = (char *)&data;
+		int flag = disable_interrupts();
+
+		out8(addr + 0x555, 0xAA);
+		iobarrier_rw();
+		out8(addr + 0x2AA, 0x55);
+		iobarrier_rw();
+		out8(addr + 0x555, 0xA0);
+		iobarrier_rw();
+		out8(dest+i, data_ch[i]);
+		iobarrier_rw();
+
+		/* re-enable interrupts if necessary */
+		if (flag)
+			enable_interrupts();
+
+		/* data polling for D7 */
+		start = mon_get_timer (0);
+		while ((in8(dest+i) & 0x80) != (data_ch[i] & 0x80)) {
+			if (mon_get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+				flash_reset (addr);
+				flash_to_mem();
+				return (1);
+			}
+			iobarrier_rw();
+		}
+	}
+
+	flash_reset (addr);
+	flash_to_mem();
+	return (0);
+}
+
+/*
+ * Reset bank to read mode
+ */
+static void flash_reset (ulong addr)
+{
+        flash_to_xd();
+	out8(addr, 0xF0);	/* reset bank */
+	iobarrier_rw();
+	flash_to_mem();
+}
+
+void flash_print_info (flash_info_t *info)
+{
+	int i;
+
+	if (info->flash_id == FLASH_UNKNOWN) {
+		mon_printf ("missing or unknown FLASH type\n");
+		return;
+	}
+
+	switch (info->flash_id & FLASH_VENDMASK) {
+	case FLASH_MAN_AMD:	mon_printf ("AMD ");		break;
+	case FLASH_MAN_FUJ:	mon_printf ("FUJITSU ");		break;
+	case FLASH_MAN_BM:	mon_printf ("BRIGHT MICRO ");	break;
+	case FLASH_MAN_STM:	mon_printf ("SGS THOMSON ");	break;
+	default:		mon_printf ("Unknown Vendor ");	break;
+	}
+
+	switch (info->flash_id & FLASH_TYPEMASK) {
+	case FLASH_AM040:	mon_printf ("29F040 or 29LV040 (4 Mbit, uniform sectors)\n");
+				break;
+	case FLASH_AM400B:	mon_printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+				break;
+	case FLASH_AM400T:	mon_printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+				break;
+	case FLASH_AM800B:	mon_printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+				break;
+	case FLASH_AM800T:	mon_printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+				break;
+	case FLASH_AM160B:	mon_printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+				break;
+	case FLASH_AM160T:	mon_printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+				break;
+	case FLASH_AM320B:	mon_printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+				break;
+	case FLASH_AM320T:	mon_printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+				break;
+	default:		mon_printf ("Unknown Chip Type\n");
+				break;
+	}
+
+	if (info->size % 0x100000 == 0) {
+		mon_printf ("  Size: %ld MB in %d Sectors\n",
+			info->size / 0x100000, info->sector_count);
+	} else if (info->size % 0x400 == 0) {
+		mon_printf ("  Size: %ld KB in %d Sectors\n",
+		        info->size / 0x400, info->sector_count);
+	} else {
+		mon_printf ("  Size: %ld B in %d Sectors\n",
+		        info->size, info->sector_count);
+	}
+
+	mon_printf ("  Sector Start Addresses:");
+	for (i=0; i<info->sector_count; ++i) {
+		if ((i % 5) == 0)
+			mon_printf ("\n   ");
+		mon_printf (" %08lX%s",
+			info->start[i],
+			info->protect[i] ? " (RO)" : "     "
+		);
+	}
+	mon_printf ("\n");
+}
diff --git a/tools/updater/junk b/tools/updater/junk
new file mode 100644
index 0000000..f73285a
--- /dev/null
+++ b/tools/updater/junk
@@ -0,0 +1 @@
+................................................................................................................................................................................................................................................................
\ No newline at end of file
diff --git a/tools/updater/ppcstring.S b/tools/updater/ppcstring.S
new file mode 100644
index 0000000..97023a0
--- /dev/null
+++ b/tools/updater/ppcstring.S
@@ -0,0 +1,216 @@
+/*
+ * String handling functions for PowerPC.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * 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.
+ */
+#include <ppc_asm.tmpl>
+#include <asm/errno.h>
+
+	.globl	strcpy
+strcpy:
+	addi	r5,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	stbu	r0,1(r5)
+	bne	1b
+	blr
+
+	.globl	strncpy
+strncpy:
+	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+	addi	r6,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	stbu	r0,1(r6)
+	bdnzf	2,1b		/* dec ctr, branch if ctr != 0 && !cr0.eq */
+	blr
+
+	.globl	strcat
+strcat:
+	addi	r5,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r0,1(r5)
+	cmpwi	0,r0,0
+	bne	1b
+	addi	r5,r5,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	stbu	r0,1(r5)
+	bne	1b
+	blr
+
+	.globl	strcmp
+strcmp:
+	addi	r5,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r3,1(r5)
+	cmpwi	1,r3,0
+	lbzu	r0,1(r4)
+	subf.	r3,r0,r3
+	beqlr	1
+	beq	1b
+	blr
+
+	.globl	strlen
+strlen:
+	addi	r4,r3,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	bne	1b
+	subf	r3,r3,r4
+	blr
+
+	.globl	memset
+memset:
+	rlwimi	r4,r4,8,16,23
+	rlwimi	r4,r4,16,0,15
+	addi	r6,r3,-4
+	cmplwi	0,r5,4
+	blt	7f
+	stwu	r4,4(r6)
+	beqlr
+	andi.	r0,r6,3
+	add	r5,r0,r5
+	subf	r6,r0,r6
+	rlwinm	r0,r5,32-2,2,31
+	mtctr	r0
+	bdz	6f
+1:	stwu	r4,4(r6)
+	bdnz	1b
+6:	andi.	r5,r5,3
+7:	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+	addi	r6,r6,3
+8:	stbu	r4,1(r6)
+	bdnz	8b
+	blr
+
+	.globl	bcopy
+bcopy:
+	mr	r6,r3
+	mr	r3,r4
+	mr	r4,r6
+	b	memcpy
+
+	.globl	memmove
+memmove:
+	cmplw	0,r3,r4
+	bgt	backwards_memcpy
+	/* fall through */
+
+	.globl	memcpy
+memcpy:
+	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */
+	addi	r6,r3,-4
+	addi	r4,r4,-4
+	beq	2f			/* if less than 8 bytes to do */
+	andi.	r0,r6,3			/* get dest word aligned */
+	mtctr	r7
+	bne	5f
+1:	lwz	r7,4(r4)
+	lwzu	r8,8(r4)
+	stw	r7,4(r6)
+	stwu	r8,8(r6)
+	bdnz	1b
+	andi.	r5,r5,7
+2:	cmplwi	0,r5,4
+	blt	3f
+	lwzu	r0,4(r4)
+	addi	r5,r5,-4
+	stwu	r0,4(r6)
+3:	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+	addi	r4,r4,3
+	addi	r6,r6,3
+4:	lbzu	r0,1(r4)
+	stbu	r0,1(r6)
+	bdnz	4b
+	blr
+5:	subfic	r0,r0,4
+	mtctr	r0
+6:	lbz	r7,4(r4)
+	addi	r4,r4,1
+	stb	r7,4(r6)
+	addi	r6,r6,1
+	bdnz	6b
+	subf	r5,r0,r5
+	rlwinm.	r7,r5,32-3,3,31
+	beq	2b
+	mtctr	r7
+	b	1b
+
+	.globl	backwards_memcpy
+backwards_memcpy:
+	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */
+	add	r6,r3,r5
+	add	r4,r4,r5
+	beq	2f
+	andi.	r0,r6,3
+	mtctr	r7
+	bne	5f
+1:	lwz	r7,-4(r4)
+	lwzu	r8,-8(r4)
+	stw	r7,-4(r6)
+	stwu	r8,-8(r6)
+	bdnz	1b
+	andi.	r5,r5,7
+2:	cmplwi	0,r5,4
+	blt	3f
+	lwzu	r0,-4(r4)
+	subi	r5,r5,4
+	stwu	r0,-4(r6)
+3:	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+4:	lbzu	r0,-1(r4)
+	stbu	r0,-1(r6)
+	bdnz	4b
+	blr
+5:	mtctr	r0
+6:	lbzu	r7,-1(r4)
+	stbu	r7,-1(r6)
+	bdnz	6b
+	subf	r5,r0,r5
+	rlwinm.	r7,r5,32-3,3,31
+	beq	2b
+	mtctr	r7
+	b	1b
+
+	.globl	memcmp
+memcmp:
+	cmpwi	0,r5,0
+	ble-	2f
+	mtctr	r5
+	addi	r6,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r3,1(r6)
+	lbzu	r0,1(r4)
+	subf.	r3,r0,r3
+	bdnzt	2,1b
+	blr
+2:	li	r3,0
+	blr
+
+	.global	memchr
+memchr:
+	cmpwi	0,r5,0
+	ble-	2f
+	mtctr	r5
+	addi	r3,r3,-1
+1:	lbzu	r0,1(r3)
+	cmpw	0,r0,r4
+	bdnzf	2,1b
+	beqlr
+2:	li	r3,0
+	blr
diff --git a/tools/updater/string.c b/tools/updater/string.c
new file mode 100644
index 0000000..50537a6
--- /dev/null
+++ b/tools/updater/string.c
@@ -0,0 +1,340 @@
+/*
+ *  linux/lib/string.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * stupid library routines.. The optimized versions should generally be found
+ * as inline code in <asm-xx/string.h>
+ *
+ * These are buggy as well..
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <malloc.h>
+
+#define __HAVE_ARCH_BCOPY
+#define __HAVE_ARCH_MEMCMP
+#define __HAVE_ARCH_MEMCPY
+#define __HAVE_ARCH_MEMMOVE
+#define __HAVE_ARCH_MEMSET
+#define __HAVE_ARCH_STRCAT
+#define __HAVE_ARCH_STRCMP
+#define __HAVE_ARCH_STRCPY
+#define __HAVE_ARCH_STRLEN
+#define __HAVE_ARCH_STRNCPY
+
+char * ___strtok = NULL;
+
+#ifndef __HAVE_ARCH_STRCPY
+char * strcpy(char * dest,const char *src)
+{
+	char *tmp = dest;
+
+	while ((*dest++ = *src++) != '\0')
+		/* nothing */;
+	return tmp;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRNCPY
+char * strncpy(char * dest,const char *src,size_t count)
+{
+	char *tmp = dest;
+
+	while (count-- && (*dest++ = *src++) != '\0')
+		/* nothing */;
+
+	return tmp;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRCAT
+char * strcat(char * dest, const char * src)
+{
+	char *tmp = dest;
+
+	while (*dest)
+		dest++;
+	while ((*dest++ = *src++) != '\0')
+		;
+
+	return tmp;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRNCAT
+char * strncat(char *dest, const char *src, size_t count)
+{
+	char *tmp = dest;
+
+	if (count) {
+		while (*dest)
+			dest++;
+		while ((*dest++ = *src++)) {
+			if (--count == 0) {
+				*dest = '\0';
+				break;
+			}
+		}
+	}
+
+	return tmp;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRCMP
+int strcmp(const char * cs,const char * ct)
+{
+	register signed char __res;
+
+	while (1) {
+		if ((__res = *cs - *ct++) != 0 || !*cs++)
+			break;
+	}
+
+	return __res;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRNCMP
+int strncmp(const char * cs,const char * ct,size_t count)
+{
+	register signed char __res = 0;
+
+	while (count) {
+		if ((__res = *cs - *ct++) != 0 || !*cs++)
+			break;
+		count--;
+	}
+
+	return __res;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRCHR
+char * strchr(const char * s, int c)
+{
+	for(; *s != (char) c; ++s)
+		if (*s == '\0')
+			return NULL;
+	return (char *) s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRRCHR
+char * strrchr(const char * s, int c)
+{
+       const char *p = s + strlen(s);
+       do {
+           if (*p == (char)c)
+               return (char *)p;
+       } while (--p >= s);
+       return NULL;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRLEN
+size_t strlen(const char * s)
+{
+	const char *sc;
+
+	for (sc = s; *sc != '\0'; ++sc)
+		/* nothing */;
+	return sc - s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRNLEN
+size_t strnlen(const char * s, size_t count)
+{
+	const char *sc;
+
+	for (sc = s; count-- && *sc != '\0'; ++sc)
+		/* nothing */;
+	return sc - s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRDUP
+char * strdup(const char *s)
+{
+	char *new;
+
+	if ((s == NULL)	||
+	    ((new = mon_malloc (strlen(s) + 1)) == NULL) ) {
+		return NULL;
+	}
+
+	strcpy (new, s);
+	return new;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRSPN
+size_t strspn(const char *s, const char *accept)
+{
+	const char *p;
+	const char *a;
+	size_t count = 0;
+
+	for (p = s; *p != '\0'; ++p) {
+		for (a = accept; *a != '\0'; ++a) {
+			if (*p == *a)
+				break;
+		}
+		if (*a == '\0')
+			return count;
+		++count;
+	}
+
+	return count;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRPBRK
+char * strpbrk(const char * cs,const char * ct)
+{
+	const char *sc1,*sc2;
+
+	for( sc1 = cs; *sc1 != '\0'; ++sc1) {
+		for( sc2 = ct; *sc2 != '\0'; ++sc2) {
+			if (*sc1 == *sc2)
+				return (char *) sc1;
+		}
+	}
+	return NULL;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRTOK
+char * strtok(char * s,const char * ct)
+{
+	char *sbegin, *send;
+
+	sbegin  = s ? s : ___strtok;
+	if (!sbegin) {
+		return NULL;
+	}
+	sbegin += strspn(sbegin,ct);
+	if (*sbegin == '\0') {
+		___strtok = NULL;
+		return( NULL );
+	}
+	send = strpbrk( sbegin, ct);
+	if (send && *send != '\0')
+		*send++ = '\0';
+	___strtok = send;
+	return (sbegin);
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMSET
+void * memset(void * s,char c,size_t count)
+{
+	char *xs = (char *) s;
+
+	while (count--)
+		*xs++ = c;
+
+	return s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_BCOPY
+char * bcopy(const char * src, char * dest, int count)
+{
+	char *tmp = dest;
+
+	while (count--)
+		*tmp++ = *src++;
+
+	return dest;
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMCPY
+void * memcpy(void * dest,const void *src,size_t count)
+{
+	char *tmp = (char *) dest, *s = (char *) src;
+
+	while (count--)
+		*tmp++ = *s++;
+
+	return dest;
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMMOVE
+void * memmove(void * dest,const void *src,size_t count)
+{
+	char *tmp, *s;
+
+	if (dest <= src) {
+		tmp = (char *) dest;
+		s = (char *) src;
+		while (count--)
+			*tmp++ = *s++;
+		}
+	else {
+		tmp = (char *) dest + count;
+		s = (char *) src + count;
+		while (count--)
+			*--tmp = *--s;
+		}
+
+	return dest;
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMCMP
+int memcmp(const void * cs,const void * ct,size_t count)
+{
+	const unsigned char *su1, *su2;
+	signed char res = 0;
+
+	for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+		if ((res = *su1 - *su2) != 0)
+			break;
+	return res;
+}
+#endif
+
+/*
+ * find the first occurrence of byte 'c', or 1 past the area if none
+ */
+#ifndef __HAVE_ARCH_MEMSCAN
+void * memscan(void * addr, int c, size_t size)
+{
+	unsigned char * p = (unsigned char *) addr;
+
+	while (size) {
+		if (*p == c)
+			return (void *) p;
+		p++;
+		size--;
+	}
+  	return (void *) p;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRSTR
+char * strstr(const char * s1,const char * s2)
+{
+	int l1, l2;
+
+	l2 = strlen(s2);
+	if (!l2)
+		return (char *) s1;
+	l1 = strlen(s1);
+	while (l1 >= l2) {
+		l1--;
+		if (!memcmp(s1,s2,l2))
+			return (char *) s1;
+		s1++;
+	}
+	return NULL;
+}
+#endif
diff --git a/tools/updater/update.c b/tools/updater/update.c
new file mode 100644
index 0000000..66c6dfc
--- /dev/null
+++ b/tools/updater/update.c
@@ -0,0 +1,67 @@
+#include <common.h>
+#include <syscall.h>
+
+extern unsigned long __dummy;
+void do_reset (void);
+void do_updater(void);
+
+void _main(void)
+{
+    int i;
+    mon_printf("U-Boot Firmware Updater\n\n\n");
+    mon_printf("****************************************************\n"
+	       "*  ATTENTION!! PLEASE READ THIS NOTICE CAREFULLY!  *\n"
+	       "****************************************************\n\n"
+	       "This program  will update your computer's  firmware.\n"
+	       "Do NOT  remove the disk,  reset the  machine,  or do\n"
+	       "anything that  might disrupt functionality.  If this\n");
+    mon_printf("Program fails, your computer  might be unusable, and\n"
+	       "you will  need to return your  board for reflashing.\n"
+	       "If you find this too risky,  remove the diskette and\n"
+	       "switch off your  machine now.  Otherwise  press the \n"
+	       "SPACE key now to start the process\n\n");
+    do
+    {
+	char x;
+	while (!mon_tstc());
+	x = mon_getc();
+	if (x == ' ') break;
+    } while (1);
+
+    do_updater();
+
+    i = 5;
+
+    mon_printf("\nUpdate done. Please remove diskette.\n");
+    mon_printf("The machine will automatically reset in %d seconds\n", i);
+    mon_printf("You can switch off/reset now when the floppy is removed\n\n");
+    
+    while (i)
+    {
+	mon_printf("Resetting in %d\r", i);
+	mon_udelay(1000000);
+	i--;
+    }
+    do_reset();
+    while (1);
+}
+
+int flash_sect_protect (int p, ulong addr_first, ulong addr_last);
+int flash_sect_erase (ulong addr_first, ulong addr_last);
+int flash_write (uchar *src, ulong addr, ulong cnt);
+
+void do_updater(void)
+{
+    unsigned long *addr = &__dummy + 65;
+    unsigned long flash_size = flash_init();
+    int rc;
+
+    flash_sect_protect(0, 0xFFF00000, 0xFFF7FFFF);
+    mon_printf("Erasing ");
+    flash_sect_erase(0xFFF00000, 0xFFF7FFFF);
+    mon_printf("Writing ");
+    rc = flash_write((uchar *)addr, 0xFFF00000, 0x7FFFF);
+    if (rc != 0) mon_printf("\nFlashing failed due to error %d\n", rc);
+    else mon_printf("\ndone\n");
+    flash_sect_protect(1, 0xFFF00000, 0xFFF7FFFF);
+}
diff --git a/tools/updater/utils.c b/tools/updater/utils.c
new file mode 100644
index 0000000..e230e19
--- /dev/null
+++ b/tools/updater/utils.c
@@ -0,0 +1,148 @@
+#include <common.h>
+#include <asm/processor.h>
+#include <memio.h>
+#include <linux/ctype.h>
+
+static __inline__ unsigned long
+get_msr(void)
+{
+	unsigned long msr;
+
+	asm volatile("mfmsr %0" : "=r" (msr) :);
+	return msr;
+}
+
+static __inline__ void
+set_msr(unsigned long msr)
+{
+	asm volatile("mtmsr %0" : : "r" (msr)); 
+}
+
+static __inline__ unsigned long
+get_dec(void)
+{
+	unsigned long val;
+
+	asm volatile("mfdec %0" : "=r" (val) :);
+	return val;
+}
+
+
+static __inline__ void
+set_dec(unsigned long val)
+{
+	asm volatile("mtdec %0" : : "r" (val)); 
+}
+
+
+void
+enable_interrupts(void)
+{
+    set_msr (get_msr() | MSR_EE);
+}
+
+/* returns flag if MSR_EE was set before */
+int
+disable_interrupts(void)
+{
+    ulong msr;
+
+    msr = get_msr();
+    set_msr (msr & ~MSR_EE);
+    return ((msr & MSR_EE) != 0);
+}
+
+u8 in8(u32 port)
+{
+    return in_byte(port);
+}
+
+void out8(u32 port, u8 val)
+{
+    out_byte(port, val);
+}
+
+unsigned long in32(u32 port)
+{
+    return in_long(port);
+}
+
+unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
+{
+        unsigned long result = 0,value;
+
+        if (*cp == '0') {
+                cp++;
+                if ((*cp == 'x') && isxdigit(cp[1])) {
+                        base = 16;
+                        cp++;
+                }
+                if (!base) {
+                        base = 8;
+                }
+        }
+        if (!base) {
+                base = 10;
+        }
+        while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+            ? toupper(*cp) : *cp)-'A'+10) < base) {
+                result = result*base + value;
+                cp++;
+        }
+        if (endp)
+                *endp = (char *)cp;
+        return result;
+}
+
+long simple_strtol(const char *cp,char **endp,unsigned int base)
+{
+        if(*cp=='-')
+                return -simple_strtoul(cp+1,endp,base);
+        return simple_strtoul(cp,endp,base);
+}
+
+static inline void
+soft_restart(unsigned long addr)
+{
+        /* SRR0 has system reset vector, SRR1 has default MSR value */
+        /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
+
+        __asm__ __volatile__ ("mtspr    26, %0"         :: "r" (addr));
+        __asm__ __volatile__ ("li       4, (1 << 6)"    ::: "r4");
+        __asm__ __volatile__ ("mtspr    27, 4");
+        __asm__ __volatile__ ("rfi");
+
+        while(1);       /* not reached */
+}
+
+void
+do_reset (void)
+{
+        ulong addr;
+        /* flush and disable I/D cache */
+        __asm__ __volatile__ ("mfspr    3, 1008"        ::: "r3");
+        __asm__ __volatile__ ("ori      5, 5, 0xcc00"   ::: "r5");
+        __asm__ __volatile__ ("ori      4, 3, 0xc00"    ::: "r4");
+        __asm__ __volatile__ ("andc     5, 3, 5"        ::: "r5");
+        __asm__ __volatile__ ("sync");
+        __asm__ __volatile__ ("mtspr    1008, 4");
+        __asm__ __volatile__ ("isync");
+        __asm__ __volatile__ ("sync");
+        __asm__ __volatile__ ("mtspr    1008, 5");
+        __asm__ __volatile__ ("isync");
+        __asm__ __volatile__ ("sync");
+
+#ifdef CFG_RESET_ADDRESS
+        addr = CFG_RESET_ADDRESS;
+#else
+        /*
+         * note: when CFG_MONITOR_BASE points to a RAM address,
+         * CFG_MONITOR_BASE - sizeof (ulong) is usually a valid
+         * address. Better pick an address known to be invalid on your
+         * system and assign it to CFG_RESET_ADDRESS.
+         */
+        addr = CFG_MONITOR_BASE - sizeof (ulong);
+#endif
+        soft_restart(addr);
+        while(1);       /* not reached */
+}