Patchwork [U-Boot,v5,4/6] powerpc/ppc4xx: Support gdsys multichannel iocon hardware

login
register
mail settings
Submitter Dirk Eibach
Date June 26, 2013, 2:04 p.m.
Message ID <1372255471-9383-5-git-send-email-dirk.eibach@gdsys.cc>
Download mbox | patch
Permalink /patch/254759/
State Awaiting Upstream
Delegated to: Stefan Roese
Headers show

Comments

Dirk Eibach - June 26, 2013, 2:04 p.m.
From: Dirk Eibach <dirk.eibach@gdsys.cc>

Signed-off-by: Dirk Eibach <dirk.eibach@gdsys.cc>
---
Changes in v5: None
Changes in v4:
- Move changes ins osd.c to proper commit
- do not use common FPGA register accessors here

Changes in v3:
- adapt to "powerpc/ppc4xx: Use generic accessor functions for gdsys FPGA"
- squashed with powerpc/ppc4xx: Fixup phy erratum on gdsys iocon hardware

Changes in v2:
- fpga_state has been moved to arch_global_data
- include cmd_fpgad in iocon
- use multibus soft-i2c in iocon

 board/gdsys/405ep/iocon.c   | 468 ++++++++++++++++++++++++++++++++++++++++----
 board/gdsys/common/Makefile |   2 +-
 board/gdsys/common/osd.c    |  20 +-
 include/configs/iocon.h     |  58 ++++--
 include/gdsys_fpga.h        |  15 +-
 5 files changed, 510 insertions(+), 53 deletions(-)

Patch

diff --git a/board/gdsys/405ep/iocon.c b/board/gdsys/405ep/iocon.c
index 249d901..fe14f36 100644
--- a/board/gdsys/405ep/iocon.c
+++ b/board/gdsys/405ep/iocon.c
@@ -23,6 +23,7 @@ 
 
 #include <common.h>
 #include <command.h>
+#include <errno.h>
 #include <asm/processor.h>
 #include <asm/io.h>
 #include <asm/ppc4xx-gpio.h>
@@ -31,6 +32,15 @@ 
 #include <gdsys_fpga.h>
 
 #include "../common/osd.h"
+#include "../common/mclink.h"
+
+#include <i2c.h>
+#include <pca953x.h>
+#include <pca9698.h>
+
+#include <miiphy.h>
+
+DECLARE_GLOBAL_DATA_PTR;
 
 #define LATCH0_BASE (CONFIG_SYS_LATCH_BASE)
 #define LATCH1_BASE (CONFIG_SYS_LATCH_BASE + 0x100)
