Commit | Line | Data |
---|---|---|
0e3d6777 | 1 | // SPDX-License-Identifier: ISC |
17f1de56 FF |
2 | /* |
3 | * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> | |
17f1de56 FF |
4 | */ |
5 | #include <linux/of.h> | |
6 | #include <linux/of_net.h> | |
7 | #include <linux/mtd/mtd.h> | |
8 | #include <linux/mtd/partitions.h> | |
9 | #include <linux/etherdevice.h> | |
10 | #include "mt76.h" | |
11 | ||
12 | static int | |
13 | mt76_get_of_eeprom(struct mt76_dev *dev, int len) | |
14 | { | |
15 | #if defined(CONFIG_OF) && defined(CONFIG_MTD) | |
16 | struct device_node *np = dev->dev->of_node; | |
17 | struct mtd_info *mtd; | |
18 | const __be32 *list; | |
19 | const char *part; | |
20 | phandle phandle; | |
21 | int offset = 0; | |
22 | int size; | |
23 | size_t retlen; | |
24 | int ret; | |
25 | ||
26 | if (!np) | |
27 | return -ENOENT; | |
28 | ||
29 | list = of_get_property(np, "mediatek,mtd-eeprom", &size); | |
30 | if (!list) | |
31 | return -ENOENT; | |
32 | ||
33 | phandle = be32_to_cpup(list++); | |
34 | if (!phandle) | |
35 | return -ENOENT; | |
36 | ||
37 | np = of_find_node_by_phandle(phandle); | |
38 | if (!np) | |
39 | return -EINVAL; | |
40 | ||
41 | part = of_get_property(np, "label", NULL); | |
42 | if (!part) | |
43 | part = np->name; | |
44 | ||
45 | mtd = get_mtd_device_nm(part); | |
34e022d8 WY |
46 | if (IS_ERR(mtd)) { |
47 | ret = PTR_ERR(mtd); | |
48 | goto out_put_node; | |
49 | } | |
17f1de56 | 50 | |
34e022d8 WY |
51 | if (size <= sizeof(*list)) { |
52 | ret = -EINVAL; | |
53 | goto out_put_node; | |
54 | } | |
17f1de56 FF |
55 | |
56 | offset = be32_to_cpup(list); | |
57 | ret = mtd_read(mtd, offset, len, &retlen, dev->eeprom.data); | |
58 | put_mtd_device(mtd); | |
59 | if (ret) | |
34e022d8 | 60 | goto out_put_node; |
17f1de56 | 61 | |
34e022d8 WY |
62 | if (retlen < len) { |
63 | ret = -EINVAL; | |
64 | goto out_put_node; | |
65 | } | |
17f1de56 | 66 | |
34e022d8 WY |
67 | out_put_node: |
68 | of_node_put(np); | |
69 | return ret; | |
17f1de56 FF |
70 | #else |
71 | return -ENOENT; | |
72 | #endif | |
73 | } | |
74 | ||
75 | void | |
76 | mt76_eeprom_override(struct mt76_dev *dev) | |
77 | { | |
78 | #ifdef CONFIG_OF | |
79 | struct device_node *np = dev->dev->of_node; | |
80 | const u8 *mac; | |
81 | ||
82 | if (!np) | |
83 | return; | |
84 | ||
85 | mac = of_get_mac_address(np); | |
d31a36b5 | 86 | if (!IS_ERR(mac)) |
1b9705d9 | 87 | ether_addr_copy(dev->macaddr, mac); |
17f1de56 FF |
88 | #endif |
89 | ||
90 | if (!is_valid_ether_addr(dev->macaddr)) { | |
91 | eth_random_addr(dev->macaddr); | |
92 | dev_info(dev->dev, | |
93 | "Invalid MAC address, using random address %pM\n", | |
94 | dev->macaddr); | |
95 | } | |
96 | } | |
97 | EXPORT_SYMBOL_GPL(mt76_eeprom_override); | |
98 | ||
99 | int | |
100 | mt76_eeprom_init(struct mt76_dev *dev, int len) | |
101 | { | |
102 | dev->eeprom.size = len; | |
103 | dev->eeprom.data = devm_kzalloc(dev->dev, len, GFP_KERNEL); | |
104 | if (!dev->eeprom.data) | |
105 | return -ENOMEM; | |
106 | ||
107 | return !mt76_get_of_eeprom(dev, len); | |
108 | } | |
109 | EXPORT_SYMBOL_GPL(mt76_eeprom_init); |