Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/mediatek/mt76/mt7615/eeprom.c
48526 views
1
// SPDX-License-Identifier: ISC
2
/* Copyright (C) 2019 MediaTek Inc.
3
*
4
* Author: Ryder Lee <[email protected]>
5
* Felix Fietkau <[email protected]>
6
*/
7
8
#include <linux/of.h>
9
#if defined(__FreeBSD__)
10
#include <linux/delay.h>
11
#endif
12
#include "mt7615.h"
13
#include "eeprom.h"
14
15
static int mt7615_efuse_read(struct mt7615_dev *dev, u32 base,
16
u16 addr, u8 *data)
17
{
18
u32 val;
19
int i;
20
21
val = mt76_rr(dev, base + MT_EFUSE_CTRL);
22
val &= ~(MT_EFUSE_CTRL_AIN | MT_EFUSE_CTRL_MODE);
23
val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf);
24
val |= MT_EFUSE_CTRL_KICK;
25
mt76_wr(dev, base + MT_EFUSE_CTRL, val);
26
27
if (!mt76_poll(dev, base + MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000))
28
return -ETIMEDOUT;
29
30
udelay(2);
31
32
val = mt76_rr(dev, base + MT_EFUSE_CTRL);
33
if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT ||
34
WARN_ON_ONCE(!(val & MT_EFUSE_CTRL_VALID))) {
35
memset(data, 0x0, 16);
36
return 0;
37
}
38
39
for (i = 0; i < 4; i++) {
40
val = mt76_rr(dev, base + MT_EFUSE_RDATA(i));
41
put_unaligned_le32(val, data + 4 * i);
42
}
43
44
return 0;
45
}
46
47
static int mt7615_efuse_init(struct mt7615_dev *dev, u32 base)
48
{
49
int i, len = MT7615_EEPROM_SIZE;
50
void *buf;
51
u32 val;
52
53
if (is_mt7663(&dev->mt76))
54
len = MT7663_EEPROM_SIZE;
55
56
val = mt76_rr(dev, base + MT_EFUSE_BASE_CTRL);
57
if (val & MT_EFUSE_BASE_CTRL_EMPTY)
58
return 0;
59
60
dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, len, GFP_KERNEL);
61
dev->mt76.otp.size = len;
62
if (!dev->mt76.otp.data)
63
return -ENOMEM;
64
65
buf = dev->mt76.otp.data;
66
for (i = 0; i + 16 <= len; i += 16) {
67
int ret;
68
69
#if defined(__linux__)
70
ret = mt7615_efuse_read(dev, base, i, buf + i);
71
#elif defined(__FreeBSD__)
72
ret = mt7615_efuse_read(dev, base, i, (u8 *)buf + i);
73
#endif
74
if (ret)
75
return ret;
76
}
77
78
return 0;
79
}
80
81
static int mt7615_eeprom_load(struct mt7615_dev *dev, u32 addr)
82
{
83
int ret;
84
85
BUILD_BUG_ON(MT7615_EEPROM_FULL_SIZE < MT7663_EEPROM_SIZE);
86
87
ret = mt76_eeprom_init(&dev->mt76, MT7615_EEPROM_FULL_SIZE);
88
if (ret < 0)
89
return ret;
90
91
return mt7615_efuse_init(dev, addr);
92
}
93
94
static int mt7615_check_eeprom(struct mt76_dev *dev)
95
{
96
u16 val = get_unaligned_le16(dev->eeprom.data);
97
98
switch (val) {
99
case 0x7615:
100
case 0x7622:
101
case 0x7663:
102
return 0;
103
default:
104
return -EINVAL;
105
}
106
}
107
108
static void
109
mt7615_eeprom_parse_hw_band_cap(struct mt7615_dev *dev)
110
{
111
u8 val, *eeprom = dev->mt76.eeprom.data;
112
113
if (is_mt7663(&dev->mt76)) {
114
/* dual band */
115
dev->mphy.cap.has_2ghz = true;
116
dev->mphy.cap.has_5ghz = true;
117
return;
118
}
119
120
if (is_mt7622(&dev->mt76)) {
121
/* 2GHz only */
122
dev->mphy.cap.has_2ghz = true;
123
return;
124
}
125
126
if (is_mt7611(&dev->mt76)) {
127
/* 5GHz only */
128
dev->mphy.cap.has_5ghz = true;
129
return;
130
}
131
132
val = FIELD_GET(MT_EE_NIC_WIFI_CONF_BAND_SEL,
133
eeprom[MT_EE_WIFI_CONF]);
134
switch (val) {
135
case MT_EE_5GHZ:
136
dev->mphy.cap.has_5ghz = true;
137
break;
138
case MT_EE_DBDC:
139
dev->dbdc_support = true;
140
fallthrough;
141
case MT_EE_2GHZ:
142
dev->mphy.cap.has_2ghz = true;
143
break;
144
default:
145
dev->mphy.cap.has_2ghz = true;
146
dev->mphy.cap.has_5ghz = true;
147
break;
148
}
149
}
150
151
static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev)
152
{
153
u8 *eeprom = dev->mt76.eeprom.data;
154
u8 tx_mask, max_nss;
155
156
mt7615_eeprom_parse_hw_band_cap(dev);
157
158
if (is_mt7663(&dev->mt76)) {
159
max_nss = 2;
160
tx_mask = FIELD_GET(MT_EE_HW_CONF1_TX_MASK,
161
eeprom[MT7663_EE_HW_CONF1]);
162
} else {
163
u32 val;
164
165
/* read tx-rx mask from eeprom */
166
val = mt76_rr(dev, MT_TOP_STRAP_STA);
167
max_nss = val & MT_TOP_3NSS ? 3 : 4;
168
169
tx_mask = FIELD_GET(MT_EE_NIC_CONF_TX_MASK,
170
eeprom[MT_EE_NIC_CONF_0]);
171
}
172
if (!tx_mask || tx_mask > max_nss)
173
tx_mask = max_nss;
174
175
dev->chainmask = BIT(tx_mask) - 1;
176
dev->mphy.antenna_mask = dev->chainmask;
177
dev->mphy.chainmask = dev->chainmask;
178
}
179
180
static int mt7663_eeprom_get_target_power_index(struct mt7615_dev *dev,
181
struct ieee80211_channel *chan,
182
u8 chain_idx)
183
{
184
int index, group;
185
186
if (chain_idx > 1)
187
return -EINVAL;
188
189
if (chan->band == NL80211_BAND_2GHZ)
190
return MT7663_EE_TX0_2G_TARGET_POWER + (chain_idx << 4);
191
192
group = mt7615_get_channel_group(chan->hw_value);
193
if (chain_idx == 1)
194
index = MT7663_EE_TX1_5G_G0_TARGET_POWER;
195
else
196
index = MT7663_EE_TX0_5G_G0_TARGET_POWER;
197
198
return index + group * 3;
199
}
200
201
int mt7615_eeprom_get_target_power_index(struct mt7615_dev *dev,
202
struct ieee80211_channel *chan,
203
u8 chain_idx)
204
{
205
int index;
206
207
if (is_mt7663(&dev->mt76))
208
return mt7663_eeprom_get_target_power_index(dev, chan,
209
chain_idx);
210
211
if (chain_idx > 3)
212
return -EINVAL;
213
214
/* TSSI disabled */
215
if (mt7615_ext_pa_enabled(dev, chan->band)) {
216
if (chan->band == NL80211_BAND_2GHZ)
217
return MT_EE_EXT_PA_2G_TARGET_POWER;
218
else
219
return MT_EE_EXT_PA_5G_TARGET_POWER;
220
}
221
222
/* TSSI enabled */
223
if (chan->band == NL80211_BAND_2GHZ) {
224
index = MT_EE_TX0_2G_TARGET_POWER + chain_idx * 6;
225
} else {
226
int group = mt7615_get_channel_group(chan->hw_value);
227
228
switch (chain_idx) {
229
case 1:
230
index = MT_EE_TX1_5G_G0_TARGET_POWER;
231
break;
232
case 2:
233
index = MT_EE_TX2_5G_G0_TARGET_POWER;
234
break;
235
case 3:
236
index = MT_EE_TX3_5G_G0_TARGET_POWER;
237
break;
238
case 0:
239
default:
240
index = MT_EE_TX0_5G_G0_TARGET_POWER;
241
break;
242
}
243
index += 5 * group;
244
}
245
246
return index;
247
}
248
249
int mt7615_eeprom_get_power_delta_index(struct mt7615_dev *dev,
250
enum nl80211_band band)
251
{
252
/* assume the first rate has the highest power offset */
253
if (is_mt7663(&dev->mt76)) {
254
if (band == NL80211_BAND_2GHZ)
255
return MT_EE_TX0_5G_G0_TARGET_POWER;
256
else
257
return MT7663_EE_5G_RATE_POWER;
258
}
259
260
if (band == NL80211_BAND_2GHZ)
261
return MT_EE_2G_RATE_POWER;
262
else
263
return MT_EE_5G_RATE_POWER;
264
}
265
266
#if defined(__linux__)
267
static void mt7615_apply_cal_free_data(struct mt7615_dev *dev)
268
{
269
static const u16 ical[] = {
270
0x53, 0x54, 0x55, 0x56, 0x57, 0x5c, 0x5d, 0x62, 0x63, 0x68,
271
0x69, 0x6e, 0x6f, 0x73, 0x74, 0x78, 0x79, 0x82, 0x83, 0x87,
272
0x88, 0x8c, 0x8d, 0x91, 0x92, 0x96, 0x97, 0x9b, 0x9c, 0xa0,
273
0xa1, 0xaa, 0xab, 0xaf, 0xb0, 0xb4, 0xb5, 0xb9, 0xba, 0xf4,
274
0xf7, 0xff,
275
0x140, 0x141, 0x145, 0x146, 0x14a, 0x14b, 0x154, 0x155, 0x159,
276
0x15a, 0x15e, 0x15f, 0x163, 0x164, 0x168, 0x169, 0x16d, 0x16e,
277
0x172, 0x173, 0x17c, 0x17d, 0x181, 0x182, 0x186, 0x187, 0x18b,
278
0x18c
279
};
280
static const u16 ical_nocheck[] = {
281
0x110, 0x111, 0x112, 0x113, 0x114, 0x115, 0x116, 0x117, 0x118,
282
0x1b5, 0x1b6, 0x1b7, 0x3ac, 0x3ad, 0x3ae, 0x3af, 0x3b0, 0x3b1,
283
0x3b2
284
};
285
u8 *eeprom = dev->mt76.eeprom.data;
286
u8 *otp = dev->mt76.otp.data;
287
int i;
288
289
if (!otp)
290
return;
291
292
for (i = 0; i < ARRAY_SIZE(ical); i++)
293
if (!otp[ical[i]])
294
return;
295
296
for (i = 0; i < ARRAY_SIZE(ical); i++)
297
eeprom[ical[i]] = otp[ical[i]];
298
299
for (i = 0; i < ARRAY_SIZE(ical_nocheck); i++)
300
eeprom[ical_nocheck[i]] = otp[ical_nocheck[i]];
301
}
302
303
static void mt7622_apply_cal_free_data(struct mt7615_dev *dev)
304
{
305
static const u16 ical[] = {
306
0x53, 0x54, 0x55, 0x56, 0xf4, 0xf7, 0x144, 0x156, 0x15b
307
};
308
u8 *eeprom = dev->mt76.eeprom.data;
309
u8 *otp = dev->mt76.otp.data;
310
int i;
311
312
if (!otp)
313
return;
314
315
for (i = 0; i < ARRAY_SIZE(ical); i++) {
316
if (!otp[ical[i]])
317
continue;
318
319
eeprom[ical[i]] = otp[ical[i]];
320
}
321
}
322
#endif
323
324
static void mt7615_cal_free_data(struct mt7615_dev *dev)
325
{
326
#if defined(__linux__)
327
struct device_node *np = dev->mt76.dev->of_node;
328
329
if (!np || !of_property_read_bool(np, "mediatek,eeprom-merge-otp"))
330
return;
331
332
switch (mt76_chip(&dev->mt76)) {
333
case 0x7622:
334
mt7622_apply_cal_free_data(dev);
335
break;
336
case 0x7615:
337
case 0x7611:
338
mt7615_apply_cal_free_data(dev);
339
break;
340
}
341
#endif
342
}
343
344
int mt7615_eeprom_init(struct mt7615_dev *dev, u32 addr)
345
{
346
int ret;
347
348
ret = mt7615_eeprom_load(dev, addr);
349
if (ret < 0)
350
return ret;
351
352
ret = mt7615_check_eeprom(&dev->mt76);
353
if (ret && dev->mt76.otp.data) {
354
memcpy(dev->mt76.eeprom.data, dev->mt76.otp.data,
355
dev->mt76.otp.size);
356
} else {
357
dev->flash_eeprom = true;
358
mt7615_cal_free_data(dev);
359
}
360
361
mt7615_eeprom_parse_hw_cap(dev);
362
#if defined(__linux__)
363
memcpy(dev->mphy.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
364
#elif defined(__FreeBSD__)
365
memcpy(dev->mphy.macaddr, (u8 *)dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
366
#endif
367
ETH_ALEN);
368
369
mt76_eeprom_override(&dev->mphy);
370
371
return 0;
372
}
373
EXPORT_SYMBOL_GPL(mt7615_eeprom_init);
374
375