blob: 1dae26878e61d9a241cbbc9283a52ebff1377e69 [file] [log] [blame]
Ye Licd5bb772020-05-03 22:41:14 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2020 NXP
4 */
5
Patrick Delaunayb26ef6f2021-07-20 20:15:28 +02006#define LOG_CATEGORY UCLASS_ETH_PHY
7
Ye Licd5bb772020-05-03 22:41:14 +08008#include <dm.h>
Patrick Delaunay8c937fa2021-07-20 20:09:52 +02009#include <log.h>
Ye Licd5bb772020-05-03 22:41:14 +080010#include <net.h>
Patrick Delaunaycc2ffab2021-07-20 20:09:51 +020011#include <asm-generic/gpio.h>
Patrick Delaunay8c937fa2021-07-20 20:09:52 +020012#include <dm/device_compat.h>
Ye Licd5bb772020-05-03 22:41:14 +080013#include <dm/device-internal.h>
14#include <dm/uclass-internal.h>
15#include <dm/lists.h>
Patrick Delaunaycc2ffab2021-07-20 20:09:51 +020016#include <linux/delay.h>
Ye Licd5bb772020-05-03 22:41:14 +080017
18struct eth_phy_device_priv {
19 struct mii_dev *mdio_bus;
Patrick Delaunaycc2ffab2021-07-20 20:09:51 +020020 struct gpio_desc reset_gpio;
21 u32 reset_assert_delay;
22 u32 reset_deassert_delay;
Ye Licd5bb772020-05-03 22:41:14 +080023};
24
25int eth_phy_binds_nodes(struct udevice *eth_dev)
26{
27 ofnode mdio_node, phy_node;
28 const char *node_name;
29 int ret;
30
Patrick Delaunaye4231ca2021-07-20 20:09:53 +020031 /* search a subnode named "mdio.*" */
32 dev_for_each_subnode(mdio_node, eth_dev) {
33 node_name = ofnode_get_name(mdio_node);
34 if (!strncmp(node_name, "mdio", 4))
35 break;
36 }
Ye Licd5bb772020-05-03 22:41:14 +080037 if (!ofnode_valid(mdio_node)) {
Patrick Delaunaye4231ca2021-07-20 20:09:53 +020038 dev_dbg(eth_dev, "%s: %s mdio subnode not found!\n", __func__,
Patrick Delaunay8c937fa2021-07-20 20:09:52 +020039 eth_dev->name);
Ye Licd5bb772020-05-03 22:41:14 +080040 return -ENXIO;
41 }
Patrick Delaunaye4231ca2021-07-20 20:09:53 +020042 dev_dbg(eth_dev, "%s: %s subnode found!\n", __func__, node_name);
Ye Licd5bb772020-05-03 22:41:14 +080043
44 ofnode_for_each_subnode(phy_node, mdio_node) {
45 node_name = ofnode_get_name(phy_node);
46
Patrick Delaunay8c937fa2021-07-20 20:09:52 +020047 dev_dbg(eth_dev, "* Found child node: '%s'\n", node_name);
Ye Licd5bb772020-05-03 22:41:14 +080048
49 ret = device_bind_driver_to_node(eth_dev,
50 "eth_phy_generic_drv",
51 node_name, phy_node, NULL);
52 if (ret) {
Patrick Delaunay8c937fa2021-07-20 20:09:52 +020053 dev_dbg(eth_dev, " - Eth phy binding error: %d\n", ret);
Ye Licd5bb772020-05-03 22:41:14 +080054 continue;
55 }
56
Patrick Delaunay8c937fa2021-07-20 20:09:52 +020057 dev_dbg(eth_dev, " - bound phy device: '%s'\n", node_name);
Ye Licd5bb772020-05-03 22:41:14 +080058 }
59
60 return 0;
61}
62
63int eth_phy_set_mdio_bus(struct udevice *eth_dev, struct mii_dev *mdio_bus)
64{
65 struct udevice *dev;
66 struct eth_phy_device_priv *uc_priv;
67
68 for (uclass_first_device(UCLASS_ETH_PHY, &dev); dev;
69 uclass_next_device(&dev)) {
70 if (dev->parent == eth_dev) {
Simon Glass95588622020-12-22 19:30:28 -070071 uc_priv = (struct eth_phy_device_priv *)(dev_get_uclass_priv(dev));
Ye Licd5bb772020-05-03 22:41:14 +080072
73 if (!uc_priv->mdio_bus)
74 uc_priv->mdio_bus = mdio_bus;
75 }
76 }
77
78 return 0;
79}
80
81struct mii_dev *eth_phy_get_mdio_bus(struct udevice *eth_dev)
82{
83 int ret;
84 struct udevice *phy_dev;
85 struct eth_phy_device_priv *uc_priv;
86
87 /* Will probe the parent of phy device, then phy device */
88 ret = uclass_get_device_by_phandle(UCLASS_ETH_PHY, eth_dev,
89 "phy-handle", &phy_dev);
90 if (!ret) {
91 if (eth_dev != phy_dev->parent) {
92 /*
93 * phy_dev is shared and controlled by
94 * other eth controller
95 */
Simon Glass95588622020-12-22 19:30:28 -070096 uc_priv = (struct eth_phy_device_priv *)(dev_get_uclass_priv(phy_dev));
Ye Licd5bb772020-05-03 22:41:14 +080097 if (uc_priv->mdio_bus)
Patrick Delaunay8c937fa2021-07-20 20:09:52 +020098 log_notice("Get shared mii bus on %s\n", eth_dev->name);
Ye Licd5bb772020-05-03 22:41:14 +080099 else
Patrick Delaunay8c937fa2021-07-20 20:09:52 +0200100 log_notice("Can't get shared mii bus on %s\n", eth_dev->name);
Ye Licd5bb772020-05-03 22:41:14 +0800101
102 return uc_priv->mdio_bus;
103 }
104 } else {
Marek Vasutdfd03c12022-01-01 20:12:23 +0100105 log_debug("Can't find phy-handle for %s\n", eth_dev->name);
Ye Licd5bb772020-05-03 22:41:14 +0800106 }
107
108 return NULL;
109}
110
111int eth_phy_get_addr(struct udevice *dev)
112{
113 struct ofnode_phandle_args phandle_args;
114 int reg;
115
116 if (dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
117 &phandle_args)) {
Patrick Delaunay8c937fa2021-07-20 20:09:52 +0200118 dev_dbg(dev, "Failed to find phy-handle");
Ye Licd5bb772020-05-03 22:41:14 +0800119 return -ENODEV;
120 }
121
122 reg = ofnode_read_u32_default(phandle_args.node, "reg", 0);
123
124 return reg;
125}
126
Patrick Delaunaycc2ffab2021-07-20 20:09:51 +0200127/* parsing generic properties of devicetree/bindings/net/ethernet-phy.yaml */
128static int eth_phy_of_to_plat(struct udevice *dev)
129{
130 struct eth_phy_device_priv *uc_priv = dev_get_uclass_priv(dev);
131 int ret;
132
133 if (!CONFIG_IS_ENABLED(DM_GPIO))
134 return 0;
135
136 /* search "reset-gpios" in phy node */
137 ret = gpio_request_by_name(dev, "reset-gpios", 0,
138 &uc_priv->reset_gpio,
Tim Harvey2db9dae2022-03-01 12:15:02 -0800139 GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
Marek Vasut9da5a552021-11-13 03:23:11 +0100140 if (ret && ret != -ENOENT)
Patrick Delaunaycc2ffab2021-07-20 20:09:51 +0200141 return ret;
142
143 uc_priv->reset_assert_delay = dev_read_u32_default(dev, "reset-assert-us", 0);
144 uc_priv->reset_deassert_delay = dev_read_u32_default(dev, "reset-deassert-us", 0);
145
Marek Vasut61dd9c12023-05-31 00:51:27 +0200146 /* These are used by some DTs, try these as a fallback. */
147 if (!uc_priv->reset_assert_delay && !uc_priv->reset_deassert_delay) {
148 uc_priv->reset_assert_delay =
149 dev_read_u32_default(dev, "reset-delay-us", 0);
150 uc_priv->reset_deassert_delay =
151 dev_read_u32_default(dev, "reset-post-delay-us", 0);
152 }
153
Patrick Delaunaycc2ffab2021-07-20 20:09:51 +0200154 return 0;
155}
156
Marek Vasut7b7cbd52023-05-31 00:51:18 +0200157static void eth_phy_reset(struct udevice *dev, int value)
Patrick Delaunaycc2ffab2021-07-20 20:09:51 +0200158{
159 struct eth_phy_device_priv *uc_priv = dev_get_uclass_priv(dev);
160 u32 delay;
161
162 if (!CONFIG_IS_ENABLED(DM_GPIO))
163 return;
164
165 if (!dm_gpio_is_valid(&uc_priv->reset_gpio))
166 return;
167
168 dm_gpio_set_value(&uc_priv->reset_gpio, value);
169
170 delay = value ? uc_priv->reset_assert_delay : uc_priv->reset_deassert_delay;
171 if (delay)
172 udelay(delay);
173}
174
175static int eth_phy_pre_probe(struct udevice *dev)
176{
177 /* Assert and deassert the reset signal */
178 eth_phy_reset(dev, 1);
179 eth_phy_reset(dev, 0);
180
181 return 0;
182}
183
Ye Licd5bb772020-05-03 22:41:14 +0800184UCLASS_DRIVER(eth_phy_generic) = {
185 .id = UCLASS_ETH_PHY,
186 .name = "eth_phy_generic",
Simon Glass8a2b47f2020-12-03 16:55:17 -0700187 .per_device_auto = sizeof(struct eth_phy_device_priv),
Patrick Delaunaycc2ffab2021-07-20 20:09:51 +0200188 .pre_probe = eth_phy_pre_probe,
Ye Licd5bb772020-05-03 22:41:14 +0800189};
190
191U_BOOT_DRIVER(eth_phy_generic_drv) = {
192 .name = "eth_phy_generic_drv",
193 .id = UCLASS_ETH_PHY,
Patrick Delaunaycc2ffab2021-07-20 20:09:51 +0200194 .of_to_plat = eth_phy_of_to_plat,
Ye Licd5bb772020-05-03 22:41:14 +0800195};