1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * OF helpers for the MDIO (Ethernet PHY) API |
4 | * |
5 | * Copyright (c) 2009 Secret Lab Technologies, Ltd. |
6 | * |
7 | * This file provides helper functions for extracting PHY device information |
8 | * out of the OpenFirmware device tree and using it to populate an mii_bus. |
9 | */ |
10 | |
11 | #include <linux/device.h> |
12 | #include <linux/err.h> |
13 | #include <linux/fwnode_mdio.h> |
14 | #include <linux/kernel.h> |
15 | #include <linux/module.h> |
16 | #include <linux/netdevice.h> |
17 | #include <linux/of.h> |
18 | #include <linux/of_irq.h> |
19 | #include <linux/of_mdio.h> |
20 | #include <linux/of_net.h> |
21 | #include <linux/phy.h> |
22 | #include <linux/phy_fixed.h> |
23 | |
24 | #define DEFAULT_GPIO_RESET_DELAY 10 /* in microseconds */ |
25 | |
26 | MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>" ); |
27 | MODULE_LICENSE("GPL" ); |
28 | MODULE_DESCRIPTION("OpenFirmware MDIO bus (Ethernet PHY) accessors" ); |
29 | |
30 | /* Extract the clause 22 phy ID from the compatible string of the form |
31 | * ethernet-phy-idAAAA.BBBB */ |
32 | static int of_get_phy_id(struct device_node *device, u32 *phy_id) |
33 | { |
34 | return fwnode_get_phy_id(of_fwnode_handle(device), phy_id); |
35 | } |
36 | |
37 | int of_mdiobus_phy_device_register(struct mii_bus *mdio, struct phy_device *phy, |
38 | struct device_node *child, u32 addr) |
39 | { |
40 | return fwnode_mdiobus_phy_device_register(mdio, phy, |
41 | of_fwnode_handle(child), |
42 | addr); |
43 | } |
44 | EXPORT_SYMBOL(of_mdiobus_phy_device_register); |
45 | |
46 | static int of_mdiobus_register_phy(struct mii_bus *mdio, |
47 | struct device_node *child, u32 addr) |
48 | { |
49 | return fwnode_mdiobus_register_phy(bus: mdio, of_fwnode_handle(child), addr); |
50 | } |
51 | |
52 | static int of_mdiobus_register_device(struct mii_bus *mdio, |
53 | struct device_node *child, u32 addr) |
54 | { |
55 | struct fwnode_handle *fwnode = of_fwnode_handle(child); |
56 | struct mdio_device *mdiodev; |
57 | int rc; |
58 | |
59 | mdiodev = mdio_device_create(bus: mdio, addr); |
60 | if (IS_ERR(ptr: mdiodev)) |
61 | return PTR_ERR(ptr: mdiodev); |
62 | |
63 | /* Associate the OF node with the device structure so it |
64 | * can be looked up later. |
65 | */ |
66 | fwnode_handle_get(fwnode); |
67 | device_set_node(dev: &mdiodev->dev, fwnode); |
68 | |
69 | /* All data is now stored in the mdiodev struct; register it. */ |
70 | rc = mdio_device_register(mdiodev); |
71 | if (rc) { |
72 | device_set_node(dev: &mdiodev->dev, NULL); |
73 | fwnode_handle_put(fwnode); |
74 | mdio_device_free(mdiodev); |
75 | return rc; |
76 | } |
77 | |
78 | dev_dbg(&mdio->dev, "registered mdio device %pOFn at address %i\n" , |
79 | child, addr); |
80 | return 0; |
81 | } |
82 | |
83 | /* The following is a list of PHY compatible strings which appear in |
84 | * some DTBs. The compatible string is never matched against a PHY |
85 | * driver, so is pointless. We only expect devices which are not PHYs |
86 | * to have a compatible string, so they can be matched to an MDIO |
87 | * driver. Encourage users to upgrade their DT blobs to remove these. |
88 | */ |
89 | static const struct of_device_id whitelist_phys[] = { |
90 | { .compatible = "brcm,40nm-ephy" }, |
91 | { .compatible = "broadcom,bcm5241" }, |
92 | { .compatible = "marvell,88E1111" , }, |
93 | { .compatible = "marvell,88e1116" , }, |
94 | { .compatible = "marvell,88e1118" , }, |
95 | { .compatible = "marvell,88e1145" , }, |
96 | { .compatible = "marvell,88e1149r" , }, |
97 | { .compatible = "marvell,88e1310" , }, |
98 | { .compatible = "marvell,88E1510" , }, |
99 | { .compatible = "marvell,88E1514" , }, |
100 | { .compatible = "moxa,moxart-rtl8201cp" , }, |
101 | {} |
102 | }; |
103 | |
104 | /* |
105 | * Return true if the child node is for a phy. It must either: |
106 | * o Compatible string of "ethernet-phy-idX.X" |
107 | * o Compatible string of "ethernet-phy-ieee802.3-c45" |
108 | * o Compatible string of "ethernet-phy-ieee802.3-c22" |
109 | * o In the white list above (and issue a warning) |
110 | * o No compatibility string |
111 | * |
112 | * A device which is not a phy is expected to have a compatible string |
113 | * indicating what sort of device it is. |
114 | */ |
115 | bool of_mdiobus_child_is_phy(struct device_node *child) |
116 | { |
117 | u32 phy_id; |
118 | |
119 | if (of_get_phy_id(device: child, phy_id: &phy_id) != -EINVAL) |
120 | return true; |
121 | |
122 | if (of_device_is_compatible(device: child, "ethernet-phy-ieee802.3-c45" )) |
123 | return true; |
124 | |
125 | if (of_device_is_compatible(device: child, "ethernet-phy-ieee802.3-c22" )) |
126 | return true; |
127 | |
128 | if (of_match_node(matches: whitelist_phys, node: child)) { |
129 | pr_warn(FW_WARN |
130 | "%pOF: Whitelisted compatible string. Please remove\n" , |
131 | child); |
132 | return true; |
133 | } |
134 | |
135 | if (!of_property_present(np: child, propname: "compatible" )) |
136 | return true; |
137 | |
138 | return false; |
139 | } |
140 | EXPORT_SYMBOL(of_mdiobus_child_is_phy); |
141 | |
142 | static int __of_mdiobus_parse_phys(struct mii_bus *mdio, struct device_node *np, |
143 | bool *scanphys) |
144 | { |
145 | struct device_node *child; |
146 | int addr, rc = 0; |
147 | |
148 | /* Loop over the child nodes and register a phy_device for each phy */ |
149 | for_each_available_child_of_node(np, child) { |
150 | if (of_node_name_eq(np: child, name: "ethernet-phy-package" )) { |
151 | /* Ignore invalid ethernet-phy-package node */ |
152 | if (!of_property_present(np: child, propname: "reg" )) |
153 | continue; |
154 | |
155 | rc = __of_mdiobus_parse_phys(mdio, np: child, NULL); |
156 | if (rc && rc != -ENODEV) |
157 | goto exit; |
158 | |
159 | continue; |
160 | } |
161 | |
162 | addr = of_mdio_parse_addr(dev: &mdio->dev, np: child); |
163 | if (addr < 0) { |
164 | /* Skip scanning for invalid ethernet-phy-package node */ |
165 | if (scanphys) |
166 | *scanphys = true; |
167 | continue; |
168 | } |
169 | |
170 | if (of_mdiobus_child_is_phy(child)) |
171 | rc = of_mdiobus_register_phy(mdio, child, addr); |
172 | else |
173 | rc = of_mdiobus_register_device(mdio, child, addr); |
174 | |
175 | if (rc == -ENODEV) |
176 | dev_err(&mdio->dev, |
177 | "MDIO device at address %d is missing.\n" , |
178 | addr); |
179 | else if (rc) |
180 | goto exit; |
181 | } |
182 | |
183 | return 0; |
184 | exit: |
185 | of_node_put(node: child); |
186 | return rc; |
187 | } |
188 | |
189 | /** |
190 | * __of_mdiobus_register - Register mii_bus and create PHYs from the device tree |
191 | * @mdio: pointer to mii_bus structure |
192 | * @np: pointer to device_node of MDIO bus. |
193 | * @owner: module owning the @mdio object. |
194 | * |
195 | * This function registers the mii_bus structure and registers a phy_device |
196 | * for each child node of @np. |
197 | */ |
198 | int __of_mdiobus_register(struct mii_bus *mdio, struct device_node *np, |
199 | struct module *owner) |
200 | { |
201 | struct device_node *child; |
202 | bool scanphys = false; |
203 | int addr, rc; |
204 | |
205 | if (!np) |
206 | return __mdiobus_register(bus: mdio, owner); |
207 | |
208 | /* Do not continue if the node is disabled */ |
209 | if (!of_device_is_available(device: np)) |
210 | return -ENODEV; |
211 | |
212 | /* Mask out all PHYs from auto probing. Instead the PHYs listed in |
213 | * the device tree are populated after the bus has been registered */ |
214 | mdio->phy_mask = ~0; |
215 | |
216 | device_set_node(dev: &mdio->dev, of_fwnode_handle(np)); |
217 | |
218 | /* Get bus level PHY reset GPIO details */ |
219 | mdio->reset_delay_us = DEFAULT_GPIO_RESET_DELAY; |
220 | of_property_read_u32(np, propname: "reset-delay-us" , out_value: &mdio->reset_delay_us); |
221 | mdio->reset_post_delay_us = 0; |
222 | of_property_read_u32(np, propname: "reset-post-delay-us" , out_value: &mdio->reset_post_delay_us); |
223 | |
224 | /* Register the MDIO bus */ |
225 | rc = __mdiobus_register(bus: mdio, owner); |
226 | if (rc) |
227 | return rc; |
228 | |
229 | /* Loop over the child nodes and register a phy_device for each phy */ |
230 | rc = __of_mdiobus_parse_phys(mdio, np, scanphys: &scanphys); |
231 | if (rc) |
232 | goto unregister; |
233 | |
234 | if (!scanphys) |
235 | return 0; |
236 | |
237 | /* auto scan for PHYs with empty reg property */ |
238 | for_each_available_child_of_node(np, child) { |
239 | /* Skip PHYs with reg property set or ethernet-phy-package node */ |
240 | if (of_property_present(np: child, propname: "reg" ) || |
241 | of_node_name_eq(np: child, name: "ethernet-phy-package" )) |
242 | continue; |
243 | |
244 | for (addr = 0; addr < PHY_MAX_ADDR; addr++) { |
245 | /* skip already registered PHYs */ |
246 | if (mdiobus_is_registered_device(bus: mdio, addr)) |
247 | continue; |
248 | |
249 | /* be noisy to encourage people to set reg property */ |
250 | dev_info(&mdio->dev, "scan phy %pOFn at address %i\n" , |
251 | child, addr); |
252 | |
253 | if (of_mdiobus_child_is_phy(child)) { |
254 | /* -ENODEV is the return code that PHYLIB has |
255 | * standardized on to indicate that bus |
256 | * scanning should continue. |
257 | */ |
258 | rc = of_mdiobus_register_phy(mdio, child, addr); |
259 | if (!rc) |
260 | break; |
261 | if (rc != -ENODEV) |
262 | goto put_unregister; |
263 | } |
264 | } |
265 | } |
266 | |
267 | return 0; |
268 | |
269 | put_unregister: |
270 | of_node_put(node: child); |
271 | unregister: |
272 | mdiobus_unregister(bus: mdio); |
273 | return rc; |
274 | } |
275 | EXPORT_SYMBOL(__of_mdiobus_register); |
276 | |
277 | /** |
278 | * of_mdio_find_device - Given a device tree node, find the mdio_device |
279 | * @np: pointer to the mdio_device's device tree node |
280 | * |
281 | * If successful, returns a pointer to the mdio_device with the embedded |
282 | * struct device refcount incremented by one, or NULL on failure. |
283 | * The caller should call put_device() on the mdio_device after its use |
284 | */ |
285 | struct mdio_device *of_mdio_find_device(struct device_node *np) |
286 | { |
287 | return fwnode_mdio_find_device(of_fwnode_handle(np)); |
288 | } |
289 | EXPORT_SYMBOL(of_mdio_find_device); |
290 | |
291 | /** |
292 | * of_phy_find_device - Give a PHY node, find the phy_device |
293 | * @phy_np: Pointer to the phy's device tree node |
294 | * |
295 | * If successful, returns a pointer to the phy_device with the embedded |
296 | * struct device refcount incremented by one, or NULL on failure. |
297 | */ |
298 | struct phy_device *of_phy_find_device(struct device_node *phy_np) |
299 | { |
300 | return fwnode_phy_find_device(of_fwnode_handle(phy_np)); |
301 | } |
302 | EXPORT_SYMBOL(of_phy_find_device); |
303 | |
304 | /** |
305 | * of_phy_connect - Connect to the phy described in the device tree |
306 | * @dev: pointer to net_device claiming the phy |
307 | * @phy_np: Pointer to device tree node for the PHY |
308 | * @hndlr: Link state callback for the network device |
309 | * @flags: flags to pass to the PHY |
310 | * @iface: PHY data interface type |
311 | * |
312 | * If successful, returns a pointer to the phy_device with the embedded |
313 | * struct device refcount incremented by one, or NULL on failure. The |
314 | * refcount must be dropped by calling phy_disconnect() or phy_detach(). |
315 | */ |
316 | struct phy_device *of_phy_connect(struct net_device *dev, |
317 | struct device_node *phy_np, |
318 | void (*hndlr)(struct net_device *), u32 flags, |
319 | phy_interface_t iface) |
320 | { |
321 | struct phy_device *phy = of_phy_find_device(phy_np); |
322 | int ret; |
323 | |
324 | if (!phy) |
325 | return NULL; |
326 | |
327 | phy->dev_flags |= flags; |
328 | |
329 | ret = phy_connect_direct(dev, phydev: phy, handler: hndlr, interface: iface); |
330 | |
331 | /* refcount is held by phy_connect_direct() on success */ |
332 | put_device(dev: &phy->mdio.dev); |
333 | |
334 | return ret ? NULL : phy; |
335 | } |
336 | EXPORT_SYMBOL(of_phy_connect); |
337 | |
338 | /** |
339 | * of_phy_get_and_connect |
340 | * - Get phy node and connect to the phy described in the device tree |
341 | * @dev: pointer to net_device claiming the phy |
342 | * @np: Pointer to device tree node for the net_device claiming the phy |
343 | * @hndlr: Link state callback for the network device |
344 | * |
345 | * If successful, returns a pointer to the phy_device with the embedded |
346 | * struct device refcount incremented by one, or NULL on failure. The |
347 | * refcount must be dropped by calling phy_disconnect() or phy_detach(). |
348 | */ |
349 | struct phy_device *of_phy_get_and_connect(struct net_device *dev, |
350 | struct device_node *np, |
351 | void (*hndlr)(struct net_device *)) |
352 | { |
353 | phy_interface_t iface; |
354 | struct device_node *phy_np; |
355 | struct phy_device *phy; |
356 | int ret; |
357 | |
358 | ret = of_get_phy_mode(np, interface: &iface); |
359 | if (ret) |
360 | return NULL; |
361 | if (of_phy_is_fixed_link(np)) { |
362 | ret = of_phy_register_fixed_link(np); |
363 | if (ret < 0) { |
364 | netdev_err(dev, format: "broken fixed-link specification\n" ); |
365 | return NULL; |
366 | } |
367 | phy_np = of_node_get(node: np); |
368 | } else { |
369 | phy_np = of_parse_phandle(np, phandle_name: "phy-handle" , index: 0); |
370 | if (!phy_np) |
371 | return NULL; |
372 | } |
373 | |
374 | phy = of_phy_connect(dev, phy_np, hndlr, 0, iface); |
375 | |
376 | of_node_put(node: phy_np); |
377 | |
378 | return phy; |
379 | } |
380 | EXPORT_SYMBOL(of_phy_get_and_connect); |
381 | |
382 | /* |
383 | * of_phy_is_fixed_link() and of_phy_register_fixed_link() must |
384 | * support two DT bindings: |
385 | * - the old DT binding, where 'fixed-link' was a property with 5 |
386 | * cells encoding various information about the fixed PHY |
387 | * - the new DT binding, where 'fixed-link' is a sub-node of the |
388 | * Ethernet device. |
389 | */ |
390 | bool of_phy_is_fixed_link(struct device_node *np) |
391 | { |
392 | struct device_node *dn; |
393 | int len, err; |
394 | const char *managed; |
395 | |
396 | /* New binding */ |
397 | dn = of_get_child_by_name(node: np, name: "fixed-link" ); |
398 | if (dn) { |
399 | of_node_put(node: dn); |
400 | return true; |
401 | } |
402 | |
403 | err = of_property_read_string(np, propname: "managed" , out_string: &managed); |
404 | if (err == 0 && strcmp(managed, "auto" ) != 0) |
405 | return true; |
406 | |
407 | /* Old binding */ |
408 | if (of_get_property(node: np, name: "fixed-link" , lenp: &len) && |
409 | len == (5 * sizeof(__be32))) |
410 | return true; |
411 | |
412 | return false; |
413 | } |
414 | EXPORT_SYMBOL(of_phy_is_fixed_link); |
415 | |
416 | int of_phy_register_fixed_link(struct device_node *np) |
417 | { |
418 | struct fixed_phy_status status = {}; |
419 | struct device_node *fixed_link_node; |
420 | u32 fixed_link_prop[5]; |
421 | const char *managed; |
422 | |
423 | if (of_property_read_string(np, propname: "managed" , out_string: &managed) == 0 && |
424 | strcmp(managed, "in-band-status" ) == 0) { |
425 | /* status is zeroed, namely its .link member */ |
426 | goto register_phy; |
427 | } |
428 | |
429 | /* New binding */ |
430 | fixed_link_node = of_get_child_by_name(node: np, name: "fixed-link" ); |
431 | if (fixed_link_node) { |
432 | status.link = 1; |
433 | status.duplex = of_property_read_bool(np: fixed_link_node, |
434 | propname: "full-duplex" ); |
435 | if (of_property_read_u32(np: fixed_link_node, propname: "speed" , |
436 | out_value: &status.speed)) { |
437 | of_node_put(node: fixed_link_node); |
438 | return -EINVAL; |
439 | } |
440 | status.pause = of_property_read_bool(np: fixed_link_node, propname: "pause" ); |
441 | status.asym_pause = of_property_read_bool(np: fixed_link_node, |
442 | propname: "asym-pause" ); |
443 | of_node_put(node: fixed_link_node); |
444 | |
445 | goto register_phy; |
446 | } |
447 | |
448 | /* Old binding */ |
449 | if (of_property_read_u32_array(np, propname: "fixed-link" , out_values: fixed_link_prop, |
450 | ARRAY_SIZE(fixed_link_prop)) == 0) { |
451 | status.link = 1; |
452 | status.duplex = fixed_link_prop[1]; |
453 | status.speed = fixed_link_prop[2]; |
454 | status.pause = fixed_link_prop[3]; |
455 | status.asym_pause = fixed_link_prop[4]; |
456 | goto register_phy; |
457 | } |
458 | |
459 | return -ENODEV; |
460 | |
461 | register_phy: |
462 | return PTR_ERR_OR_ZERO(ptr: fixed_phy_register(PHY_POLL, status: &status, np)); |
463 | } |
464 | EXPORT_SYMBOL(of_phy_register_fixed_link); |
465 | |
466 | void of_phy_deregister_fixed_link(struct device_node *np) |
467 | { |
468 | struct phy_device *phydev; |
469 | |
470 | phydev = of_phy_find_device(np); |
471 | if (!phydev) |
472 | return; |
473 | |
474 | fixed_phy_unregister(phydev); |
475 | |
476 | put_device(dev: &phydev->mdio.dev); /* of_phy_find_device() */ |
477 | phy_device_free(phydev); /* fixed_phy_register() */ |
478 | } |
479 | EXPORT_SYMBOL(of_phy_deregister_fixed_link); |
480 | |