summaryrefslogtreecommitdiff
path: root/board/amcc
diff options
context:
space:
mode:
Diffstat (limited to 'board/amcc')
-rw-r--r--board/amcc/bubinga/bubinga.c13
-rw-r--r--board/amcc/sequoia/cmd_sequoia.c205
-rw-r--r--board/amcc/taihu/Makefile49
-rw-r--r--board/amcc/taihu/config.mk24
-rw-r--r--board/amcc/taihu/flash.c1083
-rw-r--r--board/amcc/taihu/lcd.c257
-rw-r--r--board/amcc/taihu/taihu.c240
-rw-r--r--board/amcc/taihu/u-boot.lds150
-rw-r--r--board/amcc/taihu/update.c132
9 files changed, 2104 insertions, 49 deletions
diff --git a/board/amcc/bubinga/bubinga.c b/board/amcc/bubinga/bubinga.c
index fe6ce8a..66e7509 100644
--- a/board/amcc/bubinga/bubinga.c
+++ b/board/amcc/bubinga/bubinga.c
@@ -20,10 +20,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
-long int spd_sdram(void);
#include <common.h>
#include <asm/processor.h>
+#include <asm/io.h>
+
+long int spd_sdram(void);
int board_early_init_f(void)
{
@@ -34,6 +36,15 @@ int board_early_init_f(void)
mtdcr(uictr, 0x00000010); /* set int trigger levels */
mtdcr(uicsr, 0xFFFFFFFF); /* clear all ints */
+ /*
+ * Configure CPC0_PCI to enable PerWE as output
+ * and enable the internal PCI arbiter if selected
+ */
+ if (in_8((void *)FPGA_REG1) & FPGA_REG1_PCI_INT_ARB)
+ mtdcr(cpc0_pci, CPC0_PCI_HOST_CFG_EN | CPC0_PCI_ARBIT_EN);
+ else
+ mtdcr(cpc0_pci, CPC0_PCI_HOST_CFG_EN);
+
return 0;
}
diff --git a/board/amcc/sequoia/cmd_sequoia.c b/board/amcc/sequoia/cmd_sequoia.c
index 6fc60ea..f3803c0 100644
--- a/board/amcc/sequoia/cmd_sequoia.c
+++ b/board/amcc/sequoia/cmd_sequoia.c
@@ -26,76 +26,185 @@
#include <command.h>
#include <i2c.h>
-static u8 boot_533_nor[] = {
- 0x87, 0x78, 0x82, 0x52, 0x09, 0x57, 0xa0, 0x30,
- 0x40, 0x08, 0x23, 0x50, 0x0d, 0x05, 0x00, 0x00
-};
+/*
+ * There are 2 versions of production Sequoia & Rainier platforms.
+ * The primary difference is the reference clock. Those with
+ * 33333333 reference clocks will also have 667MHz rated
+ * processors. Not enough differences to have unique clock
+ * settings.
+ *
+ * NOR and NAND boot options change bytes 6, 7, 8, 9, 11. The
+ * values are independent of the rest of the clock settings.
+ *
+ * All Sequoias & Rainiers select from two possible EEPROMs in Boot
+ * Config F. One for 33MHz PCI, one for 66MHz PCI. The following
+ * values are for the 33MHz PCI configuration. Byte 5 (0 base) is
+ * the only value affected for a 66MHz PCI and simply needs a +0x10.
+ */
+
+#define NAND_COMPATIBLE 0x01
+#define NOR_COMPATIBLE 0x02
+
+/* check with Stefan on CFG_I2C_EEPROM_ADDR */
+#define I2C_EEPROM_ADDR 0x52
-static u8 boot_533_nand[] = {
- 0x87, 0x78, 0x82, 0x52, 0x09, 0x57, 0xd0, 0x10,
- 0xa0, 0x68, 0x23, 0x58, 0x0d, 0x05, 0x00, 0x00
+static char *config_labels[] = {
+ "CPU: 333 PLB: 133 OPB: 66 EBC: 66",
+ "CPU: 333 PLB: 166 OPB: 83 EBC: 55",
+ "CPU: 400 PLB: 133 OPB: 66 EBC: 66",
+ "CPU: 400 PLB: 160 OPB: 80 EBC: 53",
+ "CPU: 416 PLB: 166 OPB: 83 EBC: 55",
+ "CPU: 500 PLB: 166 OPB: 83 EBC: 55",
+ "CPU: 533 PLB: 133 OPB: 66 EBC: 66",
+ "CPU: 667 PLB: 166 OPB: 83 EBC: 55",
+ NULL
};
-static u8 boot_667_nor[] = {
- 0x87, 0x78, 0xa2, 0x52, 0x09, 0xd7, 0xa0, 0x30,
- 0x40, 0x08, 0x23, 0x50, 0x0d, 0x05, 0x00, 0x00
+static u8 boot_configs[][17] = {
+ {
+ (NOR_COMPATIBLE),
+ 0x84, 0x70, 0xa2, 0xa6, 0x05, 0x57, 0xa0, 0x10, 0x40,
+ 0x08, 0x23, 0x50, 0x0d, 0x05, 0x00, 0x00
+ },
+ {
+ (NAND_COMPATIBLE | NOR_COMPATIBLE),
+ 0xc7, 0x78, 0xf3, 0x4e, 0x05, 0xd7, 0xa0, 0x30, 0x40,
+ 0x08, 0x23, 0x50, 0x0d, 0x05, 0x00, 0x00
+ },
+ {
+ (NOR_COMPATIBLE),
+ 0x86, 0x78, 0xc2, 0xc6, 0x05, 0x57, 0xa0, 0x30, 0x40,
+ 0x08, 0x23, 0x50, 0x0d, 0x05, 0x00, 0x00
+ },
+ {
+ (NOR_COMPATIBLE),
+ 0x86, 0x78, 0xc2, 0xa6, 0x05, 0xd7, 0xa0, 0x10, 0x40,
+ 0x08, 0x23, 0x50, 0x0d, 0x05, 0x00, 0x00
+ },
+ {
+ (NAND_COMPATIBLE | NOR_COMPATIBLE),
+ 0xc6, 0x78, 0x52, 0xa6, 0x05, 0xd7, 0xa0, 0x10, 0x40,
+ 0x08, 0x23, 0x50, 0x0d, 0x05, 0x00, 0x00
+ },
+ {
+ (NAND_COMPATIBLE | NOR_COMPATIBLE),
+ 0xc7, 0x78, 0x52, 0xc6, 0x05, 0xd7, 0xa0, 0x30, 0x40,
+ 0x08, 0x23, 0x50, 0x0d, 0x05, 0x00, 0x00
+ },
+ {
+ (NOR_COMPATIBLE),
+ 0x87, 0x78, 0x82, 0x52, 0x09, 0x57, 0xa0, 0x30, 0x40,
+ 0x08, 0x23, 0x50, 0x0d, 0x05, 0x00, 0x00
+ },
+ {
+ (NAND_COMPATIBLE | NOR_COMPATIBLE),
+ 0x87, 0x78, 0xa2, 0x52, 0x09, 0xd7, 0xa0, 0x30, 0x40,
+ 0x08, 0x23, 0x50, 0x0d, 0x05, 0x00, 0x00
+ },
+ {
+ 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ }
};
-static u8 boot_667_nand[] = {
- 0x87, 0x78, 0xa2, 0x52, 0x09, 0xd7, 0xd0, 0x10,
- 0xa0, 0x68, 0x23, 0x58, 0x0d, 0x05, 0x00, 0x00
+/*
+ * Bytes 6,8,9,11 change for NAND boot
+ */
+static u8 nand_boot[] = {
+ 0xd0, 0xa0, 0x68, 0x58
};
static int do_bootstrap(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
- u8 chip;
- u8 *buf;
- int cpu_freq;
+ u8 *buf, bNAND;
+ int x, y, nbytes, selcfg;
+ extern char console_buffer[];
- if (argc < 3) {
+ if (argc < 2) {
printf("Usage:\n%s\n", cmdtp->usage);
return 1;
}
- cpu_freq = simple_strtol(argv[1], NULL, 10);
- if (!((cpu_freq == 533) || (cpu_freq == 667))) {
- printf("Unsupported cpu-frequency - only 533 and 667 supported\n");
+ if ((strcmp(argv[1], "nor") != 0) &&
+ (strcmp(argv[1], "nand") != 0)) {
+ printf("Unsupported boot-device - only nor|nand support\n");
return 1;
}
- /* use 0x52 as I2C EEPROM address for now */
- chip = 0x52;
+ /* set the nand flag based on provided input */
+ if ((strcmp(argv[1], "nand") == 0))
+ bNAND = 1;
+ else
+ bNAND = 0;
- if ((strcmp(argv[2], "nor") != 0) &&
- (strcmp(argv[2], "nand") != 0)) {
- printf("Unsupported boot-device - only nor|nand support\n");
- return 1;
- }
+ printf("Available configurations: \n\n");
- if (strcmp(argv[2], "nand") == 0) {
- switch (cpu_freq) {
- default:
- case 533:
- buf = boot_533_nand;
- break;
- case 667:
- buf = boot_667_nand;
- break;
+ if (bNAND) {
+ for(x = 0, y = 0; boot_configs[x][0] != 0; x++) {
+ /* filter on nand compatible */
+ if (boot_configs[x][0] & NAND_COMPATIBLE) {
+ printf(" %d - %s\n", (y+1), config_labels[x]);
+ y++;
+ }
}
} else {
- switch (cpu_freq) {
- default:
- case 533:
- buf = boot_533_nor;
- break;
- case 667:
- buf = boot_667_nor;
- break;
+ for(x = 0, y = 0; boot_configs[x][0] != 0; x++) {
+ /* filter on nor compatible */
+ if (boot_configs[x][0] & NOR_COMPATIBLE) {
+ printf(" %d - %s\n", (y+1), config_labels[x]);
+ y++;
+ }
}
}
- if (i2c_write(chip, 0, 1, buf, 16) != 0)
- printf("Error writing to EEPROM at address 0x%x\n", chip);
+ do {
+ nbytes = readline(" Selection [1-x / quit]: ");
+
+ if (nbytes) {
+ if (strcmp(console_buffer, "quit") == 0)
+ return 0;
+ selcfg = simple_strtol(console_buffer, NULL, 10);
+ if ((selcfg < 1) || (selcfg > y))
+ nbytes = 0;
+ }
+ } while (nbytes == 0);
+
+
+ y = (selcfg - 1);
+
+ for (x = 0; boot_configs[x][0] != 0; x++) {
+ if (bNAND) {
+ if (boot_configs[x][0] & NAND_COMPATIBLE) {
+ if (y > 0)
+ y--;
+ else if (y < 1)
+ break;
+ }
+ } else {
+ if (boot_configs[x][0] & NOR_COMPATIBLE) {
+ if (y > 0)
+ y--;
+ else if (y < 1)
+ break;
+ }
+ }
+ }
+
+ buf = &boot_configs[x][1];
+
+ if (bNAND) {
+ buf[6] = nand_boot[0];
+ buf[8] = nand_boot[1];
+ buf[9] = nand_boot[2];
+ buf[11] = nand_boot[3];
+ }
+
+ /* check CPLD register +5 for PCI 66MHz flag */
+ if (in8(CFG_BCSR_BASE + 5) & 0x01)
+ buf[5] += 0x10;
+
+ if (i2c_write(I2C_EEPROM_ADDR, 0, 1, buf, 16) != 0)
+ printf("Error writing to EEPROM at address 0x%x\n", I2C_EEPROM_ADDR);
udelay(CFG_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
printf("Done\n");
@@ -105,7 +214,7 @@ static int do_bootstrap(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
}
U_BOOT_CMD(
- bootstrap, 3, 0, do_bootstrap,
+ bootstrap, 2, 0, do_bootstrap,
"bootstrap - program the I2C bootstrap EEPROM\n",
- "<cpu-freq> <nor|nand> - program the I2C bootstrap EEPROM\n"
+ "<nand|nor> - strap to boot from NAND or NOR flash\n"
);
diff --git a/board/amcc/taihu/Makefile b/board/amcc/taihu/Makefile
new file mode 100644
index 0000000..9731c6e
--- /dev/null
+++ b/board/amcc/taihu/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2000-2006
+# 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 $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(BOARD).a
+
+COBJS = $(BOARD).o flash.o lcd.o update.o
+
+SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+
+$(LIB): $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+clean:
+ rm -f $(OBJS)
+
+distclean: clean
+ rm -f $(LIB) core *.bak .depend
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/amcc/taihu/config.mk b/board/amcc/taihu/config.mk
new file mode 100644
index 0000000..1bdf5e4
--- /dev/null
+++ b/board/amcc/taihu/config.mk
@@ -0,0 +1,24 @@
+#
+# (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
+#
+
+TEXT_BASE = 0xFFFC0000
diff --git a/board/amcc/taihu/flash.c b/board/amcc/taihu/flash.c
new file mode 100644
index 0000000..290259e
--- /dev/null
+++ b/board/amcc/taihu/flash.c
@@ -0,0 +1,1083 @@
+/*
+ * (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
+ */
+
+/*
+ * Modified 4/5/2001
+ * Wait for completion of each sector erase command issued
+ * 4/5/2001
+ * Chris Hallinan - DS4.COM, Inc. - clh@net1plus.com
+ */
+
+#include <common.h>
+#include <ppc4xx.h>
+#include <asm/processor.h>
+
+flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
+
+#undef DEBUG
+#ifdef DEBUG
+#define DEBUGF(x...) printf(x)
+#else
+#define DEBUGF(x...)
+#endif /* DEBUG */
+
+#define CFG_FLASH_CHAR_SIZE unsigned char
+#define CFG_FLASH_CHAR_ADDR0 (0x0aaa)
+#define CFG_FLASH_CHAR_ADDR1 (0x0555)
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+static ulong flash_get_size(vu_long * addr, flash_info_t * info);
+static void flash_get_offsets(ulong base, flash_info_t * info);
+static int write_word(flash_info_t * info, ulong dest, ulong data);
+#ifdef FLASH_BASE1_PRELIM
+static int write_word_1(flash_info_t * info, ulong dest, ulong data);
+static int write_word_2(flash_info_t * info, ulong dest, ulong data);
+static int flash_erase_1(flash_info_t * info, int s_first, int s_last);
+static int flash_erase_2(flash_info_t * info, int s_first, int s_last);
+static ulong flash_get_size_1(vu_long * addr, flash_info_t * info);
+static ulong flash_get_size_2(vu_long * addr, flash_info_t * info);
+#endif
+
+unsigned long flash_init(void)
+{
+ unsigned long size_b0, size_b1=0;
+ int i;
+
+ /* Init: no FLASHes known */
+ for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ }
+
+ /* Static FLASH Bank configuration here - FIXME XXX */
+
+ size_b0 =
+ flash_get_size((vu_long *) FLASH_BASE0_PRELIM, &flash_info[0]);
+
+ if (flash_info[0].flash_id == FLASH_UNKNOWN) {
+ printf("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n",
+ size_b0, size_b0 << 20);
+ }
+
+ if (size_b0) {
+ /* Setup offsets */
+ flash_get_offsets(FLASH_BASE0_PRELIM, &flash_info[0]);
+ /* Monitor protection ON by default */
+ (void)flash_protect(FLAG_PROTECT_SET,
+ CFG_MONITOR_BASE,
+ CFG_MONITOR_BASE + CFG_MONITOR_LEN - 1,
+ &flash_info[0]);
+#ifdef CFG_ENV_IS_IN_FLASH
+ (void)flash_protect(FLAG_PROTECT_SET, CFG_ENV_ADDR,
+ CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1,
+ &flash_info[0]);
+ (void)flash_protect(FLAG_PROTECT_SET, CFG_ENV_ADDR_REDUND,
+ CFG_ENV_ADDR_REDUND + CFG_ENV_SECT_SIZE - 1,
+ &flash_info[0]);
+#endif
+ /* Also protect sector containing initial power-up instruction */
+ /* (flash_protect() checks address range - other call ignored) */
+ (void)flash_protect(FLAG_PROTECT_SET,
+ 0xFFFFFFFC, 0xFFFFFFFF, &flash_info[0]);
+
+ flash_info[0].size = size_b0;
+ }
+#ifdef FLASH_BASE1_PRELIM
+ size_b1 =
+ flash_get_size((vu_long *) FLASH_BASE1_PRELIM, &flash_info[1])*2;
+
+ if (flash_info[1].flash_id == FLASH_UNKNOWN) {
+ printf("## Unknown FLASH on Bank 1 - Size = 0x%08lx = %ld MB\n",
+ size_b1, size_b1 << 20);
+ }
+
+ if (size_b1) {
+ /* Setup offsets */
+ flash_get_offsets(FLASH_BASE1_PRELIM, &flash_info[1]);
+ flash_info[1].size = size_b1;
+ }
+#endif
+ return (size_b0 + size_b1);
+}
+
+static void flash_get_offsets(ulong base, flash_info_t * info)
+{
+ int i;
+
+ /* set up sector start address table */
+ if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
+ (info->flash_id == FLASH_AM040)) {
+ for (i = 0; i < info->sector_count; i++)
+ info->start[i] = base + (i * 0x00010000);
+ } else if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMLV128U) {
+ for (i = 0; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00010000*2);
+ }
+ } else if ((info->flash_id & FLASH_TYPEMASK) == FLASH_S29GL128N ) {
+ for (i = 0; i < info->sector_count; i++) {
+ info->start[i] = base + (i * 0x00020000*2);
+ }
+ } else {
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00004000;
+ info->start[2] = base + 0x00006000;
+ info->start[3] = base + 0x00008000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] =
+ base + (i * 0x00010000) - 0x00030000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00004000;
+ info->start[i--] = base + info->size - 0x00006000;
+ info->start[i--] = base + info->size - 0x00008000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00010000;
+ }
+ }
+ }
+}
+
+
+void flash_print_info(flash_info_t * info)
+{
+ int i;
+ int k;
+ int size;
+ int erased;
+ volatile unsigned long *flash;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD:
+ printf("AMD ");
+ break;
+ case FLASH_MAN_STM:
+ printf("STM ");
+ break;
+ case FLASH_MAN_FUJ:
+ printf("FUJITSU ");
+ break;
+ case FLASH_MAN_SST:
+ printf("SST ");
+ break;
+ default:
+ printf("Unknown Vendor ");
+ break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM040:
+ printf("AM29F040 (512 Kbit, uniform sector size)\n");
+ break;
+ case FLASH_AM400B:
+ printf("AM29LV400B (4 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM400T:
+ printf("AM29LV400T (4 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM800B:
+ printf("AM29LV800B (8 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM800T:
+ printf("AM29LV800T (8 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AMD016:
+ printf("AM29F016D (16 Mbit, uniform sector size)\n");
+ break;
+ case FLASH_AM160B:
+ printf("AM29LV160B (16 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM160T:
+ printf("AM29LV160T (16 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM320B:
+ printf("AM29LV320B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM320T:
+ printf("AM29LV320T (32 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM033C:
+ printf("AM29LV033C (32 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AMLV128U:
+ printf("AM29LV128U (128 Mbit * 2, top boot sector)\n");
+ break;
+ case FLASH_SST800A:
+ printf("SST39LF/VF800 (8 Mbit, uniform sector size)\n");
+ break;
+ case FLASH_SST160A:
+ printf("SST39LF/VF160 (16 Mbit, uniform sector size)\n");
+ break;
+ case FLASH_STMW320DT:
+ printf ("M29W320DT (32 M, top sector)\n");
+ break;
+ case FLASH_S29GL128N:
+ printf ("S29GL128N (256 Mbit, uniform sector size)\n");
+ break;
+ default:
+ printf("Unknown Chip Type\n");
+ break;
+ }
+
+ printf(" Size: %ld KB in %d Sectors\n",
+ info->size >> 10, info->sector_count);
+
+ printf(" Sector Start Addresses:");
+ for (i = 0; i < info->sector_count; ++i) {
+ /*
+ * Check if whole sector is erased
+ */
+ if (i != (info->sector_count - 1))
+ size = info->start[i + 1] - info->start[i];
+ else
+ size = info->start[0] + info->size - info->start[i];
+ erased = 1;
+ flash = (volatile unsigned long *)info->start[i];
+ size = size >> 2; /* divide by 4 for longword access */
+ for (k = 0; k < size; k++) {
+ if (*flash++ != 0xffffffff) {
+ erased = 0;
+ break;
+ }
+ }
+
+ if ((i % 5) == 0)
+ printf("\n ");
+ printf(" %08lX%s%s",
+ info->start[i],
+ erased ? " E" : " ", info->protect[i] ? "RO " : " ");
+ }
+ printf("\n");
+ return;
+}
+
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+#ifdef FLASH_BASE1_PRELIM
+static ulong flash_get_size(vu_long * addr, flash_info_t * info)
+{
+ if ((ulong)addr == FLASH_BASE1_PRELIM) {
+ return flash_get_size_2(addr, info);
+ } else {
+ return flash_get_size_1(addr, info);
+ }
+}
+
+static ulong flash_get_size_1(vu_long * addr, flash_info_t * info)
+#else
+static ulong flash_get_size(vu_long * addr, flash_info_t * info)
+#endif
+{
+ short i;
+ CFG_FLASH_WORD_SIZE value;
+ ulong base = (ulong) addr;
+ volatile CFG_FLASH_WORD_SIZE *addr2 = (CFG_FLASH_WORD_SIZE *) addr;
+
+ DEBUGF("FLASH ADDR: %08x\n", (unsigned)addr);
+
+ /* Write auto select command: read Manufacturer ID */
+ addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00AA00AA;
+ addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x00550055;
+ addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00900090;
+ udelay(1000);
+
+ value = addr2[0];
+ DEBUGF("FLASH MANUFACT: %x\n", value);
+
+ switch (value) {
+ case (CFG_FLASH_WORD_SIZE) AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+ case (CFG_FLASH_WORD_SIZE) FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+ case (CFG_FLASH_WORD_SIZE) SST_MANUFACT:
+ info->flash_id = FLASH_MAN_SST;
+ break;
+ case (CFG_FLASH_WORD_SIZE) STM_MANUFACT:
+ info->flash_id = FLASH_MAN_STM;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return 0; /* no or unknown flash */
+ }
+
+ value = addr2[1]; /* device ID */
+ DEBUGF("\nFLASH DEVICEID: %x\n", value);
+
+ switch (value) {
+ case (CFG_FLASH_WORD_SIZE) AMD_ID_LV040B:
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x0080000; /* => 512 ko */
+ break;
+
+ case (CFG_FLASH_WORD_SIZE) AMD_ID_F040B:
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x0080000; /* => 512 ko */
+ break;
+
+ case (CFG_FLASH_WORD_SIZE) STM_ID_M29W040B:
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x0080000; /* => 512 ko */
+ break;
+
+ case (CFG_FLASH_WORD_SIZE) AMD_ID_F016D:
+ info->flash_id += FLASH_AMD016;
+ info->sector_count = 32;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case (CFG_FLASH_WORD_SIZE) AMD_ID_LV033C:
+ info->flash_id += FLASH_AMDLV033C;
+ info->sector_count = 64;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case (CFG_FLASH_WORD_SIZE) AMD_ID_LV400T:
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00080000;
+ break; /* => 0.5 MB */
+
+ case (CFG_FLASH_WORD_SIZE) AMD_ID_LV400B:
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00080000;
+ break; /* => 0.5 MB */
+
+ case (CFG_FLASH_WORD_SIZE) AMD_ID_LV800T:
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case (CFG_FLASH_WORD_SIZE) AMD_ID_LV800B:
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case (CFG_FLASH_WORD_SIZE) AMD_ID_LV160T:
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case (CFG_FLASH_WORD_SIZE) AMD_ID_LV160B:
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return 0; /* => no or unknown flash */
+ }
+
+ /* set up sector start address table */
+ if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMD016)) {
+ for (i = 0; i < info->sector_count; i++)
+ info->start[i] = base + (i * 0x00010000);
+ }
+ else if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMLV128U) {
+ for (i = 0; i < info->sector_count; i++)
+ info->start[i] = base + (i * 0x00010000 * 2);
+ } else {
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00004000;
+ info->start[2] = base + 0x00006000;
+ info->start[3] = base + 0x00008000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] =
+ base + (i * 0x00010000) - 0x00030000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00004000;
+ info->start[i--] = base + info->size - 0x00006000;
+ info->start[i--] = base + info->size - 0x00008000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00010000;
+ }
+ }
+ }
+
+ /* 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 */
+ addr2 = (volatile CFG_FLASH_WORD_SIZE *)(info->start[i]);
+
+ /* For AMD29033C flash we need to resend the command of *
+ * reading flash protection for upper 8 Mb of flash */
+ if (i == 32) {
+ addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0xAAAAAAAA;
+ addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x55555555;
+ addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x90909090;
+ }
+
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST)
+ info->protect[i] = 0;
+ else
+ info->protect[i] = addr2[2] & 1;
+ }
+
+ /* issue bank reset to return to read mode */
+ addr2[0] = (CFG_FLASH_WORD_SIZE) 0x00F000F0;
+
+ return info->size;
+}
+
+static int wait_for_DQ7_1(flash_info_t * info, int sect)
+{
+ ulong start, now, last;
+ volatile CFG_FLASH_WORD_SIZE *addr =
+ (CFG_FLASH_WORD_SIZE *) (info->start[sect]);
+
+ start = get_timer(0);
+ last = start;
+ while ((addr[0] & (CFG_FLASH_WORD_SIZE) 0x00800080) !=
+ (CFG_FLASH_WORD_SIZE) 0x00800080) {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf("Timeout\n");
+ return -1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc('.');
+ last = now;
+ }
+ }
+ return 0;
+}
+
+#ifdef FLASH_BASE1_PRELIM
+int flash_erase(flash_info_t * info, int s_first, int s_last)
+{
+ if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320B) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320T) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMLV128U) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_S29GL128N) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_STMW320DT)) {
+ return flash_erase_2(info, s_first, s_last);
+ } else {
+ return flash_erase_1(info, s_first, s_last);
+ }
+}
+
+static int flash_erase_1(flash_info_t * info, int s_first, int s_last)
+#else
+int flash_erase(flash_info_t * info, int s_first, int s_last)
+#endif
+{
+ volatile CFG_FLASH_WORD_SIZE *addr = (CFG_FLASH_WORD_SIZE *) (info->start[0]);
+ volatile CFG_FLASH_WORD_SIZE *addr2;
+ int flag, prot, sect, l_sect;
+ int i;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf("- missing\n");
+ } else {
+ printf("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf("Can't erase unknown flash type - aborted\n");
+ return 1;
+ }
+
+ prot = 0;
+ for (sect = s_first; sect <= s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect <= s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr2 = (CFG_FLASH_WORD_SIZE *) (info->start[sect]);
+
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
+ addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00AA00AA;
+ addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x00550055;
+ addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00800080;
+ addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00AA00AA;
+ addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x00550055;
+ addr2[0] = (CFG_FLASH_WORD_SIZE) 0x00500050; /* block erase */
+ for (i = 0; i < 50; i++)
+ udelay(1000); /* wait 1 ms */
+ } else {
+ addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00AA00AA;
+ addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x00550055;
+ addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00800080;
+ addr[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00AA00AA;
+ addr[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x00550055;
+ addr2[0] = (CFG_FLASH_WORD_SIZE) 0x00300030; /* sector erase */
+ }
+ l_sect = sect;
+ /*
+ * Wait for each sector to complete, it's more
+ * reliable. According to AMD Spec, you must
+ * issue all erase commands within a specified
+ * timeout. This has been seen to fail, especially
+ * if printf()s are included (for debug)!!
+ */
+ wait_for_DQ7_1(info, sect);
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay(1000);
+
+ /* reset to read mode */
+ addr = (CFG_FLASH_WORD_SIZE *) info->start[0];
+ addr[0] = (CFG_FLASH_WORD_SIZE) 0x00F000F0; /* reset bank */
+
+ 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;
+
+ 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) {
+ return rc;
+ }
+ wp += 4;
+ }
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ data = 0;
+ for (i = 0; i < 4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ return rc;
+ }
+ wp += 4;
+ cnt -= 4;
+ }
+
+ if (cnt == 0) {
+ 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);
+ }
+
+ return (write_word(info, wp, data));
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+#ifdef FLASH_BASE1_PRELIM
+static int write_word(flash_info_t * info, ulong dest, ulong data)
+{
+ if (((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320B) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM320T) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMLV128U) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_S29GL128N) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_STMW320DT)) {
+ return write_word_2(info, dest, data);
+ } else {
+ return write_word_1(info, dest, data);
+ }
+}
+
+static int write_word_1(flash_info_t * info, ulong dest, ulong data)
+#else
+static int write_word(flash_info_t * info, ulong dest, ulong data)
+#endif
+{
+ volatile CFG_FLASH_WORD_SIZE *addr2 = (CFG_FLASH_WORD_SIZE *) (info->start[0]);
+ volatile CFG_FLASH_WORD_SIZE *dest2 = (CFG_FLASH_WORD_SIZE *) dest;
+ volatile CFG_FLASH_WORD_SIZE *data2 = (CFG_FLASH_WORD_SIZE *) & data;
+ ulong start;
+ int i;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_long *)dest) & data) != data) {
+ return 2;
+ }
+
+ for (i = 0; i < 4 / sizeof(CFG_FLASH_WORD_SIZE); i++) {
+ int flag;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00AA00AA;
+ addr2[CFG_FLASH_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x00550055;
+ addr2[CFG_FLASH_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x00A000A0;
+
+ dest2[i] = data2[i];
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer(0);
+ while ((dest2[i] & (CFG_FLASH_WORD_SIZE) 0x00800080) !=
+ (data2[i] & (CFG_FLASH_WORD_SIZE) 0x00800080)) {
+
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+#ifdef FLASH_BASE1_PRELIM
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+static ulong flash_get_size_2(vu_long * addr, flash_info_t * info)
+{
+ short i;
+ CFG_FLASH_CHAR_SIZE value;
+ ulong base = (ulong) addr;
+ volatile CFG_FLASH_WORD_SIZE *addr2 = (CFG_FLASH_WORD_SIZE *) addr;
+
+ DEBUGF("FLASH ADDR: %08x\n", (unsigned)addr);
+
+ /* Write auto select command: read Manufacturer ID */
+ addr2[CFG_FLASH_CHAR_ADDR0] = (CFG_FLASH_WORD_SIZE) 0xAAAAAAAA;
+ addr2[CFG_FLASH_CHAR_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x55555555;
+ addr2[CFG_FLASH_CHAR_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x90909090;
+ udelay(1000);
+
+ value = (CFG_FLASH_CHAR_SIZE)addr2[0];
+ DEBUGF("FLASH MANUFACT: %x\n", value);
+
+ switch (value) {
+ case (CFG_FLASH_CHAR_SIZE) AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+ case (CFG_FLASH_CHAR_SIZE) FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+ case (CFG_FLASH_CHAR_SIZE) SST_MANUFACT:
+ info->flash_id = FLASH_MAN_SST;
+ break;
+ case (CFG_FLASH_CHAR_SIZE) STM_MANUFACT:
+ info->flash_id = FLASH_MAN_STM;
+ break;
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ return 0; /* no or unknown flash */
+ }
+
+ value = (CFG_FLASH_CHAR_SIZE)addr2[2]; /* device ID */
+ DEBUGF("\nFLASH DEVICEID: %x\n", value);
+
+ switch (value) {
+ case (CFG_FLASH_CHAR_SIZE) AMD_ID_LV040B:
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x0080000; /* => 512 ko */
+ break;
+
+ case (CFG_FLASH_CHAR_SIZE) AMD_ID_F040B:
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x0080000; /* => 512 ko */
+ break;
+
+ case (CFG_FLASH_CHAR_SIZE) STM_ID_M29W040B:
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x0080000; /* => 512 ko */
+ break;
+
+ case (CFG_FLASH_CHAR_SIZE) AMD_ID_F016D:
+ info->flash_id += FLASH_AMD016;
+ info->sector_count = 32;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case (CFG_FLASH_CHAR_SIZE) AMD_ID_LV033C:
+ info->flash_id += FLASH_AMDLV033C;
+ info->sector_count = 64;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case (CFG_FLASH_CHAR_SIZE) AMD_ID_LV400T:
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00080000;
+ break; /* => 0.5 MB */
+
+ case (CFG_FLASH_CHAR_SIZE) AMD_ID_LV400B:
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00080000;
+ break; /* => 0.5 MB */
+
+ case (CFG_FLASH_CHAR_SIZE) AMD_ID_LV800T:
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case (CFG_FLASH_CHAR_SIZE) AMD_ID_LV800B:
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case (CFG_FLASH_CHAR_SIZE) AMD_ID_LV160T:
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case (CFG_FLASH_CHAR_SIZE) AMD_ID_LV160B:
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+ case (CFG_FLASH_CHAR_SIZE) AMD_ID_MIRROR:
+ if ((CFG_FLASH_CHAR_SIZE)addr2[0x1c] == (CFG_FLASH_CHAR_SIZE)AMD_ID_LV128U_2
+ && (CFG_FLASH_CHAR_SIZE)addr2[0x1e] == (CFG_FLASH_CHAR_SIZE)AMD_ID_LV128U_3) {
+ info->flash_id += FLASH_AMLV128U;
+ info->sector_count = 256;
+ info->size = 0x01000000;
+ } else if ((CFG_FLASH_CHAR_SIZE)addr2[0x1c] == (CFG_FLASH_CHAR_SIZE)AMD_ID_GL128N_2
+ && (CFG_FLASH_CHAR_SIZE)addr2[0x1e] == (CFG_FLASH_CHAR_SIZE)AMD_ID_GL128N_3 ) {
+ info->flash_id += FLASH_S29GL128N;
+ info->sector_count = 128;
+ info->size = 0x01000000;
+ }
+ else
+ info->flash_id = FLASH_UNKNOWN;
+ break; /* => 2 MB */
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ return 0; /* => no or unknown flash */
+ }
+
+ /* set up sector start address table */
+ if (((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AM040) ||
+ ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMD016)) {
+ for (i = 0; i < info->sector_count; i++)
+ info->start[i] = base + (i * 0x00010000);
+ } else if ((info->flash_id & FLASH_TYPEMASK) == FLASH_AMLV128U) {
+ for (i = 0; i < info->sector_count; i++)
+ info->start[i] = base + (i * 0x00010000);
+ } else if ((info->flash_id & FLASH_TYPEMASK) == FLASH_S29GL128N ) {
+ for (i = 0; i < info->sector_count; i++)
+ info->start[i] = base + (i * 0x00020000);
+ } else {
+ if (info->flash_id & FLASH_BTYPE) {
+ /* set sector offsets for bottom boot block type */
+ info->start[0] = base + 0x00000000;
+ info->start[1] = base + 0x00004000;
+ info->start[2] = base + 0x00006000;
+ info->start[3] = base + 0x00008000;
+ for (i = 4; i < info->sector_count; i++) {
+ info->start[i] =
+ base + (i * 0x00010000) - 0x00030000;
+ }
+ } else {
+ /* set sector offsets for top boot block type */
+ i = info->sector_count - 1;
+ info->start[i--] = base + info->size - 0x00004000;
+ info->start[i--] = base + info->size - 0x00006000;
+ info->start[i--] = base + info->size - 0x00008000;
+ for (; i >= 0; i--) {
+ info->start[i] = base + i * 0x00010000;
+ }
+ }
+ }
+
+ /* 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 */
+ addr2 = (volatile CFG_FLASH_WORD_SIZE *)(info->start[i]);
+
+ /* For AMD29033C flash we need to resend the command of *
+ * reading flash protection for upper 8 Mb of flash */
+ if (i == 32) {
+ addr2[CFG_FLASH_CHAR_ADDR0] = (CFG_FLASH_WORD_SIZE) 0xAAAAAAAA;
+ addr2[CFG_FLASH_CHAR_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x55555555;
+ addr2[CFG_FLASH_CHAR_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x90909090;
+ }
+
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST)
+ info->protect[i] = 0;
+ else
+ info->protect[i] = (CFG_FLASH_CHAR_SIZE)addr2[4] & 1;
+ }
+
+ /* issue bank reset to return to read mode */
+ addr2[0] = (CFG_FLASH_WORD_SIZE) 0xF0F0F0F0;
+ return info->size;
+}
+
+static int wait_for_DQ7_2(flash_info_t * info, int sect)
+{
+ ulong start, now, last;
+ volatile CFG_FLASH_WORD_SIZE *addr =
+ (CFG_FLASH_WORD_SIZE *) (info->start[sect]);
+
+ start = get_timer(0);
+ last = start;
+ while (((CFG_FLASH_WORD_SIZE)addr[0] & (CFG_FLASH_WORD_SIZE) 0x80808080) !=
+ (CFG_FLASH_WORD_SIZE) 0x80808080) {
+ if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {
+ printf("Timeout\n");
+ return -1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc('.');
+ last = now;
+ }
+ }
+ return 0;
+}
+
+static int flash_erase_2(flash_info_t * info, int s_first, int s_last)
+{
+ volatile CFG_FLASH_WORD_SIZE *addr = (CFG_FLASH_WORD_SIZE *) (info->start[0]);
+ volatile CFG_FLASH_WORD_SIZE *addr2;
+ int flag, prot, sect, l_sect;
+ int i;
+
+ if ((s_first < 0) || (s_first > s_last)) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf("- missing\n");
+ } else {
+ printf("- no sectors to erase\n");
+ }
+ return 1;
+ }
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf("Can't erase unknown flash type - aborted\n");
+ return 1;
+ }
+
+ prot = 0;
+ for (sect = s_first; sect <= s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf("\n");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect <= s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr2 = (CFG_FLASH_WORD_SIZE *) (info->start[sect]);
+
+ if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) {
+ addr[CFG_FLASH_CHAR_ADDR0] = (CFG_FLASH_WORD_SIZE) 0xAAAAAAAA;
+ addr[CFG_FLASH_CHAR_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x55555555;
+ addr[CFG_FLASH_CHAR_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x80808080;
+ addr[CFG_FLASH_CHAR_ADDR0] = (CFG_FLASH_WORD_SIZE) 0xAAAAAAAA;
+ addr[CFG_FLASH_CHAR_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x55555555;
+ addr2[0] = (CFG_FLASH_WORD_SIZE) 0x50505050; /* block erase */
+ for (i = 0; i < 50; i++)
+ udelay(1000); /* wait 1 ms */
+ } else {
+ addr[CFG_FLASH_CHAR_ADDR0] = (CFG_FLASH_WORD_SIZE) 0xAAAAAAAA;
+ addr[CFG_FLASH_CHAR_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x55555555;
+ addr[CFG_FLASH_CHAR_ADDR0] = (CFG_FLASH_WORD_SIZE) 0x80808080;
+ addr[CFG_FLASH_CHAR_ADDR0] = (CFG_FLASH_WORD_SIZE) 0xAAAAAAAA;
+ addr[CFG_FLASH_CHAR_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x55555555;
+ addr2[0] = (CFG_FLASH_WORD_SIZE) 0x30303030; /* sector erase */
+ }
+ l_sect = sect;
+ /*
+ * Wait for each sector to complete, it's more
+ * reliable. According to AMD Spec, you must
+ * issue all erase commands within a specified
+ * timeout. This has been seen to fail, especially
+ * if printf()s are included (for debug)!!
+ */
+ wait_for_DQ7_2(info, sect);
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay(1000);
+
+ /* reset to read mode */
+ addr = (CFG_FLASH_WORD_SIZE *) info->start[0];
+ addr[0] = (CFG_FLASH_WORD_SIZE) 0xF0F0F0F0; /* reset bank */
+
+ printf(" done\n");
+ return 0;
+}
+
+static int write_word_2(flash_info_t * info, ulong dest, ulong data)
+{
+ volatile CFG_FLASH_WORD_SIZE *addr2 = (CFG_FLASH_WORD_SIZE *) (info->start[0]);
+ volatile CFG_FLASH_WORD_SIZE *dest2 = (CFG_FLASH_WORD_SIZE *) dest;
+ volatile CFG_FLASH_WORD_SIZE *data2 = (CFG_FLASH_WORD_SIZE *) & data;
+ ulong start;
+ int i;
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((*((vu_long *)dest) & data) != data) {
+ return 2;
+ }
+
+ for (i = 0; i < 4 / sizeof(CFG_FLASH_WORD_SIZE); i++) {
+ int flag;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ addr2[CFG_FLASH_CHAR_ADDR0] = (CFG_FLASH_WORD_SIZE) 0xAAAAAAAA;
+ addr2[CFG_FLASH_CHAR_ADDR1] = (CFG_FLASH_WORD_SIZE) 0x55555555;
+ addr2[CFG_FLASH_CHAR_ADDR0] = (CFG_FLASH_WORD_SIZE) 0xA0A0A0A0;
+
+ dest2[i] = data2[i];
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer(0);
+ while ((dest2[i] & (CFG_FLASH_WORD_SIZE) 0x80808080) !=
+ (data2[i] & (CFG_FLASH_WORD_SIZE) 0x80808080)) {
+
+ if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif /* FLASH_BASE1_PRELIM */
diff --git a/board/amcc/taihu/lcd.c b/board/amcc/taihu/lcd.c
new file mode 100644
index 0000000..3d042df
--- /dev/null
+++ b/board/amcc/taihu/lcd.c
@@ -0,0 +1,257 @@
+/*
+ * 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 <config.h>
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+
+#define LCD_CMD_ADDR 0x50100002
+#define LCD_DATA_ADDR 0x50100003
+#define LCD_BLK_CTRL CPLD_REG1_ADDR
+
+static char *amcc_logo = "AMCC 405EP TAIHU EVALUATION KIT";
+static int addr_flag = 0x80;
+
+static void lcd_bl_ctrl(char val)
+{
+ out_8((u8 *) LCD_BLK_CTRL, in_8((u8 *) LCD_BLK_CTRL) | val);
+}
+
+static void lcd_putc(int val)
+{
+ int i = 100;
+ char addr;
+
+ while (i--) {
+ if ((in_8((u8 *) LCD_CMD_ADDR) & 0x80) != 0x80) { /*BF = 1 ?*/
+ udelay(50);
+ break;
+ }
+ udelay(50);
+ }
+
+ if (in_8((u8 *) LCD_CMD_ADDR) & 0x80) {
+ printf("LCD is busy\n");
+ return;
+ }
+
+ addr = in_8((u8 *) LCD_CMD_ADDR);
+ udelay(50);
+ if ((addr != 0) && (addr % 0x10 == 0)) {
+ addr_flag ^= 0x40;
+ out_8((u8 *) LCD_CMD_ADDR, addr_flag);
+ }
+
+ udelay(50);
+ out_8((u8 *) LCD_DATA_ADDR, val);
+ udelay(50);
+}
+
+static void lcd_puts(char *s)
+{
+ char *p = s;
+ int i = 100;
+
+ while (i--) {
+ if ((in_8((u8 *) LCD_CMD_ADDR) & 0x80) != 0x80) { /*BF = 1 ?*/
+ udelay(50);
+ break;
+ }
+ udelay(50);
+ }
+
+ if (in_8((u8 *) LCD_CMD_ADDR) & 0x80) {
+ printf("LCD is busy\n");
+ return;
+ }
+
+ while (*p)
+ lcd_putc(*p++);
+}
+
+static void lcd_put_logo(void)
+{
+ int i = 100;
+ char *p = amcc_logo;
+
+ while (i--) {
+ if ((in_8((u8 *) LCD_CMD_ADDR) & 0x80) != 0x80) { /*BF = 1 ?*/
+ udelay(50);
+ break;
+ }
+ udelay(50);
+ }
+
+ if (in_8((u8 *) LCD_CMD_ADDR) & 0x80) {
+ printf("LCD is busy\n");
+ return;
+ }
+
+ out_8((u8 *) LCD_CMD_ADDR, 0x80);
+ while (*p)
+ lcd_putc(*p++);
+}
+
+int lcd_init(void)
+{
+ puts("LCD: ");
+ out_8((u8 *) LCD_CMD_ADDR, 0x38); /* set function:8-bit,2-line,5x7 font type */
+ udelay(50);
+ out_8((u8 *) LCD_CMD_ADDR, 0x0f); /* set display on,cursor on,blink on */
+ udelay(50);
+ out_8((u8 *) LCD_CMD_ADDR, 0x01); /* display clear */
+ udelay(2000);
+ out_8((u8 *) LCD_CMD_ADDR, 0x06); /* set entry */
+ udelay(50);
+ lcd_bl_ctrl(0x02); /* set backlight on */
+ lcd_put_logo();
+ puts("ready\n");
+
+ return 0;
+}
+
+static int do_lcd_clear (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ out_8((u8 *) LCD_CMD_ADDR, 0x01);
+ udelay(2000);
+
+ return 0;
+}
+
+static int do_lcd_puts (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ if (argc < 2) {
+ printf("%s", cmdtp->usage);
+ return 1;
+ }
+ lcd_puts(argv[1]);
+
+ return 0;
+}
+
+static int do_lcd_putc (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ if (argc < 2) {
+ printf("%s", cmdtp->usage);
+ return 1;
+ }
+ lcd_putc((char)argv[1][0]);
+
+ return 0;
+}
+
+static int do_lcd_cur (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ ulong count;
+ ulong dir;
+ char cur_addr;
+
+ if (argc < 3) {
+ printf("%s", cmdtp->usage);
+ return 1;
+ }
+
+ count = simple_strtoul(argv[1], NULL, 16);
+ if (count > 31) {
+ printf("unable to shift > 0x20\n");
+ count = 0;
+ }
+
+ dir = simple_strtoul(argv[2], NULL, 16);
+ cur_addr = in_8((u8 *) LCD_CMD_ADDR);
+ udelay(50);
+
+ if (dir == 0x0) {
+ if (addr_flag == 0x80) {
+ if (count >= (cur_addr & 0xf)) {
+ out_8((u8 *) LCD_CMD_ADDR, 0x80);
+ udelay(50);
+ count = 0;
+ }
+ } else {
+ if (count >= ((cur_addr & 0x0f) + 0x0f)) {
+ out_8((u8 *) LCD_CMD_ADDR, 0x80);
+ addr_flag = 0x80;
+ udelay(50);
+ count = 0x0;
+ } else if (count >= ( cur_addr & 0xf)) {
+ count -= cur_addr & 0xf ;
+ out_8((u8 *) LCD_CMD_ADDR, 0x80 | 0xf);
+ addr_flag = 0x80;
+ udelay(50);
+ }
+ }
+ } else {
+ if (addr_flag == 0x80) {
+ if (count >= (0x1f - (cur_addr & 0xf))) {
+ count = 0x0;
+ addr_flag = 0xc0;
+ out_8((u8 *) LCD_CMD_ADDR, 0xc0 | 0xf);
+ udelay(50);
+ } else if ((count + (cur_addr & 0xf ))>= 0x0f) {
+ count = count + (cur_addr & 0xf) - 0x0f;
+ addr_flag = 0xc0;
+ out_8((u8 *) LCD_CMD_ADDR, 0xc0);
+ udelay(50);
+ }
+ } else if ((count + (cur_addr & 0xf )) >= 0x0f) {
+ count = 0x0;
+ out_8((u8 *) LCD_CMD_ADDR, 0xC0 | 0x0F);
+ udelay(50);
+ }
+ }
+ while (count--) {
+ if (dir == 0)
+ out_8((u8 *) LCD_CMD_ADDR, 0x10);
+ else
+ out_8((u8 *) LCD_CMD_ADDR, 0x14);
+ udelay(50);
+ }
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ lcd_cls, 1, 1, do_lcd_clear,
+ "lcd_cls - lcd clear display\n",
+ NULL
+ );
+
+U_BOOT_CMD(
+ lcd_puts, 2, 1, do_lcd_puts,
+ "lcd_puts - display string on lcd\n",
+ "<string> - <string> to be displayed\n"
+ );
+
+U_BOOT_CMD(
+ lcd_putc, 2, 1, do_lcd_putc,
+ "lcd_putc - display char on lcd\n",
+ "<char> - <char> to be displayed\n"
+ );
+
+U_BOOT_CMD(
+ lcd_cur, 3, 1, do_lcd_cur,
+ "lcd_cur - shift cursor on lcd\n",
+ "<count> <dir> - shift cursor on lcd <count> times, direction is <dir> \n"
+ " <count> - 0..31\n"
+ " <dir> - 0=backward 1=forward\n"
+ );
diff --git a/board/amcc/taihu/taihu.c b/board/amcc/taihu/taihu.c
new file mode 100644
index 0000000..ea83671
--- /dev/null
+++ b/board/amcc/taihu/taihu.c
@@ -0,0 +1,240 @@
+/*
+ * (C) Copyright 2000-2005
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2005-2007
+ * Beijing UD Technology Co., Ltd., taihusupport@amcc.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <asm/gpio.h>
+
+extern int lcd_init(void);
+
+/*
+ * board_early_init_f
+ */
+int board_early_init_f(void)
+{
+ lcd_init();
+
+ mtdcr(uicsr, 0xFFFFFFFF); /* clear all ints */
+ mtdcr(uicer, 0x00000000); /* disable all ints */
+ mtdcr(uiccr, 0x00000000);
+ mtdcr(uicpr, 0xFFFF7F00); /* set int polarities */
+ mtdcr(uictr, 0x00000000); /* set int trigger levels */
+ mtdcr(uicsr, 0xFFFFFFFF); /* clear all ints */
+ mtdcr(uicvcr, 0x00000001); /* set vect base=0,INT0 highest priority */
+
+ mtebc(pb3ap, CFG_EBC_PB3AP); /* memory bank 3 (CPLD_LCM) initialization */
+ mtebc(pb3cr, CFG_EBC_PB3CR);
+
+ /*
+ * Configure CPC0_PCI to enable PerWE as output
+ * and enable the internal PCI arbiter
+ */
+ mtdcr(cpc0_pci, CPC0_PCI_SPE | CPC0_PCI_HOST_CFG_EN | CPC0_PCI_ARBIT_EN);
+
+ return 0;
+}
+
+/*
+ * Check Board Identity:
+ */
+int checkboard(void)
+{
+ char *s = getenv("serial#");
+
+ puts("Board: Taihu - AMCC PPC405EP Evaluation Board");
+
+ if (s != NULL) {
+ puts(", serial# ");
+ puts(s);
+ }
+ putc('\n');
+
+ return 0;
+}
+
+/*************************************************************************
+ * long int initdram
+ *
+ ************************************************************************/
+long int initdram(int board)
+{
+ return CFG_SDRAM_SIZE_PER_BANK * CFG_SDRAM_BANKS; /* 128Mbytes */
+}
+
+static int do_sw_stat(cmd_tbl_t* cmd_tp, int flags, int argc, char *argv[])
+{
+ char stat;
+ int i;
+
+ stat = in_8((u8 *) CPLD_REG0_ADDR);
+ printf("SW2 status: ");
+ for (i=0; i<4; i++) /* 4-position */
+ printf("%d:%s ", i, stat & (0x08 >> i)?"on":"off");
+ printf("\n");
+ return 0;
+}
+
+U_BOOT_CMD (
+ sw2_stat, 1, 1, do_sw_stat,
+ "sw2_stat - show status of switch 2\n",
+ NULL
+ );
+
+static int do_led_ctl(cmd_tbl_t* cmd_tp, int flags, int argc, char *argv[])
+{
+ int led_no;
+
+ if (argc != 3) {
+ printf("%s", cmd_tp->usage);
+ return -1;
+ }
+
+ led_no = simple_strtoul(argv[1], NULL, 16);
+ if (led_no != 1 && led_no != 2) {
+ printf("%s", cmd_tp->usage);
+ return -1;
+ }
+
+ if (strcmp(argv[2],"off") == 0x0) {
+ if (led_no == 1)
+ gpio_write_bit(30, 1);
+ else
+ gpio_write_bit(31, 1);
+ } else if (strcmp(argv[2],"on") == 0x0) {
+ if (led_no == 1)
+ gpio_write_bit(30, 0);
+ else
+ gpio_write_bit(31, 0);
+ } else {
+ printf("%s", cmd_tp->usage);
+ return -1;
+ }
+
+ return 0;
+}
+
+U_BOOT_CMD (
+ led_ctl, 3, 1, do_led_ctl,
+ "led_ctl - make led 1 or 2 on or off\n",
+ "<led_no> <on/off> - make led <led_no> on/off,\n"
+ "\tled_no is 1 or 2\t"
+ );
+
+#define SPI_CS_GPIO0 0
+#define SPI_SCLK_GPIO14 14
+#define SPI_DIN_GPIO15 15
+#define SPI_DOUT_GPIO16 16
+
+void spi_scl(int bit)
+{
+ gpio_write_bit(SPI_SCLK_GPIO14, bit);
+}
+
+void spi_sda(int bit)
+{
+ gpio_write_bit(SPI_DOUT_GPIO16, bit);
+}
+
+unsigned char spi_read(void)
+{
+ return (unsigned char)gpio_read_out_bit(SPI_DIN_GPIO15);
+}
+
+void taihu_spi_chipsel(int cs)
+{
+ gpio_write_bit(SPI_CS_GPIO0, cs);
+}
+
+spi_chipsel_type spi_chipsel[]= {
+ taihu_spi_chipsel
+};
+
+int spi_chipsel_cnt = sizeof(spi_chipsel) / sizeof(spi_chipsel[0]);
+
+#ifdef CONFIG_PCI
+static unsigned char int_lines[32] = {
+ 29, 30, 27, 28, 29, 30, 25, 27,
+ 29, 30, 27, 28, 29, 30, 27, 28,
+ 29, 30, 27, 28, 29, 30, 27, 28,
+ 29, 30, 27, 28, 29, 30, 27, 28};
+
+static void taihu_pci_fixup_irq(struct pci_controller *hose, pci_dev_t dev)
+{
+ unsigned char int_line = int_lines[PCI_DEV(dev) & 31];
+
+ pci_hose_write_config_byte(hose, dev, PCI_INTERRUPT_LINE, int_line);
+}
+
+int pci_pre_init(struct pci_controller *hose)
+{
+ hose->fixup_irq = taihu_pci_fixup_irq;
+ return 1;
+}
+#endif /* CONFIG_PCI */
+
+#ifdef CFG_DRAM_TEST
+int testdram(void)
+{
+ unsigned long *mem = (unsigned long *)0;
+ const unsigned long kend = (1024 / sizeof(unsigned long));
+ unsigned long k, n;
+ unsigned long msr;
+ unsigned long total_kbytes = CFG_SDRAM_SIZE_PER_BANK * CFG_SDRAM_BANKS / 1024;
+
+ msr = mfmsr();
+ mtmsr(msr & ~(MSR_EE));
+
+ for (k = 0; k < total_kbytes ;
+ ++k, mem += (1024 / sizeof(unsigned long))) {
+ if ((k & 1023) == 0)
+ printf("%3d MB\r", k / 1024);
+
+ memset(mem, 0xaaaaaaaa, 1024);
+ for (n = 0; n < kend; ++n) {
+ if (mem[n] != 0xaaaaaaaa) {
+ printf("SDRAM test fails at: %08x\n",
+ (uint) & mem[n]);
+ return 1;
+ }
+ }
+
+ memset(mem, 0x55555555, 1024);
+ for (n = 0; n < kend; ++n) {
+ if (mem[n] != 0x55555555) {
+ printf("SDRAM test fails at: %08x\n",
+ (uint) & mem[n]);
+ return 1;
+ }
+ }
+ }
+ printf("SDRAM test passes\n");
+ mtmsr(msr);
+
+ return 0;
+}
+#endif /* CFG_DRAM_TEST */
diff --git a/board/amcc/taihu/u-boot.lds b/board/amcc/taihu/u-boot.lds
new file mode 100644
index 0000000..be03092
--- /dev/null
+++ b/board/amcc/taihu/u-boot.lds
@@ -0,0 +1,150 @@
+/*
+ * (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
+ */
+
+OUTPUT_ARCH(powerpc)
+SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+SECTIONS
+{
+ .resetvec 0xFFFFFFFC :
+ {
+ *(.resetvec)
+ } = 0xffff
+
+ /* Read-only sections, merged into text segment: */
+ . = + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .rel.text : { *(.rel.text) }
+ .rela.text : { *(.rela.text) }
+ .rel.data : { *(.rel.data) }
+ .rela.data : { *(.rela.data) }
+ .rel.rodata : { *(.rel.rodata) }
+ .rela.rodata : { *(.rela.rodata) }
+ .rel.got : { *(.rel.got) }
+ .rela.got : { *(.rela.got) }
+ .rel.ctors : { *(.rel.ctors) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rel.dtors : { *(.rel.dtors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rel.bss : { *(.rel.bss) }
+ .rela.bss : { *(.rela.bss) }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .init : { *(.init) }
+ .plt : { *(.plt) }
+ .text :
+ {
+ /* WARNING - the following is hand-optimized to fit within */
+ /* the sector layout of our flash chips! XXX FIXME XXX */
+
+ cpu/ppc4xx/start.o (.text)
+ cpu/ppc4xx/kgdb.o (.text)
+ cpu/ppc4xx/traps.o (.text)
+ cpu/ppc4xx/interrupts.o (.text)
+ cpu/ppc4xx/serial.o (.text)
+ cpu/ppc4xx/cpu_init.o (.text)
+ cpu/ppc4xx/speed.o (.text)
+ common/dlmalloc.o (.text)
+ lib_generic/crc32.o (.text)
+ lib_ppc/extable.o (.text)
+ lib_generic/zlib.o (.text)
+
+/* . = env_offset;*/
+/* common/environment.o(.text)*/
+
+ *(.text)
+ *(.fixup)
+ *(.got1)
+ }
+ _etext = .;
+ PROVIDE (etext = .);
+ .rodata :
+ {
+ *(.rodata)
+ *(.rodata1)
+ *(.rodata.str1.4)
+ *(.eh_frame)
+ }
+ .fini : { *(.fini) } =0
+ .ctors : { *(.ctors) }
+ .dtors : { *(.dtors) }
+
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x00FF) & 0xFFFFFF00;
+ _erotext = .;
+ PROVIDE (erotext = .);
+ .reloc :
+ {
+ *(.got)
+ _GOT2_TABLE_ = .;
+ *(.got2)
+ _FIXUP_TABLE_ = .;
+ *(.fixup)
+ }
+ __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >>2;
+ __fixup_entries = (. - _FIXUP_TABLE_)>>2;
+
+ .data :
+ {
+ *(.data)
+ *(.data1)
+ *(.sdata)
+ *(.sdata2)
+ *(.dynamic)
+ CONSTRUCTORS
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+
+ . = .;
+ __u_boot_cmd_start = .;
+ .u_boot_cmd : { *(.u_boot_cmd) }
+ __u_boot_cmd_end = .;
+
+ . = .;
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ . = ALIGN(256);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(256);
+ __init_end = .;
+
+ __bss_start = .;
+ .bss :
+ {
+ *(.sbss) *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ }
+ _end = . ;
+ PROVIDE (end = .);
+}
diff --git a/board/amcc/taihu/update.c b/board/amcc/taihu/update.c
new file mode 100644
index 0000000..55ad535
--- /dev/null
+++ b/board/amcc/taihu/update.c
@@ -0,0 +1,132 @@
+/*
+ * 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 <config.h>
+#include <common.h>
+#include <command.h>
+#include <asm/processor.h>
+#include <i2c.h>
+
+#define PCI_M66EN 0x10
+
+static uchar buf_33[] =
+{
+ 0xb5, /* 0x00:hce =1, bss = 0, pae=1, ppdv= 0b10,spe = 1,ebw=0b01*/
+ 0x80, /* 0x01~0x03:ptm1ms =0x80000001 */
+ 0x00,
+ 0x00,
+ 0x00, /* 0x04~0x06:ptm1la = 0x00000000 */
+ 0x00,
+ 0x00,
+ 0x00, /* 0x07~0x09:ptm2ma = 0x00000000 */
+ 0x00,
+ 0x00,
+ 0x00, /* 0x0a~0x0c:ptm2la = 0x00000000 */
+ 0x00,
+ 0x00,
+ 0x10, /* 0x0d~0x0e:vendor id 0x1014*/
+ 0x14,
+ 0x00, /* 0x0f~0x10:device id 0x0000*/
+ 0x00,
+ 0x00, /* 0x11:revision 0x00 */
+ 0x00, /* 0x12~0x14:class 0x000000 */
+ 0x00,
+ 0x00,
+ 0x10, /* 0x15~0x16:subsystem vendor id */
+ 0xe8,
+ 0x00, /* 0x17~0x18:subsystem device id */
+ 0x00,
+ 0x61, /* 0x19: opdv=0b01,cbdv=0b10,ccdv=0b00,ptm2ms_ena=0, ptm1ms_ena=1 */
+ 0x68, /* 0x1a: rpci=1,fbmul=0b1010,epdv=0b00 */
+ 0x2d, /* 0x1b: fwdvb=0b101,fwdva=0b101 */
+ 0x82, /* 0x1c: pllr=1,sscs=0,mpdv=0b00,tun[22-23]=0b10 */
+ 0xbe, /* 0x1d: tun[24-31]=0xbe */
+ 0x00,
+ 0x00
+};
+
+static uchar buf_66[] =
+{
+ 0xb5, /* 0x00:hce =1, bss = 0, pae=1, ppdv= 0b10,spe = 1,ebw=0b01*/
+ 0x80, /* 0x01~0x03:ptm1ms =0x80000001 */
+ 0x00,
+ 0x00,
+ 0x00, /* 0x04~0x06:ptm1la = 0x00000000 */
+ 0x00,
+ 0x00,
+ 0x00, /* 0x07~0x09:ptm2ma = 0x00000000 */
+ 0x00,
+ 0x00,
+ 0x00, /* 0x0a~0x0c:ptm2la = 0x00000000 */
+ 0x00,
+ 0x00,
+ 0x10, /* 0x0d~0x0e:vendor id 0x1014*/
+ 0x14,
+ 0x00, /* 0x0f~0x10:device id 0x0000*/
+ 0x00,
+ 0x00, /* 0x11:revision 0x00 */
+ 0x00, /* 0x12~0x14:class 0x000000 */
+ 0x00,
+ 0x00,
+ 0x10, /* 0x15~0x16:subsystem vendor id */
+ 0xe8,
+ 0x00, /* 0x17~0x18:subsystem device id */
+ 0x00,
+ 0x61, /* 0x19: opdv=0b01,cbdv=0b10,ccdv=0b00,ptm2ms_ena=0, ptm1ms_ena=1 */
+ 0x68, /* 0x1a: rpci=1,fbmul=0b1010,epdv=0b00 */
+ 0x2d, /* 0x1b: fwdvb=0b101,fwdva=0b101 */
+ 0x82, /* 0x1c: pllr=1,sscs=0,mpdv=0b00,tun[22-23]=0b10 */
+ 0xbe, /* 0x1d: tun[24-31]=0xbe */
+ 0x00,
+ 0x00
+};
+
+static int update_boot_eeprom(cmd_tbl_t* cmdtp, int flag, int argc, char *argv[])
+{
+ ulong len = 0x20;
+ uchar chip = CFG_I2C_EEPROM_ADDR;
+ uchar *pbuf;
+ uchar base;
+ int i;
+
+ if ((*(volatile char*)CPLD_REG0_ADDR & PCI_M66EN) != PCI_M66EN) {
+ pbuf = buf_33;
+ base = 0x00;
+ } else {
+ pbuf = buf_66;
+ base = 0x40;
+ }
+
+ for (i = 0; i< len; i++, base++) {
+ if (i2c_write(chip, base, 1, &pbuf[i],1)!= 0) {
+ printf("i2c_write fail\n");
+ return 1;
+ }
+ udelay(11000);
+ }
+
+ return 0;
+}
+
+U_BOOT_CMD (
+ update_boot_eeprom, 1, 1, update_boot_eeprom,
+ "update_boot_eeprom - update boot eeprom content\n",
+ NULL
+ );