162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
262306a36Sopenharmony_ci/* Copyright(c) 2019-2020  Realtek Corporation
362306a36Sopenharmony_ci */
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include "debug.h"
662306a36Sopenharmony_ci#include "efuse.h"
762306a36Sopenharmony_ci#include "mac.h"
862306a36Sopenharmony_ci#include "reg.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define EF_FV_OFSET 0x5ea
1162306a36Sopenharmony_ci#define EF_CV_MASK GENMASK(7, 4)
1262306a36Sopenharmony_ci#define EF_CV_INV 15
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cienum rtw89_efuse_bank {
1562306a36Sopenharmony_ci	RTW89_EFUSE_BANK_WIFI,
1662306a36Sopenharmony_ci	RTW89_EFUSE_BANK_BT,
1762306a36Sopenharmony_ci};
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic int rtw89_switch_efuse_bank(struct rtw89_dev *rtwdev,
2062306a36Sopenharmony_ci				   enum rtw89_efuse_bank bank)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	u8 val;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	if (rtwdev->chip->chip_id != RTL8852A)
2562306a36Sopenharmony_ci		return 0;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	val = rtw89_read32_mask(rtwdev, R_AX_EFUSE_CTRL_1,
2862306a36Sopenharmony_ci				B_AX_EF_CELL_SEL_MASK);
2962306a36Sopenharmony_ci	if (bank == val)
3062306a36Sopenharmony_ci		return 0;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	rtw89_write32_mask(rtwdev, R_AX_EFUSE_CTRL_1, B_AX_EF_CELL_SEL_MASK,
3362306a36Sopenharmony_ci			   bank);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	val = rtw89_read32_mask(rtwdev, R_AX_EFUSE_CTRL_1,
3662306a36Sopenharmony_ci				B_AX_EF_CELL_SEL_MASK);
3762306a36Sopenharmony_ci	if (bank == val)
3862306a36Sopenharmony_ci		return 0;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	return -EBUSY;
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic void rtw89_enable_otp_burst_mode(struct rtw89_dev *rtwdev, bool en)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	if (en)
4662306a36Sopenharmony_ci		rtw89_write32_set(rtwdev, R_AX_EFUSE_CTRL_1_V1, B_AX_EF_BURST);
4762306a36Sopenharmony_ci	else
4862306a36Sopenharmony_ci		rtw89_write32_clr(rtwdev, R_AX_EFUSE_CTRL_1_V1, B_AX_EF_BURST);
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic void rtw89_enable_efuse_pwr_cut_ddv(struct rtw89_dev *rtwdev)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
5462306a36Sopenharmony_ci	struct rtw89_hal *hal = &rtwdev->hal;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	if (chip_id == RTL8852A)
5762306a36Sopenharmony_ci		return;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	rtw89_write8_set(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK);
6062306a36Sopenharmony_ci	rtw89_write16_set(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B14);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	fsleep(1000);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	rtw89_write16_set(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B15);
6562306a36Sopenharmony_ci	rtw89_write16_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_ISO_EB2CORE);
6662306a36Sopenharmony_ci	if (chip_id == RTL8852B && hal->cv == CHIP_CAV)
6762306a36Sopenharmony_ci		rtw89_enable_otp_burst_mode(rtwdev, true);
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic void rtw89_disable_efuse_pwr_cut_ddv(struct rtw89_dev *rtwdev)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
7362306a36Sopenharmony_ci	struct rtw89_hal *hal = &rtwdev->hal;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	if (chip_id == RTL8852A)
7662306a36Sopenharmony_ci		return;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	if (chip_id == RTL8852B && hal->cv == CHIP_CAV)
7962306a36Sopenharmony_ci		rtw89_enable_otp_burst_mode(rtwdev, false);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	rtw89_write16_set(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_ISO_EB2CORE);
8262306a36Sopenharmony_ci	rtw89_write16_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B15);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	fsleep(1000);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	rtw89_write16_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B14);
8762306a36Sopenharmony_ci	rtw89_write8_clr(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic int rtw89_dump_physical_efuse_map_ddv(struct rtw89_dev *rtwdev, u8 *map,
9162306a36Sopenharmony_ci					     u32 dump_addr, u32 dump_size)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	u32 efuse_ctl;
9462306a36Sopenharmony_ci	u32 addr;
9562306a36Sopenharmony_ci	int ret;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	rtw89_enable_efuse_pwr_cut_ddv(rtwdev);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	for (addr = dump_addr; addr < dump_addr + dump_size; addr++) {
10062306a36Sopenharmony_ci		efuse_ctl = u32_encode_bits(addr, B_AX_EF_ADDR_MASK);
10162306a36Sopenharmony_ci		rtw89_write32(rtwdev, R_AX_EFUSE_CTRL, efuse_ctl & ~B_AX_EF_RDY);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci		ret = read_poll_timeout_atomic(rtw89_read32, efuse_ctl,
10462306a36Sopenharmony_ci					       efuse_ctl & B_AX_EF_RDY, 1, 1000000,
10562306a36Sopenharmony_ci					       true, rtwdev, R_AX_EFUSE_CTRL);
10662306a36Sopenharmony_ci		if (ret)
10762306a36Sopenharmony_ci			return -EBUSY;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci		*map++ = (u8)(efuse_ctl & 0xff);
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	rtw89_disable_efuse_pwr_cut_ddv(rtwdev);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	return 0;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic int rtw89_dump_physical_efuse_map_dav(struct rtw89_dev *rtwdev, u8 *map,
11862306a36Sopenharmony_ci					     u32 dump_addr, u32 dump_size)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	u32 addr;
12162306a36Sopenharmony_ci	u8 val8;
12262306a36Sopenharmony_ci	int err;
12362306a36Sopenharmony_ci	int ret;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	for (addr = dump_addr; addr < dump_addr + dump_size; addr++) {
12662306a36Sopenharmony_ci		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0x40, FULL_BIT_MASK);
12762306a36Sopenharmony_ci		if (ret)
12862306a36Sopenharmony_ci			return ret;
12962306a36Sopenharmony_ci		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_LOW_ADDR,
13062306a36Sopenharmony_ci					      addr & 0xff, XTAL_SI_LOW_ADDR_MASK);
13162306a36Sopenharmony_ci		if (ret)
13262306a36Sopenharmony_ci			return ret;
13362306a36Sopenharmony_ci		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, addr >> 8,
13462306a36Sopenharmony_ci					      XTAL_SI_HIGH_ADDR_MASK);
13562306a36Sopenharmony_ci		if (ret)
13662306a36Sopenharmony_ci			return ret;
13762306a36Sopenharmony_ci		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0,
13862306a36Sopenharmony_ci					      XTAL_SI_MODE_SEL_MASK);
13962306a36Sopenharmony_ci		if (ret)
14062306a36Sopenharmony_ci			return ret;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci		ret = read_poll_timeout_atomic(rtw89_mac_read_xtal_si, err,
14362306a36Sopenharmony_ci					       !err && (val8 & XTAL_SI_RDY),
14462306a36Sopenharmony_ci					       1, 10000, false,
14562306a36Sopenharmony_ci					       rtwdev, XTAL_SI_CTRL, &val8);
14662306a36Sopenharmony_ci		if (ret) {
14762306a36Sopenharmony_ci			rtw89_warn(rtwdev, "failed to read dav efuse\n");
14862306a36Sopenharmony_ci			return ret;
14962306a36Sopenharmony_ci		}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci		ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_READ_VAL, &val8);
15262306a36Sopenharmony_ci		if (ret)
15362306a36Sopenharmony_ci			return ret;
15462306a36Sopenharmony_ci		*map++ = val8;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	return 0;
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map,
16162306a36Sopenharmony_ci					 u32 dump_addr, u32 dump_size, bool dav)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	int ret;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	if (!map || dump_size == 0)
16662306a36Sopenharmony_ci		return 0;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	rtw89_switch_efuse_bank(rtwdev, RTW89_EFUSE_BANK_WIFI);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	if (dav) {
17162306a36Sopenharmony_ci		ret = rtw89_dump_physical_efuse_map_dav(rtwdev, map, dump_addr, dump_size);
17262306a36Sopenharmony_ci		if (ret)
17362306a36Sopenharmony_ci			return ret;
17462306a36Sopenharmony_ci	} else {
17562306a36Sopenharmony_ci		ret = rtw89_dump_physical_efuse_map_ddv(rtwdev, map, dump_addr, dump_size);
17662306a36Sopenharmony_ci		if (ret)
17762306a36Sopenharmony_ci			return ret;
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	return 0;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci#define invalid_efuse_header(hdr1, hdr2) \
18462306a36Sopenharmony_ci	((hdr1) == 0xff || (hdr2) == 0xff)
18562306a36Sopenharmony_ci#define invalid_efuse_content(word_en, i) \
18662306a36Sopenharmony_ci	(((word_en) & BIT(i)) != 0x0)
18762306a36Sopenharmony_ci#define get_efuse_blk_idx(hdr1, hdr2) \
18862306a36Sopenharmony_ci	((((hdr2) & 0xf0) >> 4) | (((hdr1) & 0x0f) << 4))
18962306a36Sopenharmony_ci#define block_idx_to_logical_idx(blk_idx, i) \
19062306a36Sopenharmony_ci	(((blk_idx) << 3) + ((i) << 1))
19162306a36Sopenharmony_cistatic int rtw89_dump_logical_efuse_map(struct rtw89_dev *rtwdev, u8 *phy_map,
19262306a36Sopenharmony_ci					u8 *log_map)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	u32 physical_size = rtwdev->chip->physical_efuse_size;
19562306a36Sopenharmony_ci	u32 logical_size = rtwdev->chip->logical_efuse_size;
19662306a36Sopenharmony_ci	u8 sec_ctrl_size = rtwdev->chip->sec_ctrl_efuse_size;
19762306a36Sopenharmony_ci	u32 phy_idx = sec_ctrl_size;
19862306a36Sopenharmony_ci	u32 log_idx;
19962306a36Sopenharmony_ci	u8 hdr1, hdr2;
20062306a36Sopenharmony_ci	u8 blk_idx;
20162306a36Sopenharmony_ci	u8 word_en;
20262306a36Sopenharmony_ci	int i;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (!phy_map)
20562306a36Sopenharmony_ci		return 0;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	while (phy_idx < physical_size - sec_ctrl_size) {
20862306a36Sopenharmony_ci		hdr1 = phy_map[phy_idx];
20962306a36Sopenharmony_ci		hdr2 = phy_map[phy_idx + 1];
21062306a36Sopenharmony_ci		if (invalid_efuse_header(hdr1, hdr2))
21162306a36Sopenharmony_ci			break;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci		blk_idx = get_efuse_blk_idx(hdr1, hdr2);
21462306a36Sopenharmony_ci		word_en = hdr2 & 0xf;
21562306a36Sopenharmony_ci		phy_idx += 2;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		for (i = 0; i < 4; i++) {
21862306a36Sopenharmony_ci			if (invalid_efuse_content(word_en, i))
21962306a36Sopenharmony_ci				continue;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci			log_idx = block_idx_to_logical_idx(blk_idx, i);
22262306a36Sopenharmony_ci			if (phy_idx + 1 > physical_size - sec_ctrl_size - 1 ||
22362306a36Sopenharmony_ci			    log_idx + 1 > logical_size)
22462306a36Sopenharmony_ci				return -EINVAL;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci			log_map[log_idx] = phy_map[phy_idx];
22762306a36Sopenharmony_ci			log_map[log_idx + 1] = phy_map[phy_idx + 1];
22862306a36Sopenharmony_ci			phy_idx += 2;
22962306a36Sopenharmony_ci		}
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci	return 0;
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ciint rtw89_parse_efuse_map(struct rtw89_dev *rtwdev)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	u32 phy_size = rtwdev->chip->physical_efuse_size;
23762306a36Sopenharmony_ci	u32 log_size = rtwdev->chip->logical_efuse_size;
23862306a36Sopenharmony_ci	u32 dav_phy_size = rtwdev->chip->dav_phy_efuse_size;
23962306a36Sopenharmony_ci	u32 dav_log_size = rtwdev->chip->dav_log_efuse_size;
24062306a36Sopenharmony_ci	u32 full_log_size = log_size + dav_log_size;
24162306a36Sopenharmony_ci	u8 *phy_map = NULL;
24262306a36Sopenharmony_ci	u8 *log_map = NULL;
24362306a36Sopenharmony_ci	u8 *dav_phy_map = NULL;
24462306a36Sopenharmony_ci	u8 *dav_log_map = NULL;
24562306a36Sopenharmony_ci	int ret;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (rtw89_read16(rtwdev, R_AX_SYS_WL_EFUSE_CTRL) & B_AX_AUTOLOAD_SUS)
24862306a36Sopenharmony_ci		rtwdev->efuse.valid = true;
24962306a36Sopenharmony_ci	else
25062306a36Sopenharmony_ci		rtw89_warn(rtwdev, "failed to check efuse autoload\n");
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	phy_map = kmalloc(phy_size, GFP_KERNEL);
25362306a36Sopenharmony_ci	log_map = kmalloc(full_log_size, GFP_KERNEL);
25462306a36Sopenharmony_ci	if (dav_phy_size && dav_log_size) {
25562306a36Sopenharmony_ci		dav_phy_map = kmalloc(dav_phy_size, GFP_KERNEL);
25662306a36Sopenharmony_ci		dav_log_map = log_map + log_size;
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	if (!phy_map || !log_map || (dav_phy_size && !dav_phy_map)) {
26062306a36Sopenharmony_ci		ret = -ENOMEM;
26162306a36Sopenharmony_ci		goto out_free;
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	ret = rtw89_dump_physical_efuse_map(rtwdev, phy_map, 0, phy_size, false);
26562306a36Sopenharmony_ci	if (ret) {
26662306a36Sopenharmony_ci		rtw89_warn(rtwdev, "failed to dump efuse physical map\n");
26762306a36Sopenharmony_ci		goto out_free;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci	ret = rtw89_dump_physical_efuse_map(rtwdev, dav_phy_map, 0, dav_phy_size, true);
27062306a36Sopenharmony_ci	if (ret) {
27162306a36Sopenharmony_ci		rtw89_warn(rtwdev, "failed to dump efuse dav physical map\n");
27262306a36Sopenharmony_ci		goto out_free;
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	memset(log_map, 0xff, full_log_size);
27662306a36Sopenharmony_ci	ret = rtw89_dump_logical_efuse_map(rtwdev, phy_map, log_map);
27762306a36Sopenharmony_ci	if (ret) {
27862306a36Sopenharmony_ci		rtw89_warn(rtwdev, "failed to dump efuse logical map\n");
27962306a36Sopenharmony_ci		goto out_free;
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci	ret = rtw89_dump_logical_efuse_map(rtwdev, dav_phy_map, dav_log_map);
28262306a36Sopenharmony_ci	if (ret) {
28362306a36Sopenharmony_ci		rtw89_warn(rtwdev, "failed to dump efuse dav logical map\n");
28462306a36Sopenharmony_ci		goto out_free;
28562306a36Sopenharmony_ci	}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "log_map: ", log_map, full_log_size);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map);
29062306a36Sopenharmony_ci	if (ret) {
29162306a36Sopenharmony_ci		rtw89_warn(rtwdev, "failed to read efuse map\n");
29262306a36Sopenharmony_ci		goto out_free;
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ciout_free:
29662306a36Sopenharmony_ci	kfree(dav_phy_map);
29762306a36Sopenharmony_ci	kfree(log_map);
29862306a36Sopenharmony_ci	kfree(phy_map);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	return ret;
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ciint rtw89_parse_phycap_map(struct rtw89_dev *rtwdev)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	u32 phycap_addr = rtwdev->chip->phycap_addr;
30662306a36Sopenharmony_ci	u32 phycap_size = rtwdev->chip->phycap_size;
30762306a36Sopenharmony_ci	u8 *phycap_map = NULL;
30862306a36Sopenharmony_ci	int ret = 0;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	if (!phycap_size)
31162306a36Sopenharmony_ci		return 0;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	phycap_map = kmalloc(phycap_size, GFP_KERNEL);
31462306a36Sopenharmony_ci	if (!phycap_map)
31562306a36Sopenharmony_ci		return -ENOMEM;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	ret = rtw89_dump_physical_efuse_map(rtwdev, phycap_map,
31862306a36Sopenharmony_ci					    phycap_addr, phycap_size, false);
31962306a36Sopenharmony_ci	if (ret) {
32062306a36Sopenharmony_ci		rtw89_warn(rtwdev, "failed to dump phycap map\n");
32162306a36Sopenharmony_ci		goto out_free;
32262306a36Sopenharmony_ci	}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	ret = rtwdev->chip->ops->read_phycap(rtwdev, phycap_map);
32562306a36Sopenharmony_ci	if (ret) {
32662306a36Sopenharmony_ci		rtw89_warn(rtwdev, "failed to read phycap map\n");
32762306a36Sopenharmony_ci		goto out_free;
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ciout_free:
33162306a36Sopenharmony_ci	kfree(phycap_map);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	return ret;
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ciint rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *ecv)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	int ret;
33962306a36Sopenharmony_ci	u8 val;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	ret = rtw89_dump_physical_efuse_map(rtwdev, &val, EF_FV_OFSET, 1, false);
34262306a36Sopenharmony_ci	if (ret)
34362306a36Sopenharmony_ci		return ret;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	*ecv = u8_get_bits(val, EF_CV_MASK);
34662306a36Sopenharmony_ci	if (*ecv == EF_CV_INV)
34762306a36Sopenharmony_ci		return -ENOENT;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	return 0;
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_read_efuse_ver);
352