]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
net: phy: Add support for ethernet-phy-id with gpio reset
authorMichal Simek <michal.simek@xilinx.com>
Wed, 23 Feb 2022 14:45:42 +0000 (15:45 +0100)
committerMichal Simek <michal.simek@xilinx.com>
Wed, 9 Mar 2022 11:43:16 +0000 (12:43 +0100)
Ethernet phy like dp83867 is using strapping resistors to setup PHY
address. On Xilinx boards strapping is setup on wires which are connected
to SOC where internal pull ups/downs influnce phy address. That's why there
is a need to setup pins properly (via pinctrl driver for example) and then
perform phy reset. I can be workarounded by reset gpio done for mdio bus
but this is not working properly when multiply phys sitting on the same
bus. That's why it needs to be done via ethernet-phy-id driver where dt
binding has gpio reset per phy.

DT binding is available here:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/net/ethernet-phy.yaml

The driver is are reading the vendor and device id from valid phy node
using ofnode_read_eth_phy_id() and creating a phy device.
Kconfig PHY_ETHERNET_ID symbol is used because not every platform has gpio
support.

Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Signed-off-by: T Karthik Reddy <t.karthik.reddy@xilinx.com>
Link: https://lore.kernel.org/r/70ab7d71c812b2c972d48c129e416c921af0d7f5.1645627539.git.michal.simek@xilinx.com
MAINTAINERS
drivers/net/phy/Kconfig
drivers/net/phy/Makefile
drivers/net/phy/ethernet_id.c [new file with mode: 0644]
drivers/net/phy/phy.c
include/phy.h

index c58947fb2ff4eba271984375be77754e212d7c10..4e740fb5d262f61629deb4e606a4ca111ca47fdf 100644 (file)
@@ -617,6 +617,7 @@ F:  drivers/i2c/muxes/pca954x.c
 F:     drivers/i2c/zynq_i2c.c
 F:     drivers/mmc/zynq_sdhci.c
 F:     drivers/mtd/nand/raw/zynq_nand.c
+F:     drivers/net/phy/ethernet_id.c
 F:     drivers/net/phy/xilinx_phy.c
 F:     drivers/net/zynq_gem.c
 F:     drivers/serial/serial_zynq.c
index 4f8d33ce8fd5a1531c6bd6bd4194dc5e207700d9..74339a25ca53e3a767f26cde75c633ecf9ce7256 100644 (file)
@@ -307,6 +307,14 @@ config PHY_XILINX_GMII2RGMII
          as bridge between MAC connected over GMII and external phy that
          is connected over RGMII interface.
 
+config PHY_ETHERNET_ID
+       bool "Read ethernet PHY id"
+       depends on DM_GPIO
+       default y if ZYNQ_GEM
+       help
+         Enable this config to read ethernet phy id from the phy node of DT
+         and create a phy device using id.
+
 config PHY_FIXED
        bool "Fixed-Link PHY"
        depends on DM_ETH
index 77f7f606215c9752c67792a214cb1607ef3f67b2..b28440bc4e52a7d47421f7d3f8895598c5e87193 100644 (file)
@@ -32,6 +32,7 @@ obj-$(CONFIG_PHY_TI_DP83867) += dp83867.o
 obj-$(CONFIG_PHY_TI_DP83869) += dp83869.o
 obj-$(CONFIG_PHY_XILINX) += xilinx_phy.o
 obj-$(CONFIG_PHY_XILINX_GMII2RGMII) += xilinx_gmii2rgmii.o
+obj-$(CONFIG_PHY_ETHERNET_ID) += ethernet_id.o
 obj-$(CONFIG_PHY_VITESSE) += vitesse.o
 obj-$(CONFIG_PHY_MSCC) += mscc.o
 obj-$(CONFIG_PHY_FIXED) += fixed.o
