diff mbox

[U-Boot,08/11] powerpc/ppc4xx: Fixup phy erratum on gdsys iocon hardware

Message ID 1366629372-32022-9-git-send-email-eibach@gdsys.de
State Superseded
Delegated to: Stefan Roese
Headers show

Commit Message

Dirk Eibach April 22, 2013, 11:16 a.m. UTC
Marvell 88E1518 has an erratum that requires fixing up.
This patch checks for presence of this phy and adds code
for fixup.

Signed-off-by: Dirk Eibach <eibach@gdsys.de>
---
 board/gdsys/405ep/iocon.c |  214 +++++++++++++++++++++++++++++++++++++++++++++
 include/configs/iocon.h   |    3 +
 2 files changed, 217 insertions(+)
diff mbox

Patch

diff --git a/board/gdsys/405ep/iocon.c b/board/gdsys/405ep/iocon.c
index ece45d6..45c5b36 100644
--- a/board/gdsys/405ep/iocon.c
+++ b/board/gdsys/405ep/iocon.c
@@ -38,6 +38,8 @@ 
 #include <pca953x.h>
 #include <pca9698.h>
 
+#include <miiphy.h>
+
 DECLARE_GLOBAL_DATA_PTR;
 
 #define LATCH0_BASE (CONFIG_SYS_LATCH_BASE)
@@ -95,8 +97,16 @@  enum {
 	MCFPGA_RESET_N = 1 << 4,
 };
 
+enum {
+	GPIO_MDC = 1 << 14,
+	GPIO_MDIO = 1 << 15,
+};
+
 unsigned int mclink_fpgacount;
 
+static int setup_88e1518(const char *bus, unsigned char addr);
+static int verify_88e1518(const char *bus, unsigned char addr);
+
 void fpga_set_reg(unsigned int fpga, u16 reg, u16 data)
 {
 	int res;
@@ -339,6 +349,7 @@  int last_stage_init(void)
 	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);
@@ -360,6 +371,16 @@  int last_stage_init(void)
 		}
 	}
 
+	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);
+		}
+	}
+
 	/* wait for slave-PLLs to be up and running */
 	udelay(500000);
 
@@ -375,6 +396,13 @@  int last_stage_init(void)
 	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;
@@ -446,3 +474,189 @@  int gd405ep_get_fpga_done(unsigned 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, REG(gpio.set), GPIO_MDIO);
+	else
+		fpga_set_reg(fpga_mii->fpga, REG(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, REG(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, REG(gpio.set), GPIO_MDIO);
+	else
+		fpga_set_reg(fpga_mii->fpga, REG(gpio.clear), GPIO_MDIO);
+
+	fpga_mii->mdio = v;
+
+	return 0;
+}
+
+static int mii_get_mdio(struct bb_miiphy_bus *bus, int *v)
+{
+	struct fpga_mii *fpga_mii = bus->priv;
+
+	*v = ((fpga_get_reg(fpga_mii->fpga, REG(gpio.read)) & 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, REG(gpio.set), GPIO_MDC);
+	else
+		fpga_set_reg(fpga_mii->fpga, REG(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/include/configs/iocon.h b/include/configs/iocon.h
index e99efa6..441b37b 100644
--- a/include/configs/iocon.h
+++ b/include/configs/iocon.h
@@ -274,4 +274,7 @@  int fpga_gpio_get(unsigned int bus, int pin);
 #define CONFIG_SYS_CH7301
 #define CONFIG_SYS_OSD_SCREENS		1
 
+#define CONFIG_BITBANGMII		/* bit-bang MII PHY management */
+#define CONFIG_BITBANGMII_MULTI
+
 #endif	/* __CONFIG_H */