Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/rtw89/efuse.c
104522 views
1
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2
/* Copyright(c) 2019-2020 Realtek Corporation
3
*/
4
5
#include "debug.h"
6
#include "efuse.h"
7
#include "mac.h"
8
#include "reg.h"
9
10
#define EF_FV_OFSET 0x5ea
11
#define EF_CV_MASK GENMASK(7, 4)
12
#define EF_CV_INV 15
13
14
#define EFUSE_B1_MSSDEVTYPE_MASK GENMASK(3, 0)
15
#define EFUSE_B1_MSSCUSTIDX0_MASK GENMASK(7, 4)
16
#define EFUSE_B2_MSSKEYNUM_MASK GENMASK(3, 0)
17
#define EFUSE_B2_MSSCUSTIDX1_MASK BIT(6)
18
19
#define EFUSE_EXTERNALPN_ADDR_AX 0x5EC
20
#define EFUSE_CUSTOMER_ADDR_AX 0x5ED
21
#define EFUSE_SERIALNUM_ADDR_AX 0x5ED
22
23
#define EFUSE_B1_EXTERNALPN_MASK GENMASK(7, 0)
24
#define EFUSE_B2_CUSTOMER_MASK GENMASK(3, 0)
25
#define EFUSE_B2_SERIALNUM_MASK GENMASK(6, 4)
26
27
#define OTP_KEY_INFO_NUM 2
28
29
static const u8 otp_key_info_externalPN[OTP_KEY_INFO_NUM] = {0x0, 0x0};
30
static const u8 otp_key_info_customer[OTP_KEY_INFO_NUM] = {0x0, 0x1};
31
static const u8 otp_key_info_serialNum[OTP_KEY_INFO_NUM] = {0x0, 0x1};
32
33
enum rtw89_efuse_bank {
34
RTW89_EFUSE_BANK_WIFI,
35
RTW89_EFUSE_BANK_BT,
36
};
37
38
enum rtw89_efuse_mss_dev_type {
39
MSS_DEV_TYPE_FWSEC_DEF = 0xF,
40
MSS_DEV_TYPE_FWSEC_WINLIN_INBOX = 0xC,
41
MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB = 0xA,
42
MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB = 0x9,
43
MSS_DEV_TYPE_FWSEC_NONWIN_INBOX = 0x6,
44
};
45
46
static int rtw89_switch_efuse_bank(struct rtw89_dev *rtwdev,
47
enum rtw89_efuse_bank bank)
48
{
49
u8 val;
50
51
if (rtwdev->chip->chip_id != RTL8852A)
52
return 0;
53
54
val = rtw89_read32_mask(rtwdev, R_AX_EFUSE_CTRL_1,
55
B_AX_EF_CELL_SEL_MASK);
56
if (bank == val)
57
return 0;
58
59
rtw89_write32_mask(rtwdev, R_AX_EFUSE_CTRL_1, B_AX_EF_CELL_SEL_MASK,
60
bank);
61
62
val = rtw89_read32_mask(rtwdev, R_AX_EFUSE_CTRL_1,
63
B_AX_EF_CELL_SEL_MASK);
64
if (bank == val)
65
return 0;
66
67
return -EBUSY;
68
}
69
70
static void rtw89_enable_otp_burst_mode(struct rtw89_dev *rtwdev, bool en)
71
{
72
if (en)
73
rtw89_write32_set(rtwdev, R_AX_EFUSE_CTRL_1_V1, B_AX_EF_BURST);
74
else
75
rtw89_write32_clr(rtwdev, R_AX_EFUSE_CTRL_1_V1, B_AX_EF_BURST);
76
}
77
78
static void rtw89_enable_efuse_pwr_cut_ddv(struct rtw89_dev *rtwdev)
79
{
80
enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
81
struct rtw89_hal *hal = &rtwdev->hal;
82
83
if (chip_id == RTL8852A)
84
return;
85
86
rtw89_write8_set(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK);
87
rtw89_write16_set(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B14);
88
89
fsleep(1000);
90
91
rtw89_write16_set(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B15);
92
rtw89_write16_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_ISO_EB2CORE);
93
if (chip_id == RTL8852B && hal->cv == CHIP_CAV)
94
rtw89_enable_otp_burst_mode(rtwdev, true);
95
}
96
97
static void rtw89_disable_efuse_pwr_cut_ddv(struct rtw89_dev *rtwdev)
98
{
99
enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
100
struct rtw89_hal *hal = &rtwdev->hal;
101
102
if (chip_id == RTL8852A)
103
return;
104
105
if (chip_id == RTL8852B && hal->cv == CHIP_CAV)
106
rtw89_enable_otp_burst_mode(rtwdev, false);
107
108
rtw89_write16_set(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_ISO_EB2CORE);
109
rtw89_write16_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B15);
110
111
fsleep(1000);
112
113
rtw89_write16_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B14);
114
rtw89_write8_clr(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK);
115
}
116
117
static int rtw89_dump_physical_efuse_map_ddv(struct rtw89_dev *rtwdev, u8 *map,
118
u32 dump_addr, u32 dump_size)
119
{
120
u32 efuse_ctl;
121
u32 addr;
122
int ret;
123
124
rtw89_enable_efuse_pwr_cut_ddv(rtwdev);
125
126
for (addr = dump_addr; addr < dump_addr + dump_size; addr++) {
127
efuse_ctl = u32_encode_bits(addr, B_AX_EF_ADDR_MASK);
128
rtw89_write32(rtwdev, R_AX_EFUSE_CTRL, efuse_ctl & ~B_AX_EF_RDY);
129
130
ret = read_poll_timeout_atomic(rtw89_read32, efuse_ctl,
131
efuse_ctl & B_AX_EF_RDY, 1, 1000000,
132
true, rtwdev, R_AX_EFUSE_CTRL);
133
if (ret)
134
return -EBUSY;
135
136
*map++ = (u8)(efuse_ctl & 0xff);
137
}
138
139
rtw89_disable_efuse_pwr_cut_ddv(rtwdev);
140
141
return 0;
142
}
143
144
int rtw89_cnv_efuse_state_ax(struct rtw89_dev *rtwdev, bool idle)
145
{
146
return 0;
147
}
148
149
static int rtw89_dump_physical_efuse_map_dav(struct rtw89_dev *rtwdev, u8 *map,
150
u32 dump_addr, u32 dump_size)
151
{
152
u32 addr;
153
u8 val8;
154
int err;
155
int ret;
156
157
for (addr = dump_addr; addr < dump_addr + dump_size; addr++) {
158
ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0x40, FULL_BIT_MASK);
159
if (ret)
160
return ret;
161
ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_LOW_ADDR,
162
addr & 0xff, XTAL_SI_LOW_ADDR_MASK);
163
if (ret)
164
return ret;
165
ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, addr >> 8,
166
XTAL_SI_HIGH_ADDR_MASK);
167
if (ret)
168
return ret;
169
ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0,
170
XTAL_SI_MODE_SEL_MASK);
171
if (ret)
172
return ret;
173
174
ret = read_poll_timeout_atomic(rtw89_mac_read_xtal_si, err,
175
!err && (val8 & XTAL_SI_RDY),
176
1, 10000, false,
177
rtwdev, XTAL_SI_CTRL, &val8);
178
if (ret) {
179
rtw89_warn(rtwdev, "failed to read dav efuse\n");
180
return ret;
181
}
182
183
ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_READ_VAL, &val8);
184
if (ret)
185
return ret;
186
*map++ = val8;
187
}
188
189
return 0;
190
}
191
192
static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map,
193
u32 dump_addr, u32 dump_size, bool dav)
194
{
195
int ret;
196
197
if (!map || dump_size == 0)
198
return 0;
199
200
rtw89_switch_efuse_bank(rtwdev, RTW89_EFUSE_BANK_WIFI);
201
202
if (dav) {
203
ret = rtw89_dump_physical_efuse_map_dav(rtwdev, map, dump_addr, dump_size);
204
if (ret)
205
return ret;
206
} else {
207
ret = rtw89_dump_physical_efuse_map_ddv(rtwdev, map, dump_addr, dump_size);
208
if (ret)
209
return ret;
210
}
211
212
return 0;
213
}
214
215
#define invalid_efuse_header(hdr1, hdr2) \
216
((hdr1) == 0xff || (hdr2) == 0xff)
217
#define invalid_efuse_content(word_en, i) \
218
(((word_en) & BIT(i)) != 0x0)
219
#define get_efuse_blk_idx(hdr1, hdr2) \
220
((((hdr2) & 0xf0) >> 4) | (((hdr1) & 0x0f) << 4))
221
#define block_idx_to_logical_idx(blk_idx, i) \
222
(((blk_idx) << 3) + ((i) << 1))
223
static int rtw89_dump_logical_efuse_map(struct rtw89_dev *rtwdev, u8 *phy_map,
224
u8 *log_map)
225
{
226
u32 physical_size = rtwdev->chip->physical_efuse_size;
227
u32 logical_size = rtwdev->chip->logical_efuse_size;
228
u8 sec_ctrl_size = rtwdev->chip->sec_ctrl_efuse_size;
229
u32 phy_idx = sec_ctrl_size;
230
u32 log_idx;
231
u8 hdr1, hdr2;
232
u8 blk_idx;
233
u8 word_en;
234
int i;
235
236
if (!phy_map)
237
return 0;
238
239
while (phy_idx < physical_size - sec_ctrl_size) {
240
hdr1 = phy_map[phy_idx];
241
hdr2 = phy_map[phy_idx + 1];
242
if (invalid_efuse_header(hdr1, hdr2))
243
break;
244
245
blk_idx = get_efuse_blk_idx(hdr1, hdr2);
246
word_en = hdr2 & 0xf;
247
phy_idx += 2;
248
249
for (i = 0; i < 4; i++) {
250
if (invalid_efuse_content(word_en, i))
251
continue;
252
253
log_idx = block_idx_to_logical_idx(blk_idx, i);
254
if (phy_idx + 1 > physical_size - sec_ctrl_size - 1 ||
255
log_idx + 1 > logical_size)
256
return -EINVAL;
257
258
log_map[log_idx] = phy_map[phy_idx];
259
log_map[log_idx + 1] = phy_map[phy_idx + 1];
260
phy_idx += 2;
261
}
262
}
263
return 0;
264
}
265
266
int rtw89_parse_efuse_map_ax(struct rtw89_dev *rtwdev)
267
{
268
u32 phy_size = rtwdev->chip->physical_efuse_size;
269
u32 log_size = rtwdev->chip->logical_efuse_size;
270
u32 dav_phy_size = rtwdev->chip->dav_phy_efuse_size;
271
u32 dav_log_size = rtwdev->chip->dav_log_efuse_size;
272
u32 full_log_size = log_size + dav_log_size;
273
u8 *phy_map = NULL;
274
u8 *log_map = NULL;
275
u8 *dav_phy_map = NULL;
276
u8 *dav_log_map = NULL;
277
int ret;
278
279
if (rtw89_read16(rtwdev, R_AX_SYS_WL_EFUSE_CTRL) & B_AX_AUTOLOAD_SUS)
280
rtwdev->efuse.valid = true;
281
else
282
rtw89_warn(rtwdev, "failed to check efuse autoload\n");
283
284
phy_map = kmalloc(phy_size, GFP_KERNEL);
285
log_map = kmalloc(full_log_size, GFP_KERNEL);
286
if (dav_phy_size && dav_log_size) {
287
dav_phy_map = kmalloc(dav_phy_size, GFP_KERNEL);
288
dav_log_map = log_map + log_size;
289
}
290
291
if (!phy_map || !log_map || (dav_phy_size && !dav_phy_map)) {
292
ret = -ENOMEM;
293
goto out_free;
294
}
295
296
ret = rtw89_dump_physical_efuse_map(rtwdev, phy_map, 0, phy_size, false);
297
if (ret) {
298
rtw89_warn(rtwdev, "failed to dump efuse physical map\n");
299
goto out_free;
300
}
301
ret = rtw89_dump_physical_efuse_map(rtwdev, dav_phy_map, 0, dav_phy_size, true);
302
if (ret) {
303
rtw89_warn(rtwdev, "failed to dump efuse dav physical map\n");
304
goto out_free;
305
}
306
307
memset(log_map, 0xff, full_log_size);
308
ret = rtw89_dump_logical_efuse_map(rtwdev, phy_map, log_map);
309
if (ret) {
310
rtw89_warn(rtwdev, "failed to dump efuse logical map\n");
311
goto out_free;
312
}
313
ret = rtw89_dump_logical_efuse_map(rtwdev, dav_phy_map, dav_log_map);
314
if (ret) {
315
rtw89_warn(rtwdev, "failed to dump efuse dav logical map\n");
316
goto out_free;
317
}
318
319
rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "log_map: ", log_map, full_log_size);
320
321
ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map, RTW89_EFUSE_BLOCK_IGNORE);
322
if (ret) {
323
rtw89_warn(rtwdev, "failed to read efuse map\n");
324
goto out_free;
325
}
326
327
out_free:
328
kfree(dav_phy_map);
329
kfree(log_map);
330
kfree(phy_map);
331
332
return ret;
333
}
334
335
int rtw89_parse_phycap_map_ax(struct rtw89_dev *rtwdev)
336
{
337
u32 phycap_addr = rtwdev->chip->phycap_addr;
338
u32 phycap_size = rtwdev->chip->phycap_size;
339
u8 *phycap_map = NULL;
340
int ret = 0;
341
342
if (!phycap_size)
343
return 0;
344
345
phycap_map = kmalloc(phycap_size, GFP_KERNEL);
346
if (!phycap_map)
347
return -ENOMEM;
348
349
ret = rtw89_dump_physical_efuse_map(rtwdev, phycap_map,
350
phycap_addr, phycap_size, false);
351
if (ret) {
352
rtw89_warn(rtwdev, "failed to dump phycap map\n");
353
goto out_free;
354
}
355
356
ret = rtwdev->chip->ops->read_phycap(rtwdev, phycap_map);
357
if (ret) {
358
rtw89_warn(rtwdev, "failed to read phycap map\n");
359
goto out_free;
360
}
361
362
out_free:
363
kfree(phycap_map);
364
365
return ret;
366
}
367
368
int rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *ecv)
369
{
370
int ret;
371
u8 val;
372
373
ret = rtw89_dump_physical_efuse_map(rtwdev, &val, EF_FV_OFSET, 1, false);
374
if (ret)
375
return ret;
376
377
*ecv = u8_get_bits(val, EF_CV_MASK);
378
if (*ecv == EF_CV_INV)
379
return -ENOENT;
380
381
return 0;
382
}
383
EXPORT_SYMBOL(rtw89_read_efuse_ver);
384
385
static u8 get_mss_dev_type_idx(struct rtw89_dev *rtwdev, u8 mss_dev_type)
386
{
387
switch (mss_dev_type) {
388
case MSS_DEV_TYPE_FWSEC_WINLIN_INBOX:
389
mss_dev_type = 0x0;
390
break;
391
case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB:
392
mss_dev_type = 0x1;
393
break;
394
case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB:
395
mss_dev_type = 0x2;
396
break;
397
case MSS_DEV_TYPE_FWSEC_NONWIN_INBOX:
398
mss_dev_type = 0x3;
399
break;
400
case MSS_DEV_TYPE_FWSEC_DEF:
401
mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_DEF;
402
break;
403
default:
404
rtw89_warn(rtwdev, "unknown mss_dev_type %d", mss_dev_type);
405
mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_INV;
406
break;
407
}
408
409
return mss_dev_type;
410
}
411
412
int rtw89_efuse_recognize_mss_info_v1(struct rtw89_dev *rtwdev, u8 b1, u8 b2)
413
{
414
const struct rtw89_chip_info *chip = rtwdev->chip;
415
struct rtw89_fw_secure *sec = &rtwdev->fw.sec;
416
u8 mss_dev_type;
417
418
if (chip->chip_id == RTL8852B && b1 == 0xFF && b2 == 0x6E) {
419
mss_dev_type = MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB;
420
sec->mss_cust_idx = 0;
421
sec->mss_key_num = 0;
422
423
goto mss_dev_type;
424
}
425
426
mss_dev_type = u8_get_bits(b1, EFUSE_B1_MSSDEVTYPE_MASK);
427
sec->mss_cust_idx = 0x1F - (u8_get_bits(b1, EFUSE_B1_MSSCUSTIDX0_MASK) |
428
u8_get_bits(b2, EFUSE_B2_MSSCUSTIDX1_MASK) << 4);
429
sec->mss_key_num = 0xF - u8_get_bits(b2, EFUSE_B2_MSSKEYNUM_MASK);
430
431
mss_dev_type:
432
sec->mss_dev_type = get_mss_dev_type_idx(rtwdev, mss_dev_type);
433
if (sec->mss_dev_type == RTW89_FW_MSS_DEV_TYPE_FWSEC_INV) {
434
rtw89_warn(rtwdev, "invalid mss_dev_type %d\n", mss_dev_type);
435
return -ENOENT;
436
}
437
438
sec->can_mss_v1 = true;
439
440
return 0;
441
}
442
443
static
444
int rtw89_efuse_recognize_mss_index_v0(struct rtw89_dev *rtwdev, u8 b1, u8 b2)
445
{
446
struct rtw89_fw_secure *sec = &rtwdev->fw.sec;
447
u8 externalPN;
448
u8 serialNum;
449
u8 customer;
450
u8 i;
451
452
externalPN = 0xFF - u8_get_bits(b1, EFUSE_B1_EXTERNALPN_MASK);
453
customer = 0xF - u8_get_bits(b2, EFUSE_B2_CUSTOMER_MASK);
454
serialNum = 0x7 - u8_get_bits(b2, EFUSE_B2_SERIALNUM_MASK);
455
456
for (i = 0; i < OTP_KEY_INFO_NUM; i++) {
457
if (externalPN == otp_key_info_externalPN[i] &&
458
customer == otp_key_info_customer[i] &&
459
serialNum == otp_key_info_serialNum[i]) {
460
sec->mss_idx = i;
461
sec->can_mss_v0 = true;
462
return 0;
463
}
464
}
465
466
return -ENOENT;
467
}
468
469
int rtw89_efuse_read_fw_secure_ax(struct rtw89_dev *rtwdev)
470
{
471
struct rtw89_fw_secure *sec = &rtwdev->fw.sec;
472
u32 sec_addr = EFUSE_EXTERNALPN_ADDR_AX;
473
u32 sec_size = 2;
474
u8 sec_map[2];
475
u8 b1, b2;
476
int ret;
477
478
ret = rtw89_dump_physical_efuse_map(rtwdev, sec_map,
479
sec_addr, sec_size, false);
480
if (ret) {
481
rtw89_warn(rtwdev, "failed to dump secsel map\n");
482
return ret;
483
}
484
485
b1 = sec_map[0];
486
b2 = sec_map[1];
487
488
if (b1 == 0xFF && b2 == 0xFF)
489
return 0;
490
491
rtw89_efuse_recognize_mss_index_v0(rtwdev, b1, b2);
492
rtw89_efuse_recognize_mss_info_v1(rtwdev, b1, b2);
493
if (!sec->can_mss_v1 && !sec->can_mss_v0)
494
goto out;
495
496
sec->secure_boot = true;
497
498
out:
499
rtw89_debug(rtwdev, RTW89_DBG_FW,
500
"MSS secure_boot=%d(%d/%d) dev_type=%d cust_idx=%d key_num=%d mss_index=%d\n",
501
sec->secure_boot, sec->can_mss_v0, sec->can_mss_v1,
502
sec->mss_dev_type, sec->mss_cust_idx,
503
sec->mss_key_num, sec->mss_idx);
504
505
return 0;
506
}
507
508