1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /* Copyright(c) 2023 Realtek Corporation
3 */
4
5 #include "debug.h"
6 #include "efuse.h"
7 #include "mac.h"
8 #include "reg.h"
9
10 #define EFUSE_EXTERNALPN_ADDR_BE 0x1580
11 #define EFUSE_SERIALNUM_ADDR_BE 0x1581
12 #define EFUSE_SB_CRYP_SEL_ADDR 0x1582
13 #define EFUSE_SB_CRYP_SEL_SIZE 2
14 #define EFUSE_SB_CRYP_SEL_DEFAULT 0xFFFF
15 #define SB_SEL_MGN_MAX_SIZE 2
16 #define EFUSE_SEC_BE_START 0x1580
17 #define EFUSE_SEC_BE_SIZE 4
18
19 #define EFUSE_VCORE_PWR_BE 0x17D6
20 #define EFUSE_VCORE_PWR_BE_VALID BIT(12)
21 #define EFUSE_VCORE_PWR_BE_VAL GENMASK(11, 0)
22 #define SWR_DIG_MIN 860
23 #define EFUSE_DIG_K_STEP 0xC
24 #define EFUSE_DSWR_V0_86_BE 0x17DA
25 #define EFUSE_DSWR_V0_86_BE_VALID BIT(5)
26 #define EFUSE_DSWR_V0_86_BE_VAL GENMASK(4, 0)
27
28 static const u32 sb_sel_mgn[SB_SEL_MGN_MAX_SIZE] = {
29 0x8000100, 0xC000180
30 };
31
rtw89_enable_efuse_pwr_cut_ddv_be(struct rtw89_dev * rtwdev)32 static void rtw89_enable_efuse_pwr_cut_ddv_be(struct rtw89_dev *rtwdev)
33 {
34 const struct rtw89_chip_info *chip = rtwdev->chip;
35 struct rtw89_hal *hal = &rtwdev->hal;
36 bool aphy_patch = true;
37
38 if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV)
39 aphy_patch = false;
40
41 rtw89_write8_set(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK);
42
43 if (aphy_patch) {
44 rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_S);
45 mdelay(1);
46 rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_B);
47 rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE);
48 }
49
50 rtw89_write32_set(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_EF_BURST);
51 }
52
rtw89_disable_efuse_pwr_cut_ddv_be(struct rtw89_dev * rtwdev)53 static void rtw89_disable_efuse_pwr_cut_ddv_be(struct rtw89_dev *rtwdev)
54 {
55 const struct rtw89_chip_info *chip = rtwdev->chip;
56 struct rtw89_hal *hal = &rtwdev->hal;
57 bool aphy_patch = true;
58
59 if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV)
60 aphy_patch = false;
61
62 if (aphy_patch) {
63 rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE);
64 rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_B);
65 mdelay(1);
66 rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_S);
67 }
68
69 rtw89_write8_clr(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK);
70 rtw89_write32_clr(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_EF_BURST);
71 }
72
rtw89_dump_physical_efuse_map_ddv_be(struct rtw89_dev * rtwdev,u8 * map,u32 dump_addr,u32 dump_size)73 static int rtw89_dump_physical_efuse_map_ddv_be(struct rtw89_dev *rtwdev, u8 *map,
74 u32 dump_addr, u32 dump_size)
75 {
76 u32 efuse_ctl;
77 u32 addr;
78 u32 data;
79 int ret;
80
81 if (!IS_ALIGNED(dump_addr, 4) || !IS_ALIGNED(dump_size, 4)) {
82 rtw89_err(rtwdev, "Efuse addr 0x%x or size 0x%x not aligned\n",
83 dump_addr, dump_size);
84 return -EINVAL;
85 }
86
87 rtw89_enable_efuse_pwr_cut_ddv_be(rtwdev);
88
89 for (addr = dump_addr; addr < dump_addr + dump_size; addr += 4, map += 4) {
90 efuse_ctl = u32_encode_bits(addr, B_BE_EF_ADDR_MASK);
91 rtw89_write32(rtwdev, R_BE_EFUSE_CTRL, efuse_ctl & ~B_BE_EF_RDY);
92
93 ret = read_poll_timeout_atomic(rtw89_read32, efuse_ctl,
94 efuse_ctl & B_BE_EF_RDY, 1, 1000000,
95 true, rtwdev, R_BE_EFUSE_CTRL);
96 if (ret)
97 return -EBUSY;
98
99 data = rtw89_read32(rtwdev, R_BE_EFUSE_CTRL_1_V1);
100 *((__le32 *)map) = cpu_to_le32(data);
101 }
102
103 rtw89_disable_efuse_pwr_cut_ddv_be(rtwdev);
104
105 return 0;
106 }
107
rtw89_dump_physical_efuse_map_dav_be(struct rtw89_dev * rtwdev,u8 * map,u32 dump_addr,u32 dump_size)108 static int rtw89_dump_physical_efuse_map_dav_be(struct rtw89_dev *rtwdev, u8 *map,
109 u32 dump_addr, u32 dump_size)
110 {
111 u32 addr;
112 u8 val8;
113 int err;
114 int ret;
115
116 for (addr = dump_addr; addr < dump_addr + dump_size; addr++) {
117 ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0x40,
118 FULL_BIT_MASK);
119 if (ret)
120 return ret;
121 ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_LOW_ADDR, addr & 0xff,
122 XTAL_SI_LOW_ADDR_MASK);
123 if (ret)
124 return ret;
125 ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, addr >> 8,
126 XTAL_SI_HIGH_ADDR_MASK);
127 if (ret)
128 return ret;
129 ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0,
130 XTAL_SI_MODE_SEL_MASK);
131 if (ret)
132 return ret;
133
134 ret = read_poll_timeout_atomic(rtw89_mac_read_xtal_si, err,
135 !err && (val8 & XTAL_SI_RDY),
136 1, 10000, false,
137 rtwdev, XTAL_SI_CTRL, &val8);
138 if (ret) {
139 rtw89_warn(rtwdev, "failed to read dav efuse\n");
140 return ret;
141 }
142
143 ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_READ_VAL, &val8);
144 if (ret)
145 return ret;
146 *map++ = val8;
147 }
148
149 return 0;
150 }
151
rtw89_cnv_efuse_state_be(struct rtw89_dev * rtwdev,bool idle)152 int rtw89_cnv_efuse_state_be(struct rtw89_dev *rtwdev, bool idle)
153 {
154 u32 val;
155 int ret = 0;
156
157 if (idle) {
158 rtw89_write32_set(rtwdev, R_BE_WL_BT_PWR_CTRL, B_BE_BT_DISN_EN);
159 } else {
160 rtw89_write32_clr(rtwdev, R_BE_WL_BT_PWR_CTRL, B_BE_BT_DISN_EN);
161
162 ret = read_poll_timeout(rtw89_read32_mask, val,
163 val == MAC_AX_SYS_ACT, 50, 5000,
164 false, rtwdev, R_BE_IC_PWR_STATE,
165 B_BE_WHOLE_SYS_PWR_STE_MASK);
166 if (ret)
167 rtw89_warn(rtwdev, "failed to convert efuse state\n");
168 }
169
170 return ret;
171 }
172
rtw89_dump_physical_efuse_map_be(struct rtw89_dev * rtwdev,u8 * map,u32 dump_addr,u32 dump_size,bool dav)173 static int rtw89_dump_physical_efuse_map_be(struct rtw89_dev *rtwdev, u8 *map,
174 u32 dump_addr, u32 dump_size, bool dav)
175 {
176 int ret;
177
178 if (!map || dump_size == 0)
179 return 0;
180
181 rtw89_cnv_efuse_state_be(rtwdev, false);
182
183 if (dav) {
184 ret = rtw89_dump_physical_efuse_map_dav_be(rtwdev, map,
185 dump_addr, dump_size);
186 if (ret)
187 return ret;
188
189 rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "phy_map dav: ", map, dump_size);
190 } else {
191 ret = rtw89_dump_physical_efuse_map_ddv_be(rtwdev, map,
192 dump_addr, dump_size);
193 if (ret)
194 return ret;
195
196 rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "phy_map ddv: ", map, dump_size);
197 }
198
199 rtw89_cnv_efuse_state_be(rtwdev, true);
200
201 return 0;
202 }
203
204 #define EFUSE_HDR_CONST_MASK GENMASK(23, 20)
205 #define EFUSE_HDR_PAGE_MASK GENMASK(19, 17)
206 #define EFUSE_HDR_OFFSET_MASK GENMASK(16, 4)
207 #define EFUSE_HDR_OFFSET_DAV_MASK GENMASK(11, 4)
208 #define EFUSE_HDR_WORD_EN_MASK GENMASK(3, 0)
209
210 #define invalid_efuse_header_be(hdr1, hdr2, hdr3) \
211 ((hdr1) == 0xff || (hdr2) == 0xff || (hdr3) == 0xff)
212 #define invalid_efuse_content_be(word_en, i) \
213 (((word_en) & BIT(i)) != 0x0)
214 #define get_efuse_blk_idx_be(hdr1, hdr2, hdr3) \
215 (((hdr1) << 16) | ((hdr2) << 8) | (hdr3))
216 #define block_idx_to_logical_idx_be(blk_idx, i) \
217 (((blk_idx) << 3) + ((i) << 1))
218
219 #define invalid_efuse_header_dav_be(hdr1, hdr2) \
220 ((hdr1) == 0xff || (hdr2) == 0xff)
221 #define get_efuse_blk_idx_dav_be(hdr1, hdr2) \
222 (((hdr1) << 8) | (hdr2))
223
rtw89_eeprom_parser_be(struct rtw89_dev * rtwdev,const u8 * phy_map,u32 phy_size,u8 * log_map,const struct rtw89_efuse_block_cfg * efuse_block)224 static int rtw89_eeprom_parser_be(struct rtw89_dev *rtwdev,
225 const u8 *phy_map, u32 phy_size, u8 *log_map,
226 const struct rtw89_efuse_block_cfg *efuse_block)
227 {
228 const struct rtw89_chip_info *chip = rtwdev->chip;
229 enum rtw89_efuse_block blk_page, page;
230 u32 size = efuse_block->size;
231 u32 phy_idx, log_idx;
232 u32 hdr, page_offset;
233 u8 hdr1, hdr2, hdr3;
234 u8 i, val0, val1;
235 u32 min, max;
236 u16 blk_idx;
237 u8 word_en;
238
239 page = u32_get_bits(efuse_block->offset, RTW89_EFUSE_BLOCK_ID_MASK);
240 page_offset = u32_get_bits(efuse_block->offset, RTW89_EFUSE_BLOCK_SIZE_MASK);
241
242 min = ALIGN_DOWN(page_offset, 2);
243 max = ALIGN(page_offset + size, 2);
244
245 memset(log_map, 0xff, size);
246
247 phy_idx = chip->sec_ctrl_efuse_size;
248
249 do {
250 if (page == RTW89_EFUSE_BLOCK_ADIE) {
251 hdr1 = phy_map[phy_idx];
252 hdr2 = phy_map[phy_idx + 1];
253 if (invalid_efuse_header_dav_be(hdr1, hdr2))
254 break;
255
256 phy_idx += 2;
257
258 hdr = get_efuse_blk_idx_dav_be(hdr1, hdr2);
259
260 blk_page = RTW89_EFUSE_BLOCK_ADIE;
261 blk_idx = u32_get_bits(hdr, EFUSE_HDR_OFFSET_DAV_MASK);
262 word_en = u32_get_bits(hdr, EFUSE_HDR_WORD_EN_MASK);
263 } else {
264 hdr1 = phy_map[phy_idx];
265 hdr2 = phy_map[phy_idx + 1];
266 hdr3 = phy_map[phy_idx + 2];
267 if (invalid_efuse_header_be(hdr1, hdr2, hdr3))
268 break;
269
270 phy_idx += 3;
271
272 hdr = get_efuse_blk_idx_be(hdr1, hdr2, hdr3);
273
274 blk_page = u32_get_bits(hdr, EFUSE_HDR_PAGE_MASK);
275 blk_idx = u32_get_bits(hdr, EFUSE_HDR_OFFSET_MASK);
276 word_en = u32_get_bits(hdr, EFUSE_HDR_WORD_EN_MASK);
277 }
278
279 if (blk_idx >= RTW89_EFUSE_MAX_BLOCK_SIZE >> 3) {
280 rtw89_err(rtwdev, "[ERR]efuse idx:0x%X\n", phy_idx - 3);
281 rtw89_err(rtwdev, "[ERR]read hdr:0x%X\n", hdr);
282 return -EINVAL;
283 }
284
285 for (i = 0; i < 4; i++) {
286 if (invalid_efuse_content_be(word_en, i))
287 continue;
288
289 if (phy_idx >= phy_size - 1)
290 return -EINVAL;
291
292 log_idx = block_idx_to_logical_idx_be(blk_idx, i);
293
294 if (blk_page == page && log_idx >= min && log_idx < max) {
295 val0 = phy_map[phy_idx];
296 val1 = phy_map[phy_idx + 1];
297
298 if (log_idx == min && page_offset > min) {
299 log_map[log_idx - page_offset + 1] = val1;
300 } else if (log_idx + 2 == max &&
301 page_offset + size < max) {
302 log_map[log_idx - page_offset] = val0;
303 } else {
304 log_map[log_idx - page_offset] = val0;
305 log_map[log_idx - page_offset + 1] = val1;
306 }
307 }
308 phy_idx += 2;
309 }
310 } while (phy_idx < phy_size);
311
312 return 0;
313 }
314
rtw89_parse_logical_efuse_block_be(struct rtw89_dev * rtwdev,const u8 * phy_map,u32 phy_size,enum rtw89_efuse_block block)315 static int rtw89_parse_logical_efuse_block_be(struct rtw89_dev *rtwdev,
316 const u8 *phy_map, u32 phy_size,
317 enum rtw89_efuse_block block)
318 {
319 const struct rtw89_chip_info *chip = rtwdev->chip;
320 const struct rtw89_efuse_block_cfg *efuse_block;
321 u8 *log_map;
322 int ret;
323
324 efuse_block = &chip->efuse_blocks[block];
325
326 log_map = kmalloc(efuse_block->size, GFP_KERNEL);
327 if (!log_map)
328 return -ENOMEM;
329
330 ret = rtw89_eeprom_parser_be(rtwdev, phy_map, phy_size, log_map, efuse_block);
331 if (ret) {
332 rtw89_warn(rtwdev, "failed to dump efuse logical block %d\n", block);
333 goto out_free;
334 }
335
336 rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "log_map: ", log_map, efuse_block->size);
337
338 ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map, block);
339 if (ret) {
340 rtw89_warn(rtwdev, "failed to read efuse map\n");
341 goto out_free;
342 }
343
344 out_free:
345 kfree(log_map);
346
347 return ret;
348 }
349
rtw89_parse_efuse_map_be(struct rtw89_dev * rtwdev)350 int rtw89_parse_efuse_map_be(struct rtw89_dev *rtwdev)
351 {
352 u32 phy_size = rtwdev->chip->physical_efuse_size;
353 u32 dav_phy_size = rtwdev->chip->dav_phy_efuse_size;
354 enum rtw89_efuse_block block;
355 u8 *phy_map = NULL;
356 u8 *dav_phy_map = NULL;
357 int ret;
358
359 if (rtw89_read16(rtwdev, R_BE_SYS_WL_EFUSE_CTRL) & B_BE_AUTOLOAD_SUS)
360 rtwdev->efuse.valid = true;
361 else
362 rtw89_warn(rtwdev, "failed to check efuse autoload\n");
363
364 phy_map = kmalloc(phy_size, GFP_KERNEL);
365 if (dav_phy_size)
366 dav_phy_map = kmalloc(dav_phy_size, GFP_KERNEL);
367
368 if (!phy_map || (dav_phy_size && !dav_phy_map)) {
369 ret = -ENOMEM;
370 goto out_free;
371 }
372
373 ret = rtw89_dump_physical_efuse_map_be(rtwdev, phy_map, 0, phy_size, false);
374 if (ret) {
375 rtw89_warn(rtwdev, "failed to dump efuse physical map\n");
376 goto out_free;
377 }
378 ret = rtw89_dump_physical_efuse_map_be(rtwdev, dav_phy_map, 0, dav_phy_size, true);
379 if (ret) {
380 rtw89_warn(rtwdev, "failed to dump efuse dav physical map\n");
381 goto out_free;
382 }
383
384 if (rtwdev->hci.type == RTW89_HCI_TYPE_USB)
385 block = RTW89_EFUSE_BLOCK_HCI_DIG_USB;
386 else
387 block = RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO;
388
389 ret = rtw89_parse_logical_efuse_block_be(rtwdev, phy_map, phy_size, block);
390 if (ret) {
391 rtw89_warn(rtwdev, "failed to parse efuse logic block %d\n",
392 RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO);
393 goto out_free;
394 }
395
396 ret = rtw89_parse_logical_efuse_block_be(rtwdev, phy_map, phy_size,
397 RTW89_EFUSE_BLOCK_RF);
398 if (ret) {
399 rtw89_warn(rtwdev, "failed to parse efuse logic block %d\n",
400 RTW89_EFUSE_BLOCK_RF);
401 goto out_free;
402 }
403
404 if (rtwdev->chip->chip_id != RTL8922D)
405 goto out_free;
406
407 ret = rtw89_parse_logical_efuse_block_be(rtwdev, phy_map, phy_size,
408 RTW89_EFUSE_BLOCK_SYS);
409 if (ret) {
410 rtw89_warn(rtwdev, "failed to parse efuse logic block %d\n",
411 RTW89_EFUSE_BLOCK_SYS);
412 goto out_free;
413 }
414
415 out_free:
416 kfree(dav_phy_map);
417 kfree(phy_map);
418
419 return ret;
420 }
421
rtw89_parse_phycap_map_be(struct rtw89_dev * rtwdev)422 int rtw89_parse_phycap_map_be(struct rtw89_dev *rtwdev)
423 {
424 u32 phycap_addr = rtwdev->chip->phycap_addr;
425 u32 phycap_size = rtwdev->chip->phycap_size;
426 u8 *phycap_map = NULL;
427 int ret = 0;
428
429 if (!phycap_size)
430 return 0;
431
432 phycap_map = kmalloc(phycap_size, GFP_KERNEL);
433 if (!phycap_map)
434 return -ENOMEM;
435
436 ret = rtw89_dump_physical_efuse_map_be(rtwdev, phycap_map,
437 phycap_addr, phycap_size, false);
438 if (ret) {
439 rtw89_warn(rtwdev, "failed to dump phycap map\n");
440 goto out_free;
441 }
442
443 ret = rtwdev->chip->ops->read_phycap(rtwdev, phycap_map);
444 if (ret) {
445 rtw89_warn(rtwdev, "failed to read phycap map\n");
446 goto out_free;
447 }
448
449 out_free:
450 kfree(phycap_map);
451
452 return ret;
453 }
454
get_sb_cryp_sel_idx(u16 sb_cryp_sel)455 static u16 get_sb_cryp_sel_idx(u16 sb_cryp_sel)
456 {
457 u8 low_bit, high_bit, cnt_zero = 0;
458 u8 idx, sel_form_v, sel_idx_v;
459 u16 sb_cryp_sel_v = 0x0;
460
461 sel_form_v = u16_get_bits(sb_cryp_sel, MASKBYTE0);
462 sel_idx_v = u16_get_bits(sb_cryp_sel, MASKBYTE1);
463
464 for (idx = 0; idx < 4; idx++) {
465 low_bit = !!(sel_form_v & BIT(idx));
466 high_bit = !!(sel_form_v & BIT(7 - idx));
467 if (low_bit != high_bit)
468 return U16_MAX;
469 if (low_bit)
470 continue;
471
472 cnt_zero++;
473 if (cnt_zero == 1)
474 sb_cryp_sel_v = idx * 16;
475 else if (cnt_zero > 1)
476 return U16_MAX;
477 }
478
479 low_bit = u8_get_bits(sel_idx_v, 0x0F);
480 high_bit = u8_get_bits(sel_idx_v, 0xF0);
481
482 if ((low_bit ^ high_bit) != 0xF)
483 return U16_MAX;
484
485 return sb_cryp_sel_v + low_bit;
486 }
487
rtw89_efuse_read_fw_secure_be(struct rtw89_dev * rtwdev)488 int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev)
489 {
490 struct rtw89_fw_secure *sec = &rtwdev->fw.sec;
491 u32 sec_addr = EFUSE_SEC_BE_START;
492 u32 sec_size = EFUSE_SEC_BE_SIZE;
493 u16 sb_cryp_sel, sb_cryp_sel_idx;
494 u8 sec_map[EFUSE_SEC_BE_SIZE];
495 u8 b1, b2;
496 int ret;
497
498 ret = rtw89_dump_physical_efuse_map_be(rtwdev, sec_map,
499 sec_addr, sec_size, false);
500 if (ret) {
501 rtw89_warn(rtwdev, "failed to dump secsel map\n");
502 return ret;
503 }
504
505 sb_cryp_sel = sec_map[EFUSE_SB_CRYP_SEL_ADDR - sec_addr] |
506 sec_map[EFUSE_SB_CRYP_SEL_ADDR - sec_addr + 1] << 8;
507 if (sb_cryp_sel == EFUSE_SB_CRYP_SEL_DEFAULT)
508 goto out;
509
510 sb_cryp_sel_idx = get_sb_cryp_sel_idx(sb_cryp_sel);
511 if (sb_cryp_sel_idx >= SB_SEL_MGN_MAX_SIZE) {
512 rtw89_warn(rtwdev, "invalid SB cryp sel idx %d\n", sb_cryp_sel_idx);
513 goto out;
514 }
515
516 sec->sb_sel_mgn = sb_sel_mgn[sb_cryp_sel_idx];
517
518 b1 = sec_map[EFUSE_EXTERNALPN_ADDR_BE - sec_addr];
519 b2 = sec_map[EFUSE_SERIALNUM_ADDR_BE - sec_addr];
520
521 ret = rtw89_efuse_recognize_mss_info_v1(rtwdev, b1, b2);
522 if (ret)
523 goto out;
524
525 sec->secure_boot = true;
526
527 out:
528 rtw89_debug(rtwdev, RTW89_DBG_FW,
529 "MSS secure_boot=%d dev_type=%d cust_idx=%d key_num=%d\n",
530 sec->secure_boot, sec->mss_dev_type, sec->mss_cust_idx,
531 sec->mss_key_num);
532
533 return 0;
534 }
535
rtw89_efuse_read_ecv_be(struct rtw89_dev * rtwdev)536 int rtw89_efuse_read_ecv_be(struct rtw89_dev *rtwdev)
537 {
538 u32 dump_addr;
539 u8 buff[4]; /* efuse access must 4 bytes align */
540 int ret;
541 u8 ecv;
542 u8 val;
543
544 dump_addr = ALIGN_DOWN(EF_FV_OFSET_BE_V1, 4);
545
546 ret = rtw89_dump_physical_efuse_map_be(rtwdev, buff, dump_addr, 4, false);
547 if (ret)
548 return ret;
549
550 val = buff[EF_FV_OFSET_BE_V1 & 0x3];
551
552 ecv = u8_get_bits(val, EF_CV_MASK);
553 if (ecv == EF_CV_INV)
554 return -ENOENT;
555
556 rtwdev->hal.cv = ecv;
557
558 return 0;
559 }
560
rtw89_efuse_read_thermal_k_be(struct rtw89_dev * rtwdev)561 int rtw89_efuse_read_thermal_k_be(struct rtw89_dev *rtwdev)
562 {
563 struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
564 u32 dump_addr = EFUSE_THERMAL_K_OFFSET_BE;
565 u8 buff[4]; /* efuse access must be multiple of 4 bytes in size */
566 bool no_k;
567 u16 val16;
568 int ret;
569
570 ret = rtw89_dump_physical_efuse_map_be(rtwdev, buff, dump_addr, 4, false);
571 if (ret)
572 return ret;
573
574 val16 = buff[0] | buff[1] << 8;
575
576 no_k = !!u16_get_bits(val16, EFUSE_THERMAL_K_VALID_BE);
577 if (no_k) {
578 info->thermal_k = 0;
579 return -ENOENT;
580 }
581
582 info->thermal_k = u16_get_bits(val16, EFUSE_THERMAL_K_VAL_BE);
583
584 if (u16_get_bits(val16, EFUSE_THERMAL_K_SIGN_BE))
585 info->thermal_k *= -1;
586
587 return 0;
588 }
589
rtw89_efuse_read_pwr_data_vcore_be(struct rtw89_dev * rtwdev)590 static int rtw89_efuse_read_pwr_data_vcore_be(struct rtw89_dev *rtwdev)
591 {
592 struct rtw89_efuse *efuse = &rtwdev->efuse;
593 u32 dump_addr;
594 u8 buff[4]; /* efuse access must 4 bytes align */
595 u16 val16;
596 int ret;
597
598 dump_addr = ALIGN_DOWN(EFUSE_VCORE_PWR_BE, 4);
599
600 ret = rtw89_dump_physical_efuse_map_be(rtwdev, buff, dump_addr, 4, false);
601 if (ret)
602 return ret;
603
604 val16 = buff[EFUSE_VCORE_PWR_BE - dump_addr] |
605 buff[EFUSE_VCORE_PWR_BE - dump_addr + 1] << 8;
606
607 if (val16 & EFUSE_VCORE_PWR_BE_VALID)
608 return 0;
609
610 efuse->vcore_valid = true;
611 efuse->vcore_vmax_reduce =
612 (u16_get_bits(val16, EFUSE_VCORE_PWR_BE_VAL) - SWR_DIG_MIN) /
613 EFUSE_DIG_K_STEP;
614
615 return 0;
616 }
617
rtw89_efuse_read_pwr_data_dswr_be(struct rtw89_dev * rtwdev)618 static int rtw89_efuse_read_pwr_data_dswr_be(struct rtw89_dev *rtwdev)
619 {
620 struct rtw89_efuse *efuse = &rtwdev->efuse;
621 u32 dump_addr;
622 u8 buff[4]; /* efuse access must 4 bytes align */
623 u8 val8;
624 int ret;
625
626 dump_addr = ALIGN_DOWN(EFUSE_DSWR_V0_86_BE, 4);
627
628 ret = rtw89_dump_physical_efuse_map_be(rtwdev, buff, dump_addr, 4, false);
629 if (ret)
630 return ret;
631
632 val8 = buff[EFUSE_DSWR_V0_86_BE - dump_addr];
633
634 if (val8 & EFUSE_DSWR_V0_86_BE_VALID)
635 return 0;
636
637 efuse->dswr_valid = true;
638 efuse->dswr_vmin = u8_get_bits(val8, EFUSE_DSWR_V0_86_BE_VAL);
639
640 return 0;
641 }
642
rtw89_efuse_read_pwr_data_be(struct rtw89_dev * rtwdev)643 int rtw89_efuse_read_pwr_data_be(struct rtw89_dev *rtwdev)
644 {
645 int ret;
646
647 if (rtwdev->chip->chip_id != RTL8922D)
648 return 0;
649
650 ret = rtw89_efuse_read_pwr_data_vcore_be(rtwdev);
651 if (ret)
652 return ret;
653
654 return rtw89_efuse_read_pwr_data_dswr_be(rtwdev);
655 }
656