diff options
Diffstat (limited to 'drivers/net/eth-phy-uclass.c')
-rw-r--r-- | drivers/net/eth-phy-uclass.c | 86 |
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, }; |