ppc4xx: Add Io64 board support

Board support for the Guntermann & Drunck Io64.

Signed-off-by: Dirk Eibach <eibach@gdsys.de>
Signed-off-by: Stefan Roese <sr@denx.de>
diff --git a/board/gdsys/405ex/405ex.c b/board/gdsys/405ex/405ex.c
new file mode 100644
index 0000000..0d25214
--- /dev/null
+++ b/board/gdsys/405ex/405ex.c
@@ -0,0 +1,250 @@
+#include <common.h>
+#include <asm/ppc4xx.h>
+#include <asm/ppc405.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+
+#include <gdsys_fpga.h>
+
+#include "405ex.h"
+
+#define REFLECTION_TESTPATTERN 0xdede
+#define REFLECTION_TESTPATTERN_INV (~REFLECTION_TESTPATTERN & 0xffff)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int get_fpga_state(unsigned dev)
+{
+	return gd->fpga_state[dev];
+}
+
+void print_fpga_state(unsigned dev)
+{
+	if (gd->fpga_state[dev] & FPGA_STATE_DONE_FAILED)
+		puts("       Waiting for FPGA-DONE timed out.\n");
+	if (gd->fpga_state[dev] & FPGA_STATE_REFLECTION_FAILED)
+		puts("       FPGA reflection test failed.\n");
+}
+
+int board_early_init_f(void)
+{
+	u32 val;
+
+	/*--------------------------------------------------------------------+
+	 | Interrupt controller setup
+	 +--------------------------------------------------------------------+
+	+---------------------------------------------------------------------+
+	|Interrupt| Source                            | Pol.  | Sensi.| Crit. |
+	+---------+-----------------------------------+-------+-------+-------+
+	| IRQ 00  | UART0                             | High  | Level | Non   |
+	| IRQ 01  | UART1                             | High  | Level | Non   |
+	| IRQ 02  | IIC0                              | High  | Level | Non   |
+	| IRQ 03  | TBD                               | High  | Level | Non   |
+	| IRQ 04  | TBD                               | High  | Level | Non   |
+	| IRQ 05  | EBM                               | High  | Level | Non   |
+	| IRQ 06  | BGI                               | High  | Level | Non   |
+	| IRQ 07  | IIC1                              | Rising| Edge  | Non   |
+	| IRQ 08  | SPI                               | High  | Lvl/ed| Non   |
+	| IRQ 09  | External IRQ 0 - (PCI-Express)    | pgm H | Pgm   | Non   |
+	| IRQ 10  | MAL TX EOB                        | High  | Level | Non   |
+	| IRQ 11  | MAL RX EOB                        | High  | Level | Non   |
+	| IRQ 12  | DMA Channel 0 FIFO Full           | High  | Level | Non   |
+	| IRQ 13  | DMA Channel 0 Stat FIFO           | High  | Level | Non   |
+	| IRQ 14  | DMA Channel 1 FIFO Full           | High  | Level | Non   |
+	| IRQ 15  | DMA Channel 1 Stat FIFO           | High  | Level | Non   |
+	| IRQ 16  | PCIE0 AL                          | high  | Level | Non   |
+	| IRQ 17  | PCIE0 VPD access                  | rising| Edge  | Non   |
+	| IRQ 18  | PCIE0 hot reset request           | rising| Edge  | Non   |
+	| IRQ 19  | PCIE0 hot reset request           | faling| Edge  | Non   |
+	| IRQ 20  | PCIE0 TCR                         | High  | Level | Non   |
+	| IRQ 21  | PCIE0 MSI level0                  | High  | Level | Non   |
+	| IRQ 22  | PCIE0 MSI level1                  | High  | Level | Non   |
+	| IRQ 23  | Security EIP-94                   | High  | Level | Non   |
+	| IRQ 24  | EMAC0 interrupt                   | High  | Level | Non   |
+	| IRQ 25  | EMAC1 interrupt                   | High  | Level | Non   |
+	| IRQ 26  | PCIE0 MSI level2                  | High  | Level | Non   |
+	| IRQ 27  | External IRQ 4                    | pgm H | Pgm   | Non   |
+	| IRQ 28  | UIC2 Non-critical Int.            | High  | Level | Non   |
+	| IRQ 29  | UIC2 Critical Interrupt           | High  | Level | Crit. |
+	| IRQ 30  | UIC1 Non-critical Int.            | High  | Level | Non   |
+	| IRQ 31  | UIC1 Critical Interrupt           | High  | Level | Crit. |
+	|----------------------------------------------------------------------
+	| IRQ 32  | MAL Serr                          | High  | Level | Non   |
+	| IRQ 33  | MAL Txde                          | High  | Level | Non   |
+	| IRQ 34  | MAL Rxde                          | High  | Level | Non   |
+	| IRQ 35  | PCIE0 bus master VC0              |falling| Edge  | Non   |
+	| IRQ 36  | PCIE0 DCR Error                   | High  | Level | Non   |
+	| IRQ 37  | EBC                               | High  |Lvl Edg| Non   |
+	| IRQ 38  | NDFC                              | High  | Level | Non   |
+	| IRQ 39  | GPT Compare Timer 8               | Risin | Edge  | Non   |
+	| IRQ 40  | GPT Compare Timer 9               | Risin | Edge  | Non   |
+	| IRQ 41  | PCIE1 AL                          | high  | Level | Non   |
+	| IRQ 42  | PCIE1 VPD access                  | rising| edge  | Non   |
+	| IRQ 43  | PCIE1 hot reset request           | rising| Edge  | Non   |
+	| IRQ 44  | PCIE1 hot reset request           | faling| Edge  | Non   |
+	| IRQ 45  | PCIE1 TCR                         | High  | Level | Non   |
+	| IRQ 46  | PCIE1 bus master VC0              |falling| Edge  | Non   |
+	| IRQ 47  | GPT Compare Timer 3               | Risin | Edge  | Non   |
+	| IRQ 48  | GPT Compare Timer 4               | Risin | Edge  | Non   |
+	| IRQ 49  | Ext. IRQ 7                        |pgm/Fal|pgm/Lvl| Non   |
+	| IRQ 50  | Ext. IRQ 8 -                      |pgm (H)|pgm/Lvl| Non   |
+	| IRQ 51  | Ext. IRQ 9                        |pgm (H)|pgm/Lvl| Non   |
+	| IRQ 52  | GPT Compare Timer 5               | high  | Edge  | Non   |
+	| IRQ 53  | GPT Compare Timer 6               | high  | Edge  | Non   |
+	| IRQ 54  | GPT Compare Timer 7               | high  | Edge  | Non   |
+	| IRQ 55  | Serial ROM                        | High  | Level | Non   |
+	| IRQ 56  | GPT Decrement Pulse               | High  | Level | Non   |
+	| IRQ 57  | Ext. IRQ 2                        |pgm/Fal|pgm/Lvl| Non   |
+	| IRQ 58  | Ext. IRQ 5                        |pgm/Fal|pgm/Lvl| Non   |
+	| IRQ 59  | Ext. IRQ 6                        |pgm/Fal|pgm/Lvl| Non   |
+	| IRQ 60  | EMAC0 Wake-up                     | High  | Level | Non   |
+	| IRQ 61  | Ext. IRQ 1                        |pgm/Fal|pgm/Lvl| Non   |
+	| IRQ 62  | EMAC1 Wake-up                     | High  | Level | Non   |
+	|----------------------------------------------------------------------
+	| IRQ 64  | PE0 AL                            | High  | Level | Non   |
+	| IRQ 65  | PE0 VPD Access                    | Risin | Edge  | Non   |
+	| IRQ 66  | PE0 Hot Reset Request             | Risin | Edge  | Non   |
+	| IRQ 67  | PE0 Hot Reset Request             | Falli | Edge  | Non   |
+	| IRQ 68  | PE0 TCR                           | High  | Level | Non   |
+	| IRQ 69  | PE0 BusMaster VCO                 | Falli | Edge  | Non   |
+	| IRQ 70  | PE0 DCR Error                     | High  | Level | Non   |
+	| IRQ 71  | Reserved                          | N/A   | N/A   | Non   |
+	| IRQ 72  | PE1 AL                            | High  | Level | Non   |
+	| IRQ 73  | PE1 VPD Access                    | Risin | Edge  | Non   |
+	| IRQ 74  | PE1 Hot Reset Request             | Risin | Edge  | Non   |
+	| IRQ 75  | PE1 Hot Reset Request             | Falli | Edge  | Non   |
+	| IRQ 76  | PE1 TCR                           | High  | Level | Non   |
+	| IRQ 77  | PE1 BusMaster VCO                 | Falli | Edge  | Non   |
+	| IRQ 78  | PE1 DCR Error                     | High  | Level | Non   |
+	| IRQ 79  | Reserved                          | N/A   | N/A   | Non   |
+	| IRQ 80  | PE2 AL                            | High  | Level | Non   |
+	| IRQ 81  | PE2 VPD Access                    | Risin | Edge  | Non   |
+	| IRQ 82  | PE2 Hot Reset Request             | Risin | Edge  | Non   |
+	| IRQ 83  | PE2 Hot Reset Request             | Falli | Edge  | Non   |
+	| IRQ 84  | PE2 TCR                           | High  | Level | Non   |
+	| IRQ 85  | PE2 BusMaster VCO                 | Falli | Edge  | Non   |
+	| IRQ 86  | PE2 DCR Error                     | High  | Level | Non   |
+	| IRQ 87  | Reserved                          | N/A   | N/A   | Non   |
+	| IRQ 88  | External IRQ(5)                   | Progr | Progr | Non   |
+	| IRQ 89  | External IRQ 4 - Ethernet         | Progr | Progr | Non   |
+	| IRQ 90  | External IRQ 3 - PCI-X            | Progr | Progr | Non   |
+	| IRQ 91  | External IRQ 2 - PCI-X            | Progr | Progr | Non   |
+	| IRQ 92  | External IRQ 1 - PCI-X            | Progr | Progr | Non   |
+	| IRQ 93  | External IRQ 0 - PCI-X            | Progr | Progr | Non   |
+	| IRQ 94  | Reserved                          | N/A   | N/A   | Non   |
+	| IRQ 95  | Reserved                          | N/A   | N/A   | Non   |
+	|---------------------------------------------------------------------
+	+---------+-----------------------------------+-------+-------+------*/
+	/*--------------------------------------------------------------------+
+	 | Initialise UIC registers.  Clear all interrupts.  Disable all
+	 | interrupts.
+	 | Set critical interrupt values.  Set interrupt polarities.  Set
+	 | interrupt trigger levels.  Make bit 0 High  priority.  Clear all
+	 | interrupts again.
+	 +-------------------------------------------------------------------*/
+
+	mtdcr(UIC2SR, 0xffffffff); /* Clear all interrupts */
+	mtdcr(UIC2ER, 0x00000000); /* disable all interrupts */
+	mtdcr(UIC2CR, 0x00000000); /* Set Critical / Non Critical interrupts */
+	mtdcr(UIC2PR, 0xf7ffffff); /* Set Interrupt Polarities */
+	mtdcr(UIC2TR, 0x01e1fff8); /* Set Interrupt Trigger Levels */
+	mtdcr(UIC2VR, 0x00000001); /* Set Vect base=0,INT31 Highest priority */
+	mtdcr(UIC2SR, 0x00000000); /* clear all interrupts */
+	mtdcr(UIC2SR, 0xffffffff); /* clear all interrupts */
+
+	mtdcr(UIC1SR, 0xffffffff); /* Clear all interrupts */
+	mtdcr(UIC1ER, 0x00000000); /* disable all interrupts */
+	mtdcr(UIC1CR, 0x00000000); /* Set Critical / Non Critical interrupts */
+	mtdcr(UIC1PR, 0xfffac785); /* Set Interrupt Polarities */
+	mtdcr(UIC1TR, 0x001d0040); /* Set Interrupt Trigger Levels */
+	mtdcr(UIC1VR, 0x00000001); /* Set Vect base=0,INT31 Highest priority */
+	mtdcr(UIC1SR, 0x00000000); /* clear all interrupts */
+	mtdcr(UIC1SR, 0xffffffff); /* clear all interrupts */
+
+	mtdcr(UIC0SR, 0xffffffff); /* Clear all interrupts */
+	mtdcr(UIC0ER, 0x0000000a); /* Disable all interrupts */
+				   /* Except cascade UIC0 and UIC1 */
+	mtdcr(UIC0CR, 0x00000000); /* Set Critical / Non Critical interrupts */
+	mtdcr(UIC0PR, 0xffbfefef); /* Set Interrupt Polarities */
+	mtdcr(UIC0TR, 0x00007000); /* Set Interrupt Trigger Levels */
+	mtdcr(UIC0VR, 0x00000001); /* Set Vect base=0,INT31 Highest priority */
+	mtdcr(UIC0SR, 0x00000000); /* clear all interrupts */
+	mtdcr(UIC0SR, 0xffffffff); /* clear all interrupts */
+
+	/*
+	 * Note: Some cores are still in reset when the chip starts, so
+	 * take them out of reset
+	 */
+	mtsdr(SDR0_SRST, 0);
+
+	/*
+	 * Configure PFC (Pin Function Control) registers
+	 */
+	val = SDR0_PFC1_GPT_FREQ;
+	mtsdr(SDR0_PFC1, val);
+
+	return 0;
+}
+
+int board_early_init_r(void)
+{
+	unsigned k;
+	unsigned ctr;
+
+	for (k = 0; k < CONFIG_SYS_FPGA_COUNT; ++k)
+		gd->fpga_state[k] = 0;
+
+	/*
+	 * reset FPGA
+	 */
+	gd405ex_init();
+
+	gd405ex_set_fpga_reset(1);
+
+	gd405ex_setup_hw();
+
+	for (k = 0; k < CONFIG_SYS_FPGA_COUNT; ++k) {
+		ctr = 0;
+		while (!gd405ex_get_fpga_done(k)) {
+			udelay(100000);
+			if (ctr++ > 5) {
+				gd->fpga_state[k] |= FPGA_STATE_DONE_FAILED;
+				break;
+			}
+		}
+	}
+
+	udelay(10);
+
+	gd405ex_set_fpga_reset(0);
+
+	for (k = 0; k < CONFIG_SYS_FPGA_COUNT; ++k) {
+		ihs_fpga_t *fpga = (ihs_fpga_t *) CONFIG_SYS_FPGA_BASE(k);
+#ifdef CONFIG_SYS_FPGA_NO_RFL_HI
+		u16 *reflection_target = &fpga->reflection_low;
+#else
+		u16 *reflection_target = &fpga->reflection_high;
+#endif
+		/*
+		 * wait for fpga out of reset
+		 */
+		ctr = 0;
+		while (1) {
+			out_le16(&fpga->reflection_low,
+				REFLECTION_TESTPATTERN);
+
+			if (in_le16(reflection_target) ==
+				REFLECTION_TESTPATTERN_INV)
+				break;
+
+			udelay(100000);
+			if (ctr++ > 5) {
+				gd->fpga_state[k] |=
+					FPGA_STATE_REFLECTION_FAILED;
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
diff --git a/board/gdsys/405ex/405ex.h b/board/gdsys/405ex/405ex.h
new file mode 100644
index 0000000..b15623f
--- /dev/null
+++ b/board/gdsys/405ex/405ex.h
@@ -0,0 +1,10 @@
+#ifndef __405EX_H_
+#define __405EX_H_
+
+/* functions to be provided by board implementation */
+void gd405ex_init(void);
+void gd405ex_set_fpga_reset(unsigned state);
+void gd405ex_setup_hw(void);
+int gd405ex_get_fpga_done(unsigned fpga);
+
+#endif /* __405EX_H_ */
diff --git a/board/gdsys/405ex/Makefile b/board/gdsys/405ex/Makefile
new file mode 100644
index 0000000..4549705
--- /dev/null
+++ b/board/gdsys/405ex/Makefile
@@ -0,0 +1,53 @@
+#
+# (C) Copyright 2007
+# Stefan Roese, DENX Software Engineering, sr@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).o
+
+COBJS-$(CONFIG_IO64) += io64.o
+
+COBJS-$(CONFIG_CMD_CHIP_CONFIG) += chip_config.o
+
+COBJS   := $(BOARD).o $(COBJS-y)
+
+SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
+
+$(LIB):	$(obj).depend $(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+clean:
+	rm -f $(OBJS)
+
+distclean:	clean
+	rm -f $(LIB) core *.bak $(obj).depend
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/gdsys/405ex/chip_config.c b/board/gdsys/405ex/chip_config.c
new file mode 100644
index 0000000..12cb3bf
--- /dev/null
+++ b/board/gdsys/405ex/chip_config.c
@@ -0,0 +1,96 @@
+/*
+ * (C) Copyright 2009
+ * Stefan Roese, DENX Software Engineering, sr@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 <asm/ppc4xx_config.h>
+
+/* NAND booting versions differ in bytes: 6, 8, 9, 11, 12 */
+
+struct ppc4xx_config ppc4xx_config_val[] = {
+	{
+		"333-nor", "NOR  CPU: 333 PLB: 166 OPB:  83 EBC:  83",
+		{
+			0x8c, 0x12, 0xec, 0x12, 0x98, 0x00, 0x0a, 0x00,
+			0x40, 0x08, 0x23, 0x50, 0x00, 0x05, 0x00, 0x00
+		}
+	},
+	{
+		"400-133-nor", "NOR  CPU: 400 PLB: 133 OPB:  66 EBC:  66",
+		{
+			0x8e, 0x0e, 0xe8, 0x13, 0x98, 0x00, 0x0a, 0x00,
+			0x40, 0x08, 0x23, 0x50, 0x00, 0x05, 0x00, 0x00
+		}
+	},
+	{
+		"400-200-66-nor", "NOR  CPU: 400 PLB: 200 OPB:  66 EBC:  66",
+		{
+			0x8e, 0x0e, 0xe8, 0x12, 0xd8, 0x00, 0x0a, 0x00,
+			0x40, 0x08, 0x23, 0x50, 0x00, 0x05, 0x00, 0x00
+		}
+	},
+	{
+		"400-nor", "NOR  CPU: 400 PLB: 200 OPB: 100 EBC: 100",
+		{
+			0x8e, 0x0e, 0xe8, 0x12, 0x98, 0x00, 0x0a, 0x00,
+			0x40, 0x08, 0x23, 0x50, 0x00, 0x05, 0x00, 0x00
+		}
+	},
+	{
+		"533-nor", "NOR  CPU: 533 PLB: 177 OPB:  88 EBC:  88",
+		{
+			0x8e, 0x43, 0x60, 0x13, 0x98, 0x00, 0x0a, 0x00,
+			0x40, 0x08, 0x23, 0x50, 0x00, 0x05, 0x00, 0x00
+		}
+	},
+	{
+		"533-nand", "NOR  CPU: 533 PLB: 177 OPB:  88 EBC:  88",
+		{
+			0x8e, 0x43, 0x60, 0x13, 0x98, 0x00, 0x0f, 0x00,
+			0xa0, 0x68, 0x23, 0x58, 0x0d, 0x05, 0x00, 0x00
+		}
+	},
+	{
+		"600-nor", "NOR  CPU: 600 PLB: 200 OPB: 100 EBC: 100",
+		{
+			0x8d, 0x02, 0x34, 0x13, 0x98, 0x00, 0x0a, 0x00,
+			0x40, 0x08, 0x23, 0x50, 0x00, 0x05, 0x00, 0x00
+		}
+	},
+	{
+		"600-nand", "NOR  CPU: 600 PLB: 200 OPB: 100 EBC: 100",
+		{
+			0x8d, 0x02, 0x34, 0x13, 0x98, 0x00, 0x0f, 0x00,
+			0xa0, 0x68, 0x23, 0x58, 0x0d, 0x05, 0x00, 0x00
+		}
+	},
+	{
+		"666-nor", "NOR  CPU: 666 PLB: 222 OPB: 111 EBC: 111",
+		{
+			0x8d, 0x03, 0x78, 0x13, 0x98, 0x00, 0x0a, 0x00,
+			0x40, 0x08, 0x23, 0x50, 0x00, 0x05, 0x00, 0x00
+		}
+	},
+};
+
+int ppc4xx_config_count = ARRAY_SIZE(ppc4xx_config_val);
diff --git a/board/gdsys/405ex/io64.c b/board/gdsys/405ex/io64.c
new file mode 100644
index 0000000..a997571
--- /dev/null
+++ b/board/gdsys/405ex/io64.c
@@ -0,0 +1,384 @@
+/*
+ * (C) Copyright 2010
+ * Dirk Eibach,  Guntermann & Drunck GmbH, eibach@gdsys.de
+ *
+ * based on kilauea.c
+ * by Stefan Roese, DENX Software Engineering, sr@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 <asm/ppc4xx.h>
+#include <asm/ppc405.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/ppc4xx-gpio.h>
+#include <flash.h>
+
+#include <pca9698.h>
+
+#include "405ex.h"
+#include <gdsys_fpga.h>
+
+#include <miiphy.h>
+#include <i2c.h>
+#include <dtt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define PHYREG_CONTROL				0
+#define PHYREG_PAGE_ADDRESS			22
+#define PHYREG_PG0_COPPER_SPECIFIC_CONTROL_1	16
+#define PHYREG_PG2_COPPER_SPECIFIC_CONTROL_2	26
+#define PHYREG_PG2_MAC_SPECIFIC_STATUS_1	17
+#define PHYREG_PG2_MAC_SPECIFIC_CONTROL		21
+
+#define LATCH0_BASE (CONFIG_SYS_LATCH_BASE)
+#define LATCH1_BASE (CONFIG_SYS_LATCH_BASE + 0x100)
+#define LATCH2_BASE (CONFIG_SYS_LATCH_BASE + 0x200)
+#define LATCH3_BASE (CONFIG_SYS_LATCH_BASE + 0x300)
+
+enum {
+	UNITTYPE_CCD_SWITCH = 1,
+};
+
+enum {
+	HWVER_100 = 0,
+	HWVER_110 = 1,
+};
+
+static inline void blank_string(int size)
+{
+	int i;
+
+	for (i = 0; i < size; i++)
+		putc('\b');
+	for (i = 0; i < size; i++)
+		putc(' ');
+	for (i = 0; i < size; i++)
+		putc('\b');
+}
+
+/*
+ * Board early initialization function
+ */
+int misc_init_r(void)
+{
+	/* startup fans */
+	dtt_init();
+
+#ifdef CONFIG_ENV_IS_IN_FLASH
+	/* Monitor protection ON by default */
+	flash_protect(FLAG_PROTECT_SET,
+		      -CONFIG_SYS_MONITOR_LEN,
+		      0xffffffff,
+		      &flash_info[0]);
+#endif
+
+	return 0;
+}
+
+static void print_fpga_info(unsigned dev)
+{
+	ihs_fpga_t *fpga = (ihs_fpga_t *) CONFIG_SYS_FPGA_BASE(dev);
+	u16 versions = in_le16(&fpga->versions);
+	u16 fpga_version = in_le16(&fpga->fpga_version);
+	u16 fpga_features = in_le16(&fpga->fpga_features);
+	int fpga_state = get_fpga_state(dev);
+
+	unsigned unit_type;
+	unsigned hardware_version;
+	unsigned feature_channels;
+	unsigned feature_expansion;
+
+	printf("FPGA%d: ", dev);
+	if (fpga_state & FPGA_STATE_PLATFORM)
+		printf("(legacy) ");
+
+	if (fpga_state & FPGA_STATE_DONE_FAILED) {
+		printf(" done timed out\n");
+		return;
+	}
+
+	if (fpga_state & FPGA_STATE_REFLECTION_FAILED) {
+		printf(" refelectione test failed\n");
+		return;
+	}
+
+	unit_type = (versions & 0xf000) >> 12;
+	hardware_version = versions & 0x000f;
+	feature_channels = fpga_features & 0x007f;
+	feature_expansion = fpga_features & (1<<15);
+
+	switch (unit_type) {
+	case UNITTYPE_CCD_SWITCH:
+		printf("CCD-Switch");
+		break;
+
+	default:
+		printf("UnitType %d(not supported)", unit_type);
+		break;
+	}
+
+	switch (hardware_version) {
+	case HWVER_100:
+		printf(" HW-Ver 1.00\n");
+		break;
+
+	case HWVER_110:
+		printf(" HW-Ver 1.10\n");
+		break;
+
+	default:
+		printf(" HW-Ver %d(not supported)\n",
+		       hardware_version);
+		break;
+	}
+
+	printf("       FPGA V %d.%02d, features:",
+		fpga_version / 100, fpga_version % 100);
+
+	printf(" %d channel(s)", feature_channels);
+
+	printf(", expansion %ssupported\n", feature_expansion ? "" : "un");
+}
+
+int checkboard(void)
+{
+	char *s = getenv("serial#");
+
+	printf("Board: CATCenter Io64\n");
+
+	if (s != NULL) {
+		puts(", serial# ");
+		puts(s);
+	}
+
+	return 0;
+}
+
+int configure_gbit_phy(char *bus, unsigned char addr)
+{
+	unsigned short value;
+
+	/* select page 0 */
+	if (miiphy_write(bus, addr, PHYREG_PAGE_ADDRESS, 0x0000))
+		goto err_out;
+	/* switch to powerdown */
+	if (miiphy_read(bus, addr, PHYREG_PG0_COPPER_SPECIFIC_CONTROL_1,
+		&value))
+		goto err_out;
+	if (miiphy_write(bus, addr, PHYREG_PG0_COPPER_SPECIFIC_CONTROL_1,
+		value | 0x0004))
+		goto err_out;
+	/* select page 2 */
+	if (miiphy_write(bus, addr, PHYREG_PAGE_ADDRESS, 0x0002))
+		goto err_out;
+	/* disable SGMII autonegotiation */
+	if (miiphy_write(bus, addr, PHYREG_PG2_MAC_SPECIFIC_CONTROL, 48))
+		goto err_out;
+	/* select page 0 */
+	if (miiphy_write(bus, addr, PHYREG_PAGE_ADDRESS, 0x0000))
+		goto err_out;
+	/* switch from powerdown to normal operation */
+	if (miiphy_read(bus, addr, PHYREG_PG0_COPPER_SPECIFIC_CONTROL_1,
+		&value))
+		goto err_out;
+	if (miiphy_write(bus, addr, PHYREG_PG0_COPPER_SPECIFIC_CONTROL_1,
+		value & ~0x0004))
+		goto err_out;
+	/* reset phy so settings take effect */
+	if (miiphy_write(bus, addr, PHYREG_CONTROL, 0x9140))
+		goto err_out;
+
+	return 0;
+
+err_out:
+	printf("Error writing to the PHY addr=%02x\n", addr);
+	return -1;
+}
+
+int verify_gbit_phy(char *bus, unsigned char addr)
+{
+	unsigned short value;
+
+	/* select page 2 */
+	if (miiphy_write(bus, addr, PHYREG_PAGE_ADDRESS, 0x0002))
+		goto err_out;
+	/* verify SGMII link status */
+	if (miiphy_read(bus, addr, PHYREG_PG2_MAC_SPECIFIC_STATUS_1, &value))
+		goto err_out;
+	if (!(value & (1 << 10)))
+		return -2;
+
+	return 0;
+
+err_out:
+	printf("Error writing to the PHY addr=%02x\n", addr);
+	return -1;
+}
+
+int last_stage_init(void)
+{
+	unsigned int k;
+	unsigned int fpga;
+	ihs_fpga_t *fpga0 = (ihs_fpga_t *) CONFIG_SYS_FPGA_BASE(0);
+	ihs_fpga_t *fpga1 = (ihs_fpga_t *) CONFIG_SYS_FPGA_BASE(1);
+	int failed = 0;
+	char str_phys[] = "Setup PHYs -";
+	char str_serdes[] = "Start SERDES blocks";
+	char str_channels[] = "Start FPGA channels";
+	char str_locks[] = "Verify SERDES locks";
+	char str_status[] = "Verify PHY status -";
+	char slash[] = "\\|/-\\|/-";
+
+	print_fpga_info(0);
+	print_fpga_info(1);
+
+	/* setup Gbit PHYs */
+	puts("TRANS: ");
+	puts(str_phys);
+	miiphy_register(CONFIG_SYS_GBIT_MII_BUSNAME,
+		bb_miiphy_read, bb_miiphy_write);
+
+	for (k = 0; k < 32; ++k) {
+		configure_gbit_phy(CONFIG_SYS_GBIT_MII_BUSNAME, k);
+		putc('\b');
+		putc(slash[k % 8]);
+	}
+
+	miiphy_register(CONFIG_SYS_GBIT_MII1_BUSNAME,
+		bb_miiphy_read, bb_miiphy_write);
+
+	for (k = 0; k < 32; ++k) {
+		configure_gbit_phy(CONFIG_SYS_GBIT_MII1_BUSNAME, k);
+		putc('\b');
+		putc(slash[k % 8]);
+	}
+	blank_string(strlen(str_phys));
+
+	/* take fpga serdes blocks out of reset */
+	puts(str_serdes);
+	udelay(500000);
+	out_le16(&fpga0->quad_serdes_reset, 0);
+	out_le16(&fpga1->quad_serdes_reset, 0);
+	blank_string(strlen(str_serdes));
+
+	/* take channels out of reset */
+	puts(str_channels);
+	udelay(500000);
+	for (fpga = 0; fpga < 2; ++fpga) {
+		u16 *ch0_config_int = &(fpga ? fpga1 : fpga0)->ch0_config_int;
+		for (k = 0; k < 32; ++k)
+			out_le16(ch0_config_int + 4 * k, 0);
+	}
+	blank_string(strlen(str_channels));
+
+	/* verify channels serdes lock */
+	puts(str_locks);
+	udelay(500000);
+	for (fpga = 0; fpga < 2; ++fpga) {
+		u16 *ch0_status_int = &(fpga ? fpga1 : fpga0)->ch0_status_int;
+		for (k = 0; k < 32; ++k) {
+			u16 status = in_le16(ch0_status_int + 4*k);
+			if (!(status & (1 << 4))) {
+				failed = 1;
+				printf("fpga %d channel %d: no serdes lock\n",
+					fpga, k);
+			}
+			/* reset events */
+			out_le16(ch0_status_int + 4*k, status);
+		}
+	}
+	blank_string(strlen(str_locks));
+
+	/* verify phy status */
+	puts(str_status);
+	for (k = 0; k < 32; ++k) {
+		if (verify_gbit_phy(CONFIG_SYS_GBIT_MII_BUSNAME, k)) {
+			printf("verify baseboard phy %d failed\n", k);
+			failed = 1;
+		}
+		putc('\b');
+		putc(slash[k % 8]);
+	}
+	for (k = 0; k < 32; ++k) {
+		if (verify_gbit_phy(CONFIG_SYS_GBIT_MII1_BUSNAME, k)) {
+			printf("verify extensionboard phy %d failed\n", k);
+			failed = 1;
+		}
+		putc('\b');
+		putc(slash[k % 8]);
+	}
+	blank_string(strlen(str_status));
+
+	printf("Starting 64 channels %s\n", failed ? "failed" : "ok");
+
+	return 0;
+}
+
+void gd405ex_init(void)
+{
+	unsigned int k;
+
+	if (i2c_probe(0x22)) { /* i2c_probe returns 0 on success */
+		for (k = 0; k < CONFIG_SYS_FPGA_COUNT; ++k)
+			gd->fpga_state[k] |= FPGA_STATE_PLATFORM;
+	} else {
+		pca9698_direction_output(0x22, 39, 1);
+	}
+}
+
+void gd405ex_set_fpga_reset(unsigned state)
+{
+	int legacy = get_fpga_state(0) & FPGA_STATE_PLATFORM;
+
+	if (legacy) {
+		if (state) {
+			out_le16((void *)LATCH0_BASE, CONFIG_SYS_LATCH0_RESET);
+			out_le16((void *)LATCH1_BASE, CONFIG_SYS_LATCH1_RESET);
+		} else {
+			out_le16((void *)LATCH0_BASE, CONFIG_SYS_LATCH0_BOOT);
+			out_le16((void *)LATCH1_BASE, CONFIG_SYS_LATCH1_BOOT);
+		}
+	} else {
+		pca9698_set_value(0x22, 39, state ? 0 : 1);
+	}
+}
+
+void gd405ex_setup_hw(void)
+{
+	gpio_write_bit(CONFIG_SYS_GPIO_STARTUP_FINISHED_N, 0);
+	gpio_write_bit(CONFIG_SYS_GPIO_STARTUP_FINISHED, 1);
+}
+
+int gd405ex_get_fpga_done(unsigned fpga)
+{
+	int legacy = get_fpga_state(0) & FPGA_STATE_PLATFORM;
+
+	if (legacy)
+		return in_le16((void *)LATCH3_BASE)
+			& CONFIG_SYS_FPGA_DONE(fpga);
+	else
+		return pca9698_get_value(0x22, fpga ? 9 : 8);
+}
diff --git a/board/gdsys/common/Makefile b/board/gdsys/common/Makefile
index 2868cc8..05dd65d 100644
--- a/board/gdsys/common/Makefile
+++ b/board/gdsys/common/Makefile
@@ -30,6 +30,7 @@
 LIB	= $(obj)lib$(VENDOR).o
 
 COBJS-$(CONFIG_IO) += miiphybb.o
+COBJS-$(CONFIG_IO64) += miiphybb.o
 COBJS-$(CONFIG_IOCON) += osd.o
 COBJS-$(CONFIG_DLVISION_10G) += osd.o
 
diff --git a/board/gdsys/common/miiphybb.c b/board/gdsys/common/miiphybb.c
index e56e966..46f1a1e 100644
--- a/board/gdsys/common/miiphybb.c
+++ b/board/gdsys/common/miiphybb.c
@@ -26,6 +26,11 @@
 
 #include <asm/io.h>
 
+struct io_bb_pinset {
+	int mdio;
+	int mdc;
+};
+
 static int io_bb_mii_init(struct bb_miiphy_bus *bus)
 {
 	return 0;
@@ -33,47 +38,57 @@
 
 static int io_bb_mdio_active(struct bb_miiphy_bus *bus)
 {
+	struct io_bb_pinset *pins = bus->priv;
+
 	out_be32((void *)GPIO0_TCR,
-		in_be32((void *)GPIO0_TCR) | CONFIG_SYS_MDIO_PIN);
+		in_be32((void *)GPIO0_TCR) | pins->mdio);
 
 	return 0;
 }
 
 static int io_bb_mdio_tristate(struct bb_miiphy_bus *bus)
 {
+	struct io_bb_pinset *pins = bus->priv;
+
 	out_be32((void *)GPIO0_TCR,
-		in_be32((void *)GPIO0_TCR) & ~CONFIG_SYS_MDIO_PIN);
+		in_be32((void *)GPIO0_TCR) & ~pins->mdio);
 
 	return 0;
 }
 
 static int io_bb_set_mdio(struct bb_miiphy_bus *bus, int v)
 {
+	struct io_bb_pinset *pins = bus->priv;
+
 	if (v)
 		out_be32((void *)GPIO0_OR,
-			in_be32((void *)GPIO0_OR) | CONFIG_SYS_MDIO_PIN);
+			in_be32((void *)GPIO0_OR) | pins->mdio);
 	else
 		out_be32((void *)GPIO0_OR,
-			in_be32((void *)GPIO0_OR) & ~CONFIG_SYS_MDIO_PIN);
+			in_be32((void *)GPIO0_OR) & ~pins->mdio);
 
 	return 0;
 }
 
 static int io_bb_get_mdio(struct bb_miiphy_bus *bus, int *v)
 {
-	*v = ((in_be32((void *)GPIO0_IR) & CONFIG_SYS_MDIO_PIN) != 0);
+	struct io_bb_pinset *pins = bus->priv;
+
+	*v = ((in_be32((void *)GPIO0_IR) & pins->mdio) != 0);
 
 	return 0;
 }
 
 static int io_bb_set_mdc(struct bb_miiphy_bus *bus, int v)
 {
+	struct io_bb_pinset *pins = bus->priv;
+
 	if (v)
 		out_be32((void *)GPIO0_OR,
-			in_be32((void *)GPIO0_OR) | CONFIG_SYS_MDC_PIN);
+			in_be32((void *)GPIO0_OR) | pins->mdc);
 	else
 		out_be32((void *)GPIO0_OR,
-			in_be32((void *)GPIO0_OR) & ~CONFIG_SYS_MDC_PIN);
+			in_be32((void *)GPIO0_OR) & ~pins->mdc);
 
 	return 0;
 }
