xref: /linux/drivers/net/wireless/realtek/rtw89/efuse_be.c (revision eed4edda910fe34dfae8c6bfbcf57f4593a54295)
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 static void rtw89_enable_efuse_pwr_cut_ddv_be(struct rtw89_dev *rtwdev)
11 {
12 	const struct rtw89_chip_info *chip = rtwdev->chip;
13 	struct rtw89_hal *hal = &rtwdev->hal;
14 	bool aphy_patch = true;
15 
16 	if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV)
17 		aphy_patch = false;
18 
19 	rtw89_write8_set(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK);
20 
21 	if (aphy_patch) {
22 		rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_S);
23 		mdelay(1);
24 		rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_B);
25 		rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE);
26 	}
27 
28 	rtw89_write32_set(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_EF_BURST);
29 }
30 
31 static void rtw89_disable_efuse_pwr_cut_ddv_be(struct rtw89_dev *rtwdev)
32 {
33 	const struct rtw89_chip_info *chip = rtwdev->chip;
34 	struct rtw89_hal *hal = &rtwdev->hal;
35 	bool aphy_patch = true;
36 
37 	if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV)
38 		aphy_patch = false;
39 
40 	if (aphy_patch) {
41 		rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE);
42 		rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_B);
43 		mdelay(1);
44 		rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_S);
45 	}
46 
47 	rtw89_write8_clr(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK);
48 	rtw89_write32_clr(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_EF_BURST);
49 }
50 
51 static int rtw89_dump_physical_efuse_map_ddv_be(struct rtw89_dev *rtwdev, u8 *map,
52 						u32 dump_addr, u32 dump_size)
53 {
54 	u32 efuse_ctl;
55 	u32 addr;
56 	u32 data;
57 	int ret;
58 
59 	if (!IS_ALIGNED(dump_addr, 4) || !IS_ALIGNED(dump_size, 4)) {
60 		rtw89_err(rtwdev, "Efuse addr 0x%x or size 0x%x not aligned\n",
61 			  dump_addr, dump_size);
62 		return -EINVAL;
63 	}
64 
65 	rtw89_enable_efuse_pwr_cut_ddv_be(rtwdev);
66 
67 	for (addr = dump_addr; addr < dump_addr + dump_size; addr += 4, map += 4) {
68 		efuse_ctl = u32_encode_bits(addr, B_BE_EF_ADDR_MASK);
69 		rtw89_write32(rtwdev, R_BE_EFUSE_CTRL, efuse_ctl & ~B_BE_EF_RDY);
70 
71 		ret = read_poll_timeout_atomic(rtw89_read32, efuse_ctl,
72 					       efuse_ctl & B_BE_EF_RDY, 1, 1000000,
73 					       true, rtwdev, R_BE_EFUSE_CTRL);
74 		if (ret)
75 			return -EBUSY;
76 
77 		data = rtw89_read32(rtwdev, R_BE_EFUSE_CTRL_1_V1);
78 		*((__le32 *)map) = cpu_to_le32(data);
79 	}
80 
81 	rtw89_disable_efuse_pwr_cut_ddv_be(rtwdev);
82 
83 	return 0;
84 }
85 
86 static int rtw89_dump_physical_efuse_map_dav_be(struct rtw89_dev *rtwdev, u8 *map,
87 						u32 dump_addr, u32 dump_size)
88 {
89 	u32 addr;
90 	u8 val8;
91 	int err;
92 	int ret;
93 
94 	for (addr = dump_addr; addr < dump_addr + dump_size; addr++) {
95 		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0x40,
96 					      FULL_BIT_MASK);
97 		if (ret)
98 			return ret;
99 		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_LOW_ADDR, addr & 0xff,
100 					      XTAL_SI_LOW_ADDR_MASK);
101 		if (ret)
102 			return ret;
103 		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, addr >> 8,
104 					      XTAL_SI_HIGH_ADDR_MASK);
105 		if (ret)
106 			return ret;
107 		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0,
108 					      XTAL_SI_MODE_SEL_MASK);
109 		if (ret)
110 			return ret;
111 
112 		ret = read_poll_timeout_atomic(rtw89_mac_read_xtal_si, err,
113 					       !err && (val8 & XTAL_SI_RDY),
114 					       1, 10000, false,
115 					       rtwdev, XTAL_SI_CTRL, &val8);
116 		if (ret) {
117 			rtw89_warn(rtwdev, "failed to read dav efuse\n");
118 			return ret;
119 		}
120 
121 		ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_READ_VAL, &val8);
122 		if (ret)
123 			return ret;
124 		*map++ = val8;
125 	}
126 
127 	return 0;
128 }
129 
130 int rtw89_cnv_efuse_state_be(struct rtw89_dev *rtwdev, bool idle)
131 {
132 	u32 val;
133 	int ret = 0;
134 
135 	if (idle) {
136 		rtw89_write32_set(rtwdev, R_BE_WL_BT_PWR_CTRL, B_BE_BT_DISN_EN);
137 	} else {
138 		rtw89_write32_clr(rtwdev, R_BE_WL_BT_PWR_CTRL, B_BE_BT_DISN_EN);
139 
140 		ret = read_poll_timeout(rtw89_read32_mask, val,
141 					val == MAC_AX_SYS_ACT, 50, 5000,
142 					false, rtwdev, R_BE_IC_PWR_STATE,
143 					B_BE_WHOLE_SYS_PWR_STE_MASK);
144 		if (ret)
145 			rtw89_warn(rtwdev, "failed to convert efuse state\n");
146 	}
147 
148 	return ret;
149 }
150 
151 static int rtw89_dump_physical_efuse_map_be(struct rtw89_dev *rtwdev, u8 *map,
152 					    u32 dump_addr, u32 dump_size, bool dav)
153 {
154 	int ret;
155 
156 	if (!map || dump_size == 0)
157 		return 0;
158 
159 	rtw89_cnv_efuse_state_be(rtwdev, false);
160 
161 	if (dav) {
162 		ret = rtw89_dump_physical_efuse_map_dav_be(rtwdev, map,
163 							   dump_addr, dump_size);
164 		if (ret)
165 			return ret;
166 
167 		rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "phy_map dav: ", map, dump_size);
168 	} else {
169 		ret = rtw89_dump_physical_efuse_map_ddv_be(rtwdev, map,
170 							   dump_addr, dump_size);
171 		if (ret)
172 			return ret;
173 
174 		rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "phy_map ddv: ", map, dump_size);
175 	}
176 
177 	rtw89_cnv_efuse_state_be(rtwdev, true);
178 
179 	return 0;
180 }
181 
182 #define EFUSE_HDR_CONST_MASK GENMASK(23, 20)
183 #define EFUSE_HDR_PAGE_MASK GENMASK(19, 17)
184 #define EFUSE_HDR_OFFSET_MASK GENMASK(16, 4)
185 #define EFUSE_HDR_OFFSET_DAV_MASK GENMASK(11, 4)
186 #define EFUSE_HDR_WORD_EN_MASK GENMASK(3, 0)
187 
188 #define invalid_efuse_header_be(hdr1, hdr2, hdr3) \
189 	((hdr1) == 0xff || (hdr2) == 0xff || (hdr3) == 0xff)
190 #define invalid_efuse_content_be(word_en, i) \
191 	(((word_en) & BIT(i)) != 0x0)
192 #define get_efuse_blk_idx_be(hdr1, hdr2, hdr3) \
193 	(((hdr1) << 16) | ((hdr2) << 8) | (hdr3))
194 #define block_idx_to_logical_idx_be(blk_idx, i) \
195 	(((blk_idx) << 3) + ((i) << 1))
196 
197 #define invalid_efuse_header_dav_be(hdr1, hdr2) \
198 	((hdr1) == 0xff || (hdr2) == 0xff)
199 #define get_efuse_blk_idx_dav_be(hdr1, hdr2) \
200 	(((hdr1) << 8) | (hdr2))
201 
202 static int rtw89_eeprom_parser_be(struct rtw89_dev *rtwdev,
203 				  const u8 *phy_map, u32 phy_size, u8 *log_map,
204 				  const struct rtw89_efuse_block_cfg *efuse_block)
205 {
206 	const struct rtw89_chip_info *chip = rtwdev->chip;
207 	enum rtw89_efuse_block blk_page, page;
208 	u32 size = efuse_block->size;
209 	u32 phy_idx, log_idx;
210 	u32 hdr, page_offset;
211 	u8 hdr1, hdr2, hdr3;
212 	u8 i, val0, val1;
213 	u32 min, max;
214 	u16 blk_idx;
215 	u8 word_en;
216 
217 	page = u32_get_bits(efuse_block->offset, RTW89_EFUSE_BLOCK_ID_MASK);
218 	page_offset = u32_get_bits(efuse_block->offset, RTW89_EFUSE_BLOCK_SIZE_MASK);
219 
220 	min = ALIGN_DOWN(page_offset, 2);
221 	max = ALIGN(page_offset + size, 2);
222 
223 	memset(log_map, 0xff, size);
224 
225 	phy_idx = chip->sec_ctrl_efuse_size;
226 
227 	do {
228 		if (page == RTW89_EFUSE_BLOCK_ADIE) {
229 			hdr1 = phy_map[phy_idx];
230 			hdr2 = phy_map[phy_idx + 1];
231 			if (invalid_efuse_header_dav_be(hdr1, hdr2))
232 				break;
233 
234 			phy_idx += 2;
235 
236 			hdr = get_efuse_blk_idx_dav_be(hdr1, hdr2);
237 
238 			blk_page = RTW89_EFUSE_BLOCK_ADIE;
239 			blk_idx = u32_get_bits(hdr, EFUSE_HDR_OFFSET_DAV_MASK);
240 			word_en = u32_get_bits(hdr, EFUSE_HDR_WORD_EN_MASK);
241 		} else {
242 			hdr1 = phy_map[phy_idx];
243 			hdr2 = phy_map[phy_idx + 1];
244 			hdr3 = phy_map[phy_idx + 2];
245 			if (invalid_efuse_header_be(hdr1, hdr2, hdr3))
246 				break;
247 
248 			phy_idx += 3;
249 
250 			hdr = get_efuse_blk_idx_be(hdr1, hdr2, hdr3);
251 
252 			blk_page = u32_get_bits(hdr, EFUSE_HDR_PAGE_MASK);
253 			blk_idx = u32_get_bits(hdr, EFUSE_HDR_OFFSET_MASK);
254 			word_en = u32_get_bits(hdr, EFUSE_HDR_WORD_EN_MASK);
255 		}
256 
257 		if (blk_idx >= RTW89_EFUSE_MAX_BLOCK_SIZE >> 3) {
258 			rtw89_err(rtwdev, "[ERR]efuse idx:0x%X\n", phy_idx - 3);
259 			rtw89_err(rtwdev, "[ERR]read hdr:0x%X\n", hdr);
260 			return -EINVAL;
261 		}
262 
263 		for (i = 0; i < 4; i++) {
264 			if (invalid_efuse_content_be(word_en, i))
265 				continue;
266 
267 			if (phy_idx >= phy_size - 1)
268 				return -EINVAL;
269 
270 			log_idx = block_idx_to_logical_idx_be(blk_idx, i);
271 
272 			if (blk_page == page && log_idx >= min && log_idx < max) {
273 				val0 = phy_map[phy_idx];
274 				val1 = phy_map[phy_idx + 1];
275 
276 				if (log_idx == min && page_offset > min) {
277 					log_map[log_idx - page_offset + 1] = val1;
278 				} else if (log_idx + 2 == max &&
279 					   page_offset + size < max) {
280 					log_map[log_idx - page_offset] = val0;
281 				} else {
282 					log_map[log_idx - page_offset] = val0;
283 					log_map[log_idx - page_offset + 1] = val1;
284 				}
285 			}
286 			phy_idx += 2;
287 		}
288 	} while (phy_idx < phy_size);
289 
290 	return 0;
291 }
292 
293 static int rtw89_parse_logical_efuse_block_be(struct rtw89_dev *rtwdev,
294 					      const u8 *phy_map, u32 phy_size,
295 					      enum rtw89_efuse_block block)
296 {
297 	const struct rtw89_chip_info *chip = rtwdev->chip;
298 	const struct rtw89_efuse_block_cfg *efuse_block;
299 	u8 *log_map;
300 	int ret;
301 
302 	efuse_block = &chip->efuse_blocks[block];
303 
304 	log_map = kmalloc(efuse_block->size, GFP_KERNEL);
305 	if (!log_map)
306 		return -ENOMEM;
307 
308 	ret = rtw89_eeprom_parser_be(rtwdev, phy_map, phy_size, log_map, efuse_block);
309 	if (ret) {
310 		rtw89_warn(rtwdev, "failed to dump efuse logical block %d\n", block);
311 		goto out_free;
312 	}
313 
314 	rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "log_map: ", log_map, efuse_block->size);
315 
316 	ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map, block);
317 	if (ret) {
318 		rtw89_warn(rtwdev, "failed to read efuse map\n");
319 		goto out_free;
320 	}
321 
322 out_free:
323 	kfree(log_map);
324 
325 	return ret;
326 }
327 
328 int rtw89_parse_efuse_map_be(struct rtw89_dev *rtwdev)
329 {
330 	u32 phy_size = rtwdev->chip->physical_efuse_size;
331 	u32 dav_phy_size = rtwdev->chip->dav_phy_efuse_size;
332 	enum rtw89_efuse_block block;
333 	u8 *phy_map = NULL;
334 	u8 *dav_phy_map = NULL;
335 	int ret;
336 
337 	if (rtw89_read16(rtwdev, R_BE_SYS_WL_EFUSE_CTRL) & B_BE_AUTOLOAD_SUS)
338 		rtwdev->efuse.valid = true;
339 	else
340 		rtw89_warn(rtwdev, "failed to check efuse autoload\n");
341 
342 	phy_map = kmalloc(phy_size, GFP_KERNEL);
343 	if (dav_phy_size)
344 		dav_phy_map = kmalloc(dav_phy_size, GFP_KERNEL);
345 
346 	if (!phy_map || (dav_phy_size && !dav_phy_map)) {
347 		ret = -ENOMEM;
348 		goto out_free;
349 	}
350 
351 	ret = rtw89_dump_physical_efuse_map_be(rtwdev, phy_map, 0, phy_size, false);
352 	if (ret) {
353 		rtw89_warn(rtwdev, "failed to dump efuse physical map\n");
354 		goto out_free;
355 	}
356 	ret = rtw89_dump_physical_efuse_map_be(rtwdev, dav_phy_map, 0, dav_phy_size, true);
357 	if (ret) {
358 		rtw89_warn(rtwdev, "failed to dump efuse dav physical map\n");
359 		goto out_free;
360 	}
361 
362 	if (rtwdev->hci.type == RTW89_HCI_TYPE_USB)
363 		block = RTW89_EFUSE_BLOCK_HCI_DIG_USB;
364 	else
365 		block = RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO;
366 
367 	ret = rtw89_parse_logical_efuse_block_be(rtwdev, phy_map, phy_size, block);
368 	if (ret) {
369 		rtw89_warn(rtwdev, "failed to parse efuse logic block %d\n",
370 			   RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO);
371 		goto out_free;
372 	}
373 
374 	ret = rtw89_parse_logical_efuse_block_be(rtwdev, phy_map, phy_size,
375 						 RTW89_EFUSE_BLOCK_RF);
376 	if (ret) {
377 		rtw89_warn(rtwdev, "failed to parse efuse logic block %d\n",
378 			   RTW89_EFUSE_BLOCK_RF);
379 		goto out_free;
380 	}
381 
382 out_free:
383 	kfree(dav_phy_map);
384 	kfree(phy_map);
385 
386 	return ret;
387 }
388 
389 int rtw89_parse_phycap_map_be(struct rtw89_dev *rtwdev)
390 {
391 	u32 phycap_addr = rtwdev->chip->phycap_addr;
392 	u32 phycap_size = rtwdev->chip->phycap_size;
393 	u8 *phycap_map = NULL;
394 	int ret = 0;
395 
396 	if (!phycap_size)
397 		return 0;
398 
399 	phycap_map = kmalloc(phycap_size, GFP_KERNEL);
400 	if (!phycap_map)
401 		return -ENOMEM;
402 
403 	ret = rtw89_dump_physical_efuse_map_be(rtwdev, phycap_map,
404 					       phycap_addr, phycap_size, false);
405 	if (ret) {
406 		rtw89_warn(rtwdev, "failed to dump phycap map\n");
407 		goto out_free;
408 	}
409 
410 	ret = rtwdev->chip->ops->read_phycap(rtwdev, phycap_map);
411 	if (ret) {
412 		rtw89_warn(rtwdev, "failed to read phycap map\n");
413 		goto out_free;
414 	}
415 
416 out_free:
417 	kfree(phycap_map);
418 
419 	return ret;
420 }
421