aboutsummaryrefslogtreecommitdiff
path: root/tools/updater
diff options
context:
space:
mode:
authorwdenk <wdenk>2002-11-19 11:04:11 +0000
committerwdenk <wdenk>2002-11-19 11:04:11 +0000
commitc7de829c796978e519984df2f1c8cfcf921a39a4 (patch)
tree43e42aa9a09f5265783c1622a5cea080471ef50e /tools/updater
parent2262cfeef91458b01a1bfe3812ccbbfdf8b82807 (diff)
* 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.
Diffstat (limited to 'tools/updater')
-rw-r--r--tools/updater/Makefile86
-rw-r--r--tools/updater/cmd_flash.c431
-rw-r--r--tools/updater/ctype.c56
-rw-r--r--tools/updater/dummy.c1
-rw-r--r--tools/updater/flash.c184
-rw-r--r--tools/updater/flash_hw.c660
-rw-r--r--tools/updater/junk1
-rw-r--r--tools/updater/ppcstring.S216
-rw-r--r--tools/updater/string.c340
-rw-r--r--tools/updater/update.c67
-rw-r--r--tools/updater/utils.c148
11 files changed, 2190 insertions, 0 deletions
diff --git a/tools/updater/Makefile b/tools/updater/Makefile
new file mode 100644
index 000000000..a8fb4ced3
--- /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 000000000..f3465f1d5
--- /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 000000000..6ed0468a2
--- /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 000000000..9fe5ac1b1
--- /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 000000000..d2e11d212
--- /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 000000000..ec11589c7
--- /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 000000000..f73285a83
--- /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 000000000..97023a055
--- /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 000000000..50537a655
--- /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 000000000..66c6dfc30
--- /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 000000000..e230e19f9
--- /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 */
+}