diff options
Diffstat (limited to 'drivers/net/phy')
-rw-r--r-- | drivers/net/phy/Kconfig | 10 | ||||
-rw-r--r-- | drivers/net/phy/mscc.c | 56 | ||||
-rw-r--r-- | drivers/net/phy/realtek.c | 69 |
3 files changed, 99 insertions, 36 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 68ee7d7a2d..e69cd8a4b3 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -214,16 +214,6 @@ config PHY_NXP_C45_TJA11XX config PHY_REALTEK bool "Realtek Ethernet PHYs support" -config RTL8211E_PINE64_GIGABIT_FIX - bool "Fix gigabit throughput on some Pine64+ models" - depends on PHY_REALTEK - help - Configure the Realtek RTL8211E found on some Pine64+ models differently to - fix throughput on Gigabit links, turning off all internal delays in the - process. The settings that this touches are not documented in the CONFREG - section of the RTL8211E datasheet, but come from Realtek by way of the - Pine64 engineering team. - config RTL8211X_PHY_FORCE_MASTER bool "Ethernet PHY RTL8211x: force 1000BASE-T master mode" depends on PHY_REALTEK diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index d1a643cf5a..f9482b21a0 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -19,6 +19,7 @@ /* Microsemi PHY ID's */ #define PHY_ID_VSC8530 0x00070560 #define PHY_ID_VSC8531 0x00070570 +#define PHY_ID_VSC8502 0x00070630 #define PHY_ID_VSC8540 0x00070760 #define PHY_ID_VSC8541 0x00070770 #define PHY_ID_VSC8574 0x000704a0 @@ -1513,6 +1514,50 @@ static int vsc8584_config(struct phy_device *phydev) return vsc8584_config_init(phydev); } +static int vsc8502_config(struct phy_device *phydev) +{ + bool rgmii_rx_delay = false, rgmii_tx_delay = false; + u16 reg = 0; + int ret; + + /* Assume nothing needs to be done for the default GMII/MII mode */ + if (!phy_interface_is_rgmii(phydev)) + return 0; + + /* Set Extended PHY Control 1 register to RGMII */ + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_EXT_PHY_CNTL_1_REG, + BIT(13) | BIT(12)); + + /* Soft reset required after changing PHY mode from the default + * of GMII/MII + */ + ret = mscc_phy_soft_reset(phydev); + if (ret) + return ret; + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + rgmii_rx_delay = true; + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + rgmii_tx_delay = true; + + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_EXT2); + + if (rgmii_rx_delay) + reg |= VSC_PHY_RGMII_DELAY_2000_PS << RGMII_RX_CLK_DELAY_POS; + if (rgmii_tx_delay) + reg |= VSC_PHY_RGMII_DELAY_2000_PS << RGMII_TX_CLK_DELAY_POS; + + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg); + + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_STD); + + return 0; +} + static struct phy_driver VSC8530_driver = { .name = "Microsemi VSC8530", .uid = PHY_ID_VSC8530, @@ -1533,6 +1578,16 @@ static struct phy_driver VSC8531_driver = { .shutdown = &genphy_shutdown, }; +static struct phy_driver VSC8502_driver = { + .name = "Microsemi VSC8502", + .uid = PHY_ID_VSC8502, + .mask = 0x000ffff0, + .features = PHY_GBIT_FEATURES, + .config = &vsc8502_config, + .startup = &mscc_startup, + .shutdown = &genphy_shutdown, +}; + static struct phy_driver VSC8540_driver = { .name = "Microsemi VSC8540", .uid = PHY_ID_VSC8540, @@ -1577,6 +1632,7 @@ int phy_mscc_init(void) { phy_register(&VSC8530_driver); phy_register(&VSC8531_driver); + phy_register(&VSC8502_driver); phy_register(&VSC8540_driver); phy_register(&VSC8541_driver); phy_register(&VSC8574_driver); diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index b1b1fa5080..24c3ea59bb 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -12,7 +12,6 @@ #include <linux/delay.h> #define PHY_RTL8211x_FORCE_MASTER BIT(1) -#define PHY_RTL8211E_PINE64_GIGABIT_FIX BIT(2) #define PHY_RTL8211F_FORCE_EEE_RXC_ON BIT(3) #define PHY_RTL8201F_S700_RMII_TIMINGS BIT(4) @@ -49,10 +48,10 @@ #define MIIM_RTL8211F_PHYSTAT_SPDDONE 0x0800 #define MIIM_RTL8211F_PHYSTAT_LINK 0x0004 -#define MIIM_RTL8211E_CONFREG 0x1c -#define MIIM_RTL8211E_CONFREG_TXD 0x0002 -#define MIIM_RTL8211E_CONFREG_RXD 0x0004 -#define MIIM_RTL8211E_CONFREG_MAGIC 0xb400 /* Undocumented */ +#define MIIM_RTL8211E_CONFREG 0x1c +#define MIIM_RTL8211E_CTRL_DELAY BIT(13) +#define MIIM_RTL8211E_TX_DELAY BIT(12) +#define MIIM_RTL8211E_RX_DELAY BIT(11) #define MIIM_RTL8211E_EXT_PAGE_SELECT 0x1e @@ -108,10 +107,6 @@ static int rtl8211b_probe(struct phy_device *phydev) static int rtl8211e_probe(struct phy_device *phydev) { -#ifdef CONFIG_RTL8211E_PINE64_GIGABIT_FIX - phydev->flags |= PHY_RTL8211E_PINE64_GIGABIT_FIX; -#endif - return 0; } @@ -154,22 +149,6 @@ static int rtl8211x_config(struct phy_device *phydev) reg |= MIIM_RTL8211x_CTRL1000T_MASTER; phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, reg); } - if (phydev->flags & PHY_RTL8211E_PINE64_GIGABIT_FIX) { - unsigned int reg; - - phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, - 7); - phy_write(phydev, MDIO_DEVAD_NONE, - MIIM_RTL8211E_EXT_PAGE_SELECT, 0xa4); - reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG); - /* Ensure both internal delays are turned off */ - reg &= ~(MIIM_RTL8211E_CONFREG_TXD | MIIM_RTL8211E_CONFREG_RXD); - /* Flip the magic undocumented bits */ - reg |= MIIM_RTL8211E_CONFREG_MAGIC; - phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG, reg); - phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, - 0); - } /* read interrupt status just to clear it */ phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER); @@ -201,6 +180,44 @@ static int rtl8201f_config(struct phy_device *phydev) return 0; } +static int rtl8211e_config(struct phy_device *phydev) +{ + int reg, val; + + /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */ + switch (phydev->interface) { + case PHY_INTERFACE_MODE_RGMII: + val = MIIM_RTL8211E_CTRL_DELAY; + break; + case PHY_INTERFACE_MODE_RGMII_ID: + val = MIIM_RTL8211E_CTRL_DELAY | MIIM_RTL8211E_TX_DELAY | + MIIM_RTL8211E_RX_DELAY; + break; + case PHY_INTERFACE_MODE_RGMII_RXID: + val = MIIM_RTL8211E_CTRL_DELAY | MIIM_RTL8211E_RX_DELAY; + break; + case PHY_INTERFACE_MODE_RGMII_TXID: + val = MIIM_RTL8211E_CTRL_DELAY | MIIM_RTL8211E_TX_DELAY; + break; + default: /* the rest of the modes imply leaving delays as is. */ + goto default_delay; + } + + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, 7); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_EXT_PAGE_SELECT, 0xa4); + + reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG); + reg &= ~(MIIM_RTL8211E_TX_DELAY | MIIM_RTL8211E_RX_DELAY); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG, reg | val); + + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT, 0); + +default_delay: + genphy_config_aneg(phydev); + + return 0; +} + static int rtl8211f_config(struct phy_device *phydev) { u16 reg; @@ -410,7 +427,7 @@ static struct phy_driver RTL8211E_driver = { .mask = 0xffffff, .features = PHY_GBIT_FEATURES, .probe = &rtl8211e_probe, - .config = &rtl8211x_config, + .config = &rtl8211e_config, .startup = &rtl8211e_startup, .shutdown = &genphy_shutdown, }; |