@@ -85,6 +100,19 @@
 	return 0;
 }
 
+struct io_bb_pinset io_bb_pinsets[] = {
+	{
+		.mdio = CONFIG_SYS_MDIO_PIN,
+		.mdc = CONFIG_SYS_MDC_PIN,
+	},
+#ifdef CONFIG_SYS_GBIT_MII1_BUSNAME
+	{
+		.mdio = CONFIG_SYS_MDIO1_PIN,
+		.mdc = CONFIG_SYS_MDC1_PIN,
+	},
+#endif
+};
+
 struct bb_miiphy_bus bb_miiphy_buses[] = {
 	{
 		.name = CONFIG_SYS_GBIT_MII_BUSNAME,
@@ -95,7 +123,21 @@
 		.get_mdio = io_bb_get_mdio,
 		.set_mdc = io_bb_set_mdc,
 		.delay = io_bb_delay,
-	}
+		.priv = &io_bb_pinsets[0],
+	},
+#ifdef CONFIG_SYS_GBIT_MII1_BUSNAME
+	{
+		.name = CONFIG_SYS_GBIT_MII1_BUSNAME,
+		.init = io_bb_mii_init,
+		.mdio_active = io_bb_mdio_active,
+		.mdio_tristate = io_bb_mdio_tristate,
+		.set_mdio = io_bb_set_mdio,
+		.get_mdio = io_bb_get_mdio,
+		.set_mdc = io_bb_set_mdc,
+		.delay = io_bb_delay,
+		.priv = &io_bb_pinsets[1],
+	},
+#endif
 };
 
 int bb_miiphy_buses_num = sizeof(bb_miiphy_buses) /