diff options
Diffstat (limited to 'drivers/net/phy/marvell.c')
-rw-r--r-- | drivers/net/phy/marvell.c | 732 |
1 files changed, 405 insertions, 327 deletions
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 57297ba23987..5d314f143aea 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -41,6 +41,12 @@ #include <linux/uaccess.h> #define MII_MARVELL_PHY_PAGE 22 +#define MII_MARVELL_COPPER_PAGE 0x00 +#define MII_MARVELL_FIBER_PAGE 0x01 +#define MII_MARVELL_MSCR_PAGE 0x02 +#define MII_MARVELL_LED_PAGE 0x03 +#define MII_MARVELL_MISC_TEST_PAGE 0x06 +#define MII_MARVELL_WOL_PAGE 0x11 #define MII_M1011_IEVENT 0x13 #define MII_M1011_IEVENT_CLEAR 0x0000 @@ -54,7 +60,6 @@ #define MII_M1011_PHY_SCR_MDI_X 0x0020 #define MII_M1011_PHY_SCR_AUTO_CROSS 0x0060 -#define MII_M1145_PHY_EXT_ADDR_PAGE 0x16 #define MII_M1145_PHY_EXT_SR 0x1b #define MII_M1145_PHY_EXT_CR 0x14 #define MII_M1145_RGMII_RX_DELAY 0x0080 @@ -83,10 +88,6 @@ #define MII_M1111_HWCFG_FIBER_COPPER_AUTO 0x8000 #define MII_M1111_HWCFG_FIBER_COPPER_RES 0x2000 -#define MII_M1111_COPPER 0 -#define MII_M1111_FIBER 1 - -#define MII_88E1121_PHY_MSCR_PAGE 2 #define MII_88E1121_PHY_MSCR_REG 21 #define MII_88E1121_PHY_MSCR_RX_DELAY BIT(5) #define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4) @@ -112,7 +113,6 @@ #define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7) /* LED Timer Control Register */ -#define MII_88E1318S_PHY_LED_PAGE 0x03 #define MII_88E1318S_PHY_LED_TCR 0x12 #define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15) #define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7) @@ -123,13 +123,11 @@ #define MII_88E1318S_PHY_MAGIC_PACKET_WORD1 0x18 #define MII_88E1318S_PHY_MAGIC_PACKET_WORD0 0x19 -#define MII_88E1318S_PHY_WOL_PAGE 0x11 #define MII_88E1318S_PHY_WOL_CTRL 0x10 #define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS BIT(12) #define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE BIT(14) #define MII_88E1121_PHY_LED_CTRL 16 -#define MII_88E1121_PHY_LED_PAGE 3 #define MII_88E1121_PHY_LED_DEF 0x0030 #define MII_M1011_PHY_STATUS 0x11 @@ -189,6 +187,29 @@ struct marvell_priv { struct device *hwmon_dev; }; +static int marvell_get_page(struct phy_device *phydev) +{ + return phy_read(phydev, MII_MARVELL_PHY_PAGE); +} + +static int marvell_set_page(struct phy_device *phydev, int page) +{ + return phy_write(phydev, MII_MARVELL_PHY_PAGE, page); +} + +static int marvell_get_set_page(struct phy_device *phydev, int page) +{ + int oldpage = marvell_get_page(phydev); + + if (oldpage < 0) + return oldpage; + + if (page != oldpage) + return marvell_set_page(phydev, page); + + return 0; +} + static int marvell_ack_interrupt(struct phy_device *phydev) { int err; @@ -207,9 +228,11 @@ static int marvell_config_intr(struct phy_device *phydev) int err; if (phydev->interrupts == PHY_INTERRUPT_ENABLED) - err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT); + err = phy_write(phydev, MII_M1011_IMASK, + MII_M1011_IMASK_INIT); else - err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); + err = phy_write(phydev, MII_M1011_IMASK, + MII_M1011_IMASK_CLEAR); return err; } @@ -271,8 +294,7 @@ static int marvell_config_aneg(struct phy_device *phydev) if (phydev->autoneg != AUTONEG_ENABLE) { int bmcr; - /* - * A write to speed/duplex bits (that is performed by + /* A write to speed/duplex bits (that is performed by * genphy_config_aneg() call above) must be followed by * a software reset. Otherwise, the write has no effect. */ @@ -367,8 +389,7 @@ static int m88e1111_config_aneg(struct phy_device *phydev) } #ifdef CONFIG_OF_MDIO -/* - * Set and/or override some configuration registers based on the +/* Set and/or override some configuration registers based on the * marvell,reg-init property stored in the of_node for the phydev. * * marvell,reg-init = <reg-page reg mask value>,...; @@ -394,7 +415,7 @@ static int marvell_of_reg_init(struct phy_device *phydev) if (!paddr || len < (4 * sizeof(*paddr))) return 0; - saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE); + saved_page = marvell_get_page(phydev); if (saved_page < 0) return saved_page; current_page = saved_page; @@ -402,15 +423,15 @@ static int marvell_of_reg_init(struct phy_device *phydev) ret = 0; len /= sizeof(*paddr); for (i = 0; i < len - 3; i += 4) { - u16 reg_page = be32_to_cpup(paddr + i); + u16 page = be32_to_cpup(paddr + i); u16 reg = be32_to_cpup(paddr + i + 1); u16 mask = be32_to_cpup(paddr + i + 2); u16 val_bits = be32_to_cpup(paddr + i + 3); int val; - if (reg_page != current_page) { - current_page = reg_page; - ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page); + if (page != current_page) { + current_page = page; + ret = marvell_set_page(phydev, page); if (ret < 0) goto err; } @@ -429,11 +450,10 @@ static int marvell_of_reg_init(struct phy_device *phydev) ret = phy_write(phydev, reg, val); if (ret < 0) goto err; - } err: if (current_page != saved_page) { - i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page); + i = marvell_set_page(phydev, saved_page); if (ret == 0) ret = i; } @@ -450,15 +470,11 @@ static int m88e1121_config_aneg(struct phy_device *phydev) { int err, oldpage, mscr; - oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); - - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, - MII_88E1121_PHY_MSCR_PAGE); - if (err < 0) - return err; + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MSCR_PAGE); + if (oldpage < 0) + return oldpage; if (phy_interface_is_rgmii(phydev)) { - mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) & MII_88E1121_PHY_MSCR_DELAY_MASK; @@ -475,7 +491,7 @@ static int m88e1121_config_aneg(struct phy_device *phydev) return err; } - phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); + marvell_set_page(phydev, oldpage); err = phy_write(phydev, MII_BMCR, BMCR_RESET); if (err < 0) @@ -493,12 +509,9 @@ static int m88e1318_config_aneg(struct phy_device *phydev) { int err, oldpage, mscr; - oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); - - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, - MII_88E1121_PHY_MSCR_PAGE); - if (err < 0) - return err; + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MSCR_PAGE); + if (oldpage < 0) + return oldpage; mscr = phy_read(phydev, MII_88E1318S_PHY_MSCR1_REG); mscr |= MII_88E1318S_PHY_MSCR1_PAD_ODD; @@ -507,7 +520,7 @@ static int m88e1318_config_aneg(struct phy_device *phydev) if (err < 0) return err; - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); + err = marvell_set_page(phydev, oldpage); if (err < 0) return err; @@ -607,7 +620,7 @@ static int m88e1510_config_aneg(struct phy_device *phydev) { int err; - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) goto error; @@ -617,7 +630,7 @@ static int m88e1510_config_aneg(struct phy_device *phydev) goto error; /* Then the fiber link */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER); + err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; @@ -625,10 +638,10 @@ static int m88e1510_config_aneg(struct phy_device *phydev) if (err < 0) goto error; - return phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); error: - phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); return err; } @@ -651,7 +664,7 @@ static int m88e1116r_config_init(struct phy_device *phydev) mdelay(500); - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) return err; @@ -663,7 +676,7 @@ static int m88e1116r_config_init(struct phy_device *phydev) if (err < 0) return err; - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 2); + err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); if (err < 0) return err; temp = phy_read(phydev, MII_M1116R_CONTROL_REG_MAC); @@ -672,7 +685,7 @@ static int m88e1116r_config_init(struct phy_device *phydev) err = phy_write(phydev, MII_M1116R_CONTROL_REG_MAC, temp); if (err < 0) return err; - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) return err; @@ -706,103 +719,129 @@ static int m88e3016_config_init(struct phy_device *phydev) return marvell_config_init(phydev); } -static int m88e1111_config_init(struct phy_device *phydev) +static int m88e1111_config_init_rgmii(struct phy_device *phydev) { int err; int temp; - if (phy_interface_is_rgmii(phydev)) { + temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); + if (temp < 0) + return temp; - temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); - if (temp < 0) - return temp; + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { + temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); + } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { + temp &= ~MII_M1111_TX_DELAY; + temp |= MII_M1111_RX_DELAY; + } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { + temp &= ~MII_M1111_RX_DELAY; + temp |= MII_M1111_TX_DELAY; + } - if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { - temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); - } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { - temp &= ~MII_M1111_TX_DELAY; - temp |= MII_M1111_RX_DELAY; - } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { - temp &= ~MII_M1111_RX_DELAY; - temp |= MII_M1111_TX_DELAY; - } + err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); + if (err < 0) + return err; - err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); - if (err < 0) - return err; + temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); + if (temp < 0) + return temp; - temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); - if (temp < 0) - return temp; + temp &= ~(MII_M1111_HWCFG_MODE_MASK); - temp &= ~(MII_M1111_HWCFG_MODE_MASK); + if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES) + temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII; + else + temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII; - if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES) - temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII; - else - temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII; + return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); +} - err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); - if (err < 0) - return err; - } +static int m88e1111_config_init_sgmii(struct phy_device *phydev) +{ + int err; + int temp; - if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { - temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); - if (temp < 0) - return temp; + temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); + if (temp < 0) + return temp; - temp &= ~(MII_M1111_HWCFG_MODE_MASK); - temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK; - temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; + temp &= ~(MII_M1111_HWCFG_MODE_MASK); + temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK; + temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; - err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); - if (err < 0) - return err; + err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); + if (err < 0) + return err; - /* make sure copper is selected */ - err = phy_read(phydev, MII_M1145_PHY_EXT_ADDR_PAGE); - if (err < 0) - return err; + /* make sure copper is selected */ + return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); +} - err = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, - err & (~0xff)); - if (err < 0) - return err; - } +static int m88e1111_config_init_rtbi(struct phy_device *phydev) +{ + int err; + int temp; - if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { - temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); - if (temp < 0) - return temp; - temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); - err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); - if (err < 0) - return err; + temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); + if (temp < 0) + return temp; - temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); - if (temp < 0) - return temp; - temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES); - temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO; - err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); - if (err < 0) + temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY); + err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); + if (err < 0) + return err; + + temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); + if (temp < 0) + return temp; + + temp &= ~(MII_M1111_HWCFG_MODE_MASK | + MII_M1111_HWCFG_FIBER_COPPER_RES); + temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO; + + err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); + if (err < 0) + return err; + + /* soft reset */ + err = phy_write(phydev, MII_BMCR, BMCR_RESET); + if (err < 0) + return err; + + do + temp = phy_read(phydev, MII_BMCR); + while (temp & BMCR_RESET); + + temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); + if (temp < 0) + return temp; + + temp &= ~(MII_M1111_HWCFG_MODE_MASK | + MII_M1111_HWCFG_FIBER_COPPER_RES); + temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | + MII_M1111_HWCFG_FIBER_COPPER_AUTO; + + return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); +} + +static int m88e1111_config_init(struct phy_device *phydev) +{ + int err; + + if (phy_interface_is_rgmii(phydev)) { + err = m88e1111_config_init_rgmii(phydev); + if (err) return err; + } - /* soft reset */ - err = phy_write(phydev, MII_BMCR, BMCR_RESET); + if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { + err = m88e1111_config_init_sgmii(phydev); if (err < 0) return err; - do - temp = phy_read(phydev, MII_BMCR); - while (temp & BMCR_RESET); + } - temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); - if (temp < 0) - return temp; - temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES); - temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | MII_M1111_HWCFG_FIBER_COPPER_AUTO; - err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); + if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { + err = m88e1111_config_init_rtbi(phydev); if (err < 0) return err; } @@ -818,11 +857,9 @@ static int m88e1121_config_init(struct phy_device *phydev) { int err, oldpage; - oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); - - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE); - if (err < 0) - return err; + oldpage = marvell_get_set_page(phydev, MII_MARVELL_LED_PAGE); + if (oldpage < 0) + return oldpage; /* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */ err = phy_write(phydev, MII_88E1121_PHY_LED_CTRL, @@ -830,7 +867,7 @@ static int m88e1121_config_init(struct phy_device *phydev) if (err < 0) return err; - phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); + marvell_set_page(phydev, oldpage); /* Set marvell,reg-init configuration from device tree */ return marvell_config_init(phydev); @@ -844,7 +881,7 @@ static int m88e1510_config_init(struct phy_device *phydev) /* SGMII-to-Copper mode initialization */ if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { /* Select page 18 */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 18); + err = marvell_set_page(phydev, 18); if (err < 0) return err; @@ -863,7 +900,7 @@ static int m88e1510_config_init(struct phy_device *phydev) return err; /* Reset page selection */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) return err; } @@ -893,7 +930,7 @@ static int m88e1118_config_init(struct phy_device *phydev) int err; /* Change address */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002); + err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); if (err < 0) return err; @@ -903,7 +940,7 @@ static int m88e1118_config_init(struct phy_device *phydev) return err; /* Change address */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0003); + err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE); if (err < 0) return err; @@ -920,7 +957,7 @@ static int m88e1118_config_init(struct phy_device *phydev) return err; /* Reset address */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) return err; @@ -932,7 +969,7 @@ static int m88e1149_config_init(struct phy_device *phydev) int err; /* Change address */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002); + err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE); if (err < 0) return err; @@ -946,17 +983,70 @@ static int m88e1149_config_init(struct phy_device *phydev) return err; /* Reset address */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) return err; return phy_write(phydev, MII_BMCR, BMCR_RESET); } +static int m88e1145_config_init_rgmii(struct phy_device *phydev) +{ + int err; + int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR); + + if (temp < 0) + return temp; + + temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY); + + err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp); + if (err < 0) + return err; + + if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) { + err = phy_write(phydev, 0x1d, 0x0012); + if (err < 0) + return err; + + temp = phy_read(phydev, 0x1e); + if (temp < 0) + return temp; + + temp &= 0xf03f; + temp |= 2 << 9; /* 36 ohm */ + temp |= 2 << 6; /* 39 ohm */ + + err = phy_write(phydev, 0x1e, temp); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1d, 0x3); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1e, 0x8000); + } + return err; +} + +static int m88e1145_config_init_sgmii(struct phy_device *phydev) +{ + int temp = phy_read(phydev, MII_M1145_PHY_EXT_SR); + + if (temp < 0) + return temp; + + temp &= ~MII_M1145_HWCFG_MODE_MASK; + temp |= MII_M1145_HWCFG_MODE_SGMII_NO_CLK; + temp |= MII_M1145_HWCFG_FIBER_COPPER_AUTO; + + return phy_write(phydev, MII_M1145_PHY_EXT_SR, temp); +} + static int m88e1145_config_init(struct phy_device *phydev) { int err; - int temp; /* Take care of errata E0 & E1 */ err = phy_write(phydev, 0x1d, 0x001b); @@ -976,53 +1066,13 @@ static int m88e1145_config_init(struct phy_device *phydev) return err; if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { - int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR); - if (temp < 0) - return temp; - - temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY); - - err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp); + err = m88e1145_config_init_rgmii(phydev); if (err < 0) return err; - - if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) { - err = phy_write(phydev, 0x1d, 0x0012); - if (err < 0) - return err; - - temp = phy_read(phydev, 0x1e); - if (temp < 0) - return temp; - - temp &= 0xf03f; - temp |= 2 << 9; /* 36 ohm */ - temp |= 2 << 6; /* 39 ohm */ - - err = phy_write(phydev, 0x1e, temp); - if (err < 0) - return err; - - err = phy_write(phydev, 0x1d, 0x3); - if (err < 0) - return err; - - err = phy_write(phydev, 0x1e, 0x8000); - if (err < 0) - return err; - } } if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { - temp = phy_read(phydev, MII_M1145_PHY_EXT_SR); - if (temp < 0) - return temp; - - temp &= ~MII_M1145_HWCFG_MODE_MASK; - temp |= MII_M1145_HWCFG_MODE_SGMII_NO_CLK; - temp |= MII_M1145_HWCFG_FIBER_COPPER_AUTO; - - err = phy_write(phydev, MII_M1145_PHY_EXT_SR, temp); + err = m88e1145_config_init_sgmii(phydev); if (err < 0) return err; } @@ -1065,7 +1115,8 @@ static int marvell_update_link(struct phy_device *phydev, int fiber) int status; /* Use the generic register for copper link, or specific - * register for fiber case */ + * register for fiber case + */ if (fiber) { status = phy_read(phydev, MII_M1011_PHY_STATUS); if (status < 0) @@ -1082,123 +1133,136 @@ static int marvell_update_link(struct phy_device *phydev, int fiber) return 0; } -/* marvell_read_status_page - * - * Description: - * Check the link, then figure out the current state - * by comparing what we advertise with what the link partner - * advertises. Start by checking the gigabit possibilities, - * then move on to 10/100. - */ -static int marvell_read_status_page(struct phy_device *phydev, int page) +static int marvell_read_status_page_an(struct phy_device *phydev, + int fiber) { - int adv; - int err; + int status; int lpa; int lpagb; - int status = 0; - int fiber; - - /* Detect and update the link, but return if there - * was an error */ - if (page == MII_M1111_FIBER) - fiber = 1; - else - fiber = 0; - err = marvell_update_link(phydev, fiber); - if (err) - return err; + status = phy_read(phydev, MII_M1011_PHY_STATUS); + if (status < 0) + return status; - if (AUTONEG_ENABLE == phydev->autoneg) { - status = phy_read(phydev, MII_M1011_PHY_STATUS); - if (status < 0) - return status; + lpa = phy_read(phydev, MII_LPA); + if (lpa < 0) + return lpa; - lpa = phy_read(phydev, MII_LPA); - if (lpa < 0) - return lpa; + lpagb = phy_read(phydev, MII_STAT1000); + if (lpagb < 0) + return lpagb; - lpagb = phy_read(phydev, MII_STAT1000); - if (lpagb < 0) - return lpagb; + if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; - adv = phy_read(phydev, MII_ADVERTISE); - if (adv < 0) - return adv; + status = status & MII_M1011_PHY_STATUS_SPD_MASK; + phydev->pause = 0; + phydev->asym_pause = 0; - if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) - phydev->duplex = DUPLEX_FULL; - else - phydev->duplex = DUPLEX_HALF; + switch (status) { + case MII_M1011_PHY_STATUS_1000: + phydev->speed = SPEED_1000; + break; - status = status & MII_M1011_PHY_STATUS_SPD_MASK; - phydev->pause = phydev->asym_pause = 0; + case MII_M1011_PHY_STATUS_100: + phydev->speed = SPEED_100; + break; - switch (status) { - case MII_M1011_PHY_STATUS_1000: - phydev->speed = SPEED_1000; - break; + default: + phydev->speed = SPEED_10; + break; + } - case MII_M1011_PHY_STATUS_100: - phydev->speed = SPEED_100; - break; + if (!fiber) { + phydev->lp_advertising = + mii_stat1000_to_ethtool_lpa_t(lpagb) | + mii_lpa_to_ethtool_lpa_t(lpa); - default: - phydev->speed = SPEED_10; - break; + if (phydev->duplex == DUPLEX_FULL) { + phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; + phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; } - - if (!fiber) { - phydev->lp_advertising = mii_stat1000_to_ethtool_lpa_t(lpagb) | - mii_lpa_to_ethtool_lpa_t(lpa); - - if (phydev->duplex == DUPLEX_FULL) { - phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; - phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; - } - } else { - /* The fiber link is only 1000M capable */ - phydev->lp_advertising = fiber_lpa_to_ethtool_lpa_t(lpa); - - if (phydev->duplex == DUPLEX_FULL) { - if (!(lpa & LPA_PAUSE_FIBER)) { - phydev->pause = 0; - phydev->asym_pause = 0; - } else if ((lpa & LPA_PAUSE_ASYM_FIBER)) { - phydev->pause = 1; - phydev->asym_pause = 1; - } else { - phydev->pause = 1; - phydev->asym_pause = 0; - } + } else { + /* The fiber link is only 1000M capable */ + phydev->lp_advertising = fiber_lpa_to_ethtool_lpa_t(lpa); + + if (phydev->duplex == DUPLEX_FULL) { + if (!(lpa & LPA_PAUSE_FIBER)) { + phydev->pause = 0; + phydev->asym_pause = 0; + } else if ((lpa & LPA_PAUSE_ASYM_FIBER)) { + phydev->pause = 1; + phydev->asym_pause = 1; + } else { + phydev->pause = 1; + phydev->asym_pause = 0; } } - } else { - int bmcr = phy_read(phydev, MII_BMCR); + } + return 0; +} - if (bmcr < 0) - return bmcr; +static int marvell_read_status_page_fixed(struct phy_device *phydev) +{ + int bmcr = phy_read(phydev, MII_BMCR); - if (bmcr & BMCR_FULLDPLX) - phydev->duplex = DUPLEX_FULL; - else - phydev->duplex = DUPLEX_HALF; + if (bmcr < 0) + return bmcr; - if (bmcr & BMCR_SPEED1000) - phydev->speed = SPEED_1000; - else if (bmcr & BMCR_SPEED100) - phydev->speed = SPEED_100; - else - phydev->speed = SPEED_10; + if (bmcr & BMCR_FULLDPLX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; - phydev->pause = phydev->asym_pause = 0; - phydev->lp_advertising = 0; - } + if (bmcr & BMCR_SPEED1000) + phydev->speed = SPEED_1000; + else if (bmcr & BMCR_SPEED100) + phydev->speed = SPEED_100; + else + phydev->speed = SPEED_10; + + phydev->pause = 0; + phydev->asym_pause = 0; + phydev->lp_advertising = 0; return 0; } +/* marvell_read_status_page + * + * Description: + * Check the link, then figure out the current state + * by comparing what we advertise with what the link partner + * advertises. Start by checking the gigabit possibilities, + * then move on to 10/100. + */ +static int marvell_read_status_page(struct phy_device *phydev, int page) +{ + int fiber; + int err; + + /* Detect and update the link, but return if there + * was an error + */ + if (page == MII_MARVELL_FIBER_PAGE) + fiber = 1; + else + fiber = 0; + + err = marvell_update_link(phydev, fiber); + if (err) + return err; + + if (phydev->autoneg == AUTONEG_ENABLE) + err = marvell_read_status_page_an(phydev, fiber); + else + err = marvell_read_status_page_fixed(phydev); + + return err; +} + /* marvell_read_status * * Some Marvell's phys have two modes: fiber and copper. @@ -1215,33 +1279,34 @@ static int marvell_read_status(struct phy_device *phydev) /* Check the fiber mode first */ if (phydev->supported & SUPPORTED_FIBRE && phydev->interface != PHY_INTERFACE_MODE_SGMII) { - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER); + err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; - err = marvell_read_status_page(phydev, MII_M1111_FIBER); + err = marvell_read_status_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; - /* If the fiber link is up, it is the selected and used link. - * In this case, we need to stay in the fiber page. - * Please to be careful about that, avoid to restore Copper page - * in other functions which could break the behaviour - * for some fiber phy like 88E1512. - * */ + /* If the fiber link is up, it is the selected and + * used link. In this case, we need to stay in the + * fiber page. Please to be careful about that, avoid + * to restore Copper page in other functions which + * could break the behaviour for some fiber phy like + * 88E1512. + */ if (phydev->link) return 0; /* If fiber link is down, check and save copper mode state */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) goto error; } - return marvell_read_status_page(phydev, MII_M1111_COPPER); + return marvell_read_status_page(phydev, MII_MARVELL_COPPER_PAGE); error: - phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); return err; } @@ -1256,7 +1321,7 @@ static int marvell_suspend(struct phy_device *phydev) /* Suspend the fiber mode first */ if (!(phydev->supported & SUPPORTED_FIBRE)) { - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER); + err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; @@ -1266,7 +1331,7 @@ static int marvell_suspend(struct phy_device *phydev) goto error; /* Then, the copper link */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) goto error; } @@ -1275,7 +1340,7 @@ static int marvell_suspend(struct phy_device *phydev) return genphy_suspend(phydev); error: - phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); return err; } @@ -1290,7 +1355,7 @@ static int marvell_resume(struct phy_device *phydev) /* Resume the fiber mode first */ if (!(phydev->supported & SUPPORTED_FIBRE)) { - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER); + err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; @@ -1300,7 +1365,7 @@ static int marvell_resume(struct phy_device *phydev) goto error; /* Then, the copper link */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) goto error; } @@ -1309,13 +1374,14 @@ static int marvell_resume(struct phy_device *phydev) return genphy_resume(phydev); error: - phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER); + marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); return err; } static int marvell_aneg_done(struct phy_device *phydev) { int retval = phy_read(phydev, MII_M1011_PHY_STATUS); + return (retval < 0) ? retval : (retval & MII_M1011_PHY_STATUS_RESOLVED); } @@ -1331,32 +1397,33 @@ static int m88e1121_did_interrupt(struct phy_device *phydev) return 0; } -static void m88e1318_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) +static void m88e1318_get_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) { wol->supported = WAKE_MAGIC; wol->wolopts = 0; - if (phy_write(phydev, MII_MARVELL_PHY_PAGE, - MII_88E1318S_PHY_WOL_PAGE) < 0) + if (marvell_set_page(phydev, MII_MARVELL_WOL_PAGE) < 0) return; if (phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL) & MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE) wol->wolopts |= WAKE_MAGIC; - if (phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00) < 0) + if (marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE) < 0) return; } -static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) +static int m88e1318_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) { int err, oldpage, temp; - oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); + oldpage = marvell_get_page(phydev); if (wol->wolopts & WAKE_MAGIC) { /* Explicitly switch to page 0x00, just to be sure */ - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00); + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) return err; @@ -1367,8 +1434,7 @@ static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *w if (err < 0) return err; - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, - MII_88E1318S_PHY_LED_PAGE); + err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE); if (err < 0) return err; @@ -1381,8 +1447,7 @@ static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *w if (err < 0) return err; - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, - MII_88E1318S_PHY_WOL_PAGE); + err = marvell_set_page(phydev, MII_MARVELL_WOL_PAGE); if (err < 0) return err; @@ -1411,8 +1476,7 @@ static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *w if (err < 0) return err; } else { - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, - MII_88E1318S_PHY_WOL_PAGE); + err = marvell_set_page(phydev, MII_MARVELL_WOL_PAGE); if (err < 0) return err; @@ -1425,7 +1489,7 @@ static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *w return err; } - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); + err = marvell_set_page(phydev, oldpage); if (err < 0) return err; @@ -1457,13 +1521,11 @@ static u64 marvell_get_stat(struct phy_device *phydev, int i) { struct marvell_hw_stat stat = marvell_hw_stats[i]; struct marvell_priv *priv = phydev->priv; - int err, oldpage, val; + int oldpage, val; u64 ret; - oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); - err = phy_write(phydev, MII_MARVELL_PHY_PAGE, - stat.page); - if (err < 0) + oldpage = marvell_get_set_page(phydev, stat.page); + if (oldpage < 0) return UINT64_MAX; val = phy_read(phydev, stat.reg); @@ -1475,7 +1537,7 @@ static u64 marvell_get_stat(struct phy_device *phydev, int i) ret = priv->stats[i]; } - phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); + marvell_set_page(phydev, oldpage); return ret; } @@ -1492,6 +1554,7 @@ static void marvell_get_stats(struct phy_device *phydev, #ifdef CONFIG_HWMON static int m88e1121_get_temp(struct phy_device *phydev, long *temp) { + int oldpage; int ret; int val; @@ -1499,9 +1562,11 @@ static int m88e1121_get_temp(struct phy_device *phydev, long *temp) mutex_lock(&phydev->lock); - ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6); - if (ret < 0) - goto error; + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); + if (oldpage < 0) { + mutex_unlock(&phydev->lock); + return oldpage; + } /* Enable temperature sensor */ ret = phy_read(phydev, MII_88E1121_MISC_TEST); @@ -1531,7 +1596,7 @@ static int m88e1121_get_temp(struct phy_device *phydev, long *temp) *temp = ((val & MII_88E1121_MISC_TEST_TEMP_MASK) - 5) * 5000; error: - phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0); + marvell_set_page(phydev, oldpage); mutex_unlock(&phydev->lock); return ret; @@ -1608,15 +1673,18 @@ static const struct hwmon_chip_info m88e1121_hwmon_chip_info = { static int m88e1510_get_temp(struct phy_device *phydev, long *temp) { + int oldpage; int ret; *temp = 0; mutex_lock(&phydev->lock); - ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6); - if (ret < 0) - goto error; + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); + if (oldpage < 0) { + mutex_unlock(&phydev->lock); + return oldpage; + } ret = phy_read(phydev, MII_88E1510_TEMP_SENSOR); if (ret < 0) @@ -1625,23 +1693,26 @@ static int m88e1510_get_temp(struct phy_device *phydev, long *temp) *temp = ((ret & MII_88E1510_TEMP_SENSOR_MASK) - 25) * 1000; error: - phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0); + marvell_set_page(phydev, oldpage); mutex_unlock(&phydev->lock); return ret; } -int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp) +static int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp) { + int oldpage; int ret; *temp = 0; mutex_lock(&phydev->lock); - ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6); - if (ret < 0) - goto error; + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); + if (oldpage < 0) { + mutex_unlock(&phydev->lock); + return oldpage; + } ret = phy_read(phydev, MII_88E1121_MISC_TEST); if (ret < 0) @@ -1653,21 +1724,24 @@ int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp) *temp *= 1000; error: - phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0); + marvell_set_page(phydev, oldpage); mutex_unlock(&phydev->lock); return ret; } -int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) +static int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) { + int oldpage; int ret; mutex_lock(&phydev->lock); - ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6); - if (ret < 0) - goto error; + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); + if (oldpage < 0) { + mutex_unlock(&phydev->lock); + return oldpage; + } ret = phy_read(phydev, MII_88E1121_MISC_TEST); if (ret < 0) @@ -1680,23 +1754,26 @@ int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) (temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT)); error: - phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0); + marvell_set_page(phydev, oldpage); mutex_unlock(&phydev->lock); return ret; } -int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) +static int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) { + int oldpage; int ret; *alarm = false; mutex_lock(&phydev->lock); - ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6); - if (ret < 0) - goto error; + oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); + if (oldpage < 0) { + mutex_unlock(&phydev->lock); + return oldpage; + } ret = phy_read(phydev, MII_88E1121_MISC_TEST); if (ret < 0) @@ -1704,7 +1781,7 @@ int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) *alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ); error: - phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0); + marvell_set_page(phydev, oldpage); mutex_unlock(&phydev->lock); return ret; @@ -2094,6 +2171,7 @@ static struct phy_driver marvell_drivers[] = { .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, + .set_loopback = genphy_loopback, }, { .phy_id = MARVELL_PHY_ID_88E1540, |