blob: aa5b05abc8a0fc99f1f4bb3f5d7a385c64df86bd [file] [log] [blame]
Ye Licd5bb772020-05-03 22:41:14 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2020 NXP
4 */
5
6#include <common.h>
7#include <dm.h>
Patrick Delaunay8c937fa2021-07-20 20:09:52 +02008#include <log.h>
Ye Licd5bb772020-05-03 22:41:14 +08009#include <net.h>
Patrick Delaunaycc2ffab2021-07-20 20:09:51 +020010#include <asm-generic/gpio.h>
Patrick Delaunay8c937fa2021-07-20 20:09:52 +020011#include <dm/device_compat.h>
Ye Licd5bb772020-05-03 22:41:14 +080012#include <dm/device-internal.h>
13#include <dm/uclass-internal.h>
14#include <dm/lists.h>
Patrick Delaunaycc2ffab2021-07-20 20:09:51 +020015#include <linux/delay.h>
Ye Licd5bb772020-05-03 22:41:14 +080016
17struct eth_phy_device_priv {
18 struct mii_dev *mdio_bus;
Patrick Delaunaycc2ffab2021-07-20 20:09:51 +020019 struct gpio_desc reset_gpio;
20 u32 reset_assert_delay;
21 u32 reset_deassert_delay;
Ye Licd5bb772020-05-03 22:41:14 +080022};
23
24int eth_phy_binds_nodes(struct udevice *eth_dev)
25{
26 ofnode mdio_node, phy_node;
27 const char *node_name;
28 int ret;
29
30 mdio_node = dev_read_subnode(eth_dev, "mdio");
31 if (!ofnode_valid(mdio_node)) {
Patrick Delaunay8c937fa2021-07-20 20:09:52 +020032 dev_dbg(eth_dev, "%s: %s mdio subnode not found!", __func__,
33 eth_dev->name);
Ye Licd5bb772020-05-03 22:41:14 +080034 return -ENXIO;
35 }
36
37 ofnode_for_each_subnode(phy_node, mdio_node) {
38 node_name = ofnode_get_name(phy_node);
39
Patrick Delaunay8c937fa2021-07-20 20:09:52 +020040 dev_dbg(eth_dev, "* Found child node: '%s'\n", node_name);
Ye Licd5bb772020-05-03 22:41:14 +080041
42 ret = device_bind_driver_to_node(eth_dev,
43 "eth_phy_generic_drv",
44 node_name, phy_node, NULL);
45 if (ret) {
Patrick Delaunay8c937fa2021-07-20 20:09:52 +020046 dev_dbg(eth_dev, " - Eth phy binding error: %d\n", ret);
Ye Licd5bb772020-05-03 22:41:14 +080047 continue;
48 }
49
Patrick Delaunay8c937fa2021-07-20 20:09:52 +020050 dev_dbg(eth_dev, " - bound phy device: '%s'\n", node_name);
Ye Licd5bb772020-05-03 22:41:14 +080051 }
52
53 return 0;
54}
55
56int eth_phy_set_mdio_bus(struct udevice *eth_dev, struct mii_dev *mdio_bus)
57{
58 struct udevice *dev;
59 struct eth_phy_device_priv *uc_priv;
60
61 for (uclass_first_device(UCLASS_ETH_PHY, &dev); dev;
62 uclass_next_device(&dev)) {
63 if (dev->parent == eth_dev) {
Simon Glass95588622020-12-22 19:30:28 -070064 uc_priv = (struct eth_phy_device_priv *)(dev_get_uclass_priv(dev));
Ye Licd5bb772020-05-03 22:41:14 +080065
66 if (!uc_priv->mdio_bus)
67 uc_priv->mdio_bus = mdio_bus;
68 }
69 }
70
71 return 0;
72}
73
74struct mii_dev *eth_phy_get_mdio_bus(struct udevice *eth_dev)
75{
76 int ret;
77 struct udevice *phy_dev;
78 struct eth_phy_device_priv *uc_priv;
79
80 /* Will probe the parent of phy device, then phy device */
81 ret = uclass_get_device_by_phandle(UCLASS_ETH_PHY, eth_dev,
82 "phy-handle", &phy_dev);
83 if (!ret) {
84 if (eth_dev != phy_dev->parent) {
85 /*
86 * phy_dev is shared and controlled by
87 * other eth controller
88 */
Simon Glass95588622020-12-22 19:30:28 -070089 uc_priv = (struct eth_phy_device_priv *)(dev_get_uclass_priv(phy_dev));
Ye Licd5bb772020-05-03 22:41:14 +080090 if (uc_priv->mdio_bus)
Patrick Delaunay8c937fa2021-07-20 20:09:52 +020091 log_notice("Get shared mii bus on %s\n", eth_dev->name);
Ye Licd5bb772020-05-03 22:41:14 +080092 else
Patrick Delaunay8c937fa2021-07-20 20:09:52 +020093 log_notice("Can't get shared mii bus on %s\n", eth_dev->name);
Ye Licd5bb772020-05-03 22:41:14 +080094
95 return uc_priv->mdio_bus;
96 }
97 } else {
Patrick Delaunay8c937fa2021-07-20 20:09:52 +020098 log_notice("FEC: can't find phy-handle\n");
Ye Licd5bb772020-05-03 22:41:14 +080099 }
100
101 return NULL;
102}
103
104int eth_phy_get_addr(struct udevice *dev)
105{
106 struct ofnode_phandle_args phandle_args;
107 int reg;
108
109 if (dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
110 &phandle_args)) {
Patrick Delaunay8c937fa2021-07-20 20:09:52 +0200111 dev_dbg(dev, "Failed to find phy-handle");
Ye Licd5bb772020-05-03 22:41:14 +0800112 return -ENODEV;
113 }
114
115 reg = ofnode_read_u32_default(phandle_args.node, "reg", 0);
116
117 return reg;
118}
119
Patrick Delaunaycc2ffab2021-07-20 20:09:51 +0200120/* parsing generic properties of devicetree/bindings/net/ethernet-phy.yaml */
121static int eth_phy_of_to_plat(struct udevice *dev)
122{
123 struct eth_phy_device_priv *uc_priv = dev_get_uclass_priv(dev);
124 int ret;
125
126 if (!CONFIG_IS_ENABLED(DM_GPIO))
127 return 0;
128
129 /* search "reset-gpios" in phy node */
130 ret = gpio_request_by_name(dev, "reset-gpios", 0,
131 &uc_priv->reset_gpio,
132 GPIOD_IS_OUT);
133 if (ret != -ENOENT)
134 return ret;
135
136 uc_priv->reset_assert_delay = dev_read_u32_default(dev, "reset-assert-us", 0);
137 uc_priv->reset_deassert_delay = dev_read_u32_default(dev, "reset-deassert-us", 0);
138
139 return 0;
140}
141
142void eth_phy_reset(struct udevice *dev, int value)
143{
144 struct eth_phy_device_priv *uc_priv = dev_get_uclass_priv(dev);
145 u32 delay;
146
147 if (!CONFIG_IS_ENABLED(DM_GPIO))
148 return;
149
150 if (!dm_gpio_is_valid(&uc_priv->reset_gpio))
151 return;
152
153 dm_gpio_set_value(&uc_priv->reset_gpio, value);
154
155 delay = value ? uc_priv->reset_assert_delay : uc_priv->reset_deassert_delay;
156 if (delay)
157 udelay(delay);
158}
159
160static int eth_phy_pre_probe(struct udevice *dev)
161{
162 /* Assert and deassert the reset signal */
163 eth_phy_reset(dev, 1);
164 eth_phy_reset(dev, 0);
165
166 return 0;
167}
168
Ye Licd5bb772020-05-03 22:41:14 +0800169UCLASS_DRIVER(eth_phy_generic) = {
170 .id = UCLASS_ETH_PHY,
171 .name = "eth_phy_generic",
Simon Glass8a2b47f2020-12-03 16:55:17 -0700172 .per_device_auto = sizeof(struct eth_phy_device_priv),
Patrick Delaunaycc2ffab2021-07-20 20:09:51 +0200173 .pre_probe = eth_phy_pre_probe,
Ye Licd5bb772020-05-03 22:41:14 +0800174};
175
176U_BOOT_DRIVER(eth_phy_generic_drv) = {
177 .name = "eth_phy_generic_drv",
178 .id = UCLASS_ETH_PHY,
Patrick Delaunaycc2ffab2021-07-20 20:09:51 +0200179 .of_to_plat = eth_phy_of_to_plat,
Ye Licd5bb772020-05-03 22:41:14 +0800180};