123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * 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)
- {
- ofnode mdio_node, phy_node;
- const char *node_name;
- int ret;
- /* 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)) {
- 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);
- 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) {
- dev_dbg(eth_dev, " - Eth phy binding error: %d\n", ret);
- continue;
- }
- dev_dbg(eth_dev, " - bound phy device: '%s'\n", node_name);
- }
- return 0;
- }
- int eth_phy_set_mdio_bus(struct udevice *eth_dev, struct mii_dev *mdio_bus)
- {
- struct udevice *dev;
- struct eth_phy_device_priv *uc_priv;
- for (uclass_first_device(UCLASS_ETH_PHY, &dev); dev;
- uclass_next_device(&dev)) {
- if (dev->parent == eth_dev) {
- uc_priv = (struct eth_phy_device_priv *)(dev_get_uclass_priv(dev));
- if (!uc_priv->mdio_bus)
- uc_priv->mdio_bus = mdio_bus;
- }
- }
- return 0;
- }
- struct mii_dev *eth_phy_get_mdio_bus(struct udevice *eth_dev)
- {
- int ret;
- struct udevice *phy_dev;
- struct eth_phy_device_priv *uc_priv;
- /* Will probe the parent of phy device, then phy device */
- ret = uclass_get_device_by_phandle(UCLASS_ETH_PHY, eth_dev,
- "phy-handle", &phy_dev);
- if (!ret) {
- if (eth_dev != phy_dev->parent) {
- /*
- * phy_dev is shared and controlled by
- * other eth controller
- */
- uc_priv = (struct eth_phy_device_priv *)(dev_get_uclass_priv(phy_dev));
- if (uc_priv->mdio_bus)
- log_notice("Get shared mii bus on %s\n", eth_dev->name);
- else
- log_notice("Can't get shared mii bus on %s\n", eth_dev->name);
- return uc_priv->mdio_bus;
- }
- } else {
- log_notice("FEC: can't find phy-handle\n");
- }
- return NULL;
- }
- int eth_phy_get_addr(struct udevice *dev)
- {
- struct ofnode_phandle_args phandle_args;
- int reg;
- if (dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
- &phandle_args)) {
- dev_dbg(dev, "Failed to find phy-handle");
- return -ENODEV;
- }
- reg = ofnode_read_u32_default(phandle_args.node, "reg", 0);
- 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,
- };
|