blob: cf694359534824dec894599315c2e2398b4f8501 [file] [log] [blame]
xjb04a4022021-11-25 15:01:52 +08001/*
2 * OF helpers for network devices.
3 *
4 * This file is released under the GPLv2
5 *
6 * Initially copied out of arch/powerpc/kernel/prom_parse.c
7 */
8#include <linux/etherdevice.h>
9#include <linux/kernel.h>
10#include <linux/nvmem-consumer.h>
11#include <linux/of_net.h>
12#include <linux/phy.h>
13#include <linux/export.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_address_mtd(struct device_node *np)
53{
54#ifdef CONFIG_MTD
55 struct device_node *mtd_np = NULL;
56 struct property *prop;
57 size_t retlen;
58 int size, ret;
59 struct mtd_info *mtd;
60 const char *part;
61 const __be32 *list;
62 phandle phandle;
63 u32 mac_inc = 0;
64 u8 mac[ETH_ALEN];
65 void *addr;
66 u32 inc_idx;
67
68 list = of_get_property(np, "mtd-mac-address", &size);
69 if (!list || (size != (2 * sizeof(*list))))
70 return NULL;
71
72 phandle = be32_to_cpup(list++);
73 if (phandle)
74 mtd_np = of_find_node_by_phandle(phandle);
75
76 if (!mtd_np)
77 return NULL;
78
79 part = of_get_property(mtd_np, "label", NULL);
80 if (!part)
81 part = mtd_np->name;
82
83 mtd = get_mtd_device_nm(part);
84 if (IS_ERR(mtd))
85 return NULL;
86
87 ret = mtd_read(mtd, be32_to_cpup(list), 6, &retlen, mac);
88 put_mtd_device(mtd);
89
90 if (of_property_read_u32(np, "mtd-mac-address-increment-byte", &inc_idx))
91 inc_idx = 5;
92 if (inc_idx > 5)
93 return NULL;
94
95 if (!of_property_read_u32(np, "mtd-mac-address-increment", &mac_inc))
96 mac[inc_idx] += mac_inc;
97
98 if (!is_valid_ether_addr(mac))
99 return NULL;
100
101 addr = of_get_mac_addr(np, "mac-address");
102 if (addr) {
103 memcpy(addr, mac, ETH_ALEN);
104 return addr;
105 }
106
107 prop = kzalloc(sizeof(*prop), GFP_KERNEL);
108 if (!prop)
109 return NULL;
110
111 prop->name = "mac-address";
112 prop->length = ETH_ALEN;
113 prop->value = kmemdup(mac, ETH_ALEN, GFP_KERNEL);
114 if (!prop->value || of_add_property(np, prop))
115 goto free;
116
117 return prop->value;
118free:
119 kfree(prop->value);
120 kfree(prop);
121#endif
122 return NULL;
123}
124
125/**
126 * Search the device tree for the best MAC address to use. 'mac-address' is
127 * checked first, because that is supposed to contain to "most recent" MAC
128 * address. If that isn't set, then 'local-mac-address' is checked next,
129 * because that is the default address. If that isn't set, then the obsolete
130 * 'address' is checked, just in case we're using an old device tree.
131 *
132 * Note that the 'address' property is supposed to contain a virtual address of
133 * the register set, but some DTS files have redefined that property to be the
134 * MAC address.
135 *
136 * All-zero MAC addresses are rejected, because those could be properties that
137 * exist in the device tree, but were not set by U-Boot. For example, the
138 * DTS could define 'mac-address' and 'local-mac-address', with zero MAC
139 * addresses. Some older U-Boots only initialized 'local-mac-address'. In
140 * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
141 * but is all zeros.
142 *
143 * If a mtd-mac-address property exists, try to fetch the MAC address from the
144 * specified mtd device, and store it as a 'mac-address' property
145*/
146const void *of_get_mac_address(struct device_node *np)
147{
148 const void *addr;
149
150 addr = of_get_mac_address_mtd(np);
151 if (addr)
152 return addr;
153
154 addr = of_get_mac_addr(np, "mac-address");
155 if (addr)
156 return addr;
157
158 addr = of_get_mac_addr(np, "local-mac-address");
159 if (addr)
160 return addr;
161
162 return of_get_mac_addr(np, "address");
163}
164EXPORT_SYMBOL(of_get_mac_address);
165
166/**
167 * Obtain the MAC address from an nvmem provider named 'mac-address' through
168 * device tree.
169 * On success, copies the new address into memory pointed to by addr and
170 * returns 0. Returns a negative error code otherwise.
171 * @np: Device tree node containing the nvmem-cells phandle
172 * @addr: Pointer to receive the MAC address using ether_addr_copy()
173 */
174int of_get_nvmem_mac_address(struct device_node *np, void *addr)
175{
176 struct nvmem_cell *cell;
177 const void *mac;
178 size_t len;
179 int ret;
180
181 cell = of_nvmem_cell_get(np, "mac-address");
182 if (IS_ERR(cell))
183 return PTR_ERR(cell);
184
185 mac = nvmem_cell_read(cell, &len);
186
187 nvmem_cell_put(cell);
188
189 if (IS_ERR(mac))
190 return PTR_ERR(mac);
191
192 if (len < ETH_ALEN || !is_valid_ether_addr(mac)) {
193 ret = -EINVAL;
194 } else {
195 ether_addr_copy(addr, mac);
196 ret = 0;
197 }
198
199 kfree(mac);
200
201 return ret;
202}
203EXPORT_SYMBOL(of_get_nvmem_mac_address);