@@ -47,11 +57,20 @@  enum {
 	HWVER_100 = 0,
 	HWVER_104 = 1,
 	HWVER_110 = 2,
+	HWVER_120 = 3,
+	HWVER_200 = 4,
+	HWVER_210 = 5,
+};
+
+enum {
+	FPGA_HWVER_200 = 0,
+	FPGA_HWVER_210 = 1,
 };
 
 enum {
 	COMPRESSION_NONE = 0,
-	COMPRESSION_TYPE1_DELTA,
+	COMPRESSION_TYPE1_DELTA = 1,
+	COMPRESSION_TYPE1_TYPE2_DELTA = 3,
 };
 
 enum {
@@ -67,10 +86,71 @@  enum {
 
 enum {
 	RAM_DDR2_32 = 0,
+	RAM_DDR3_32 = 1,
+};
+
+enum {
+	MCFPGA_DONE = 1 << 0,
+	MCFPGA_INIT_N = 1 << 1,
+	MCFPGA_PROGRAM_N = 1 << 2,
+	MCFPGA_UPDATE_ENABLE_N = 1 << 3,
+	MCFPGA_RESET_N = 1 << 4,
+};
+
+enum {
+	GPIO_MDC = 1 << 14,
+	GPIO_MDIO = 1 << 15,
 };
 
+unsigned int mclink_fpgacount;
 struct ihs_fpga *fpga_ptr[] = CONFIG_SYS_FPGA_PTR;
 
+static int setup_88e1518(const char *bus, unsigned char addr);
+static int verify_88e1518(const char *bus, unsigned char addr);
+
+int fpga_set_reg(u32 fpga, u16 *reg, off_t regoff, u16 data)
+{
+	int res;
+
+	switch (fpga) {
+	case 0:
+		out_le16(reg, data);
+		break;
+	default:
+		res = mclink_send(fpga - 1, regoff, data);
+		if (res < 0) {
+			printf("mclink_send reg %02lx data %04x returned %d\n",
+			       regoff, data, res);
+			return res;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+int fpga_get_reg(u32 fpga, u16 *reg, off_t regoff, u16 *data)
+{
+	int res;
+
+	switch (fpga) {
+	case 0:
+		*data = in_le16(reg);
+		break;
+	default:
+		if (fpga > mclink_fpgacount)
+			return -EINVAL;
+		res = mclink_receive(fpga - 1, regoff, data);
+		if (res < 0) {
+			printf("mclink_receive reg %02lx returned %d\n",
+			       regoff, res);
+			return res;
+		}
+	}
+
+	return 0;
+}
+
 /*
  * Check Board Identity:
  */
@@ -92,7 +172,7 @@  int checkboard(void)
 	return 0;
 }
 
-static void print_fpga_info(void)
+static void print_fpga_info(unsigned int fpga)
 {
 	u16 versions;
 	u16 fpga_version;
@@ -106,13 +186,13 @@  static void print_fpga_info(void)
 	unsigned feature_ramconfig;
 	unsigned feature_carriers;
 	unsigned feature_video_channels;
+	int legacy = get_fpga_state(0) & FPGA_STATE_PLATFORM;
 
 	FPGA_GET_REG(0, versions, &versions);
 	FPGA_GET_REG(0, fpga_version, &fpga_version);
 	FPGA_GET_REG(0, fpga_features, &fpga_features);
 
 	unit_type = (versions & 0xf000) >> 12;
-	hardware_version = versions & 0x000f;
 	feature_compression = (fpga_features & 0xe000) >> 13;
 	feature_osd = fpga_features & (1<<11);
 	feature_audio = (fpga_features & 0x0600) >> 9;
@@ -121,6 +201,9 @@  static void print_fpga_info(void)
 	feature_carriers = (fpga_features & 0x000c) >> 2;
 	feature_video_channels = fpga_features & 0x0003;
 
+	if (legacy)
+		printf("legacy ");
+
 	switch (unit_type) {
 	case UNITTYPE_MAIN_USER:
 		printf("Mainchannel");
@@ -135,27 +218,68 @@  static void print_fpga_info(void)
 		break;
 	}
 
-	switch (hardware_version) {
-	case HWVER_100:
-		printf(" HW-Ver 1.00\n");
-		break;
-
-	case HWVER_104:
-		printf(" HW-Ver 1.04\n");
-		break;
-
-	case HWVER_110:
-		printf(" HW-Ver 1.10\n");
-		break;
+	if (unit_type == UNITTYPE_MAIN_USER) {
+		if (legacy)
+			hardware_version =
+				(in_le16((void *)LATCH2_BASE)>>8) & 0x0f;
+		else
+			hardware_version =
+				  (!!pca9698_get_value(0x20, 24) << 0)
+				| (!!pca9698_get_value(0x20, 25) << 1)
+				| (!!pca9698_get_value(0x20, 26) << 2)
+				| (!!pca9698_get_value(0x20, 27) << 3);
+		switch (hardware_version) {
+		case HWVER_100:
+			printf(" HW-Ver 1.00,");
+			break;
+
+		case HWVER_104:
+			printf(" HW-Ver 1.04,");
+			break;
+
+		case HWVER_110:
+			printf(" HW-Ver 1.10,");
+			break;
+
+		case HWVER_120:
+			printf(" HW-Ver 1.20-1.21,");
+			break;
+
+		case HWVER_200:
+			printf(" HW-Ver 2.00,");
+			break;
+
+		case HWVER_210:
+			printf(" HW-Ver 2.10,");
+			break;
+
+		default:
+			printf(" HW-Ver %d(not supported),",
+			       hardware_version);
+			break;
+		}
+	}
 
-	default:
-		printf(" HW-Ver %d(not supported)\n",
-		       hardware_version);
-		break;
+	if (unit_type == UNITTYPE_VIDEO_USER) {
+		hardware_version = versions & 0x000f;
+		switch (hardware_version) {
+		case FPGA_HWVER_200:
+			printf(" HW-Ver 2.00,");
+			break;
+
+		case FPGA_HWVER_210:
+			printf(" HW-Ver 2.10,");
+			break;
+
+		default:
+			printf(" HW-Ver %d(not supported),",
+			       hardware_version);
+			break;
+		}
 	}
 
-	printf("       FPGA V %d.%02d, features:",
-		fpga_version / 100, fpga_version % 100);
+	printf(" FPGA V %d.%02d\n       features:",
+	       fpga_version / 100, fpga_version % 100);
 
 
 	switch (feature_compression) {
@@ -167,6 +291,10 @@  static void print_fpga_info(void)
 		printf(" type1-deltacompression");
 		break;
 
+	case COMPRESSION_TYPE1_TYPE2_DELTA:
+		printf(" type1-deltacompression, type2-inlinecompression");
+		break;
+
 	default:
 		printf(" compression %d(not supported)", feature_compression);
 		break;
@@ -213,6 +341,10 @@  static void print_fpga_info(void)
 		printf(", RAM 32 bit DDR2");
 		break;
 
+	case RAM_DDR3_32:
+		printf(", RAM 32 bit DDR3");
+		break;
+
 	default:
 		printf(", RAM %d(not supported)", feature_ramconfig);
 		break;
@@ -225,46 +357,117 @@  static void print_fpga_info(void)
 
 int last_stage_init(void)
 {
-	print_fpga_info();
+	int slaves;
+	unsigned int k;
+	unsigned char mclink_controllers[] = { 0x24, 0x25, 0x26 };
+	int legacy = get_fpga_state(0) & FPGA_STATE_PLATFORM;
+
+	print_fpga_info(0);
+	osd_probe(0);
+
+	/* wait for FPGA done */
+	for (k = 0; k < ARRAY_SIZE(mclink_controllers); ++k) {
+		unsigned int ctr = 0;
+
+		if (i2c_probe(mclink_controllers[k]))
+			continue;
+
+		while (!(pca953x_get_val(mclink_controllers[k])
+		       & MCFPGA_DONE)) {
+			udelay(100000);
+			if (ctr++ > 5) {
+				printf("no done for mclink_controller %d\n", k);
+				break;
+			}
+		}
+	}
+
+	if (!legacy) {
+		miiphy_register(bb_miiphy_buses[0].name, bb_miiphy_read,
+				bb_miiphy_write);
+		if (!verify_88e1518(bb_miiphy_buses[0].name, 0)) {
+			printf("Fixup 88e1518 erratum on %s\n",
+			       bb_miiphy_buses[0].name);
+			setup_88e1518(bb_miiphy_buses[0].name, 0);
+		}
+	}
 
-	return osd_probe(0);
+	/* wait for slave-PLLs to be up and running */
+	udelay(500000);
+
+	mclink_fpgacount = CONFIG_SYS_MCLINK_MAX;
+	slaves = mclink_probe();
+	mclink_fpgacount = 0;
+
+	if (slaves <= 0)
+		return 0;
+
+	mclink_fpgacount = slaves;
+
+	for (k = 1; k <= slaves; ++k) {
+		print_fpga_info(k);
+		osd_probe(k);
+		miiphy_register(bb_miiphy_buses[k].name,
+				bb_miiphy_read, bb_miiphy_write);
+		if (!verify_88e1518(bb_miiphy_buses[k].name, 0)) {
+			printf("Fixup 88e1518 erratum on %s\n",
+			       bb_miiphy_buses[k].name);
+			setup_88e1518(bb_miiphy_buses[k].name, 0);
+		}
+	}
+
+	return 0;
 }
 
 /*
  * provide access to fpga gpios (for I2C bitbang)
  * (these may look all too simple but make iocon.h much more readable)
  */
-void fpga_gpio_set(int pin)
+void fpga_gpio_set(unsigned int bus, int pin)
 {
-	FPGA_SET_REG(0, gpio.set, pin);
+	FPGA_SET_REG(bus, gpio.set, pin);
 }
 
-void fpga_gpio_clear(int pin)
+void fpga_gpio_clear(unsigned int bus, int pin)
 {
-	FPGA_SET_REG(0, gpio.clear, pin);
+	FPGA_SET_REG(bus, gpio.clear, pin);
 }
 
-int fpga_gpio_get(int pin)
+int fpga_gpio_get(unsigned int bus, int pin)
 {
 	u16 val;
 
-	FPGA_GET_REG(0, gpio.read, &val);
+	FPGA_GET_REG(bus, gpio.read, &val);
 
 	return val & pin;
 }
 
 void gd405ep_init(void)
 {
+	unsigned int k;
+
+	if (i2c_probe(0x20)) { /* i2c_probe returns 0 on success */
+		for (k = 0; k < CONFIG_SYS_FPGA_COUNT; ++k)
+			gd->arch.fpga_state[k] |= FPGA_STATE_PLATFORM;
+	} else {
+		pca9698_direction_output(0x20, 4, 1);
+	}
 }
 
 void gd405ep_set_fpga_reset(unsigned state)
 {
-	if (state) {
-		out_le16((void *)LATCH0_BASE, CONFIG_SYS_LATCH0_RESET);
-		out_le16((void *)LATCH1_BASE, CONFIG_SYS_LATCH1_RESET);
+	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 {
-		out_le16((void *)LATCH0_BASE, CONFIG_SYS_LATCH0_BOOT);
-		out_le16((void *)LATCH1_BASE, CONFIG_SYS_LATCH1_BOOT);
+		pca9698_set_value(0x20, 4, state ? 0 : 1);
 	}
 }
 
@@ -279,5 +482,200 @@  void gd405ep_setup_hw(void)
 
 int gd405ep_get_fpga_done(unsigned fpga)
 {
-	return in_le16((void *)LATCH2_BASE) & CONFIG_SYS_FPGA_DONE(fpga);
+	int legacy = get_fpga_state(0) & FPGA_STATE_PLATFORM;
+
+	if (legacy)
+		return in_le16((void *)LATCH2_BASE)
+		       & CONFIG_SYS_FPGA_DONE(fpga);
+	else
+		return pca9698_get_value(0x20, 20);
+}
+
+/*
+ * FPGA MII bitbang implementation
+ */
+
+struct fpga_mii {
+	unsigned fpga;
+	int mdio;
+} fpga_mii[] = {
+	{ 0, 1},
+	{ 1, 1},
+	{ 2, 1},
+	{ 3, 1},
+};
+
+static int mii_dummy_init(struct bb_miiphy_bus *bus)
+{
+	return 0;
+}
+
+static int mii_mdio_active(struct bb_miiphy_bus *bus)
+{
+	struct fpga_mii *fpga_mii = bus->priv;
+
+	if (fpga_mii->mdio)
+		FPGA_SET_REG(fpga_mii->fpga, gpio.set, GPIO_MDIO);
+	else
+		FPGA_SET_REG(fpga_mii->fpga, gpio.clear, GPIO_MDIO);
+
+	return 0;
+}
+
+static int mii_mdio_tristate(struct bb_miiphy_bus *bus)
+{
+	struct fpga_mii *fpga_mii = bus->priv;
+
+	FPGA_SET_REG(fpga_mii->fpga, gpio.set, GPIO_MDIO);
+
+	return 0;
+}
+
+static int mii_set_mdio(struct bb_miiphy_bus *bus, int v)
+{
+	struct fpga_mii *fpga_mii = bus->priv;
+
+	if (v)
+		FPGA_SET_REG(fpga_mii->fpga, gpio.set, GPIO_MDIO);
+	else
+		FPGA_SET_REG(fpga_mii->fpga, gpio.clear, GPIO_MDIO);
+
+	fpga_mii->mdio = v;
+
+	return 0;
+}
+
+static int mii_get_mdio(struct bb_miiphy_bus *bus, int *v)
+{
+	u16 gpio;
+	struct fpga_mii *fpga_mii = bus->priv;
+
+	FPGA_GET_REG(fpga_mii->fpga, gpio.read, &gpio);
+
+	*v = ((gpio & GPIO_MDIO) != 0);
+
+	return 0;
+}
+
+static int mii_set_mdc(struct bb_miiphy_bus *bus, int v)
+{
+	struct fpga_mii *fpga_mii = bus->priv;
+
+	if (v)
+		FPGA_SET_REG(fpga_mii->fpga, gpio.set, GPIO_MDC);
+	else
+		FPGA_SET_REG(fpga_mii->fpga, gpio.clear, GPIO_MDC);
+
+	return 0;
+}
+
+static int mii_delay(struct bb_miiphy_bus *bus)
+{
+	udelay(1);
+
+	return 0;
+}
+
+struct bb_miiphy_bus bb_miiphy_buses[] = {
+	{
+		.name = "trans1",
+		.init = mii_dummy_init,
+		.mdio_active = mii_mdio_active,
+		.mdio_tristate = mii_mdio_tristate,
+		.set_mdio = mii_set_mdio,
+		.get_mdio = mii_get_mdio,
+		.set_mdc = mii_set_mdc,
+		.delay = mii_delay,
+		.priv = &fpga_mii[0],
+	},
+	{
+		.name = "trans2",
+		.init = mii_dummy_init,
+		.mdio_active = mii_mdio_active,
+		.mdio_tristate = mii_mdio_tristate,
+		.set_mdio = mii_set_mdio,
+		.get_mdio = mii_get_mdio,
+		.set_mdc = mii_set_mdc,
+		.delay = mii_delay,
+		.priv = &fpga_mii[1],
+	},
+	{
+		.name = "trans3",
+		.init = mii_dummy_init,
+		.mdio_active = mii_mdio_active,
+		.mdio_tristate = mii_mdio_tristate,
+		.set_mdio = mii_set_mdio,
+		.get_mdio = mii_get_mdio,
+		.set_mdc = mii_set_mdc,
+		.delay = mii_delay,
+		.priv = &fpga_mii[2],
+	},
+	{
+		.name = "trans4",
+		.init = mii_dummy_init,
+		.mdio_active = mii_mdio_active,
+		.mdio_tristate = mii_mdio_tristate,
+		.set_mdio = mii_set_mdio,
+		.get_mdio = mii_get_mdio,
+		.set_mdc = mii_set_mdc,
+		.delay = mii_delay,
+		.priv = &fpga_mii[3],
+	},
+};
+
+int bb_miiphy_buses_num = sizeof(bb_miiphy_buses) /
+			  sizeof(bb_miiphy_buses[0]);
+
+/*
+ * Workaround for erratum mentioned in 88E1518 release notes
+ */
+
+static int verify_88e1518(const char *bus, unsigned char addr)
+{
+	u16 phy_id1, phy_id2;
+
+	if (miiphy_read(bus, addr, 2, &phy_id1) ||
+	    miiphy_read(bus, addr, 3, &phy_id2)) {
+		printf("Error reading from the PHY addr=%02x\n", addr);
+		return -EIO;
+	}
+
+	if ((phy_id1 != 0x0141) || ((phy_id2 & 0xfff0) != 0x0dd0))
+		return -EINVAL;
+
+	return 0;
+}
+
+struct regfix_88e1518 {
+	u8 reg;
+	u16 data;
+} regfix_88e1518[] = {
+	{ 22, 0x00ff },
+	{ 17, 0x214b },
+	{ 16, 0x2144 },
+	{ 17, 0x0c28 },
+	{ 16, 0x2146 },
+	{ 17, 0xb233 },
+	{ 16, 0x214d },
+	{ 17, 0xcc0c },
+	{ 16, 0x2159 },
+	{ 22, 0x00fb },
+	{  7, 0xc00d },
+	{ 22, 0x0000 },
+};
+
+static int setup_88e1518(const char *bus, unsigned char addr)
+{
+	unsigned int k;
+
+	for (k = 0; k < ARRAY_SIZE(regfix_88e1518); ++k) {
+		if (miiphy_write(bus, addr,
+				 regfix_88e1518[k].reg,
+				 regfix_88e1518[k].data)) {
+			printf("Error writing to the PHY addr=%02x\n", addr);
+			return -1;
+		}
+	}
+
+	return 0;
 }
diff --git a/board/gdsys/common/Makefile b/board/gdsys/common/Makefile
index 2b7e754..9694eda 100644
--- a/board/gdsys/common/Makefile
+++ b/board/gdsys/common/Makefile
@@ -33,7 +33,7 @@  COBJS-$(CONFIG_SYS_FPGA_COMMON) += fpga.o
 
 COBJS-$(CONFIG_IO) += miiphybb.o
 COBJS-$(CONFIG_IO64) += miiphybb.o
-COBJS-$(CONFIG_IOCON) += osd.o
+COBJS-$(CONFIG_IOCON) += osd.o mclink.o
 COBJS-$(CONFIG_DLVISION_10G) += osd.o
 
 COBJS   := $(COBJS-y)
diff --git a/board/gdsys/common/osd.c b/board/gdsys/common/osd.c
index e5b5150..5ddd098 100644
--- a/board/gdsys/common/osd.c
+++ b/board/gdsys/common/osd.c
@@ -22,8 +22,8 @@ 
  */
 
 #include <common.h>
-#include <asm/io.h>
 #include <i2c.h>
+#include <malloc.h>
 
 #include <gdsys_fpga.h>
 
@@ -67,6 +67,12 @@  enum {
 	CH7301_DSP = 0x56,		/* DVI Sync polarity Register */
 };
 
+unsigned int max_osd_screen = CONFIG_SYS_OSD_SCREENS - 1;
+
+#ifdef CONFIG_SYS_CH7301
+int ch7301_i2c[] = CONFIG_SYS_CH7301_I2C;
+#endif
+
 #if defined(CONFIG_SYS_ICS8N3QV01) || defined(CONFIG_SYS_SIL1178)
 static void fpga_iic_write(unsigned screen, u8 slave, u8 reg, u8 data)
 {
@@ -286,7 +292,7 @@  static int osd_print(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	unsigned screen;
 
-	for (screen = 0; screen < CONFIG_SYS_OSD_SCREENS; ++screen) {
+	for (screen = 0; screen <= max_osd_screen; ++screen) {
 		unsigned x;
 		unsigned y;
 		unsigned charcount;
@@ -327,6 +333,9 @@  int osd_probe(unsigned screen)
 	unsigned width;
 	unsigned height;
 	u8 value;
+#ifdef CONFIG_SYS_CH7301
+	int old_bus = i2c_get_bus_num();
+#endif
 
 	FPGA_GET_REG(0, osd.version, &version);
 	FPGA_GET_REG(0, osd.features, &features);
@@ -338,9 +347,11 @@  int osd_probe(unsigned screen)
 		screen, version/100, version%100, width, height);
 
 #ifdef CONFIG_SYS_CH7301
+	i2c_set_bus_num(ch7301_i2c[screen]);
 	value = i2c_reg_read(CH7301_I2C_ADDR, CH7301_DID);
 	if (value != 0x17) {
 		printf("       Probing CH7301 failed, DID %02x\n", value);
+		i2c_set_bus_num(old_bus);
 		return -1;
 	}
 	i2c_reg_write(CH7301_I2C_ADDR, CH7301_TPCP, 0x08);
@@ -348,6 +359,7 @@  int osd_probe(unsigned screen)
 	i2c_reg_write(CH7301_I2C_ADDR, CH7301_TPF, 0x60);
 	i2c_reg_write(CH7301_I2C_ADDR, CH7301_DC, 0x09);
 	i2c_reg_write(CH7301_I2C_ADDR, CH7301_PM, 0xc0);
+	i2c_set_bus_num(old_bus);
 #endif
 
 #ifdef CONFIG_SYS_MPC92469AC
@@ -384,6 +396,8 @@  int osd_probe(unsigned screen)
 	FPGA_SET_REG(screen, osd.x_pos, 0x007f);
 	FPGA_SET_REG(screen, osd.y_pos, 0x005f);
 
+	if (screen > max_osd_screen)
+		max_osd_screen = screen;
 
 	return 0;
 }
@@ -392,7 +406,7 @@  int osd_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	unsigned screen;
 
-	for (screen = 0; screen < CONFIG_SYS_OSD_SCREENS; ++screen) {
+	for (screen = 0; screen <= max_osd_screen; ++screen) {
 		unsigned x;
 		unsigned y;
 		unsigned k;
diff --git a/include/configs/iocon.h b/include/configs/iocon.h
index 7f33956..561837c 100644
--- a/include/configs/iocon.h
+++ b/include/configs/iocon.h
@@ -79,6 +79,7 @@ 
  * Commands additional to the ones defined in amcc-common.h
  */
 #define CONFIG_CMD_CACHE
+#define CONFIG_CMD_FPGAD
 #undef CONFIG_CMD_EEPROM
 
 /*
@@ -116,23 +117,53 @@ 
 #define CONFIG_SYS_I2C_PPC4XX_SPEED_0		400000
 #define CONFIG_SYS_I2C_PPC4XX_SLAVE_0		0x7F
 
+#define CONFIG_SYS_I2C_SPEED		400000
+
+#define CONFIG_PCA953X			/* NXP PCA9554 */
+#define CONFIG_PCA9698			/* NXP PCA9698 */
+
 /*
  * Software (bit-bang) I2C driver configuration
  */
+#define CONFIG_SYS_I2C_SOFT
+#define CONFIG_SYS_I2C_SOFT_SPEED		50000
+#define CONFIG_SYS_I2C_SOFT_SLAVE		0x7F
+#define I2C_SOFT_DECLARATIONS2
+#define CONFIG_SYS_I2C_SOFT_SPEED_2		50000
+#define CONFIG_SYS_I2C_SOFT_SLAVE_2		0x7F
+#define I2C_SOFT_DECLARATIONS3
+#define CONFIG_SYS_I2C_SOFT_SPEED_3		50000
+#define CONFIG_SYS_I2C_SOFT_SLAVE_3		0x7F
+#define I2C_SOFT_DECLARATIONS4
+#define CONFIG_SYS_I2C_SOFT_SPEED_4		50000
+#define CONFIG_SYS_I2C_SOFT_SLAVE_4		0x7F
+
+#define CONFIG_SYS_CH7301_I2C			{1, 2, 3, 4}
 
 #ifndef __ASSEMBLY__
-void fpga_gpio_set(int pin);
-void fpga_gpio_clear(int pin);
-int fpga_gpio_get(int pin);
+void fpga_gpio_set(unsigned int bus, int pin);
+void fpga_gpio_clear(unsigned int bus, int pin);
+int fpga_gpio_get(unsigned int bus, int pin);
 #endif
 
 #define I2C_ACTIVE	{ }
 #define I2C_TRISTATE	{ }
-#define I2C_READ	fpga_gpio_get(0x0040) ? 1 : 0
-#define I2C_SDA(bit)	if (bit) fpga_gpio_set(0x0040); \
-			else fpga_gpio_clear(0x0040)
-#define I2C_SCL(bit)	if (bit) fpga_gpio_set(0x0020); \
-			else fpga_gpio_clear(0x0020)
+#define I2C_READ \
+	(fpga_gpio_get(I2C_ADAP_HWNR, 0x0040) ? 1 : 0)
+#define I2C_SDA(bit) \
+	do { \
+		if (bit) \
+			fpga_gpio_set(I2C_ADAP_HWNR, 0x0040); \
+		else \
+			fpga_gpio_clear(I2C_ADAP_HWNR, 0x0040); \
+	} while (0)
+#define I2C_SCL(bit) \
+	do { \
+		if (bit) \
+			fpga_gpio_set(I2C_ADAP_HWNR, 0x0020); \
+		else \
+			fpga_gpio_clear(I2C_ADAP_HWNR, 0x0020); \
+	} while (0)
 #define I2C_DELAY	udelay(25)	/* 1/4 I2C clock duration */
 
 /*
@@ -252,10 +283,10 @@  int fpga_gpio_get(int pin);
 
 #define CONFIG_SYS_FPGA_COUNT		1
 
-#define CONFIG_SYS_FPGA_PTR \
-	{ (struct ihs_fpga *)CONFIG_SYS_FPGA0_BASE }
+#define CONFIG_SYS_MCLINK_MAX		3
 
-#define CONFIG_SYS_FPGA_COMMON
+#define CONFIG_SYS_FPGA_PTR \
+	{ (struct ihs_fpga *)CONFIG_SYS_FPGA0_BASE, NULL, NULL, NULL }
 
 /* Memory Bank 3 (Latches) initialization */
 #define CONFIG_SYS_LATCH_BASE		0x7f200000
@@ -272,6 +303,9 @@  int fpga_gpio_get(int pin);
  */
 #define CONFIG_SYS_MPC92469AC
 #define CONFIG_SYS_CH7301
-#define CONFIG_SYS_OSD_SCREENS		CONFIG_SYS_FPGA_COUNT
+#define CONFIG_SYS_OSD_SCREENS		1
+
+#define CONFIG_BITBANGMII		/* bit-bang MII PHY management */
+#define CONFIG_BITBANGMII_MULTI
 
 #endif	/* __CONFIG_H */
diff --git a/include/gdsys_fpga.h b/include/gdsys_fpga.h
index a53ab89..dd471de 100644
--- a/include/gdsys_fpga.h
+++ b/include/gdsys_fpga.h
@@ -139,10 +139,21 @@  struct ihs_fpga {
 	u16 mpc3w_control;	/* 0x001a */
 	u16 reserved_1[19];	/* 0x001c */
 	u16 videocontrol;	/* 0x0042 */
-	u16 reserved_2[93];	/* 0x0044 */
+	u16 reserved_2[14];	/* 0x0044 */
+	u16 mc_int;		/* 0x0060 */
+	u16 mc_int_en;		/* 0x0062 */
+	u16 mc_status;		/* 0x0064 */
+	u16 mc_control;		/* 0x0066 */
+	u16 mc_tx_data;		/* 0x0068 */
+	u16 mc_tx_address;	/* 0x006a */
+	u16 mc_tx_cmd;		/* 0x006c */
+	u16 mc_res;		/* 0x006e */
+	u16 mc_rx_cmd_status;	/* 0x0070 */
+	u16 mc_rx_data;		/* 0x0072 */
+	u16 reserved_3[69];	/* 0x0074 */
 	u16 reflection_high;	/* 0x00fe */
 	struct ihs_osd osd;	/* 0x0100 */
-	u16 reserved_3[889];	/* 0x010e */
+	u16 reserved_4[889];	/* 0x010e */
 	u16 videomem[31736];	/* 0x0800 */
 };
 #endif