aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/eth-phy-uclass.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/eth-phy-uclass.c')
-rw-r--r--drivers/net/eth-phy-uclass.c86
1 files changed, 76 insertions, 10 deletions
diff --git a/drivers/net/eth-phy-uclass.c b/drivers/net/eth-phy-uclass.c
index 07aebd9..c04bab9 100644
--- a/drivers/net/eth-phy-uclass.c
+++ b/drivers/net/eth-phy-uclass.c
@@ -3,15 +3,24 @@
* Copyright 2020 NXP
*/
+#define LOG_CATEGORY UCLASS_ETH_PHY
+
#include <common.h>
#include <dm.h>
+#include <log.h>
#include <net.h>
+#include <asm-generic/gpio.h>
+#include <dm/device_compat.h>
#include <dm/device-internal.h>
#include <dm/uclass-internal.h>
#include <dm/lists.h>
+#include <linux/delay.h>
struct eth_phy_device_priv {
struct mii_dev *mdio_bus;
+ struct gpio_desc reset_gpio;
+ u32 reset_assert_delay;
+ u32 reset_deassert_delay;
};
int eth_phy_binds_nodes(struct udevice *eth_dev)
@@ -20,27 +29,33 @@ int eth_phy_binds_nodes(struct udevice *eth_dev)
const char *node_name;
int ret;
- mdio_node = dev_read_subnode(eth_dev, "mdio");
+ /* search a subnode named "mdio.*" */
+ dev_for_each_subnode(mdio_node, eth_dev) {
+ node_name = ofnode_get_name(mdio_node);
+ if (!strncmp(node_name, "mdio", 4))
+ break;
+ }
if (!ofnode_valid(mdio_node)) {
- debug("%s: %s mdio subnode not found!", __func__,
- eth_dev->name);
+ dev_dbg(eth_dev, "%s: %s mdio subnode not found!\n", __func__,
+ eth_dev->name);
return -ENXIO;
}
+ dev_dbg(eth_dev, "%s: %s subnode found!\n", __func__, node_name);
ofnode_for_each_subnode(phy_node, mdio_node) {
node_name = ofnode_get_name(phy_node);
- debug("* Found child node: '%s'\n", node_name);
+ dev_dbg(eth_dev, "* Found child node: '%s'\n", node_name);
ret = device_bind_driver_to_node(eth_dev,
"eth_phy_generic_drv",
node_name, phy_node, NULL);
if (ret) {
- debug(" - Eth phy binding error: %d\n", ret);
+ dev_dbg(eth_dev, " - Eth phy binding error: %d\n", ret);
continue;
}
- debug(" - bound phy device: '%s'\n", node_name);
+ dev_dbg(eth_dev, " - bound phy device: '%s'\n", node_name);
}
return 0;
@@ -81,14 +96,14 @@ struct mii_dev *eth_phy_get_mdio_bus(struct udevice *eth_dev)
*/
uc_priv = (struct eth_phy_device_priv *)(dev_get_uclass_priv(phy_dev));
if (uc_priv->mdio_bus)
- printf("Get shared mii bus on %s\n", eth_dev->name);
+ log_notice("Get shared mii bus on %s\n", eth_dev->name);
else
- printf("Can't get shared mii bus on %s\n", eth_dev->name);
+ log_notice("Can't get shared mii bus on %s\n", eth_dev->name);
return uc_priv->mdio_bus;
}
} else {
- printf("FEC: can't find phy-handle\n");
+ log_notice("FEC: can't find phy-handle\n");
}
return NULL;
@@ -101,7 +116,7 @@ int eth_phy_get_addr(struct udevice *dev)
if (dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
&phandle_args)) {
- debug("Failed to find phy-handle");
+ dev_dbg(dev, "Failed to find phy-handle");
return -ENODEV;
}
@@ -110,13 +125,64 @@ int eth_phy_get_addr(struct udevice *dev)
return reg;
}
+/* parsing generic properties of devicetree/bindings/net/ethernet-phy.yaml */
+static int eth_phy_of_to_plat(struct udevice *dev)
+{
+ struct eth_phy_device_priv *uc_priv = dev_get_uclass_priv(dev);
+ int ret;
+
+ if (!CONFIG_IS_ENABLED(DM_GPIO))
+ return 0;
+
+ /* search "reset-gpios" in phy node */
+ ret = gpio_request_by_name(dev, "reset-gpios", 0,
+ &uc_priv->reset_gpio,
+ GPIOD_IS_OUT);
+ if (ret != -ENOENT)
+ return ret;
+
+ uc_priv->reset_assert_delay = dev_read_u32_default(dev, "reset-assert-us", 0);
+ uc_priv->reset_deassert_delay = dev_read_u32_default(dev, "reset-deassert-us", 0);
+
+ return 0;
+}
+
+void eth_phy_reset(struct udevice *dev, int value)
+{
+ struct eth_phy_device_priv *uc_priv = dev_get_uclass_priv(dev);
+ u32 delay;
+
+ if (!CONFIG_IS_ENABLED(DM_GPIO))
+ return;
+
+ if (!dm_gpio_is_valid(&uc_priv->reset_gpio))
+ return;
+
+ dm_gpio_set_value(&uc_priv->reset_gpio, value);
+
+ delay = value ? uc_priv->reset_assert_delay : uc_priv->reset_deassert_delay;
+ if (delay)
+ udelay(delay);
+}
+
+static int eth_phy_pre_probe(struct udevice *dev)
+{
+ /* Assert and deassert the reset signal */
+ eth_phy_reset(dev, 1);
+ eth_phy_reset(dev, 0);
+
+ return 0;
+}
+
UCLASS_DRIVER(eth_phy_generic) = {
.id = UCLASS_ETH_PHY,
.name = "eth_phy_generic",
.per_device_auto = sizeof(struct eth_phy_device_priv),
+ .pre_probe = eth_phy_pre_probe,
};
U_BOOT_DRIVER(eth_phy_generic_drv) = {
.name = "eth_phy_generic_drv",
.id = UCLASS_ETH_PHY,
+ .of_to_plat = eth_phy_of_to_plat,
};