diff options
author | Dirk Eibach <dirk.eibach@gdsys.cc> | 2013-08-09 10:52:53 +0200 |
---|---|---|
committer | Stefan Roese <sr@denx.de> | 2013-08-19 10:27:12 +0200 |
commit | f24c8e8dce83b9e4ed61894a8d962438d93754eb (patch) | |
tree | a923a7473744027803910b6136275c100df0fa15 /board/gdsys | |
parent | d78951db56cd98217b626657f3e754d786b27e3c (diff) | |
download | u-boot-f24c8e8dce83b9e4ed61894a8d962438d93754eb.tar.gz |
powerpc/ppc4xx: Do full iocon PHY initialization in software
Up to this point some PHY initialization was done from the FPGA
and some from u-boot.
From now all initialization is done from u-boot.
To keep this maintainable a PHY setup machine was implemented that can
execute commands from initialization arrays.
Signed-off-by: Dirk Eibach <dirk.eibach@gdsys.cc>
Signed-off-by: Stefan Roese <sr@denx.de>
Diffstat (limited to 'board/gdsys')
-rw-r--r-- | board/gdsys/405ep/iocon.c | 220 |
1 files changed, 172 insertions, 48 deletions
diff --git a/board/gdsys/405ep/iocon.c b/board/gdsys/405ep/iocon.c index 664b1e164e..7a98e41d0a 100644 --- a/board/gdsys/405ep/iocon.c +++ b/board/gdsys/405ep/iocon.c @@ -99,7 +99,6 @@ 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) { @@ -405,11 +404,7 @@ int last_stage_init(void) if ((mux_ch == 1) && !ch0_rgmii2_present) continue; - if (!verify_88e1518(bb_miiphy_buses[0].name, mux_ch)) { - printf("Fixup 88e1518 erratum on %s phy %u\n", - bb_miiphy_buses[0].name, mux_ch); - setup_88e1518(bb_miiphy_buses[0].name, mux_ch); - } + setup_88e1518(bb_miiphy_buses[0].name, mux_ch); } } @@ -434,11 +429,7 @@ int last_stage_init(void) if (feature_carrier_speed == CARRIER_SPEED_1G) { 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); - } + setup_88e1518(bb_miiphy_buses[k].name, 0); } } @@ -652,56 +643,189 @@ struct bb_miiphy_bus bb_miiphy_buses[] = { int bb_miiphy_buses_num = sizeof(bb_miiphy_buses) / sizeof(bb_miiphy_buses[0]); +enum { + MIICMD_SET, + MIICMD_MODIFY, + MIICMD_VERIFY_VALUE, + MIICMD_WAIT_FOR_VALUE, +}; + +struct mii_setupcmd { + u8 token; + u8 reg; + u16 data; + u16 mask; + u32 timeout; +}; + /* - * Workaround for erratum mentioned in 88E1518 release notes + * verify we are talking to a 88e1518 */ +struct mii_setupcmd verify_88e1518[] = { + { MIICMD_SET, 22, 0x0000 }, + { MIICMD_VERIFY_VALUE, 2, 0x0141, 0xffff }, + { MIICMD_VERIFY_VALUE, 3, 0x0dd0, 0xfff0 }, +}; -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; - } +/* + * workaround for erratum mentioned in 88E1518 release notes + */ +struct mii_setupcmd fixup_88e1518[] = { + { MIICMD_SET, 22, 0x00ff }, + { MIICMD_SET, 17, 0x214b }, + { MIICMD_SET, 16, 0x2144 }, + { MIICMD_SET, 17, 0x0c28 }, + { MIICMD_SET, 16, 0x2146 }, + { MIICMD_SET, 17, 0xb233 }, + { MIICMD_SET, 16, 0x214d }, + { MIICMD_SET, 17, 0xcc0c }, + { MIICMD_SET, 16, 0x2159 }, + { MIICMD_SET, 22, 0x00fb }, + { MIICMD_SET, 7, 0xc00d }, + { MIICMD_SET, 22, 0x0000 }, +}; - if ((phy_id1 != 0x0141) || ((phy_id2 & 0xfff0) != 0x0dd0)) - return -EINVAL; +/* + * default initialization: + * - set RGMII receive timing to "receive clock transition when data stable" + * - set RGMII transmit timing to "transmit clock internally delayed" + * - set RGMII output impedance target to 78,8 Ohm + * - run output impedance calibration + * - set autonegotiation advertise to 1000FD only + */ +struct mii_setupcmd default_88e1518[] = { + { MIICMD_SET, 22, 0x0002 }, + { MIICMD_MODIFY, 21, 0x0030, 0x0030 }, + { MIICMD_MODIFY, 25, 0x0000, 0x0003 }, + { MIICMD_MODIFY, 24, 0x8000, 0x8000 }, + { MIICMD_WAIT_FOR_VALUE, 24, 0x4000, 0x4000, 2000 }, + { MIICMD_SET, 22, 0x0000 }, + { MIICMD_MODIFY, 4, 0x0000, 0x01e0 }, + { MIICMD_MODIFY, 9, 0x0200, 0x0300 }, +}; - return 0; -} +/* + * turn off CLK125 for PHY daughterboard + */ +struct mii_setupcmd ch1fix_88e1518[] = { + { MIICMD_SET, 22, 0x0002 }, + { MIICMD_MODIFY, 16, 0x0006, 0x0006 }, + { MIICMD_SET, 22, 0x0000 }, +}; -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 }, +/* + * perform copper software reset + */ +struct mii_setupcmd swreset_88e1518[] = { + { MIICMD_SET, 22, 0x0000 }, + { MIICMD_MODIFY, 0, 0x8000, 0x8000 }, + { MIICMD_WAIT_FOR_VALUE, 0, 0x0000, 0x8000, 2000 }, }; -static int setup_88e1518(const char *bus, unsigned char addr) +static int process_setupcmd(const char *bus, unsigned char addr, + struct mii_setupcmd *setupcmd) { + int res; + u8 reg = setupcmd->reg; + u16 data = setupcmd->data; + u16 mask = setupcmd->mask; + u32 timeout = setupcmd->timeout; + u16 orig_data; + unsigned long start; + + debug("mii %s:%u reg %2u ", bus, addr, reg); + + switch (setupcmd->token) { + case MIICMD_MODIFY: + res = miiphy_read(bus, addr, reg, &orig_data); + if (res) + break; + debug("is %04x. (value %04x mask %04x) ", orig_data, data, + mask); + data = (orig_data & ~mask) | (data & mask); + case MIICMD_SET: + debug("=> %04x\n", data); + res = miiphy_write(bus, addr, reg, data); + break; + case MIICMD_VERIFY_VALUE: + res = miiphy_read(bus, addr, reg, &orig_data); + if (res) + break; + if ((orig_data & mask) != (data & mask)) + res = -1; + debug("(value %04x mask %04x) == %04x? %s\n", data, mask, + orig_data, res ? "FAIL" : "PASS"); + break; + case MIICMD_WAIT_FOR_VALUE: + res = -1; + start = get_timer(0); + while ((res != 0) && (get_timer(start) < timeout)) { + res = miiphy_read(bus, addr, reg, &orig_data); + if (res) + continue; + if ((orig_data & mask) != (data & mask)) + res = -1; + } + debug("(value %04x mask %04x) == %04x? %s after %lu ms\n", data, + mask, orig_data, res ? "FAIL" : "PASS", + get_timer(start)); + break; + default: + res = -1; + break; + } + + return res; +} + +static int process_setup(const char *bus, unsigned char addr, + struct mii_setupcmd *setupcmd, unsigned int count) +{ + int res = 0; 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; + for (k = 0; k < count; ++k) { + res = process_setupcmd(bus, addr, &setupcmd[k]); + if (res) { + printf("mii cmd %u on bus %s addr %u failed, aborting setup", + setupcmd[k].token, bus, addr); + break; } } + return res; +} + +static int setup_88e1518(const char *bus, unsigned char addr) +{ + int res; + + res = process_setup(bus, addr, + verify_88e1518, ARRAY_SIZE(verify_88e1518)); + if (res) + return res; + + res = process_setup(bus, addr, + fixup_88e1518, ARRAY_SIZE(fixup_88e1518)); + if (res) + return res; + + res = process_setup(bus, addr, + default_88e1518, ARRAY_SIZE(default_88e1518)); + if (res) + return res; + + if (addr) { + res = process_setup(bus, addr, + ch1fix_88e1518, ARRAY_SIZE(ch1fix_88e1518)); + if (res) + return res; + } + + res = process_setup(bus, addr, + swreset_88e1518, ARRAY_SIZE(swreset_88e1518)); + if (res) + return res; + return 0; } |