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