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