@@ -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;
+}
@@ -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 */
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(+)