xref: /freebsd/sys/contrib/dev/rtw89/efuse.c (revision e2340276)
18e93258fSBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
28e93258fSBjoern A. Zeeb /* Copyright(c) 2019-2020  Realtek Corporation
38e93258fSBjoern A. Zeeb  */
48e93258fSBjoern A. Zeeb 
58e93258fSBjoern A. Zeeb #include "debug.h"
68e93258fSBjoern A. Zeeb #include "efuse.h"
78e93258fSBjoern A. Zeeb #include "mac.h"
88e93258fSBjoern A. Zeeb #include "reg.h"
98e93258fSBjoern A. Zeeb 
10e2340276SBjoern A. Zeeb #define EF_FV_OFSET 0x5ea
11e2340276SBjoern A. Zeeb #define EF_CV_MASK GENMASK(7, 4)
12e2340276SBjoern A. Zeeb #define EF_CV_INV 15
13e2340276SBjoern A. Zeeb 
148e93258fSBjoern A. Zeeb enum rtw89_efuse_bank {
158e93258fSBjoern A. Zeeb 	RTW89_EFUSE_BANK_WIFI,
168e93258fSBjoern A. Zeeb 	RTW89_EFUSE_BANK_BT,
178e93258fSBjoern A. Zeeb };
188e93258fSBjoern A. Zeeb 
rtw89_switch_efuse_bank(struct rtw89_dev * rtwdev,enum rtw89_efuse_bank bank)198e93258fSBjoern A. Zeeb static int rtw89_switch_efuse_bank(struct rtw89_dev *rtwdev,
208e93258fSBjoern A. Zeeb 				   enum rtw89_efuse_bank bank)
218e93258fSBjoern A. Zeeb {
228e93258fSBjoern A. Zeeb 	u8 val;
238e93258fSBjoern A. Zeeb 
248e93258fSBjoern A. Zeeb 	if (rtwdev->chip->chip_id != RTL8852A)
258e93258fSBjoern A. Zeeb 		return 0;
268e93258fSBjoern A. Zeeb 
278e93258fSBjoern A. Zeeb 	val = rtw89_read32_mask(rtwdev, R_AX_EFUSE_CTRL_1,
288e93258fSBjoern A. Zeeb 				B_AX_EF_CELL_SEL_MASK);
298e93258fSBjoern A. Zeeb 	if (bank == val)
308e93258fSBjoern A. Zeeb 		return 0;
318e93258fSBjoern A. Zeeb 
328e93258fSBjoern A. Zeeb 	rtw89_write32_mask(rtwdev, R_AX_EFUSE_CTRL_1, B_AX_EF_CELL_SEL_MASK,
338e93258fSBjoern A. Zeeb 			   bank);
348e93258fSBjoern A. Zeeb 
358e93258fSBjoern A. Zeeb 	val = rtw89_read32_mask(rtwdev, R_AX_EFUSE_CTRL_1,
368e93258fSBjoern A. Zeeb 				B_AX_EF_CELL_SEL_MASK);
378e93258fSBjoern A. Zeeb 	if (bank == val)
388e93258fSBjoern A. Zeeb 		return 0;
398e93258fSBjoern A. Zeeb 
408e93258fSBjoern A. Zeeb 	return -EBUSY;
418e93258fSBjoern A. Zeeb }
428e93258fSBjoern A. Zeeb 
rtw89_enable_otp_burst_mode(struct rtw89_dev * rtwdev,bool en)438e93258fSBjoern A. Zeeb static void rtw89_enable_otp_burst_mode(struct rtw89_dev *rtwdev, bool en)
448e93258fSBjoern A. Zeeb {
458e93258fSBjoern A. Zeeb 	if (en)
468e93258fSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, R_AX_EFUSE_CTRL_1_V1, B_AX_EF_BURST);
478e93258fSBjoern A. Zeeb 	else
488e93258fSBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, R_AX_EFUSE_CTRL_1_V1, B_AX_EF_BURST);
498e93258fSBjoern A. Zeeb }
508e93258fSBjoern A. Zeeb 
rtw89_enable_efuse_pwr_cut_ddv(struct rtw89_dev * rtwdev)518e93258fSBjoern A. Zeeb static void rtw89_enable_efuse_pwr_cut_ddv(struct rtw89_dev *rtwdev)
528e93258fSBjoern A. Zeeb {
538e93258fSBjoern A. Zeeb 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
548e93258fSBjoern A. Zeeb 	struct rtw89_hal *hal = &rtwdev->hal;
558e93258fSBjoern A. Zeeb 
568e93258fSBjoern A. Zeeb 	if (chip_id == RTL8852A)
578e93258fSBjoern A. Zeeb 		return;
588e93258fSBjoern A. Zeeb 
598e93258fSBjoern A. Zeeb 	rtw89_write8_set(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK);
608e93258fSBjoern A. Zeeb 	rtw89_write16_set(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B14);
618e93258fSBjoern A. Zeeb 
628e93258fSBjoern A. Zeeb 	fsleep(1000);
638e93258fSBjoern A. Zeeb 
648e93258fSBjoern A. Zeeb 	rtw89_write16_set(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B15);
658e93258fSBjoern A. Zeeb 	rtw89_write16_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_ISO_EB2CORE);
668e93258fSBjoern A. Zeeb 	if (chip_id == RTL8852B && hal->cv == CHIP_CAV)
678e93258fSBjoern A. Zeeb 		rtw89_enable_otp_burst_mode(rtwdev, true);
688e93258fSBjoern A. Zeeb }
698e93258fSBjoern A. Zeeb 
rtw89_disable_efuse_pwr_cut_ddv(struct rtw89_dev * rtwdev)708e93258fSBjoern A. Zeeb static void rtw89_disable_efuse_pwr_cut_ddv(struct rtw89_dev *rtwdev)
718e93258fSBjoern A. Zeeb {
728e93258fSBjoern A. Zeeb 	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
738e93258fSBjoern A. Zeeb 	struct rtw89_hal *hal = &rtwdev->hal;
748e93258fSBjoern A. Zeeb 
758e93258fSBjoern A. Zeeb 	if (chip_id == RTL8852A)
768e93258fSBjoern A. Zeeb 		return;
778e93258fSBjoern A. Zeeb 
788e93258fSBjoern A. Zeeb 	if (chip_id == RTL8852B && hal->cv == CHIP_CAV)
798e93258fSBjoern A. Zeeb 		rtw89_enable_otp_burst_mode(rtwdev, false);
808e93258fSBjoern A. Zeeb 
818e93258fSBjoern A. Zeeb 	rtw89_write16_set(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_ISO_EB2CORE);
828e93258fSBjoern A. Zeeb 	rtw89_write16_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B15);
838e93258fSBjoern A. Zeeb 
848e93258fSBjoern A. Zeeb 	fsleep(1000);
858e93258fSBjoern A. Zeeb 
868e93258fSBjoern A. Zeeb 	rtw89_write16_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B14);
878e93258fSBjoern A. Zeeb 	rtw89_write8_clr(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK);
888e93258fSBjoern A. Zeeb }
898e93258fSBjoern A. Zeeb 
rtw89_dump_physical_efuse_map_ddv(struct rtw89_dev * rtwdev,u8 * map,u32 dump_addr,u32 dump_size)908e93258fSBjoern A. Zeeb static int rtw89_dump_physical_efuse_map_ddv(struct rtw89_dev *rtwdev, u8 *map,
918e93258fSBjoern A. Zeeb 					     u32 dump_addr, u32 dump_size)
928e93258fSBjoern A. Zeeb {
938e93258fSBjoern A. Zeeb 	u32 efuse_ctl;
948e93258fSBjoern A. Zeeb 	u32 addr;
958e93258fSBjoern A. Zeeb 	int ret;
968e93258fSBjoern A. Zeeb 
978e93258fSBjoern A. Zeeb 	rtw89_enable_efuse_pwr_cut_ddv(rtwdev);
988e93258fSBjoern A. Zeeb 
998e93258fSBjoern A. Zeeb 	for (addr = dump_addr; addr < dump_addr + dump_size; addr++) {
1008e93258fSBjoern A. Zeeb 		efuse_ctl = u32_encode_bits(addr, B_AX_EF_ADDR_MASK);
1018e93258fSBjoern A. Zeeb 		rtw89_write32(rtwdev, R_AX_EFUSE_CTRL, efuse_ctl & ~B_AX_EF_RDY);
1028e93258fSBjoern A. Zeeb 
1038e93258fSBjoern A. Zeeb 		ret = read_poll_timeout_atomic(rtw89_read32, efuse_ctl,
1048e93258fSBjoern A. Zeeb 					       efuse_ctl & B_AX_EF_RDY, 1, 1000000,
1058e93258fSBjoern A. Zeeb 					       true, rtwdev, R_AX_EFUSE_CTRL);
1068e93258fSBjoern A. Zeeb 		if (ret)
1078e93258fSBjoern A. Zeeb 			return -EBUSY;
1088e93258fSBjoern A. Zeeb 
1098e93258fSBjoern A. Zeeb 		*map++ = (u8)(efuse_ctl & 0xff);
1108e93258fSBjoern A. Zeeb 	}
1118e93258fSBjoern A. Zeeb 
1128e93258fSBjoern A. Zeeb 	rtw89_disable_efuse_pwr_cut_ddv(rtwdev);
1138e93258fSBjoern A. Zeeb 
1148e93258fSBjoern A. Zeeb 	return 0;
1158e93258fSBjoern A. Zeeb }
1168e93258fSBjoern A. Zeeb 
rtw89_dump_physical_efuse_map_dav(struct rtw89_dev * rtwdev,u8 * map,u32 dump_addr,u32 dump_size)1178e93258fSBjoern A. Zeeb static int rtw89_dump_physical_efuse_map_dav(struct rtw89_dev *rtwdev, u8 *map,
1188e93258fSBjoern A. Zeeb 					     u32 dump_addr, u32 dump_size)
1198e93258fSBjoern A. Zeeb {
1208e93258fSBjoern A. Zeeb 	u32 addr;
1218e93258fSBjoern A. Zeeb 	u8 val8;
1228e93258fSBjoern A. Zeeb 	int err;
1238e93258fSBjoern A. Zeeb 	int ret;
1248e93258fSBjoern A. Zeeb 
1258e93258fSBjoern A. Zeeb 	for (addr = dump_addr; addr < dump_addr + dump_size; addr++) {
1268e93258fSBjoern A. Zeeb 		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0x40, FULL_BIT_MASK);
1278e93258fSBjoern A. Zeeb 		if (ret)
1288e93258fSBjoern A. Zeeb 			return ret;
1298e93258fSBjoern A. Zeeb 		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_LOW_ADDR,
1308e93258fSBjoern A. Zeeb 					      addr & 0xff, XTAL_SI_LOW_ADDR_MASK);
1318e93258fSBjoern A. Zeeb 		if (ret)
1328e93258fSBjoern A. Zeeb 			return ret;
1338e93258fSBjoern A. Zeeb 		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, addr >> 8,
1348e93258fSBjoern A. Zeeb 					      XTAL_SI_HIGH_ADDR_MASK);
1358e93258fSBjoern A. Zeeb 		if (ret)
1368e93258fSBjoern A. Zeeb 			return ret;
1378e93258fSBjoern A. Zeeb 		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0,
1388e93258fSBjoern A. Zeeb 					      XTAL_SI_MODE_SEL_MASK);
1398e93258fSBjoern A. Zeeb 		if (ret)
1408e93258fSBjoern A. Zeeb 			return ret;
1418e93258fSBjoern A. Zeeb 
1428e93258fSBjoern A. Zeeb 		ret = read_poll_timeout_atomic(rtw89_mac_read_xtal_si, err,
1438e93258fSBjoern A. Zeeb 					       !err && (val8 & XTAL_SI_RDY),
1448e93258fSBjoern A. Zeeb 					       1, 10000, false,
1458e93258fSBjoern A. Zeeb 					       rtwdev, XTAL_SI_CTRL, &val8);
1468e93258fSBjoern A. Zeeb 		if (ret) {
1478e93258fSBjoern A. Zeeb 			rtw89_warn(rtwdev, "failed to read dav efuse\n");
1488e93258fSBjoern A. Zeeb 			return ret;
1498e93258fSBjoern A. Zeeb 		}
1508e93258fSBjoern A. Zeeb 
1518e93258fSBjoern A. Zeeb 		ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_READ_VAL, &val8);
1528e93258fSBjoern A. Zeeb 		if (ret)
1538e93258fSBjoern A. Zeeb 			return ret;
1548e93258fSBjoern A. Zeeb 		*map++ = val8;
1558e93258fSBjoern A. Zeeb 	}
1568e93258fSBjoern A. Zeeb 
1578e93258fSBjoern A. Zeeb 	return 0;
1588e93258fSBjoern A. Zeeb }
1598e93258fSBjoern A. Zeeb 
rtw89_dump_physical_efuse_map(struct rtw89_dev * rtwdev,u8 * map,u32 dump_addr,u32 dump_size,bool dav)1608e93258fSBjoern A. Zeeb static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map,
1618e93258fSBjoern A. Zeeb 					 u32 dump_addr, u32 dump_size, bool dav)
1628e93258fSBjoern A. Zeeb {
1638e93258fSBjoern A. Zeeb 	int ret;
1648e93258fSBjoern A. Zeeb 
1658e93258fSBjoern A. Zeeb 	if (!map || dump_size == 0)
1668e93258fSBjoern A. Zeeb 		return 0;
1678e93258fSBjoern A. Zeeb 
1688e93258fSBjoern A. Zeeb 	rtw89_switch_efuse_bank(rtwdev, RTW89_EFUSE_BANK_WIFI);
1698e93258fSBjoern A. Zeeb 
1708e93258fSBjoern A. Zeeb 	if (dav) {
1718e93258fSBjoern A. Zeeb 		ret = rtw89_dump_physical_efuse_map_dav(rtwdev, map, dump_addr, dump_size);
1728e93258fSBjoern A. Zeeb 		if (ret)
1738e93258fSBjoern A. Zeeb 			return ret;
1748e93258fSBjoern A. Zeeb 	} else {
1758e93258fSBjoern A. Zeeb 		ret = rtw89_dump_physical_efuse_map_ddv(rtwdev, map, dump_addr, dump_size);
1768e93258fSBjoern A. Zeeb 		if (ret)
1778e93258fSBjoern A. Zeeb 			return ret;
1788e93258fSBjoern A. Zeeb 	}
1798e93258fSBjoern A. Zeeb 
1808e93258fSBjoern A. Zeeb 	return 0;
1818e93258fSBjoern A. Zeeb }
1828e93258fSBjoern A. Zeeb 
1838e93258fSBjoern A. Zeeb #define invalid_efuse_header(hdr1, hdr2) \
1848e93258fSBjoern A. Zeeb 	((hdr1) == 0xff || (hdr2) == 0xff)
1858e93258fSBjoern A. Zeeb #define invalid_efuse_content(word_en, i) \
1868e93258fSBjoern A. Zeeb 	(((word_en) & BIT(i)) != 0x0)
1878e93258fSBjoern A. Zeeb #define get_efuse_blk_idx(hdr1, hdr2) \
1888e93258fSBjoern A. Zeeb 	((((hdr2) & 0xf0) >> 4) | (((hdr1) & 0x0f) << 4))
1898e93258fSBjoern A. Zeeb #define block_idx_to_logical_idx(blk_idx, i) \
1908e93258fSBjoern A. Zeeb 	(((blk_idx) << 3) + ((i) << 1))
rtw89_dump_logical_efuse_map(struct rtw89_dev * rtwdev,u8 * phy_map,u8 * log_map)1918e93258fSBjoern A. Zeeb static int rtw89_dump_logical_efuse_map(struct rtw89_dev *rtwdev, u8 *phy_map,
1928e93258fSBjoern A. Zeeb 					u8 *log_map)
1938e93258fSBjoern A. Zeeb {
1948e93258fSBjoern A. Zeeb 	u32 physical_size = rtwdev->chip->physical_efuse_size;
1958e93258fSBjoern A. Zeeb 	u32 logical_size = rtwdev->chip->logical_efuse_size;
1968e93258fSBjoern A. Zeeb 	u8 sec_ctrl_size = rtwdev->chip->sec_ctrl_efuse_size;
1978e93258fSBjoern A. Zeeb 	u32 phy_idx = sec_ctrl_size;
1988e93258fSBjoern A. Zeeb 	u32 log_idx;
1998e93258fSBjoern A. Zeeb 	u8 hdr1, hdr2;
2008e93258fSBjoern A. Zeeb 	u8 blk_idx;
2018e93258fSBjoern A. Zeeb 	u8 word_en;
2028e93258fSBjoern A. Zeeb 	int i;
2038e93258fSBjoern A. Zeeb 
2048e93258fSBjoern A. Zeeb 	if (!phy_map)
2058e93258fSBjoern A. Zeeb 		return 0;
2068e93258fSBjoern A. Zeeb 
2078e93258fSBjoern A. Zeeb 	while (phy_idx < physical_size - sec_ctrl_size) {
2088e93258fSBjoern A. Zeeb 		hdr1 = phy_map[phy_idx];
2098e93258fSBjoern A. Zeeb 		hdr2 = phy_map[phy_idx + 1];
2108e93258fSBjoern A. Zeeb 		if (invalid_efuse_header(hdr1, hdr2))
2118e93258fSBjoern A. Zeeb 			break;
2128e93258fSBjoern A. Zeeb 
2138e93258fSBjoern A. Zeeb 		blk_idx = get_efuse_blk_idx(hdr1, hdr2);
2148e93258fSBjoern A. Zeeb 		word_en = hdr2 & 0xf;
2158e93258fSBjoern A. Zeeb 		phy_idx += 2;
2168e93258fSBjoern A. Zeeb 
2178e93258fSBjoern A. Zeeb 		for (i = 0; i < 4; i++) {
2188e93258fSBjoern A. Zeeb 			if (invalid_efuse_content(word_en, i))
2198e93258fSBjoern A. Zeeb 				continue;
2208e93258fSBjoern A. Zeeb 
2218e93258fSBjoern A. Zeeb 			log_idx = block_idx_to_logical_idx(blk_idx, i);
2228e93258fSBjoern A. Zeeb 			if (phy_idx + 1 > physical_size - sec_ctrl_size - 1 ||
2238e93258fSBjoern A. Zeeb 			    log_idx + 1 > logical_size)
2248e93258fSBjoern A. Zeeb 				return -EINVAL;
2258e93258fSBjoern A. Zeeb 
2268e93258fSBjoern A. Zeeb 			log_map[log_idx] = phy_map[phy_idx];
2278e93258fSBjoern A. Zeeb 			log_map[log_idx + 1] = phy_map[phy_idx + 1];
2288e93258fSBjoern A. Zeeb 			phy_idx += 2;
2298e93258fSBjoern A. Zeeb 		}
2308e93258fSBjoern A. Zeeb 	}
2318e93258fSBjoern A. Zeeb 	return 0;
2328e93258fSBjoern A. Zeeb }
2338e93258fSBjoern A. Zeeb 
rtw89_parse_efuse_map(struct rtw89_dev * rtwdev)2348e93258fSBjoern A. Zeeb int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev)
2358e93258fSBjoern A. Zeeb {
2368e93258fSBjoern A. Zeeb 	u32 phy_size = rtwdev->chip->physical_efuse_size;
2378e93258fSBjoern A. Zeeb 	u32 log_size = rtwdev->chip->logical_efuse_size;
2388e93258fSBjoern A. Zeeb 	u32 dav_phy_size = rtwdev->chip->dav_phy_efuse_size;
2398e93258fSBjoern A. Zeeb 	u32 dav_log_size = rtwdev->chip->dav_log_efuse_size;
2408e93258fSBjoern A. Zeeb 	u32 full_log_size = log_size + dav_log_size;
2418e93258fSBjoern A. Zeeb 	u8 *phy_map = NULL;
2428e93258fSBjoern A. Zeeb 	u8 *log_map = NULL;
2438e93258fSBjoern A. Zeeb 	u8 *dav_phy_map = NULL;
2448e93258fSBjoern A. Zeeb 	u8 *dav_log_map = NULL;
2458e93258fSBjoern A. Zeeb 	int ret;
2468e93258fSBjoern A. Zeeb 
2478e93258fSBjoern A. Zeeb 	if (rtw89_read16(rtwdev, R_AX_SYS_WL_EFUSE_CTRL) & B_AX_AUTOLOAD_SUS)
2488e93258fSBjoern A. Zeeb 		rtwdev->efuse.valid = true;
2498e93258fSBjoern A. Zeeb 	else
2508e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to check efuse autoload\n");
2518e93258fSBjoern A. Zeeb 
2528e93258fSBjoern A. Zeeb 	phy_map = kmalloc(phy_size, GFP_KERNEL);
2538e93258fSBjoern A. Zeeb 	log_map = kmalloc(full_log_size, GFP_KERNEL);
2548e93258fSBjoern A. Zeeb 	if (dav_phy_size && dav_log_size) {
2558e93258fSBjoern A. Zeeb 		dav_phy_map = kmalloc(dav_phy_size, GFP_KERNEL);
2568e93258fSBjoern A. Zeeb 		dav_log_map = log_map + log_size;
2578e93258fSBjoern A. Zeeb 	}
2588e93258fSBjoern A. Zeeb 
2598e93258fSBjoern A. Zeeb 	if (!phy_map || !log_map || (dav_phy_size && !dav_phy_map)) {
2608e93258fSBjoern A. Zeeb 		ret = -ENOMEM;
2618e93258fSBjoern A. Zeeb 		goto out_free;
2628e93258fSBjoern A. Zeeb 	}
2638e93258fSBjoern A. Zeeb 
2648e93258fSBjoern A. Zeeb 	ret = rtw89_dump_physical_efuse_map(rtwdev, phy_map, 0, phy_size, false);
2658e93258fSBjoern A. Zeeb 	if (ret) {
2668e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to dump efuse physical map\n");
2678e93258fSBjoern A. Zeeb 		goto out_free;
2688e93258fSBjoern A. Zeeb 	}
2698e93258fSBjoern A. Zeeb 	ret = rtw89_dump_physical_efuse_map(rtwdev, dav_phy_map, 0, dav_phy_size, true);
2708e93258fSBjoern A. Zeeb 	if (ret) {
2718e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to dump efuse dav physical map\n");
2728e93258fSBjoern A. Zeeb 		goto out_free;
2738e93258fSBjoern A. Zeeb 	}
2748e93258fSBjoern A. Zeeb 
2758e93258fSBjoern A. Zeeb 	memset(log_map, 0xff, full_log_size);
2768e93258fSBjoern A. Zeeb 	ret = rtw89_dump_logical_efuse_map(rtwdev, phy_map, log_map);
2778e93258fSBjoern A. Zeeb 	if (ret) {
2788e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to dump efuse logical map\n");
2798e93258fSBjoern A. Zeeb 		goto out_free;
2808e93258fSBjoern A. Zeeb 	}
2818e93258fSBjoern A. Zeeb 	ret = rtw89_dump_logical_efuse_map(rtwdev, dav_phy_map, dav_log_map);
2828e93258fSBjoern A. Zeeb 	if (ret) {
2838e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to dump efuse dav logical map\n");
2848e93258fSBjoern A. Zeeb 		goto out_free;
2858e93258fSBjoern A. Zeeb 	}
2868e93258fSBjoern A. Zeeb 
2878e93258fSBjoern A. Zeeb 	rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "log_map: ", log_map, full_log_size);
2888e93258fSBjoern A. Zeeb 
2898e93258fSBjoern A. Zeeb 	ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map);
2908e93258fSBjoern A. Zeeb 	if (ret) {
2918e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to read efuse map\n");
2928e93258fSBjoern A. Zeeb 		goto out_free;
2938e93258fSBjoern A. Zeeb 	}
2948e93258fSBjoern A. Zeeb 
2958e93258fSBjoern A. Zeeb out_free:
2968e93258fSBjoern A. Zeeb 	kfree(dav_phy_map);
2978e93258fSBjoern A. Zeeb 	kfree(log_map);
2988e93258fSBjoern A. Zeeb 	kfree(phy_map);
2998e93258fSBjoern A. Zeeb 
3008e93258fSBjoern A. Zeeb 	return ret;
3018e93258fSBjoern A. Zeeb }
3028e93258fSBjoern A. Zeeb 
rtw89_parse_phycap_map(struct rtw89_dev * rtwdev)3038e93258fSBjoern A. Zeeb int rtw89_parse_phycap_map(struct rtw89_dev *rtwdev)
3048e93258fSBjoern A. Zeeb {
3058e93258fSBjoern A. Zeeb 	u32 phycap_addr = rtwdev->chip->phycap_addr;
3068e93258fSBjoern A. Zeeb 	u32 phycap_size = rtwdev->chip->phycap_size;
3078e93258fSBjoern A. Zeeb 	u8 *phycap_map = NULL;
3088e93258fSBjoern A. Zeeb 	int ret = 0;
3098e93258fSBjoern A. Zeeb 
3108e93258fSBjoern A. Zeeb 	if (!phycap_size)
3118e93258fSBjoern A. Zeeb 		return 0;
3128e93258fSBjoern A. Zeeb 
3138e93258fSBjoern A. Zeeb 	phycap_map = kmalloc(phycap_size, GFP_KERNEL);
3148e93258fSBjoern A. Zeeb 	if (!phycap_map)
3158e93258fSBjoern A. Zeeb 		return -ENOMEM;
3168e93258fSBjoern A. Zeeb 
3178e93258fSBjoern A. Zeeb 	ret = rtw89_dump_physical_efuse_map(rtwdev, phycap_map,
3188e93258fSBjoern A. Zeeb 					    phycap_addr, phycap_size, false);
3198e93258fSBjoern A. Zeeb 	if (ret) {
3208e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to dump phycap map\n");
3218e93258fSBjoern A. Zeeb 		goto out_free;
3228e93258fSBjoern A. Zeeb 	}
3238e93258fSBjoern A. Zeeb 
3248e93258fSBjoern A. Zeeb 	ret = rtwdev->chip->ops->read_phycap(rtwdev, phycap_map);
3258e93258fSBjoern A. Zeeb 	if (ret) {
3268e93258fSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to read phycap map\n");
3278e93258fSBjoern A. Zeeb 		goto out_free;
3288e93258fSBjoern A. Zeeb 	}
3298e93258fSBjoern A. Zeeb 
3308e93258fSBjoern A. Zeeb out_free:
3318e93258fSBjoern A. Zeeb 	kfree(phycap_map);
3328e93258fSBjoern A. Zeeb 
3338e93258fSBjoern A. Zeeb 	return ret;
3348e93258fSBjoern A. Zeeb }
335e2340276SBjoern A. Zeeb 
rtw89_read_efuse_ver(struct rtw89_dev * rtwdev,u8 * ecv)336e2340276SBjoern A. Zeeb int rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *ecv)
337e2340276SBjoern A. Zeeb {
338e2340276SBjoern A. Zeeb 	int ret;
339e2340276SBjoern A. Zeeb 	u8 val;
340e2340276SBjoern A. Zeeb 
341e2340276SBjoern A. Zeeb 	ret = rtw89_dump_physical_efuse_map(rtwdev, &val, EF_FV_OFSET, 1, false);
342e2340276SBjoern A. Zeeb 	if (ret)
343e2340276SBjoern A. Zeeb 		return ret;
344e2340276SBjoern A. Zeeb 
345e2340276SBjoern A. Zeeb 	*ecv = u8_get_bits(val, EF_CV_MASK);
346e2340276SBjoern A. Zeeb 	if (*ecv == EF_CV_INV)
347e2340276SBjoern A. Zeeb 		return -ENOENT;
348e2340276SBjoern A. Zeeb 
349e2340276SBjoern A. Zeeb 	return 0;
350e2340276SBjoern A. Zeeb }
351e2340276SBjoern A. Zeeb EXPORT_SYMBOL(rtw89_read_efuse_ver);
352