uboot/drivers/net/eth-phy-uclass.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2020 NXP
   4 */
   5
   6#define LOG_CATEGORY UCLASS_ETH_PHY
   7
   8#include <common.h>
   9#include <dm.h>
  10#include <log.h>
  11#include <net.h>
  12#include <asm-generic/gpio.h>
  13#include <dm/device_compat.h>
  14#include <dm/device-internal.h>
  15#include <dm/uclass-internal.h>
  16#include <dm/lists.h>
  17#include <linux/delay.h>
  18
  19struct eth_phy_device_priv {
  20        struct mii_dev *mdio_bus;
  21        struct gpio_desc reset_gpio;
  22        u32 reset_assert_delay;
  23        u32 reset_deassert_delay;
  24};
  25
  26int eth_phy_binds_nodes(struct udevice *eth_dev)
  27{
  28        ofnode mdio_node, phy_node;
  29        const char *node_name;
  30        int ret;
  31
  32        /* search a subnode named "mdio.*" */
  33        dev_for_each_subnode(mdio_node, eth_dev) {
  34                node_name = ofnode_get_name(mdio_node);
  35                if (!strncmp(node_name, "mdio", 4))
  36                        break;
  37        }
  38        if (!ofnode_valid(mdio_node)) {
  39                dev_dbg(eth_dev, "%s: %s mdio subnode not found!\n", __func__,
  40                        eth_dev->name);
  41                return -ENXIO;
  42        }
  43        dev_dbg(eth_dev, "%s: %s subnode found!\n", __func__, node_name);
  44
  45        ofnode_for_each_subnode(phy_node, mdio_node) {
  46                node_name = ofnode_get_name(phy_node);
  47
  48                dev_dbg(eth_dev, "* Found child node: '%s'\n", node_name);
  49
  50                ret = device_bind_driver_to_node(eth_dev,
  51                                                 "eth_phy_generic_drv",
  52                                                 node_name, phy_node, NULL);
  53                if (ret) {
  54                        dev_dbg(eth_dev, "  - Eth phy binding error: %d\n", ret);
  55                        continue;
  56                }
  57
  58                dev_dbg(eth_dev, "  - bound phy device: '%s'\n", node_name);
  59        }
  60
  61        return 0;
  62}
  63
  64int eth_phy_set_mdio_bus(struct udevice *eth_dev, struct mii_dev *mdio_bus)
  65{
  66        struct udevice *dev;
  67        struct eth_phy_device_priv *uc_priv;
  68
  69        for (uclass_first_device(UCLASS_ETH_PHY, &dev); dev;
  70             uclass_next_device(&dev)) {
  71                if (dev->parent == eth_dev) {
  72                        uc_priv = (struct eth_phy_device_priv *)(dev_get_uclass_priv(dev));
  73
  74                        if (!uc_priv->mdio_bus)
  75                                uc_priv->mdio_bus = mdio_bus;
  76                }
  77        }
  78
  79        return 0;
  80}
  81
  82struct mii_dev *eth_phy_get_mdio_bus(struct udevice *eth_dev)
  83{
  84        int ret;
  85        struct udevice *phy_dev;
  86        struct eth_phy_device_priv *uc_priv;
  87
  88        /* Will probe the parent of phy device, then phy device */
  89        ret = uclass_get_device_by_phandle(UCLASS_ETH_PHY, eth_dev,
  90                                           "phy-handle", &phy_dev);
  91        if (!ret) {
  92                if (eth_dev != phy_dev->parent) {
  93                        /*
  94                         * phy_dev is shared and controlled by
  95                         * other eth controller
  96                         */
  97                        uc_priv = (struct eth_phy_device_priv *)(dev_get_uclass_priv(phy_dev));
  98                        if (uc_priv->mdio_bus)
  99                                log_notice("Get shared mii bus on %s\n", eth_dev->name);
 100                        else
 101                                log_notice("Can't get shared mii bus on %s\n", eth_dev->name);
 102
 103                        return uc_priv->mdio_bus;
 104                }
 105        } else {
 106                log_notice("FEC: can't find phy-handle\n");
 107        }
 108
 109        return NULL;
 110}
 111
 112int eth_phy_get_addr(struct udevice *dev)
 113{
 114        struct ofnode_phandle_args phandle_args;
 115        int reg;
 116
 117        if (dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
 118                                       &phandle_args)) {
 119                dev_dbg(dev, "Failed to find phy-handle");
 120                return -ENODEV;
 121        }
 122
 123        reg = ofnode_read_u32_default(phandle_args.node, "reg", 0);
 124
 125        return reg;
 126}
 127
 128/* parsing generic properties of devicetree/bindings/net/ethernet-phy.yaml */
 129static int eth_phy_of_to_plat(struct udevice *dev)
 130{
 131        struct eth_phy_device_priv *uc_priv = dev_get_uclass_priv(dev);
 132        int ret;
 133
 134        if (!CONFIG_IS_ENABLED(DM_GPIO))
 135                return 0;
 136
 137        /* search "reset-gpios" in phy node */
 138        ret = gpio_request_by_name(dev, "reset-gpios", 0,
 139                                   &uc_priv->reset_gpio,
 140                                   GPIOD_IS_OUT);
 141        if (ret != -ENOENT)
 142                return ret;
 143
 144        uc_priv->reset_assert_delay = dev_read_u32_default(dev, "reset-assert-us", 0);
 145        uc_priv->reset_deassert_delay = dev_read_u32_default(dev, "reset-deassert-us", 0);
 146
 147        return 0;
 148}
 149
 150void eth_phy_reset(struct udevice *dev, int value)
 151{
 152        struct eth_phy_device_priv *uc_priv = dev_get_uclass_priv(dev);
 153        u32 delay;
 154
 155        if (!CONFIG_IS_ENABLED(DM_GPIO))
 156                return;
 157
 158        if (!dm_gpio_is_valid(&uc_priv->reset_gpio))
 159                return;
 160
 161        dm_gpio_set_value(&uc_priv->reset_gpio, value);
 162
 163        delay = value ? uc_priv->reset_assert_delay : uc_priv->reset_deassert_delay;
 164        if (delay)
 165                udelay(delay);
 166}
 167
 168static int eth_phy_pre_probe(struct udevice *dev)
 169{
 170        /* Assert and deassert the reset signal */
 171        eth_phy_reset(dev, 1);
 172        eth_phy_reset(dev, 0);
 173
 174        return 0;
 175}
 176
 177UCLASS_DRIVER(eth_phy_generic) = {
 178        .id             = UCLASS_ETH_PHY,
 179        .name           = "eth_phy_generic",
 180        .per_device_auto        = sizeof(struct eth_phy_device_priv),
 181        .pre_probe      = eth_phy_pre_probe,
 182};
 183
 184U_BOOT_DRIVER(eth_phy_generic_drv) = {
 185        .name           = "eth_phy_generic_drv",
 186        .id             = UCLASS_ETH_PHY,
 187        .of_to_plat     = eth_phy_of_to_plat,
 188};
 189