Port devicetree based clock select support from kernel micrel driver (v5.15-rc1). This support is needed to make netboot work on boards with PHY node and "rmii-ref" property. Signed-off-by: Oleksij Rempel <o.rempel@xxxxxxxxxxxxxx> --- drivers/net/phy/micrel.c | 101 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index ea193c84a7..958abdd9d6 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -14,6 +14,7 @@ #include <common.h> #include <init.h> +#include <linux/clk.h> #include <linux/mii.h> #include <linux/ethtool.h> #include <linux/phy.h> @@ -38,6 +39,10 @@ /* PHY Control 1 */ #define MII_KSZPHY_CTRL_1 0x1e +/* PHY Control 2 / PHY Control (if no PHY Control 1) */ +#define MII_KSZPHY_CTRL_2 0x1f +#define KSZPHY_RMII_REF_CLK_SEL BIT(7) + /* Write/read to/from extended registers */ #define MII_KSZPHY_EXTREG 0x0b #define KSZPHY_EXTREG_WRITE 0x8000 @@ -52,6 +57,20 @@ #define PS_TO_REG 200 +struct kszphy_type { + bool has_rmii_ref_clk_sel; +}; + +struct kszphy_priv { + const struct kszphy_type *type; + bool rmii_ref_clk_sel; + bool rmii_ref_clk_sel_val; +}; + +static const struct kszphy_type ksz8081_type = { + .has_rmii_ref_clk_sel = true, +}; + static int kszphy_extended_write(struct phy_device *phydev, u32 regnum, u16 val) { @@ -66,6 +85,22 @@ static int kszphy_extended_read(struct phy_device *phydev, return phy_read(phydev, MII_KSZPHY_EXTREG_READ); } +static int kszphy_rmii_clk_sel(struct phy_device *phydev, bool val) +{ + int ctrl; + + ctrl = phy_read(phydev, MII_KSZPHY_CTRL); + if (ctrl < 0) + return ctrl; + + if (val) + ctrl |= KSZPHY_RMII_REF_CLK_SEL; + else + ctrl &= ~KSZPHY_RMII_REF_CLK_SEL; + + return phy_write(phydev, MII_KSZPHY_CTRL, ctrl); +} + /* Handle LED mode, shift = position of first led mode bit, usually 4 or 14 */ static int kszphy_led_mode(struct phy_device *phydev, int reg, int shift) { @@ -83,6 +118,24 @@ static int kszphy_led_mode(struct phy_device *phydev, int reg, int shift) return 0; } +/* Some config bits need to be set again on resume, handle them here. */ +static int kszphy_config_reset(struct phy_device *phydev) +{ + struct kszphy_priv *priv = phydev->priv; + int ret; + + if (priv->rmii_ref_clk_sel) { + ret = kszphy_rmii_clk_sel(phydev, priv->rmii_ref_clk_sel_val); + if (ret) { + dev_err(&phydev->dev, + "failed to set rmii reference clock\n"); + return ret; + } + } + + return 0; +} + static int kszphy_config_init(struct phy_device *phydev) { kszphy_led_mode(phydev, MII_KSZPHY_CTRL_1, 14); @@ -96,7 +149,7 @@ static int ksz8021_config_init(struct phy_device *phydev) kszphy_led_mode(phydev, MII_KSZPHY_CTRL, 4); - return 0; + return kszphy_config_reset(phydev); } static int ks8051_config_init(struct phy_device *phydev) @@ -468,6 +521,50 @@ static int ksz8873mll_config_init(struct phy_device *phydev) return 0; } +static int kszphy_probe(struct phy_device *phydev) +{ + struct device_d *dev = &phydev->dev; + struct device_node *np = dev->device_node; + struct phy_driver *drv = to_phy_driver(dev->driver); + const struct kszphy_type *type = drv->driver_data; + struct kszphy_priv *priv; + struct clk *clk; + + priv = xzalloc(sizeof(*priv)); + + phydev->priv = priv; + + priv->type = type; + + clk = clk_get(dev, "rmii-ref"); + /* NOTE: clk may be NULL if building without CONFIG_HAVE_CLK */ + if (!IS_ERR_OR_NULL(clk)) { + unsigned long rate = clk_get_rate(clk); + bool rmii_ref_clk_sel_25_mhz; + + priv->rmii_ref_clk_sel = type->has_rmii_ref_clk_sel; + rmii_ref_clk_sel_25_mhz = of_property_read_bool(np, + "micrel,rmii-reference-clock-select-25-mhz"); + + if (rate > 24500000 && rate < 25500000) { + priv->rmii_ref_clk_sel_val = rmii_ref_clk_sel_25_mhz; + } else if (rate > 49500000 && rate < 50500000) { + priv->rmii_ref_clk_sel_val = !rmii_ref_clk_sel_25_mhz; + } else { + dev_err(dev, "Clock rate out of range: %ld\n", rate); + return -EINVAL; + } + } + + /* Support legacy board-file configuration */ + if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) { + priv->rmii_ref_clk_sel = true; + priv->rmii_ref_clk_sel_val = true; + } + + return 0; +} + static struct phy_driver ksphy_driver[] = { { .phy_id = PHY_ID_KS8737, @@ -517,7 +614,9 @@ static struct phy_driver ksphy_driver[] = { .phy_id = PHY_ID_KSZ8081, .phy_id_mask = MICREL_PHY_ID_MASK, .drv.name = "Micrel KSZ8081/91", + .driver_data = &ksz8081_type, .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), + .probe = kszphy_probe, .config_init = ksz8021_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, -- 2.30.2 _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox