diff options
Diffstat (limited to 'tools/updater')
-rw-r--r-- | tools/updater/Makefile | 86 | ||||
-rw-r--r-- | tools/updater/cmd_flash.c | 431 | ||||
-rw-r--r-- | tools/updater/ctype.c | 56 | ||||
-rw-r--r-- | tools/updater/dummy.c | 1 | ||||
-rw-r--r-- | tools/updater/flash.c | 184 | ||||
-rw-r--r-- | tools/updater/flash_hw.c | 660 | ||||
-rw-r--r-- | tools/updater/junk | 1 | ||||
-rw-r--r-- | tools/updater/ppcstring.S | 216 | ||||
-rw-r--r-- | tools/updater/string.c | 340 | ||||
-rw-r--r-- | tools/updater/update.c | 67 | ||||
-rw-r--r-- | tools/updater/utils.c | 148 |
11 files changed, 2190 insertions, 0 deletions
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, §_first, §_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, §_first, §_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 */ +} |