From 9cfd98c804906e4233650780271426825d2e4edb Mon Sep 17 00:00:00 2001 From: Samin Guo Date: Tue, 1 Nov 2022 19:03:46 +0800 Subject: [PATCH] net:phy:motorcomm: support modifying RGMII_TX_CLK delay train from dts support use original or inverted RGMII_TX_CLK delay train. 10M/100M/1000M can be configured independently. tx_inverted_xx = val; for example: &gmac0 { #address-cells = <1>; #size-cells = <0>; phy0: ethernet-phy@0 { tx_inverted_10 = <0>; tx_inverted_100 = <1>; tx_inverted_1000 = <1>; }; }; 0: original (default) 1: inverted Signed-off-by: Samin Guo --- drivers/net/phy/motorcomm.c | 113 ++++++++++++++++++++++++++++++++---- 1 file changed, 102 insertions(+), 11 deletions(-) diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index 6149e7984558..cdebebf37609 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -143,6 +143,8 @@ #define YTPHY_EXTREG_CHIP_CONFIG 0xa001 #define YTPHY_EXTREG_RGMII_CONFIG1 0xa003 +#define YTPHY_PAD_DRIVES_STRENGTH_CFG 0xa010 +#define YTPHY_RGMII_SW_DR_MASK GENMASK(5, 4) enum ytphy_wol_feature_trigger_type_e { YTPHY_WOL_FEATURE_PULSE_TRIGGER, @@ -204,12 +206,24 @@ struct ytphy_reg_field { const u8 dflt; /* Default value */ }; +struct ytphy_priv_t { + u32 tx_inverted_1000; + u32 tx_inverted_100; + u32 tx_inverted_10; +}; + static const struct ytphy_reg_field ytphy_rxtxd_grp[] = { { "rx_delay_sel", 4, 10, 0x0 }, { "tx_delay_sel_fe", 4, 4, 0xf }, { "tx_delay_sel", 4, 0, 0x1 } }; +static const struct ytphy_reg_field ytphy_txinver_grp[] = { + { "tx_inverted_1000", 1, 14, 0x0 }, + { "tx_inverted_100", 1, 14, 0x0 }, + { "tx_inverted_10", 1, 14, 0x0 } +}; + static const struct ytphy_reg_field ytphy_rxden_grp[] = { { "rxc_dly_en", 1, 8, 0x1 } }; @@ -785,26 +799,35 @@ static int yt8521_hw_strap_polling(struct phy_device *phydev) } } -static int ytphy_of_config(struct phy_device *phydev) +static struct device_node *ytphy_get_of_node(struct phy_device *phydev) { + struct device *dev = &phydev->mdio.dev; const struct device_node *of_node; - const struct device *dev; - u32 val; - u32 cfg; - int ret; int i = 0; - dev = &phydev->mdio.dev; do { of_node = dev->of_node; dev = dev->parent; if (i++ > 5) { phydev_err(phydev, "Get of node timeout\n"); - return -EINVAL; + return NULL; } } while (!of_node && dev); - of_node = of_node->child; + return of_node->child; +} + +static int ytphy_of_config(struct phy_device *phydev) +{ + const struct device_node *of_node; + const struct device *dev; + u32 val; + u32 cfg; + int ret; + int i; + + dev = &phydev->mdio.dev; + of_node = ytphy_get_of_node(phydev); if (of_node) { ret = of_property_read_u32(of_node, ytphy_rxden_grp[0].name, &cfg); if (!ret) { @@ -818,6 +841,10 @@ static int ytphy_of_config(struct phy_device *phydev) ytphy_write_ext(phydev, YTPHY_EXTREG_CHIP_CONFIG, val); } + val = ytphy_read_ext(phydev, YTPHY_PAD_DRIVES_STRENGTH_CFG); + val |= YTPHY_RGMII_SW_DR_MASK; + ytphy_write_ext(phydev, YTPHY_PAD_DRIVES_STRENGTH_CFG, val); + val = ytphy_read_ext(phydev, YTPHY_EXTREG_RGMII_CONFIG1); for (i = 0; i < ARRAY_SIZE(ytphy_rxtxd_grp); i++) { ret = of_property_read_u32(of_node, ytphy_rxtxd_grp[i].name, &cfg); @@ -834,7 +861,6 @@ static int ytphy_of_config(struct phy_device *phydev) } return ytphy_write_ext(phydev, YTPHY_EXTREG_RGMII_CONFIG1, val); } - phydev_err(phydev, "Get of node fail\n"); return -EINVAL; } @@ -1125,6 +1151,71 @@ static int yt8531S_config_init(struct phy_device *phydev) return ret; } +static int yt8531_read_status(struct phy_device *phydev) +{ + int ret; + u32 val; + struct ytphy_priv_t *ytphy_priv = phydev->priv; + + val = ytphy_read_ext(phydev, YTPHY_EXTREG_RGMII_CONFIG1); + ret = genphy_read_status(phydev); + if (ret) + return ret; + + switch (phydev->speed) { + case SPEED_1000: + val = bitfield_replace(val, ytphy_txinver_grp[0].off, + ytphy_txinver_grp[0].size, + ytphy_priv->tx_inverted_1000); + break; + case SPEED_100: + val = bitfield_replace(val, ytphy_txinver_grp[1].off, + ytphy_txinver_grp[1].size, + ytphy_priv->tx_inverted_100); + break; + case SPEED_10: + val = bitfield_replace(val, ytphy_txinver_grp[2].off, + ytphy_txinver_grp[2].size, + ytphy_priv->tx_inverted_10); + break; + default: + break; + } + ret = ytphy_write_ext(phydev, YTPHY_EXTREG_RGMII_CONFIG1, val); + return ret; +} + +static int yt8531_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct ytphy_priv_t *priv; + const struct device_node *of_node; + u32 val; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + of_node = ytphy_get_of_node(phydev); + if (of_node) { + ret = of_property_read_u32(of_node, ytphy_txinver_grp[0].name, &val); + if (!ret) + priv->tx_inverted_1000 = val; + + ret = of_property_read_u32(of_node, ytphy_txinver_grp[1].name, &val); + if (!ret) + priv->tx_inverted_100 = val; + + ret = of_property_read_u32(of_node, ytphy_txinver_grp[2].name, &val); + if (!ret) + priv->tx_inverted_10 = val; + + } + phydev->priv = priv; + return 0; +} + static int yt8531_config_init(struct phy_device *phydev) { int ret; @@ -2097,10 +2188,10 @@ static struct phy_driver ytphy_drvs[] = { .phy_id_mask = MOTORCOMM_PHY_ID_MASK, .features = PHY_GBIT_FEATURES, .flags = PHY_POLL, + .probe = yt8531_probe, .config_aneg = genphy_config_aneg, - .config_init = yt8531_config_init, - .read_status = genphy_read_status, + .read_status = yt8531_read_status, .suspend = genphy_suspend, .resume = genphy_resume, #if (YTPHY_WOL_FEATURE_ENABLE) -- 2.34.1