blob: dbac3a172a11eb855b1fb135ea680b1ab1a2692d [file] [log] [blame]
Thomas Gleixner55716d22019-06-01 10:08:42 +02001// SPDX-License-Identifier: GPL-2.0-only
David Daney4b6ba8a2010-10-26 15:07:13 -07002/*
3 * OF helpers for network devices.
4 *
David Daney4b6ba8a2010-10-26 15:07:13 -07005 * Initially copied out of arch/powerpc/kernel/prom_parse.c
6 */
7#include <linux/etherdevice.h>
8#include <linux/kernel.h>
9#include <linux/of_net.h>
Petr Štetiard01f4492019-05-03 16:27:06 +020010#include <linux/of_platform.h>
Shawn Guo6ca1a112011-07-04 14:03:17 +080011#include <linux/phy.h>
Paul Gortmaker2c8d6672011-07-29 16:05:38 +100012#include <linux/export.h>
Petr Štetiard01f4492019-05-03 16:27:06 +020013#include <linux/device.h>
Michael Wallef10843e2021-04-12 19:47:18 +020014#include <linux/nvmem-consumer.h>
Shawn Guo6ca1a112011-07-04 14:03:17 +080015
16/**
Shawn Guo6ca1a112011-07-04 14:03:17 +080017 * of_get_phy_mode - Get phy mode for given device_node
18 * @np: Pointer to the given device_node
Andrew Lunn0c65b2b2019-11-04 02:40:33 +010019 * @interface: Pointer to the result
Shawn Guo6ca1a112011-07-04 14:03:17 +080020 *
Florian Fainellicf4c9eb2013-11-15 06:23:32 +000021 * The function gets phy interface string from property 'phy-mode' or
Andrew Lunn0c65b2b2019-11-04 02:40:33 +010022 * 'phy-connection-type'. The index in phy_modes table is set in
23 * interface and 0 returned. In case of error interface is set to
24 * PHY_INTERFACE_MODE_NA and an errno is returned, e.g. -ENODEV.
Shawn Guo6ca1a112011-07-04 14:03:17 +080025 */
Andrew Lunn0c65b2b2019-11-04 02:40:33 +010026int of_get_phy_mode(struct device_node *np, phy_interface_t *interface)
Shawn Guo6ca1a112011-07-04 14:03:17 +080027{
28 const char *pm;
29 int err, i;
30
Andrew Lunn0c65b2b2019-11-04 02:40:33 +010031 *interface = PHY_INTERFACE_MODE_NA;
32
Shawn Guo6ca1a112011-07-04 14:03:17 +080033 err = of_property_read_string(np, "phy-mode", &pm);
34 if (err < 0)
Florian Fainellicf4c9eb2013-11-15 06:23:32 +000035 err = of_property_read_string(np, "phy-connection-type", &pm);
36 if (err < 0)
Shawn Guo6ca1a112011-07-04 14:03:17 +080037 return err;
38
Florian Fainelli8a2fe562014-02-11 17:27:39 -080039 for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
Andrew Lunn0c65b2b2019-11-04 02:40:33 +010040 if (!strcasecmp(pm, phy_modes(i))) {
41 *interface = i;
42 return 0;
43 }
Shawn Guo6ca1a112011-07-04 14:03:17 +080044
45 return -ENODEV;
46}
47EXPORT_SYMBOL_GPL(of_get_phy_mode);
David Daney4b6ba8a2010-10-26 15:07:13 -070048
Michael Walle83216e32021-04-12 19:47:17 +020049static int of_get_mac_addr(struct device_node *np, const char *name, u8 *addr)
Sergei Shtylyov3eb46a12015-03-18 22:25:46 +030050{
51 struct property *pp = of_find_property(np, name, NULL);
52
Michael Walle83216e32021-04-12 19:47:17 +020053 if (pp && pp->length == ETH_ALEN && is_valid_ether_addr(pp->value)) {
54 memcpy(addr, pp->value, ETH_ALEN);
55 return 0;
56 }
57 return -ENODEV;
Sergei Shtylyov3eb46a12015-03-18 22:25:46 +030058}
59
Michael Walle83216e32021-04-12 19:47:17 +020060static int of_get_mac_addr_nvmem(struct device_node *np, u8 *addr)
Petr Štetiard01f4492019-05-03 16:27:06 +020061{
Petr Štetiard01f4492019-05-03 16:27:06 +020062 struct platform_device *pdev = of_find_device_by_node(np);
Michael Wallef10843e2021-04-12 19:47:18 +020063 struct nvmem_cell *cell;
64 const void *mac;
65 size_t len;
Michael Walle83216e32021-04-12 19:47:17 +020066 int ret;
Petr Štetiard01f4492019-05-03 16:27:06 +020067
Michael Wallef10843e2021-04-12 19:47:18 +020068 /* Try lookup by device first, there might be a nvmem_cell_lookup
69 * associated with a given device.
70 */
71 if (pdev) {
72 ret = nvmem_get_mac_address(&pdev->dev, addr);
73 put_device(&pdev->dev);
74 return ret;
75 }
Petr Štetiard01f4492019-05-03 16:27:06 +020076
Michael Wallef10843e2021-04-12 19:47:18 +020077 cell = of_nvmem_cell_get(np, "mac-address");
78 if (IS_ERR(cell))
79 return PTR_ERR(cell);
Petr Štetiard01f4492019-05-03 16:27:06 +020080
Michael Wallef10843e2021-04-12 19:47:18 +020081 mac = nvmem_cell_read(cell, &len);
82 nvmem_cell_put(cell);
83
84 if (IS_ERR(mac))
85 return PTR_ERR(mac);
86
87 if (len != ETH_ALEN || !is_valid_ether_addr(mac)) {
88 kfree(mac);
89 return -EINVAL;
90 }
91
92 memcpy(addr, mac, ETH_ALEN);
93 kfree(mac);
94
95 return 0;
Petr Štetiard01f4492019-05-03 16:27:06 +020096}
97
David Daney4b6ba8a2010-10-26 15:07:13 -070098/**
Lee Jones21e0b8f2021-03-18 10:40:34 +000099 * of_get_mac_address()
100 * @np: Caller's Device Node
Michael Walle83216e32021-04-12 19:47:17 +0200101 * @addr: Pointer to a six-byte array for the result
Lee Jones21e0b8f2021-03-18 10:40:34 +0000102 *
David Daney4b6ba8a2010-10-26 15:07:13 -0700103 * Search the device tree for the best MAC address to use. 'mac-address' is
104 * checked first, because that is supposed to contain to "most recent" MAC
105 * address. If that isn't set, then 'local-mac-address' is checked next,
Petr Štetiard01f4492019-05-03 16:27:06 +0200106 * because that is the default address. If that isn't set, then the obsolete
107 * 'address' is checked, just in case we're using an old device tree. If any
108 * of the above isn't set, then try to get MAC address from nvmem cell named
109 * 'mac-address'.
David Daney4b6ba8a2010-10-26 15:07:13 -0700110 *
111 * Note that the 'address' property is supposed to contain a virtual address of
112 * the register set, but some DTS files have redefined that property to be the
113 * MAC address.
114 *
115 * All-zero MAC addresses are rejected, because those could be properties that
116 * exist in the device tree, but were not set by U-Boot. For example, the
117 * DTS could define 'mac-address' and 'local-mac-address', with zero MAC
118 * addresses. Some older U-Boots only initialized 'local-mac-address'. In
119 * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
120 * but is all zeros.
Petr Štetiard01f4492019-05-03 16:27:06 +0200121 *
Michael Walle83216e32021-04-12 19:47:17 +0200122 * Return: 0 on success and errno in case of error.
David Daney4b6ba8a2010-10-26 15:07:13 -0700123*/
Michael Walle83216e32021-04-12 19:47:17 +0200124int of_get_mac_address(struct device_node *np, u8 *addr)
David Daney4b6ba8a2010-10-26 15:07:13 -0700125{
Michael Walle83216e32021-04-12 19:47:17 +0200126 int ret;
David Daney4b6ba8a2010-10-26 15:07:13 -0700127
Michael Walle83216e32021-04-12 19:47:17 +0200128 if (!np)
129 return -ENODEV;
David Daney4b6ba8a2010-10-26 15:07:13 -0700130
Michael Walle83216e32021-04-12 19:47:17 +0200131 ret = of_get_mac_addr(np, "mac-address", addr);
132 if (!ret)
133 return 0;
David Daney4b6ba8a2010-10-26 15:07:13 -0700134
Michael Walle83216e32021-04-12 19:47:17 +0200135 ret = of_get_mac_addr(np, "local-mac-address", addr);
136 if (!ret)
137 return 0;
Petr Štetiard01f4492019-05-03 16:27:06 +0200138
Michael Walle83216e32021-04-12 19:47:17 +0200139 ret = of_get_mac_addr(np, "address", addr);
140 if (!ret)
141 return 0;
142
143 return of_get_mac_addr_nvmem(np, addr);
David Daney4b6ba8a2010-10-26 15:07:13 -0700144}
145EXPORT_SYMBOL(of_get_mac_address);