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 <[email protected]>
---
 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
[email protected]
http://lists.infradead.org/mailman/listinfo/barebox

Reply via email to