diff options
Diffstat (limited to 'drivers/net/phy/marvell.c')
-rw-r--r-- | drivers/net/phy/marvell.c | 204 |
1 files changed, 154 insertions, 50 deletions
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 5aec673a0120..620052c023a5 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -80,8 +80,11 @@ #define MII_M1111_HWCFG_MODE_FIBER_RGMII 0x3 #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4 #define MII_M1111_HWCFG_MODE_RTBI 0x7 +#define MII_M1111_HWCFG_MODE_COPPER_1000X_AN 0x8 #define MII_M1111_HWCFG_MODE_COPPER_RTBI 0x9 #define MII_M1111_HWCFG_MODE_COPPER_RGMII 0xb +#define MII_M1111_HWCFG_MODE_COPPER_1000X_NOAN 0xc +#define MII_M1111_HWCFG_SERIAL_AN_BYPASS BIT(12) #define MII_M1111_HWCFG_FIBER_COPPER_RES BIT(13) #define MII_M1111_HWCFG_FIBER_COPPER_AUTO BIT(15) @@ -314,16 +317,43 @@ static int marvell_config_intr(struct phy_device *phydev) { int err; - if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + err = marvell_ack_interrupt(phydev); + if (err) + return err; + err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT); - else + } else { err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); + if (err) + return err; + + err = marvell_ack_interrupt(phydev); + } return err; } +static irqreturn_t marvell_handle_interrupt(struct phy_device *phydev) +{ + int irq_status; + + irq_status = phy_read(phydev, MII_M1011_IEVENT); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + if (!(irq_status & MII_M1011_IMASK_INIT)) + return IRQ_NONE; + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + static int marvell_set_polarity(struct phy_device *phydev, int polarity) { int reg; @@ -629,6 +659,51 @@ static int marvell_config_aneg_fiber(struct phy_device *phydev) return genphy_check_and_restart_aneg(phydev, changed); } +static int m88e1111_config_aneg(struct phy_device *phydev) +{ + int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR); + int err; + + if (extsr < 0) + return extsr; + + /* If not using SGMII or copper 1000BaseX modes, use normal process. + * Steps below are only required for these modes. + */ + if (phydev->interface != PHY_INTERFACE_MODE_SGMII && + (extsr & MII_M1111_HWCFG_MODE_MASK) != + MII_M1111_HWCFG_MODE_COPPER_1000X_AN) + return marvell_config_aneg(phydev); + + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); + if (err < 0) + goto error; + + /* Configure the copper link first */ + err = marvell_config_aneg(phydev); + if (err < 0) + goto error; + + /* Do not touch the fiber page if we're in copper->sgmii mode */ + if (phydev->interface == PHY_INTERFACE_MODE_SGMII) + return 0; + + /* Then the fiber link */ + err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); + if (err < 0) + goto error; + + err = marvell_config_aneg_fiber(phydev); + if (err < 0) + goto error; + + return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); + +error: + marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); + return err; +} + static int m88e1510_config_aneg(struct phy_device *phydev) { int err; @@ -696,7 +771,7 @@ static void marvell_config_led(struct phy_device *phydev) static int marvell_config_init(struct phy_device *phydev) { - /* Set defalut LED */ + /* Set default LED */ marvell_config_led(phydev); /* Set registers from marvell,reg-init DT property */ @@ -814,6 +889,28 @@ static int m88e1111_config_init_rtbi(struct phy_device *phydev) MII_M1111_HWCFG_FIBER_COPPER_AUTO); } +static int m88e1111_config_init_1000basex(struct phy_device *phydev) +{ + int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR); + int err, mode; + + if (extsr < 0) + return extsr; + + /* If using copper mode, ensure 1000BaseX auto-negotiation is enabled */ + mode = extsr & MII_M1111_HWCFG_MODE_MASK; + if (mode == MII_M1111_HWCFG_MODE_COPPER_1000X_NOAN) { + err = phy_modify(phydev, MII_M1111_PHY_EXT_SR, + MII_M1111_HWCFG_MODE_MASK | + MII_M1111_HWCFG_SERIAL_AN_BYPASS, + MII_M1111_HWCFG_MODE_COPPER_1000X_AN | + MII_M1111_HWCFG_SERIAL_AN_BYPASS); + if (err < 0) + return err; + } + return 0; +} + static int m88e1111_config_init(struct phy_device *phydev) { int err; @@ -836,6 +933,12 @@ static int m88e1111_config_init(struct phy_device *phydev) return err; } + if (phydev->interface == PHY_INTERFACE_MODE_1000BASEX) { + err = m88e1111_config_init_1000basex(phydev); + if (err < 0) + return err; + } + err = marvell_of_reg_init(phydev); if (err < 0) return err; @@ -1029,8 +1132,8 @@ static int m88e1510_config_init(struct phy_device *phydev) return err; /* PHY reset is necessary after changing MODE[2:0] */ - err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1, 0, - MII_88E1510_GEN_CTRL_REG_1_RESET); + err = phy_set_bits(phydev, MII_88E1510_GEN_CTRL_REG_1, + MII_88E1510_GEN_CTRL_REG_1_RESET); if (err < 0) return err; @@ -1583,18 +1686,6 @@ static int marvell_aneg_done(struct phy_device *phydev) return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED); } -static int m88e1121_did_interrupt(struct phy_device *phydev) -{ - int imask; - - imask = phy_read(phydev, MII_M1011_IEVENT); - - if (imask & MII_M1011_IMASK_INIT) - return 1; - - return 0; -} - static void m88e1318_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) { @@ -1634,8 +1725,8 @@ static int m88e1318_set_wol(struct phy_device *phydev, __phy_read(phydev, MII_M1011_IEVENT); /* Enable the WOL interrupt */ - err = __phy_modify(phydev, MII_88E1318S_PHY_CSIER, 0, - MII_88E1318S_PHY_CSIER_WOL_EIE); + err = __phy_set_bits(phydev, MII_88E1318S_PHY_CSIER, + MII_88E1318S_PHY_CSIER_WOL_EIE); if (err < 0) goto error; @@ -1673,9 +1764,9 @@ static int m88e1318_set_wol(struct phy_device *phydev, goto error; /* Clear WOL status and enable magic packet matching */ - err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 0, - MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS | - MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE); + err = __phy_set_bits(phydev, MII_88E1318S_PHY_WOL_CTRL, + MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS | + MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE); if (err < 0) goto error; } else { @@ -1904,7 +1995,7 @@ static int marvell_cable_test_start_common(struct phy_device *phydev) return bmsr; if (bmcr & BMCR_ANENABLE) { - ret = phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0); + ret = phy_clear_bits(phydev, MII_BMCR, BMCR_ANENABLE); if (ret < 0) return ret; ret = genphy_soft_reset(phydev); @@ -2621,8 +2712,8 @@ static struct phy_driver marvell_drivers[] = { .probe = marvell_probe, .config_init = marvell_config_init, .config_aneg = m88e1101_config_aneg, - .ack_interrupt = marvell_ack_interrupt, .config_intr = marvell_config_intr, + .handle_interrupt = marvell_handle_interrupt, .resume = genphy_resume, .suspend = genphy_suspend, .read_page = marvell_read_page, @@ -2639,8 +2730,8 @@ static struct phy_driver marvell_drivers[] = { .probe = marvell_probe, .config_init = m88e1111_config_init, .config_aneg = marvell_config_aneg, - .ack_interrupt = marvell_ack_interrupt, .config_intr = marvell_config_intr, + .handle_interrupt = marvell_handle_interrupt, .resume = genphy_resume, .suspend = genphy_suspend, .read_page = marvell_read_page, @@ -2658,10 +2749,31 @@ static struct phy_driver marvell_drivers[] = { /* PHY_GBIT_FEATURES */ .probe = marvell_probe, .config_init = m88e1111_config_init, - .config_aneg = marvell_config_aneg, + .config_aneg = m88e1111_config_aneg, + .read_status = marvell_read_status, + .config_intr = marvell_config_intr, + .handle_interrupt = marvell_handle_interrupt, + .resume = genphy_resume, + .suspend = genphy_suspend, + .read_page = marvell_read_page, + .write_page = marvell_write_page, + .get_sset_count = marvell_get_sset_count, + .get_strings = marvell_get_strings, + .get_stats = marvell_get_stats, + .get_tunable = m88e1111_get_tunable, + .set_tunable = m88e1111_set_tunable, + }, + { + .phy_id = MARVELL_PHY_ID_88E1111_FINISAR, + .phy_id_mask = MARVELL_PHY_ID_MASK, + .name = "Marvell 88E1111 (Finisar)", + /* PHY_GBIT_FEATURES */ + .probe = marvell_probe, + .config_init = m88e1111_config_init, + .config_aneg = m88e1111_config_aneg, .read_status = marvell_read_status, - .ack_interrupt = marvell_ack_interrupt, .config_intr = marvell_config_intr, + .handle_interrupt = marvell_handle_interrupt, .resume = genphy_resume, .suspend = genphy_suspend, .read_page = marvell_read_page, @@ -2680,8 +2792,8 @@ static struct phy_driver marvell_drivers[] = { .probe = marvell_probe, .config_init = m88e1118_config_init, .config_aneg = m88e1118_config_aneg, - .ack_interrupt = marvell_ack_interrupt, .config_intr = marvell_config_intr, + .handle_interrupt = marvell_handle_interrupt, .resume = genphy_resume, .suspend = genphy_suspend, .read_page = marvell_read_page, @@ -2699,9 +2811,8 @@ static struct phy_driver marvell_drivers[] = { .config_init = marvell_config_init, .config_aneg = m88e1121_config_aneg, .read_status = marvell_read_status, - .ack_interrupt = marvell_ack_interrupt, .config_intr = marvell_config_intr, - .did_interrupt = m88e1121_did_interrupt, + .handle_interrupt = marvell_handle_interrupt, .resume = genphy_resume, .suspend = genphy_suspend, .read_page = marvell_read_page, @@ -2721,9 +2832,8 @@ static struct phy_driver marvell_drivers[] = { .config_init = m88e1318_config_init, .config_aneg = m88e1318_config_aneg, .read_status = marvell_read_status, - .ack_interrupt = marvell_ack_interrupt, .config_intr = marvell_config_intr, - .did_interrupt = m88e1121_did_interrupt, + .handle_interrupt = marvell_handle_interrupt, .get_wol = m88e1318_get_wol, .set_wol = m88e1318_set_wol, .resume = genphy_resume, @@ -2743,8 +2853,8 @@ static struct phy_driver marvell_drivers[] = { .config_init = m88e1145_config_init, .config_aneg = m88e1101_config_aneg, .read_status = genphy_read_status, - .ack_interrupt = marvell_ack_interrupt, .config_intr = marvell_config_intr, + .handle_interrupt = marvell_handle_interrupt, .resume = genphy_resume, .suspend = genphy_suspend, .read_page = marvell_read_page, @@ -2763,8 +2873,8 @@ static struct phy_driver marvell_drivers[] = { .probe = marvell_probe, .config_init = m88e1149_config_init, .config_aneg = m88e1118_config_aneg, - .ack_interrupt = marvell_ack_interrupt, .config_intr = marvell_config_intr, + .handle_interrupt = marvell_handle_interrupt, .resume = genphy_resume, .suspend = genphy_suspend, .read_page = marvell_read_page, @@ -2781,8 +2891,8 @@ static struct phy_driver marvell_drivers[] = { .probe = marvell_probe, .config_init = m88e1111_config_init, .config_aneg = marvell_config_aneg, - .ack_interrupt = marvell_ack_interrupt, .config_intr = marvell_config_intr, + .handle_interrupt = marvell_handle_interrupt, .resume = genphy_resume, .suspend = genphy_suspend, .read_page = marvell_read_page, @@ -2798,8 +2908,8 @@ static struct phy_driver marvell_drivers[] = { /* PHY_GBIT_FEATURES */ .probe = marvell_probe, .config_init = m88e1116r_config_init, - .ack_interrupt = marvell_ack_interrupt, .config_intr = marvell_config_intr, + .handle_interrupt = marvell_handle_interrupt, .resume = genphy_resume, .suspend = genphy_suspend, .read_page = marvell_read_page, @@ -2820,9 +2930,8 @@ static struct phy_driver marvell_drivers[] = { .config_init = m88e1510_config_init, .config_aneg = m88e1510_config_aneg, .read_status = marvell_read_status, - .ack_interrupt = marvell_ack_interrupt, .config_intr = marvell_config_intr, - .did_interrupt = m88e1121_did_interrupt, + .handle_interrupt = marvell_handle_interrupt, .get_wol = m88e1318_get_wol, .set_wol = m88e1318_set_wol, .resume = marvell_resume, @@ -2849,9 +2958,8 @@ static struct phy_driver marvell_drivers[] = { .config_init = marvell_config_init, .config_aneg = m88e1510_config_aneg, .read_status = marvell_read_status, - .ack_interrupt = marvell_ack_interrupt, .config_intr = marvell_config_intr, - .did_interrupt = m88e1121_did_interrupt, + .handle_interrupt = marvell_handle_interrupt, .resume = genphy_resume, .suspend = genphy_suspend, .read_page = marvell_read_page, @@ -2875,9 +2983,8 @@ static struct phy_driver marvell_drivers[] = { .config_init = marvell_config_init, .config_aneg = m88e1510_config_aneg, .read_status = marvell_read_status, - .ack_interrupt = marvell_ack_interrupt, .config_intr = marvell_config_intr, - .did_interrupt = m88e1121_did_interrupt, + .handle_interrupt = marvell_handle_interrupt, .resume = genphy_resume, .suspend = genphy_suspend, .read_page = marvell_read_page, @@ -2900,9 +3007,8 @@ static struct phy_driver marvell_drivers[] = { .config_init = m88e3016_config_init, .aneg_done = marvell_aneg_done, .read_status = marvell_read_status, - .ack_interrupt = marvell_ack_interrupt, .config_intr = marvell_config_intr, - .did_interrupt = m88e1121_did_interrupt, + .handle_interrupt = marvell_handle_interrupt, .resume = genphy_resume, .suspend = genphy_suspend, .read_page = marvell_read_page, @@ -2921,9 +3027,8 @@ static struct phy_driver marvell_drivers[] = { .config_init = marvell_config_init, .config_aneg = m88e6390_config_aneg, .read_status = marvell_read_status, - .ack_interrupt = marvell_ack_interrupt, .config_intr = marvell_config_intr, - .did_interrupt = m88e1121_did_interrupt, + .handle_interrupt = marvell_handle_interrupt, .resume = genphy_resume, .suspend = genphy_suspend, .read_page = marvell_read_page, @@ -2946,9 +3051,8 @@ static struct phy_driver marvell_drivers[] = { .config_init = marvell_config_init, .config_aneg = m88e1510_config_aneg, .read_status = marvell_read_status, - .ack_interrupt = marvell_ack_interrupt, .config_intr = marvell_config_intr, - .did_interrupt = m88e1121_did_interrupt, + .handle_interrupt = marvell_handle_interrupt, .resume = genphy_resume, .suspend = genphy_suspend, .read_page = marvell_read_page, @@ -2968,9 +3072,8 @@ static struct phy_driver marvell_drivers[] = { .config_init = marvell_config_init, .config_aneg = m88e1510_config_aneg, .read_status = marvell_read_status, - .ack_interrupt = marvell_ack_interrupt, .config_intr = marvell_config_intr, - .did_interrupt = m88e1121_did_interrupt, + .handle_interrupt = marvell_handle_interrupt, .resume = genphy_resume, .suspend = genphy_suspend, .read_page = marvell_read_page, @@ -2989,6 +3092,7 @@ static struct mdio_device_id __maybe_unused marvell_tbl[] = { { MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK }, { MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK }, { MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK }, + { MARVELL_PHY_ID_88E1111_FINISAR, MARVELL_PHY_ID_MASK }, { MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK }, { MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK }, { MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK }, |