summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMichal Simek <michal.simek@xilinx.com>2022-02-23 17:45:42 +0300
committerMichal Simek <michal.simek@xilinx.com>2022-03-09 14:43:16 +0300
commita744a284e35420077b0c838598eb24c98710412a (patch)
tree5645040c87668bc7ae5ff2b9321d08c5009589eb /drivers
parent3249116d8381a1a8f0d17c95acecd7c78b40e569 (diff)
downloadu-boot-a744a284e35420077b0c838598eb24c98710412a.tar.xz
net: phy: Add support for ethernet-phy-id with gpio reset
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
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/phy/Kconfig8
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/ethernet_id.c69
-rw-r--r--drivers/net/phy/phy.c5
4 files changed, 83 insertions, 0 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 4f8d33ce8f..74339a25ca 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -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
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 77f7f60621..b28440bc4e 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -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
index 0000000000..5617ac3ad6
--- /dev/null
+++ b/drivers/net/phy/ethernet_id.c
@@ -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;
+}
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index f63705e1b9..fffa10f68b 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -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);