diff --git a/drivers/net/phy/ethernet_id.c b/drivers/net/phy/ethernet_id.c
new file mode 100644 (file)
index 0000000..5617ac3
--- /dev/null
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Xilinx ethernet phy reset driver
+ *
+ * Copyright (C) 2022 Xilinx, Inc.
+ */
+
+#include <common.h>
+#include <dm/device_compat.h>
+#include <phy.h>
+#include <linux/delay.h>
+#include <asm/gpio.h>
+
+struct phy_device *phy_connect_phy_id(struct mii_dev *bus, struct udevice *dev,
+                                     phy_interface_t interface)
+{
+       struct phy_device *phydev;
+       struct ofnode_phandle_args phandle_args;
+       struct gpio_desc gpio;
+       ofnode node;
+       u32 id, assert, deassert;
+       u16 vendor, device;
+       int ret;
+
+       if (dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
+                                      &phandle_args))
+               return NULL;
+
+       if (!ofnode_valid(phandle_args.node))
+               return NULL;
+
+       node = phandle_args.node;
+
+       ret = ofnode_read_eth_phy_id(node, &vendor, &device);
+       if (ret) {
+               dev_err(dev, "Failed to read eth PHY id, err: %d\n", ret);
+               return NULL;
+       }
+
+       ret = gpio_request_by_name_nodev(node, "reset-gpios", 0, &gpio,
+                                        GPIOD_ACTIVE_LOW);
+       if (!ret) {
+               assert = ofnode_read_u32_default(node, "reset-assert-us", 0);
+               deassert = ofnode_read_u32_default(node,
+                                                  "reset-deassert-us", 0);
+               ret = dm_gpio_set_value(&gpio, 1);
+               if (ret) {
+                       dev_err(dev, "Failed assert gpio, err: %d\n", ret);
+                       return NULL;
+               }
+
+               udelay(assert);
+
+               ret = dm_gpio_set_value(&gpio, 0);
+               if (ret) {
+                       dev_err(dev, "Failed deassert gpio, err: %d\n", ret);
+                       return NULL;
+               }
+
+               udelay(deassert);
+       }
+
+       id =  vendor << 16 | device;
+       phydev = phy_device_create(bus, 0, id, false, interface);
+       if (phydev)
+               phydev->node = node;
+
+       return phydev;
+}
index f63705e1b9a1207e5161990549d02fa7e0500014..fffa10f68b3caba9e4b82e1e6fe4a7418f046ae2 100644 (file)
@@ -1047,6 +1047,11 @@ struct phy_device *phy_connect(struct mii_dev *bus, int addr,
                phydev = phy_device_create(bus, 0, PHY_NCSI_ID, false, interface);
 #endif
 
+#ifdef CONFIG_PHY_ETHERNET_ID
+       if (!phydev)
+               phydev = phy_connect_phy_id(bus, dev, interface);
+#endif
+
 #ifdef CONFIG_PHY_XILINX_GMII2RGMII
        if (!phydev)
                phydev = phy_connect_gmii2rgmii(bus, dev, interface);
index 832d7a1695785b1656150983849570b51182075d..9ea4bd42db4de6a71ee6efcbb21ffb629b0368fc 100644 (file)
@@ -468,6 +468,19 @@ struct phy_device *phy_device_create(struct mii_dev *bus, int addr,
                                     u32 phy_id, bool is_c45,
                                     phy_interface_t interface);
 
+/**
+ * phy_connect_phy_id() - Connect to phy device by reading PHY id
+ *                       from phy node.
+ *
+ * @bus:               MII/MDIO bus that hosts the PHY
+ * @dev:               Ethernet device to associate to the PHY
+ * @interface:         Interface between the MAC and PHY
+ * @return:            pointer to phy_device if a PHY is found,
+ *                     or NULL otherwise
+ */
+struct phy_device *phy_connect_phy_id(struct mii_dev *bus, struct udevice *dev,
+                                     phy_interface_t interface);
+
 static inline ofnode phy_get_ofnode(struct phy_device *phydev)
 {
        if (ofnode_valid(phydev->node))