[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20191029174819.3502-4-michael@walle.cc>
Date: Tue, 29 Oct 2019 18:48:19 +0100
From: Michael Walle <michael@...le.cc>
To: linux-kernel@...r.kernel.org, devicetree@...r.kernel.org,
netdev@...r.kernel.org
Cc: Michael Walle <michael@...le.cc>
Subject: [PATCH 3/3] net: phy: Use device tree properties to initialize any PHYs
Some PHYs drivers, like the marvell and the broadcom one, are able to
initialize PHY registers via device tree properties. This patch adds a
more generic property which applies to any PHY. It supports clause-22,
clause-45 and paged PHY writes.
Hopefully, some board maintainers will pick this up and switch to this
instead of adding more phy_fixups in architecture specific code,
although it is board specific. For example have a look at
arch/arm/mach-imx/ for phy_register_fixup.
Signed-off-by: Michael Walle <michael@...le.cc>
---
drivers/net/phy/phy_device.c | 97 +++++++++++++++++++++++++++++++++++-
1 file changed, 96 insertions(+), 1 deletion(-)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 9d2bbb13293e..3c4cbaf72c27 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -30,6 +30,9 @@
#include <linux/mdio.h>
#include <linux/io.h>
#include <linux/uaccess.h>
+#include <linux/of.h>
+
+#include <dt-bindings/net/phy.h>
MODULE_DESCRIPTION("PHY library");
MODULE_AUTHOR("Andy Fleming");
@@ -1064,6 +1067,95 @@ static int phy_poll_reset(struct phy_device *phydev)
return 0;
}
+/**
+ * phy_of_reg_init - Set and/or override configuration registers.
+ * @phydev: target phy_device struct
+ *
+ * Description: Set and/or override some configuration registers based
+ * on the reg-init property stored in the of_node for the phydev.
+ *
+ * reg-init = <dev reg mask value>,...;
+ * There may be one or more sets of <dev reg mask value>:
+ */
+static int phy_of_reg_init(struct phy_device *phydev)
+{
+ struct device_node *node = phydev->mdio.dev.of_node;
+ int oldpage = -1, savedpage = -1;
+ const __be32 *paddr;
+ int len, i;
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_OF_MDIO))
+ return 0;
+
+ if (!node)
+ return 0;
+
+ paddr = of_get_property(node, "reg-init", &len);
+ if (!paddr || len < (4 * sizeof(*paddr)))
+ return 0;
+
+ mutex_lock(&phydev->mdio.bus->mdio_lock);
+
+ savedpage = -1;
+ len /= sizeof(*paddr);
+ for (i = 0; i < len - 3; i += 4) {
+ u32 dev = be32_to_cpup(paddr + i);
+ u16 reg = be32_to_cpup(paddr + i + 1);
+ u16 mask = be32_to_cpup(paddr + i + 2);
+ u16 val_bits = be32_to_cpup(paddr + i + 3);
+ int page = dev & 0xffff;
+ int devad = dev & 0x1f;
+ int val;
+
+ if (dev & PHY_REG_PAGE) {
+ if (savedpage < 0) {
+ savedpage = __phy_read_page(phydev);
+ if (savedpage < 0) {
+ ret = savedpage;
+ goto err;
+ }
+ oldpage = savedpage;
+ }
+ if (oldpage != page) {
+ ret = __phy_write_page(phydev, page);
+ if (ret < 0)
+ goto err;
+ oldpage = page;
+ }
+ }
+
+ val = 0;
+ if (mask) {
+ if (dev & PHY_REG_C45)
+ val = __phy_read_mmd(phydev, devad, reg);
+ else
+ val = __phy_read(phydev, reg);
+ if (val < 0) {
+ ret = val;
+ goto err;
+ }
+ val &= mask;
+ }
+ val |= val_bits;
+
+ if (dev & PHY_REG_C45)
+ ret = __phy_write_mmd(phydev, devad, reg, val);
+ else
+ ret = __phy_write(phydev, reg, val);
+ if (ret < 0)
+ goto err;
+ }
+
+err:
+ if (savedpage >= 0)
+ __phy_write_page(phydev, savedpage);
+
+ mutex_unlock(&phydev->mdio.bus->mdio_lock);
+
+ return ret;
+}
+
int phy_init_hw(struct phy_device *phydev)
{
int ret = 0;
@@ -1087,7 +1179,10 @@ int phy_init_hw(struct phy_device *phydev)
if (phydev->drv->config_init)
ret = phydev->drv->config_init(phydev);
- return ret;
+ if (ret < 0)
+ return ret;
+
+ return phy_of_reg_init(phydev);
}
EXPORT_SYMBOL(phy_init_hw);
--
2.20.1
Powered by blists - more mailing lists