diff options
-rw-r--r-- | drivers/net/phy/micrel.c | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 9c21508332dc..2c114bac90b7 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -646,6 +646,70 @@ static int ksz9131_of_load_skew_values(struct phy_device *phydev, return ksz9031_extended_write(phydev, OP_DATA, 2, reg, newval); } +#define KSZ9131RN_MMD_COMMON_CTRL_REG 2 +#define KSZ9131RN_RXC_DLL_CTRL 76 +#define KSZ9131RN_TXC_DLL_CTRL 77 +#define KSZ9131RN_DLL_CTRL_BYPASS BIT_MASK(12) +#define KSZ9131RN_DLL_ENABLE_DELAY 0 +#define KSZ9131RN_DLL_DISABLE_DELAY BIT(12) + +static int ksz9131_config_rgmii_delay(struct phy_device *phydev) +{ + u16 rxcdll_val, txcdll_val; + int new, ret; + + switch (phydev->interface) { + case PHY_INTERFACE_MODE_RGMII: + rxcdll_val = KSZ9131RN_DLL_DISABLE_DELAY; + txcdll_val = KSZ9131RN_DLL_DISABLE_DELAY; + break; + case PHY_INTERFACE_MODE_RGMII_ID: + rxcdll_val = KSZ9131RN_DLL_ENABLE_DELAY; + txcdll_val = KSZ9131RN_DLL_ENABLE_DELAY; + break; + case PHY_INTERFACE_MODE_RGMII_RXID: + rxcdll_val = KSZ9131RN_DLL_ENABLE_DELAY; + txcdll_val = KSZ9131RN_DLL_DISABLE_DELAY; + break; + case PHY_INTERFACE_MODE_RGMII_TXID: + rxcdll_val = KSZ9131RN_DLL_DISABLE_DELAY; + txcdll_val = KSZ9131RN_DLL_ENABLE_DELAY; + break; + default: + return 0; + } + + ret = phy_read_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG, + KSZ9131RN_RXC_DLL_CTRL); + if (ret < 0) + return ret; + + new = (ret & ~KSZ9131RN_DLL_CTRL_BYPASS) | rxcdll_val; + + if (new != ret) { + ret = phy_write_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG, + KSZ9131RN_RXC_DLL_CTRL, new); + if (ret < 0) + return ret; + } + + ret = phy_read_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG, + KSZ9131RN_TXC_DLL_CTRL); + if (ret < 0) + return ret; + + new = (ret & ~KSZ9131RN_DLL_CTRL_BYPASS) | txcdll_val; + + if (new != ret) { + ret = phy_write_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG, + KSZ9131RN_TXC_DLL_CTRL, new); + if (ret < 0) + return ret; + } + + return 0; +} + static int ksz9131_config_init(struct phy_device *phydev) { const struct device *dev = &phydev->mdio.dev; @@ -672,6 +736,12 @@ static int ksz9131_config_init(struct phy_device *phydev) if (!of_node) return 0; + if (phy_interface_is_rgmii(phydev)) { + ret = ksz9131_config_rgmii_delay(phydev); + if (ret < 0) + return ret; + } + ret = ksz9131_of_load_skew_values(phydev, of_node, MII_KSZ9031RN_CLK_PAD_SKEW, 5, clk_skews, 2); |