b355031aa5ebcc01e2d6a4764f76ffd1597e9eb0
[openwrt/staging/neocturne.git] /
1 From 385ef48f468696d6d172eb367656a3466fa0408d Mon Sep 17 00:00:00 2001
2 From: Christian Marangi <ansuelsmth@gmail.com>
3 Date: Tue, 6 Feb 2024 18:31:05 +0100
4 Subject: [PATCH 02/10] net: phy: add support for scanning PHY in PHY packages
5 nodes
6
7 Add support for scanning PHY in PHY package nodes. PHY packages nodes
8 are just container for actual PHY on the MDIO bus.
9
10 Their PHY address defined in the PHY package node are absolute and
11 reflect the address on the MDIO bus.
12
13 mdio_bus.c and of_mdio.c is updated to now support and parse also
14 PHY package subnode by checking if the node name match
15 "ethernet-phy-package".
16
17 As PHY package reg is mandatory and each PHY in the PHY package must
18 have a reg, every invalid PHY Package node is ignored and will be
19 skipped by the autoscan fallback.
20
21 Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
22 Reviewed-by: Andrew Lunn <andrew@lunn.ch>
23 Signed-off-by: David S. Miller <davem@davemloft.net>
24 ---
25 drivers/net/mdio/of_mdio.c | 79 +++++++++++++++++++++++++++-----------
26 drivers/net/phy/mdio_bus.c | 44 +++++++++++++++++----
27 2 files changed, 92 insertions(+), 31 deletions(-)
28
29 --- a/drivers/net/mdio/of_mdio.c
30 +++ b/drivers/net/mdio/of_mdio.c
31 @@ -138,6 +138,53 @@ bool of_mdiobus_child_is_phy(struct devi
32 }
33 EXPORT_SYMBOL(of_mdiobus_child_is_phy);
34
35 +static int __of_mdiobus_parse_phys(struct mii_bus *mdio, struct device_node *np,
36 + bool *scanphys)
37 +{
38 + struct device_node *child;
39 + int addr, rc = 0;
40 +
41 + /* Loop over the child nodes and register a phy_device for each phy */
42 + for_each_available_child_of_node(np, child) {
43 + if (of_node_name_eq(child, "ethernet-phy-package")) {
44 + /* Ignore invalid ethernet-phy-package node */
45 + if (!of_find_property(child, "reg", NULL))
46 + continue;
47 +
48 + rc = __of_mdiobus_parse_phys(mdio, child, NULL);
49 + if (rc && rc != -ENODEV)
50 + goto exit;
51 +
52 + continue;
53 + }
54 +
55 + addr = of_mdio_parse_addr(&mdio->dev, child);
56 + if (addr < 0) {
57 + /* Skip scanning for invalid ethernet-phy-package node */
58 + if (scanphys)
59 + *scanphys = true;
60 + continue;
61 + }
62 +
63 + if (of_mdiobus_child_is_phy(child))
64 + rc = of_mdiobus_register_phy(mdio, child, addr);
65 + else
66 + rc = of_mdiobus_register_device(mdio, child, addr);
67 +
68 + if (rc == -ENODEV)
69 + dev_err(&mdio->dev,
70 + "MDIO device at address %d is missing.\n",
71 + addr);
72 + else if (rc)
73 + goto exit;
74 + }
75 +
76 + return 0;
77 +exit:
78 + of_node_put(child);
79 + return rc;
80 +}
81 +
82 /**
83 * __of_mdiobus_register - Register mii_bus and create PHYs from the device tree
84 * @mdio: pointer to mii_bus structure
85 @@ -179,33 +226,18 @@ int __of_mdiobus_register(struct mii_bus
86 return rc;
87
88 /* Loop over the child nodes and register a phy_device for each phy */
89 - for_each_available_child_of_node(np, child) {
90 - addr = of_mdio_parse_addr(&mdio->dev, child);
91 - if (addr < 0) {
92 - scanphys = true;
93 - continue;
94 - }
95 -
96 - if (of_mdiobus_child_is_phy(child))
97 - rc = of_mdiobus_register_phy(mdio, child, addr);
98 - else
99 - rc = of_mdiobus_register_device(mdio, child, addr);
100 -
101 - if (rc == -ENODEV)
102 - dev_err(&mdio->dev,
103 - "MDIO device at address %d is missing.\n",
104 - addr);
105 - else if (rc)
106 - goto unregister;
107 - }
108 + rc = __of_mdiobus_parse_phys(mdio, np, &scanphys);
109 + if (rc)
110 + goto unregister;
111
112 if (!scanphys)
113 return 0;
114
115 /* auto scan for PHYs with empty reg property */
116 for_each_available_child_of_node(np, child) {
117 - /* Skip PHYs with reg property set */
118 - if (of_find_property(child, "reg", NULL))
119 + /* Skip PHYs with reg property set or ethernet-phy-package node */
120 + if (of_find_property(child, "reg", NULL) ||
121 + of_node_name_eq(child, "ethernet-phy-package"))
122 continue;
123
124 for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
125 @@ -226,15 +258,16 @@ int __of_mdiobus_register(struct mii_bus
126 if (!rc)
127 break;
128 if (rc != -ENODEV)
129 - goto unregister;
130 + goto put_unregister;
131 }
132 }
133 }
134
135 return 0;
136
137 -unregister:
138 +put_unregister:
139 of_node_put(child);
140 +unregister:
141 mdiobus_unregister(mdio);
142 return rc;
143 }
144 --- a/drivers/net/phy/mdio_bus.c
145 +++ b/drivers/net/phy/mdio_bus.c
146 @@ -448,19 +448,34 @@ EXPORT_SYMBOL(of_mdio_find_bus);
147 * found, set the of_node pointer for the mdio device. This allows
148 * auto-probed phy devices to be supplied with information passed in
149 * via DT.
150 + * If a PHY package is found, PHY is searched also there.
151 */
152 -static void of_mdiobus_link_mdiodev(struct mii_bus *bus,
153 - struct mdio_device *mdiodev)
154 +static int of_mdiobus_find_phy(struct device *dev, struct mdio_device *mdiodev,
155 + struct device_node *np)
156 {
157 - struct device *dev = &mdiodev->dev;
158 struct device_node *child;
159
160 - if (dev->of_node || !bus->dev.of_node)
161 - return;
162 -
163 - for_each_available_child_of_node(bus->dev.of_node, child) {
164 + for_each_available_child_of_node(np, child) {
165 int addr;
166
167 + if (of_node_name_eq(child, "ethernet-phy-package")) {
168 + /* Validate PHY package reg presence */
169 + if (!of_find_property(child, "reg", NULL)) {
170 + of_node_put(child);
171 + return -EINVAL;
172 + }
173 +
174 + if (!of_mdiobus_find_phy(dev, mdiodev, child)) {
175 + /* The refcount for the PHY package will be
176 + * incremented later when PHY join the Package.
177 + */
178 + of_node_put(child);
179 + return 0;
180 + }
181 +
182 + continue;
183 + }
184 +
185 addr = of_mdio_parse_addr(dev, child);
186 if (addr < 0)
187 continue;
188 @@ -470,9 +485,22 @@ static void of_mdiobus_link_mdiodev(stru
189 /* The refcount on "child" is passed to the mdio
190 * device. Do _not_ use of_node_put(child) here.
191 */
192 - return;
193 + return 0;
194 }
195 }
196 +
197 + return -ENODEV;
198 +}
199 +
200 +static void of_mdiobus_link_mdiodev(struct mii_bus *bus,
201 + struct mdio_device *mdiodev)
202 +{
203 + struct device *dev = &mdiodev->dev;
204 +
205 + if (dev->of_node || !bus->dev.of_node)
206 + return;
207 +
208 + of_mdiobus_find_phy(dev, mdiodev, bus->dev.of_node);
209 }
210 #else /* !IS_ENABLED(CONFIG_OF_MDIO) */
211 static inline void of_mdiobus_link_mdiodev(struct mii_bus *mdio,