blob: f2310fe58e7a9b286ee224efb6ee1330a5399a1d [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * OF helpers for network devices.
4 *
5 * 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>
10#include <linux/of_platform.h>
11#include <linux/phy.h>
12#include <linux/export.h>
13#include <linux/device.h>
14#include <linux/mtd/mtd.h>
15
16/**
17 * of_get_phy_mode - Get phy mode for given device_node
18 * @np: Pointer to the given device_node
19 *
20 * The function gets phy interface string from property 'phy-mode' or
21 * 'phy-connection-type', and return its index in phy_modes table, or errno in
22 * error case.
23 */
24int of_get_phy_mode(struct device_node *np)
25{
26 const char *pm;
27 int err, i;
28
29 err = of_property_read_string(np, "phy-mode", &pm);
30 if (err < 0)
31 err = of_property_read_string(np, "phy-connection-type", &pm);
32 if (err < 0)
33 return err;
34
35 for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
36 if (!strcasecmp(pm, phy_modes(i)))
37 return i;
38
39 return -ENODEV;
40}
41EXPORT_SYMBOL_GPL(of_get_phy_mode);
42
43static void *of_get_mac_addr(struct device_node *np, const char *name)
44{
45 struct property *pp = of_find_property(np, name, NULL);
46
47 if (pp && pp->length == ETH_ALEN && is_valid_ether_addr(pp->value))
48 return pp->value;
49 return NULL;
50}
51
52static const void *of_get_mac_addr_nvmem(struct device_node *np)
53{
54 int ret;
55 const void *mac;
56 u8 nvmem_mac[ETH_ALEN];
57 struct platform_device *pdev = of_find_device_by_node(np);
58
59 if (!pdev)
60 return ERR_PTR(-ENODEV);
61
62 ret = nvmem_get_mac_address(&pdev->dev, &nvmem_mac);
63 if (ret) {
64 put_device(&pdev->dev);
65 return ERR_PTR(ret);
66 }
67
68 mac = devm_kmemdup(&pdev->dev, nvmem_mac, ETH_ALEN, GFP_KERNEL);
69 put_device(&pdev->dev);
70 if (!mac)
71 return ERR_PTR(-ENOMEM);
72
73 return mac;
74}
75
76static const void *of_get_mac_address_mtd(struct device_node *np)
77{
78#ifdef CONFIG_MTD
79 struct device_node *mtd_np = NULL;
80 struct property *prop;
81 size_t retlen;
82 int size, ret;
83 struct mtd_info *mtd;
84 const char *part;
85 const __be32 *list;
86 phandle phandle;
87 u32 mac_inc = 0;
88 u8 mac[ETH_ALEN];
89 void *addr;
90 u32 inc_idx;
91
92 list = of_get_property(np, "mtd-mac-address", &size);
93 if (!list || (size != (2 * sizeof(*list))))
94 return NULL;
95
96 phandle = be32_to_cpup(list++);
97 if (phandle)
98 mtd_np = of_find_node_by_phandle(phandle);
99
100 if (!mtd_np)
101 return NULL;
102
103 part = of_get_property(mtd_np, "label", NULL);
104 if (!part)
105 part = mtd_np->name;
106
107 mtd = get_mtd_device_nm(part);
108 if (IS_ERR(mtd))
109 return NULL;
110
111 ret = mtd_read(mtd, be32_to_cpup(list), 6, &retlen, mac);
112 put_mtd_device(mtd);
113
114 if (of_property_read_u32(np, "mtd-mac-address-increment-byte", &inc_idx))
115 inc_idx = 5;
116 if (inc_idx > 5)
117 return NULL;
118
119 if (!of_property_read_u32(np, "mtd-mac-address-increment", &mac_inc))
120 mac[inc_idx] += mac_inc;
121
122 if (!is_valid_ether_addr(mac))
123 return NULL;
124
125 addr = of_get_mac_addr(np, "mac-address");
126 if (addr) {
127 memcpy(addr, mac, ETH_ALEN);
128 return addr;
129 }
130
131 prop = kzalloc(sizeof(*prop), GFP_KERNEL);
132 if (!prop)
133 return NULL;
134
135 prop->name = "mac-address";
136 prop->length = ETH_ALEN;
137 prop->value = kmemdup(mac, ETH_ALEN, GFP_KERNEL);
138 if (!prop->value || of_add_property(np, prop))
139 goto free;
140
141 return prop->value;
142free:
143 kfree(prop->value);
144 kfree(prop);
145#endif
146 return NULL;
147}
148
149/**
150 * Search the device tree for the best MAC address to use. 'mac-address' is
151 * checked first, because that is supposed to contain to "most recent" MAC
152 * address. If that isn't set, then 'local-mac-address' is checked next,
153 * because that is the default address. If that isn't set, then the obsolete
154 * 'address' is checked, just in case we're using an old device tree. If any
155 * of the above isn't set, then try to get MAC address from nvmem cell named
156 * 'mac-address'.
157 *
158 * Note that the 'address' property is supposed to contain a virtual address of
159 * the register set, but some DTS files have redefined that property to be the
160 * MAC address.
161 *
162 * All-zero MAC addresses are rejected, because those could be properties that
163 * exist in the device tree, but were not set by U-Boot. For example, the
164 * DTS could define 'mac-address' and 'local-mac-address', with zero MAC
165 * addresses. Some older U-Boots only initialized 'local-mac-address'. In
166 * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
167 * but is all zeros.
168 *
169 *
170 * If a mtd-mac-address property exists, try to fetch the MAC address from the
171 * specified mtd device, and store it as a 'mac-address' property
172 *
173 * Return: Will be a valid pointer on success and ERR_PTR in case of error.
174*/
175const void *of_get_mac_address(struct device_node *np)
176{
177 const void *addr;
178
179 addr = of_get_mac_address_mtd(np);
180 if (addr)
181 return addr;
182
183 addr = of_get_mac_addr(np, "mac-address");
184 if (addr)
185 return addr;
186
187 addr = of_get_mac_addr(np, "local-mac-address");
188 if (addr)
189 return addr;
190
191 addr = of_get_mac_addr(np, "address");
192 if (addr)
193 return addr;
194
195 return of_get_mac_addr_nvmem(np);
196}
197EXPORT_SYMBOL(of_get_mac_address);