diff options
Diffstat (limited to 'drivers/net/phy/realtek.c')
-rw-r--r-- | drivers/net/phy/realtek.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index d6a10f323117..cfbc0ca61123 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -23,11 +23,15 @@ #define RTL821x_INSR 0x13 +#define RTL821x_EXT_PAGE_SELECT 0x1e #define RTL821x_PAGE_SELECT 0x1f #define RTL8211F_INSR 0x1d #define RTL8211F_TX_DELAY BIT(8) +#define RTL8211E_TX_DELAY BIT(1) +#define RTL8211E_RX_DELAY BIT(2) +#define RTL8211E_MODE_MII_GMII BIT(3) #define RTL8201F_ISR 0x1e #define RTL8201F_IER 0x13 @@ -167,6 +171,52 @@ static int rtl8211f_config_init(struct phy_device *phydev) return phy_modify_paged(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY, val); } +static int rtl8211e_config_init(struct phy_device *phydev) +{ + int ret = 0, oldpage; + u16 val; + + /* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */ + switch (phydev->interface) { + case PHY_INTERFACE_MODE_RGMII: + val = 0; + break; + case PHY_INTERFACE_MODE_RGMII_ID: + val = RTL8211E_TX_DELAY | RTL8211E_RX_DELAY; + break; + case PHY_INTERFACE_MODE_RGMII_RXID: + val = RTL8211E_RX_DELAY; + break; + case PHY_INTERFACE_MODE_RGMII_TXID: + val = RTL8211E_TX_DELAY; + break; + default: /* the rest of the modes imply leaving delays as is. */ + return 0; + } + + /* According to a sample driver there is a 0x1c config register on the + * 0xa4 extension page (0x7) layout. It can be used to disable/enable + * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins. It can + * also be used to customize the whole configuration register: + * 8:6 = PHY Address, 5:4 = Auto-Negotiation, 3 = Interface Mode Select, + * 2 = RX Delay, 1 = TX Delay, 0 = SELRGV (see original PHY datasheet + * for details). + */ + oldpage = phy_select_page(phydev, 0x7); + if (oldpage < 0) + goto err_restore_page; + + ret = phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4); + if (ret) + goto err_restore_page; + + ret = phy_modify(phydev, 0x1c, RTL8211E_TX_DELAY | RTL8211E_RX_DELAY, + val); + +err_restore_page: + return phy_restore_page(phydev, oldpage, ret); +} + static int rtl8211b_suspend(struct phy_device *phydev) { phy_write(phydev, MII_MMD_DATA, BIT(9)); @@ -239,6 +289,7 @@ static struct phy_driver realtek_drvs[] = { }, { PHY_ID_MATCH_EXACT(0x001cc915), .name = "RTL8211E Gigabit Ethernet", + .config_init = &rtl8211e_config_init, .ack_interrupt = &rtl821x_ack_interrupt, .config_intr = &rtl8211e_config_intr, .suspend = genphy_suspend, |