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
14enum rtw89_efuse_bank {
15	RTW89_EFUSE_BANK_WIFI,
16	RTW89_EFUSE_BANK_BT,
17};
18
19static int rtw89_switch_efuse_bank(struct rtw89_dev *rtwdev,
20				   enum rtw89_efuse_bank bank)
21{
22	u8 val;
23
24	if (rtwdev->chip->chip_id != RTL8852A)
25		return 0;
26
27	val = rtw89_read32_mask(rtwdev, R_AX_EFUSE_CTRL_1,
28				B_AX_EF_CELL_SEL_MASK);
29	if (bank == val)
30		return 0;
31
32	rtw89_write32_mask(rtwdev, R_AX_EFUSE_CTRL_1, B_AX_EF_CELL_SEL_MASK,
33			   bank);
34
35	val = rtw89_read32_mask(rtwdev, R_AX_EFUSE_CTRL_1,
36				B_AX_EF_CELL_SEL_MASK);
37	if (bank == val)
38		return 0;
39
40	return -EBUSY;
41}
42
43static void rtw89_enable_otp_burst_mode(struct rtw89_dev *rtwdev, bool en)
44{
45	if (en)
46		rtw89_write32_set(rtwdev, R_AX_EFUSE_CTRL_1_V1, B_AX_EF_BURST);
47	else
48		rtw89_write32_clr(rtwdev, R_AX_EFUSE_CTRL_1_V1, B_AX_EF_BURST);
49}
50
51static void rtw89_enable_efuse_pwr_cut_ddv(struct rtw89_dev *rtwdev)
52{
53	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
54	struct rtw89_hal *hal = &rtwdev->hal;
55
56	if (chip_id == RTL8852A)
57		return;
58
59	rtw89_write8_set(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK);
60	rtw89_write16_set(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B14);
61
62	fsleep(1000);
63
64	rtw89_write16_set(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B15);
65	rtw89_write16_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_ISO_EB2CORE);
66	if (chip_id == RTL8852B && hal->cv == CHIP_CAV)
67		rtw89_enable_otp_burst_mode(rtwdev, true);
68}
69
70static void rtw89_disable_efuse_pwr_cut_ddv(struct rtw89_dev *rtwdev)
71{
72	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
73	struct rtw89_hal *hal = &rtwdev->hal;
74
75	if (chip_id == RTL8852A)
76		return;
77
78	if (chip_id == RTL8852B && hal->cv == CHIP_CAV)
79		rtw89_enable_otp_burst_mode(rtwdev, false);
80
81	rtw89_write16_set(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_ISO_EB2CORE);
82	rtw89_write16_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B15);
83
84	fsleep(1000);
85
86	rtw89_write16_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B14);
87	rtw89_write8_clr(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK);
88}
89
90static int rtw89_dump_physical_efuse_map_ddv(struct rtw89_dev *rtwdev, u8 *map,
91					     u32 dump_addr, u32 dump_size)
92{
93	u32 efuse_ctl;
94	u32 addr;
95	int ret;
96
97	rtw89_enable_efuse_pwr_cut_ddv(rtwdev);
98
99	for (addr = dump_addr; addr < dump_addr + dump_size; addr++) {
100		efuse_ctl = u32_encode_bits(addr, B_AX_EF_ADDR_MASK);
101		rtw89_write32(rtwdev, R_AX_EFUSE_CTRL, efuse_ctl & ~B_AX_EF_RDY);
102
103		ret = read_poll_timeout_atomic(rtw89_read32, efuse_ctl,
104					       efuse_ctl & B_AX_EF_RDY, 1, 1000000,
105					       true, rtwdev, R_AX_EFUSE_CTRL);
106		if (ret)
107			return -EBUSY;
108
109		*map++ = (u8)(efuse_ctl & 0xff);
110	}
111
112	rtw89_disable_efuse_pwr_cut_ddv(rtwdev);
113
114	return 0;
115}
116
117static int rtw89_dump_physical_efuse_map_dav(struct rtw89_dev *rtwdev, u8 *map,
118					     u32 dump_addr, u32 dump_size)
119{
120	u32 addr;
121	u8 val8;
122	int err;
123	int ret;
124
125	for (addr = dump_addr; addr < dump_addr + dump_size; addr++) {
126		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0x40, FULL_BIT_MASK);
127		if (ret)
128			return ret;
129		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_LOW_ADDR,
130					      addr & 0xff, XTAL_SI_LOW_ADDR_MASK);
131		if (ret)
132			return ret;
133		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, addr >> 8,
134					      XTAL_SI_HIGH_ADDR_MASK);
135		if (ret)
136			return ret;
137		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0,
138					      XTAL_SI_MODE_SEL_MASK);
139		if (ret)
140			return ret;
141
142		ret = read_poll_timeout_atomic(rtw89_mac_read_xtal_si, err,
143					       !err && (val8 & XTAL_SI_RDY),
144					       1, 10000, false,
145					       rtwdev, XTAL_SI_CTRL, &val8);
146		if (ret) {
147			rtw89_warn(rtwdev, "failed to read dav efuse\n");
148			return ret;
149		}
150
151		ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_READ_VAL, &val8);
152		if (ret)
153			return ret;
154		*map++ = val8;
155	}
156
157	return 0;
158}
159
160static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map,
161					 u32 dump_addr, u32 dump_size, bool dav)
162{
163	int ret;
164
165	if (!map || dump_size == 0)
166		return 0;
167
168	rtw89_switch_efuse_bank(rtwdev, RTW89_EFUSE_BANK_WIFI);
169
170	if (dav) {
171		ret = rtw89_dump_physical_efuse_map_dav(rtwdev, map, dump_addr, dump_size);
172		if (ret)
173			return ret;
174	} else {
175		ret = rtw89_dump_physical_efuse_map_ddv(rtwdev, map, dump_addr, dump_size);
176		if (ret)
177			return ret;
178	}
179
180	return 0;
181}
182
183#define invalid_efuse_header(hdr1, hdr2) \
184	((hdr1) == 0xff || (hdr2) == 0xff)
185#define invalid_efuse_content(word_en, i) \
186	(((word_en) & BIT(i)) != 0x0)
187#define get_efuse_blk_idx(hdr1, hdr2) \
188	((((hdr2) & 0xf0) >> 4) | (((hdr1) & 0x0f) << 4))
189#define block_idx_to_logical_idx(blk_idx, i) \
190	(((blk_idx) << 3) + ((i) << 1))
191static int rtw89_dump_logical_efuse_map(struct rtw89_dev *rtwdev, u8 *phy_map,
192					u8 *log_map)
193{
194	u32 physical_size = rtwdev->chip->physical_efuse_size;
195	u32 logical_size = rtwdev->chip->logical_efuse_size;
196	u8 sec_ctrl_size = rtwdev->chip->sec_ctrl_efuse_size;
197	u32 phy_idx = sec_ctrl_size;
198	u32 log_idx;
199	u8 hdr1, hdr2;
200	u8 blk_idx;
201	u8 word_en;
202	int i;
203
204	if (!phy_map)
205		return 0;
206
207	while (phy_idx < physical_size - sec_ctrl_size) {
208		hdr1 = phy_map[phy_idx];
209		hdr2 = phy_map[phy_idx + 1];
210		if (invalid_efuse_header(hdr1, hdr2))
211			break;
212
213		blk_idx = get_efuse_blk_idx(hdr1, hdr2);
214		word_en = hdr2 & 0xf;
215		phy_idx += 2;
216
217		for (i = 0; i < 4; i++) {
218			if (invalid_efuse_content(word_en, i))
219				continue;
220
221			log_idx = block_idx_to_logical_idx(blk_idx, i);
222			if (phy_idx + 1 > physical_size - sec_ctrl_size - 1 ||
223			    log_idx + 1 > logical_size)
224				return -EINVAL;
225
226			log_map[log_idx] = phy_map[phy_idx];
227			log_map[log_idx + 1] = phy_map[phy_idx + 1];
228			phy_idx += 2;
229		}
230	}
231	return 0;
232}
233
234int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev)
235{
236	u32 phy_size = rtwdev->chip->physical_efuse_size;
237	u32 log_size = rtwdev->chip->logical_efuse_size;
238	u32 dav_phy_size = rtwdev->chip->dav_phy_efuse_size;
239	u32 dav_log_size = rtwdev->chip->dav_log_efuse_size;
240	u32 full_log_size = log_size + dav_log_size;
241	u8 *phy_map = NULL;
242	u8 *log_map = NULL;
243	u8 *dav_phy_map = NULL;
244	u8 *dav_log_map = NULL;
245	int ret;
246
247	if (rtw89_read16(rtwdev, R_AX_SYS_WL_EFUSE_CTRL) & B_AX_AUTOLOAD_SUS)
248		rtwdev->efuse.valid = true;
249	else
250		rtw89_warn(rtwdev, "failed to check efuse autoload\n");
251
252	phy_map = kmalloc(phy_size, GFP_KERNEL);
253	log_map = kmalloc(full_log_size, GFP_KERNEL);
254	if (dav_phy_size && dav_log_size) {
255		dav_phy_map = kmalloc(dav_phy_size, GFP_KERNEL);
256		dav_log_map = log_map + log_size;
257	}
258
259	if (!phy_map || !log_map || (dav_phy_size && !dav_phy_map)) {
260		ret = -ENOMEM;
261		goto out_free;
262	}
263
264	ret = rtw89_dump_physical_efuse_map(rtwdev, phy_map, 0, phy_size, false);
265	if (ret) {
266		rtw89_warn(rtwdev, "failed to dump efuse physical map\n");
267		goto out_free;
268	}
269	ret = rtw89_dump_physical_efuse_map(rtwdev, dav_phy_map, 0, dav_phy_size, true);
270	if (ret) {
271		rtw89_warn(rtwdev, "failed to dump efuse dav physical map\n");
272		goto out_free;
273	}
274
275	memset(log_map, 0xff, full_log_size);
276	ret = rtw89_dump_logical_efuse_map(rtwdev, phy_map, log_map);
277	if (ret) {
278		rtw89_warn(rtwdev, "failed to dump efuse logical map\n");
279		goto out_free;
280	}
281	ret = rtw89_dump_logical_efuse_map(rtwdev, dav_phy_map, dav_log_map);
282	if (ret) {
283		rtw89_warn(rtwdev, "failed to dump efuse dav logical map\n");
284		goto out_free;
285	}
286
287	rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "log_map: ", log_map, full_log_size);
288
289	ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map);
290	if (ret) {
291		rtw89_warn(rtwdev, "failed to read efuse map\n");
292		goto out_free;
293	}
294
295out_free:
296	kfree(dav_phy_map);
297	kfree(log_map);
298	kfree(phy_map);
299
300	return ret;
301}
302
303int rtw89_parse_phycap_map(struct rtw89_dev *rtwdev)
304{
305	u32 phycap_addr = rtwdev->chip->phycap_addr;
306	u32 phycap_size = rtwdev->chip->phycap_size;
307	u8 *phycap_map = NULL;
308	int ret = 0;
309
310	if (!phycap_size)
311		return 0;
312
313	phycap_map = kmalloc(phycap_size, GFP_KERNEL);
314	if (!phycap_map)
315		return -ENOMEM;
316
317	ret = rtw89_dump_physical_efuse_map(rtwdev, phycap_map,
318					    phycap_addr, phycap_size, false);
319	if (ret) {
320		rtw89_warn(rtwdev, "failed to dump phycap map\n");
321		goto out_free;
322	}
323
324	ret = rtwdev->chip->ops->read_phycap(rtwdev, phycap_map);
325	if (ret) {
326		rtw89_warn(rtwdev, "failed to read phycap map\n");
327		goto out_free;
328	}
329
330out_free:
331	kfree(phycap_map);
332
333	return ret;
334}
335
336int rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *ecv)
337{
338	int ret;
339	u8 val;
340
341	ret = rtw89_dump_physical_efuse_map(rtwdev, &val, EF_FV_OFSET, 1, false);
342	if (ret)
343		return ret;
344
345	*ecv = u8_get_bits(val, EF_CV_MASK);
346	if (*ecv == EF_CV_INV)
347		return -ENOENT;
348
349	return 0;
350}
351EXPORT_SYMBOL(rtw89_read_efuse_ver);
352