xref: /freebsd/sys/contrib/dev/rtw89/efuse_be.c (revision df279a26d3315e7abc9e6f0744137959a4c2fb86)
16d67aabdSBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
26d67aabdSBjoern A. Zeeb /* Copyright(c) 2023  Realtek Corporation
36d67aabdSBjoern A. Zeeb  */
46d67aabdSBjoern A. Zeeb 
56d67aabdSBjoern A. Zeeb #include "debug.h"
66d67aabdSBjoern A. Zeeb #include "efuse.h"
76d67aabdSBjoern A. Zeeb #include "mac.h"
86d67aabdSBjoern A. Zeeb #include "reg.h"
96d67aabdSBjoern A. Zeeb 
106d67aabdSBjoern A. Zeeb #define EFUSE_EXTERNALPN_ADDR_BE 0x1580
116d67aabdSBjoern A. Zeeb #define EFUSE_SERIALNUM_ADDR_BE 0x1581
126d67aabdSBjoern A. Zeeb #define EFUSE_SB_CRYP_SEL_ADDR 0x1582
136d67aabdSBjoern A. Zeeb #define EFUSE_SB_CRYP_SEL_SIZE 2
146d67aabdSBjoern A. Zeeb #define EFUSE_SB_CRYP_SEL_DEFAULT 0xFFFF
156d67aabdSBjoern A. Zeeb #define SB_SEL_MGN_MAX_SIZE 2
166d67aabdSBjoern A. Zeeb #define EFUSE_SEC_BE_START 0x1580
176d67aabdSBjoern A. Zeeb #define EFUSE_SEC_BE_SIZE 4
186d67aabdSBjoern A. Zeeb 
196d67aabdSBjoern A. Zeeb static const u32 sb_sel_mgn[SB_SEL_MGN_MAX_SIZE] = {
206d67aabdSBjoern A. Zeeb 	0x8000100, 0xC000180
216d67aabdSBjoern A. Zeeb };
226d67aabdSBjoern A. Zeeb 
236d67aabdSBjoern A. Zeeb static void rtw89_enable_efuse_pwr_cut_ddv_be(struct rtw89_dev *rtwdev)
246d67aabdSBjoern A. Zeeb {
256d67aabdSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
266d67aabdSBjoern A. Zeeb 	struct rtw89_hal *hal = &rtwdev->hal;
276d67aabdSBjoern A. Zeeb 	bool aphy_patch = true;
286d67aabdSBjoern A. Zeeb 
296d67aabdSBjoern A. Zeeb 	if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV)
306d67aabdSBjoern A. Zeeb 		aphy_patch = false;
316d67aabdSBjoern A. Zeeb 
326d67aabdSBjoern A. Zeeb 	rtw89_write8_set(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK);
336d67aabdSBjoern A. Zeeb 
346d67aabdSBjoern A. Zeeb 	if (aphy_patch) {
356d67aabdSBjoern A. Zeeb 		rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_S);
366d67aabdSBjoern A. Zeeb 		mdelay(1);
376d67aabdSBjoern A. Zeeb 		rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_B);
386d67aabdSBjoern A. Zeeb 		rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE);
396d67aabdSBjoern A. Zeeb 	}
406d67aabdSBjoern A. Zeeb 
416d67aabdSBjoern A. Zeeb 	rtw89_write32_set(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_EF_BURST);
426d67aabdSBjoern A. Zeeb }
436d67aabdSBjoern A. Zeeb 
446d67aabdSBjoern A. Zeeb static void rtw89_disable_efuse_pwr_cut_ddv_be(struct rtw89_dev *rtwdev)
456d67aabdSBjoern A. Zeeb {
466d67aabdSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
476d67aabdSBjoern A. Zeeb 	struct rtw89_hal *hal = &rtwdev->hal;
486d67aabdSBjoern A. Zeeb 	bool aphy_patch = true;
496d67aabdSBjoern A. Zeeb 
506d67aabdSBjoern A. Zeeb 	if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV)
516d67aabdSBjoern A. Zeeb 		aphy_patch = false;
526d67aabdSBjoern A. Zeeb 
536d67aabdSBjoern A. Zeeb 	if (aphy_patch) {
546d67aabdSBjoern A. Zeeb 		rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE);
556d67aabdSBjoern A. Zeeb 		rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_B);
566d67aabdSBjoern A. Zeeb 		mdelay(1);
576d67aabdSBjoern A. Zeeb 		rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_S);
586d67aabdSBjoern A. Zeeb 	}
596d67aabdSBjoern A. Zeeb 
606d67aabdSBjoern A. Zeeb 	rtw89_write8_clr(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK);
616d67aabdSBjoern A. Zeeb 	rtw89_write32_clr(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_EF_BURST);
626d67aabdSBjoern A. Zeeb }
636d67aabdSBjoern A. Zeeb 
646d67aabdSBjoern A. Zeeb static int rtw89_dump_physical_efuse_map_ddv_be(struct rtw89_dev *rtwdev, u8 *map,
656d67aabdSBjoern A. Zeeb 						u32 dump_addr, u32 dump_size)
666d67aabdSBjoern A. Zeeb {
676d67aabdSBjoern A. Zeeb 	u32 efuse_ctl;
686d67aabdSBjoern A. Zeeb 	u32 addr;
696d67aabdSBjoern A. Zeeb 	u32 data;
706d67aabdSBjoern A. Zeeb 	int ret;
716d67aabdSBjoern A. Zeeb 
726d67aabdSBjoern A. Zeeb 	if (!IS_ALIGNED(dump_addr, 4) || !IS_ALIGNED(dump_size, 4)) {
736d67aabdSBjoern A. Zeeb 		rtw89_err(rtwdev, "Efuse addr 0x%x or size 0x%x not aligned\n",
746d67aabdSBjoern A. Zeeb 			  dump_addr, dump_size);
756d67aabdSBjoern A. Zeeb 		return -EINVAL;
766d67aabdSBjoern A. Zeeb 	}
776d67aabdSBjoern A. Zeeb 
786d67aabdSBjoern A. Zeeb 	rtw89_enable_efuse_pwr_cut_ddv_be(rtwdev);
796d67aabdSBjoern A. Zeeb 
806d67aabdSBjoern A. Zeeb 	for (addr = dump_addr; addr < dump_addr + dump_size; addr += 4, map += 4) {
816d67aabdSBjoern A. Zeeb 		efuse_ctl = u32_encode_bits(addr, B_BE_EF_ADDR_MASK);
826d67aabdSBjoern A. Zeeb 		rtw89_write32(rtwdev, R_BE_EFUSE_CTRL, efuse_ctl & ~B_BE_EF_RDY);
836d67aabdSBjoern A. Zeeb 
846d67aabdSBjoern A. Zeeb 		ret = read_poll_timeout_atomic(rtw89_read32, efuse_ctl,
856d67aabdSBjoern A. Zeeb 					       efuse_ctl & B_BE_EF_RDY, 1, 1000000,
866d67aabdSBjoern A. Zeeb 					       true, rtwdev, R_BE_EFUSE_CTRL);
876d67aabdSBjoern A. Zeeb 		if (ret)
886d67aabdSBjoern A. Zeeb 			return -EBUSY;
896d67aabdSBjoern A. Zeeb 
906d67aabdSBjoern A. Zeeb 		data = rtw89_read32(rtwdev, R_BE_EFUSE_CTRL_1_V1);
916d67aabdSBjoern A. Zeeb 		*((__le32 *)map) = cpu_to_le32(data);
926d67aabdSBjoern A. Zeeb 	}
936d67aabdSBjoern A. Zeeb 
946d67aabdSBjoern A. Zeeb 	rtw89_disable_efuse_pwr_cut_ddv_be(rtwdev);
956d67aabdSBjoern A. Zeeb 
966d67aabdSBjoern A. Zeeb 	return 0;
976d67aabdSBjoern A. Zeeb }
986d67aabdSBjoern A. Zeeb 
996d67aabdSBjoern A. Zeeb static int rtw89_dump_physical_efuse_map_dav_be(struct rtw89_dev *rtwdev, u8 *map,
1006d67aabdSBjoern A. Zeeb 						u32 dump_addr, u32 dump_size)
1016d67aabdSBjoern A. Zeeb {
1026d67aabdSBjoern A. Zeeb 	u32 addr;
1036d67aabdSBjoern A. Zeeb 	u8 val8;
1046d67aabdSBjoern A. Zeeb 	int err;
1056d67aabdSBjoern A. Zeeb 	int ret;
1066d67aabdSBjoern A. Zeeb 
1076d67aabdSBjoern A. Zeeb 	for (addr = dump_addr; addr < dump_addr + dump_size; addr++) {
1086d67aabdSBjoern A. Zeeb 		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0x40,
1096d67aabdSBjoern A. Zeeb 					      FULL_BIT_MASK);
1106d67aabdSBjoern A. Zeeb 		if (ret)
1116d67aabdSBjoern A. Zeeb 			return ret;
1126d67aabdSBjoern A. Zeeb 		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_LOW_ADDR, addr & 0xff,
1136d67aabdSBjoern A. Zeeb 					      XTAL_SI_LOW_ADDR_MASK);
1146d67aabdSBjoern A. Zeeb 		if (ret)
1156d67aabdSBjoern A. Zeeb 			return ret;
1166d67aabdSBjoern A. Zeeb 		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, addr >> 8,
1176d67aabdSBjoern A. Zeeb 					      XTAL_SI_HIGH_ADDR_MASK);
1186d67aabdSBjoern A. Zeeb 		if (ret)
1196d67aabdSBjoern A. Zeeb 			return ret;
1206d67aabdSBjoern A. Zeeb 		ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0,
1216d67aabdSBjoern A. Zeeb 					      XTAL_SI_MODE_SEL_MASK);
1226d67aabdSBjoern A. Zeeb 		if (ret)
1236d67aabdSBjoern A. Zeeb 			return ret;
1246d67aabdSBjoern A. Zeeb 
1256d67aabdSBjoern A. Zeeb 		ret = read_poll_timeout_atomic(rtw89_mac_read_xtal_si, err,
1266d67aabdSBjoern A. Zeeb 					       !err && (val8 & XTAL_SI_RDY),
1276d67aabdSBjoern A. Zeeb 					       1, 10000, false,
1286d67aabdSBjoern A. Zeeb 					       rtwdev, XTAL_SI_CTRL, &val8);
1296d67aabdSBjoern A. Zeeb 		if (ret) {
1306d67aabdSBjoern A. Zeeb 			rtw89_warn(rtwdev, "failed to read dav efuse\n");
1316d67aabdSBjoern A. Zeeb 			return ret;
1326d67aabdSBjoern A. Zeeb 		}
1336d67aabdSBjoern A. Zeeb 
1346d67aabdSBjoern A. Zeeb 		ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_READ_VAL, &val8);
1356d67aabdSBjoern A. Zeeb 		if (ret)
1366d67aabdSBjoern A. Zeeb 			return ret;
1376d67aabdSBjoern A. Zeeb 		*map++ = val8;
1386d67aabdSBjoern A. Zeeb 	}
1396d67aabdSBjoern A. Zeeb 
1406d67aabdSBjoern A. Zeeb 	return 0;
1416d67aabdSBjoern A. Zeeb }
1426d67aabdSBjoern A. Zeeb 
1436d67aabdSBjoern A. Zeeb int rtw89_cnv_efuse_state_be(struct rtw89_dev *rtwdev, bool idle)
1446d67aabdSBjoern A. Zeeb {
1456d67aabdSBjoern A. Zeeb 	u32 val;
1466d67aabdSBjoern A. Zeeb 	int ret = 0;
1476d67aabdSBjoern A. Zeeb 
1486d67aabdSBjoern A. Zeeb 	if (idle) {
1496d67aabdSBjoern A. Zeeb 		rtw89_write32_set(rtwdev, R_BE_WL_BT_PWR_CTRL, B_BE_BT_DISN_EN);
1506d67aabdSBjoern A. Zeeb 	} else {
1516d67aabdSBjoern A. Zeeb 		rtw89_write32_clr(rtwdev, R_BE_WL_BT_PWR_CTRL, B_BE_BT_DISN_EN);
1526d67aabdSBjoern A. Zeeb 
1536d67aabdSBjoern A. Zeeb 		ret = read_poll_timeout(rtw89_read32_mask, val,
1546d67aabdSBjoern A. Zeeb 					val == MAC_AX_SYS_ACT, 50, 5000,
1556d67aabdSBjoern A. Zeeb 					false, rtwdev, R_BE_IC_PWR_STATE,
1566d67aabdSBjoern A. Zeeb 					B_BE_WHOLE_SYS_PWR_STE_MASK);
1576d67aabdSBjoern A. Zeeb 		if (ret)
1586d67aabdSBjoern A. Zeeb 			rtw89_warn(rtwdev, "failed to convert efuse state\n");
1596d67aabdSBjoern A. Zeeb 	}
1606d67aabdSBjoern A. Zeeb 
1616d67aabdSBjoern A. Zeeb 	return ret;
1626d67aabdSBjoern A. Zeeb }
1636d67aabdSBjoern A. Zeeb 
1646d67aabdSBjoern A. Zeeb static int rtw89_dump_physical_efuse_map_be(struct rtw89_dev *rtwdev, u8 *map,
1656d67aabdSBjoern A. Zeeb 					    u32 dump_addr, u32 dump_size, bool dav)
1666d67aabdSBjoern A. Zeeb {
1676d67aabdSBjoern A. Zeeb 	int ret;
1686d67aabdSBjoern A. Zeeb 
1696d67aabdSBjoern A. Zeeb 	if (!map || dump_size == 0)
1706d67aabdSBjoern A. Zeeb 		return 0;
1716d67aabdSBjoern A. Zeeb 
1726d67aabdSBjoern A. Zeeb 	rtw89_cnv_efuse_state_be(rtwdev, false);
1736d67aabdSBjoern A. Zeeb 
1746d67aabdSBjoern A. Zeeb 	if (dav) {
1756d67aabdSBjoern A. Zeeb 		ret = rtw89_dump_physical_efuse_map_dav_be(rtwdev, map,
1766d67aabdSBjoern A. Zeeb 							   dump_addr, dump_size);
1776d67aabdSBjoern A. Zeeb 		if (ret)
1786d67aabdSBjoern A. Zeeb 			return ret;
1796d67aabdSBjoern A. Zeeb 
1806d67aabdSBjoern A. Zeeb 		rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "phy_map dav: ", map, dump_size);
1816d67aabdSBjoern A. Zeeb 	} else {
1826d67aabdSBjoern A. Zeeb 		ret = rtw89_dump_physical_efuse_map_ddv_be(rtwdev, map,
1836d67aabdSBjoern A. Zeeb 							   dump_addr, dump_size);
1846d67aabdSBjoern A. Zeeb 		if (ret)
1856d67aabdSBjoern A. Zeeb 			return ret;
1866d67aabdSBjoern A. Zeeb 
1876d67aabdSBjoern A. Zeeb 		rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "phy_map ddv: ", map, dump_size);
1886d67aabdSBjoern A. Zeeb 	}
1896d67aabdSBjoern A. Zeeb 
1906d67aabdSBjoern A. Zeeb 	rtw89_cnv_efuse_state_be(rtwdev, true);
1916d67aabdSBjoern A. Zeeb 
1926d67aabdSBjoern A. Zeeb 	return 0;
1936d67aabdSBjoern A. Zeeb }
1946d67aabdSBjoern A. Zeeb 
1956d67aabdSBjoern A. Zeeb #define EFUSE_HDR_CONST_MASK GENMASK(23, 20)
1966d67aabdSBjoern A. Zeeb #define EFUSE_HDR_PAGE_MASK GENMASK(19, 17)
1976d67aabdSBjoern A. Zeeb #define EFUSE_HDR_OFFSET_MASK GENMASK(16, 4)
1986d67aabdSBjoern A. Zeeb #define EFUSE_HDR_OFFSET_DAV_MASK GENMASK(11, 4)
1996d67aabdSBjoern A. Zeeb #define EFUSE_HDR_WORD_EN_MASK GENMASK(3, 0)
2006d67aabdSBjoern A. Zeeb 
2016d67aabdSBjoern A. Zeeb #define invalid_efuse_header_be(hdr1, hdr2, hdr3) \
2026d67aabdSBjoern A. Zeeb 	((hdr1) == 0xff || (hdr2) == 0xff || (hdr3) == 0xff)
2036d67aabdSBjoern A. Zeeb #define invalid_efuse_content_be(word_en, i) \
2046d67aabdSBjoern A. Zeeb 	(((word_en) & BIT(i)) != 0x0)
2056d67aabdSBjoern A. Zeeb #define get_efuse_blk_idx_be(hdr1, hdr2, hdr3) \
2066d67aabdSBjoern A. Zeeb 	(((hdr1) << 16) | ((hdr2) << 8) | (hdr3))
2076d67aabdSBjoern A. Zeeb #define block_idx_to_logical_idx_be(blk_idx, i) \
2086d67aabdSBjoern A. Zeeb 	(((blk_idx) << 3) + ((i) << 1))
2096d67aabdSBjoern A. Zeeb 
2106d67aabdSBjoern A. Zeeb #define invalid_efuse_header_dav_be(hdr1, hdr2) \
2116d67aabdSBjoern A. Zeeb 	((hdr1) == 0xff || (hdr2) == 0xff)
2126d67aabdSBjoern A. Zeeb #define get_efuse_blk_idx_dav_be(hdr1, hdr2) \
2136d67aabdSBjoern A. Zeeb 	(((hdr1) << 8) | (hdr2))
2146d67aabdSBjoern A. Zeeb 
2156d67aabdSBjoern A. Zeeb static int rtw89_eeprom_parser_be(struct rtw89_dev *rtwdev,
2166d67aabdSBjoern A. Zeeb 				  const u8 *phy_map, u32 phy_size, u8 *log_map,
2176d67aabdSBjoern A. Zeeb 				  const struct rtw89_efuse_block_cfg *efuse_block)
2186d67aabdSBjoern A. Zeeb {
2196d67aabdSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
2206d67aabdSBjoern A. Zeeb 	enum rtw89_efuse_block blk_page, page;
2216d67aabdSBjoern A. Zeeb 	u32 size = efuse_block->size;
2226d67aabdSBjoern A. Zeeb 	u32 phy_idx, log_idx;
2236d67aabdSBjoern A. Zeeb 	u32 hdr, page_offset;
2246d67aabdSBjoern A. Zeeb 	u8 hdr1, hdr2, hdr3;
2256d67aabdSBjoern A. Zeeb 	u8 i, val0, val1;
2266d67aabdSBjoern A. Zeeb 	u32 min, max;
2276d67aabdSBjoern A. Zeeb 	u16 blk_idx;
2286d67aabdSBjoern A. Zeeb 	u8 word_en;
2296d67aabdSBjoern A. Zeeb 
2306d67aabdSBjoern A. Zeeb 	page = u32_get_bits(efuse_block->offset, RTW89_EFUSE_BLOCK_ID_MASK);
2316d67aabdSBjoern A. Zeeb 	page_offset = u32_get_bits(efuse_block->offset, RTW89_EFUSE_BLOCK_SIZE_MASK);
2326d67aabdSBjoern A. Zeeb 
2336d67aabdSBjoern A. Zeeb 	min = ALIGN_DOWN(page_offset, 2);
2346d67aabdSBjoern A. Zeeb 	max = ALIGN(page_offset + size, 2);
2356d67aabdSBjoern A. Zeeb 
2366d67aabdSBjoern A. Zeeb 	memset(log_map, 0xff, size);
2376d67aabdSBjoern A. Zeeb 
2386d67aabdSBjoern A. Zeeb 	phy_idx = chip->sec_ctrl_efuse_size;
2396d67aabdSBjoern A. Zeeb 
2406d67aabdSBjoern A. Zeeb 	do {
2416d67aabdSBjoern A. Zeeb 		if (page == RTW89_EFUSE_BLOCK_ADIE) {
2426d67aabdSBjoern A. Zeeb 			hdr1 = phy_map[phy_idx];
2436d67aabdSBjoern A. Zeeb 			hdr2 = phy_map[phy_idx + 1];
2446d67aabdSBjoern A. Zeeb 			if (invalid_efuse_header_dav_be(hdr1, hdr2))
2456d67aabdSBjoern A. Zeeb 				break;
2466d67aabdSBjoern A. Zeeb 
2476d67aabdSBjoern A. Zeeb 			phy_idx += 2;
2486d67aabdSBjoern A. Zeeb 
2496d67aabdSBjoern A. Zeeb 			hdr = get_efuse_blk_idx_dav_be(hdr1, hdr2);
2506d67aabdSBjoern A. Zeeb 
2516d67aabdSBjoern A. Zeeb 			blk_page = RTW89_EFUSE_BLOCK_ADIE;
2526d67aabdSBjoern A. Zeeb 			blk_idx = u32_get_bits(hdr, EFUSE_HDR_OFFSET_DAV_MASK);
2536d67aabdSBjoern A. Zeeb 			word_en = u32_get_bits(hdr, EFUSE_HDR_WORD_EN_MASK);
2546d67aabdSBjoern A. Zeeb 		} else {
2556d67aabdSBjoern A. Zeeb 			hdr1 = phy_map[phy_idx];
2566d67aabdSBjoern A. Zeeb 			hdr2 = phy_map[phy_idx + 1];
2576d67aabdSBjoern A. Zeeb 			hdr3 = phy_map[phy_idx + 2];
2586d67aabdSBjoern A. Zeeb 			if (invalid_efuse_header_be(hdr1, hdr2, hdr3))
2596d67aabdSBjoern A. Zeeb 				break;
2606d67aabdSBjoern A. Zeeb 
2616d67aabdSBjoern A. Zeeb 			phy_idx += 3;
2626d67aabdSBjoern A. Zeeb 
2636d67aabdSBjoern A. Zeeb 			hdr = get_efuse_blk_idx_be(hdr1, hdr2, hdr3);
2646d67aabdSBjoern A. Zeeb 
2656d67aabdSBjoern A. Zeeb 			blk_page = u32_get_bits(hdr, EFUSE_HDR_PAGE_MASK);
2666d67aabdSBjoern A. Zeeb 			blk_idx = u32_get_bits(hdr, EFUSE_HDR_OFFSET_MASK);
2676d67aabdSBjoern A. Zeeb 			word_en = u32_get_bits(hdr, EFUSE_HDR_WORD_EN_MASK);
2686d67aabdSBjoern A. Zeeb 		}
2696d67aabdSBjoern A. Zeeb 
2706d67aabdSBjoern A. Zeeb 		if (blk_idx >= RTW89_EFUSE_MAX_BLOCK_SIZE >> 3) {
2716d67aabdSBjoern A. Zeeb 			rtw89_err(rtwdev, "[ERR]efuse idx:0x%X\n", phy_idx - 3);
2726d67aabdSBjoern A. Zeeb 			rtw89_err(rtwdev, "[ERR]read hdr:0x%X\n", hdr);
2736d67aabdSBjoern A. Zeeb 			return -EINVAL;
2746d67aabdSBjoern A. Zeeb 		}
2756d67aabdSBjoern A. Zeeb 
2766d67aabdSBjoern A. Zeeb 		for (i = 0; i < 4; i++) {
2776d67aabdSBjoern A. Zeeb 			if (invalid_efuse_content_be(word_en, i))
2786d67aabdSBjoern A. Zeeb 				continue;
2796d67aabdSBjoern A. Zeeb 
2806d67aabdSBjoern A. Zeeb 			if (phy_idx >= phy_size - 1)
2816d67aabdSBjoern A. Zeeb 				return -EINVAL;
2826d67aabdSBjoern A. Zeeb 
2836d67aabdSBjoern A. Zeeb 			log_idx = block_idx_to_logical_idx_be(blk_idx, i);
2846d67aabdSBjoern A. Zeeb 
2856d67aabdSBjoern A. Zeeb 			if (blk_page == page && log_idx >= min && log_idx < max) {
2866d67aabdSBjoern A. Zeeb 				val0 = phy_map[phy_idx];
2876d67aabdSBjoern A. Zeeb 				val1 = phy_map[phy_idx + 1];
2886d67aabdSBjoern A. Zeeb 
2896d67aabdSBjoern A. Zeeb 				if (log_idx == min && page_offset > min) {
2906d67aabdSBjoern A. Zeeb 					log_map[log_idx - page_offset + 1] = val1;
2916d67aabdSBjoern A. Zeeb 				} else if (log_idx + 2 == max &&
2926d67aabdSBjoern A. Zeeb 					   page_offset + size < max) {
2936d67aabdSBjoern A. Zeeb 					log_map[log_idx - page_offset] = val0;
2946d67aabdSBjoern A. Zeeb 				} else {
2956d67aabdSBjoern A. Zeeb 					log_map[log_idx - page_offset] = val0;
2966d67aabdSBjoern A. Zeeb 					log_map[log_idx - page_offset + 1] = val1;
2976d67aabdSBjoern A. Zeeb 				}
2986d67aabdSBjoern A. Zeeb 			}
2996d67aabdSBjoern A. Zeeb 			phy_idx += 2;
3006d67aabdSBjoern A. Zeeb 		}
3016d67aabdSBjoern A. Zeeb 	} while (phy_idx < phy_size);
3026d67aabdSBjoern A. Zeeb 
3036d67aabdSBjoern A. Zeeb 	return 0;
3046d67aabdSBjoern A. Zeeb }
3056d67aabdSBjoern A. Zeeb 
3066d67aabdSBjoern A. Zeeb static int rtw89_parse_logical_efuse_block_be(struct rtw89_dev *rtwdev,
3076d67aabdSBjoern A. Zeeb 					      const u8 *phy_map, u32 phy_size,
3086d67aabdSBjoern A. Zeeb 					      enum rtw89_efuse_block block)
3096d67aabdSBjoern A. Zeeb {
3106d67aabdSBjoern A. Zeeb 	const struct rtw89_chip_info *chip = rtwdev->chip;
3116d67aabdSBjoern A. Zeeb 	const struct rtw89_efuse_block_cfg *efuse_block;
3126d67aabdSBjoern A. Zeeb 	u8 *log_map;
3136d67aabdSBjoern A. Zeeb 	int ret;
3146d67aabdSBjoern A. Zeeb 
3156d67aabdSBjoern A. Zeeb 	efuse_block = &chip->efuse_blocks[block];
3166d67aabdSBjoern A. Zeeb 
3176d67aabdSBjoern A. Zeeb 	log_map = kmalloc(efuse_block->size, GFP_KERNEL);
3186d67aabdSBjoern A. Zeeb 	if (!log_map)
3196d67aabdSBjoern A. Zeeb 		return -ENOMEM;
3206d67aabdSBjoern A. Zeeb 
3216d67aabdSBjoern A. Zeeb 	ret = rtw89_eeprom_parser_be(rtwdev, phy_map, phy_size, log_map, efuse_block);
3226d67aabdSBjoern A. Zeeb 	if (ret) {
3236d67aabdSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to dump efuse logical block %d\n", block);
3246d67aabdSBjoern A. Zeeb 		goto out_free;
3256d67aabdSBjoern A. Zeeb 	}
3266d67aabdSBjoern A. Zeeb 
3276d67aabdSBjoern A. Zeeb 	rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "log_map: ", log_map, efuse_block->size);
3286d67aabdSBjoern A. Zeeb 
3296d67aabdSBjoern A. Zeeb 	ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map, block);
3306d67aabdSBjoern A. Zeeb 	if (ret) {
3316d67aabdSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to read efuse map\n");
3326d67aabdSBjoern A. Zeeb 		goto out_free;
3336d67aabdSBjoern A. Zeeb 	}
3346d67aabdSBjoern A. Zeeb 
3356d67aabdSBjoern A. Zeeb out_free:
3366d67aabdSBjoern A. Zeeb 	kfree(log_map);
3376d67aabdSBjoern A. Zeeb 
3386d67aabdSBjoern A. Zeeb 	return ret;
3396d67aabdSBjoern A. Zeeb }
3406d67aabdSBjoern A. Zeeb 
3416d67aabdSBjoern A. Zeeb int rtw89_parse_efuse_map_be(struct rtw89_dev *rtwdev)
3426d67aabdSBjoern A. Zeeb {
3436d67aabdSBjoern A. Zeeb 	u32 phy_size = rtwdev->chip->physical_efuse_size;
3446d67aabdSBjoern A. Zeeb 	u32 dav_phy_size = rtwdev->chip->dav_phy_efuse_size;
3456d67aabdSBjoern A. Zeeb 	enum rtw89_efuse_block block;
3466d67aabdSBjoern A. Zeeb 	u8 *phy_map = NULL;
3476d67aabdSBjoern A. Zeeb 	u8 *dav_phy_map = NULL;
3486d67aabdSBjoern A. Zeeb 	int ret;
3496d67aabdSBjoern A. Zeeb 
3506d67aabdSBjoern A. Zeeb 	if (rtw89_read16(rtwdev, R_BE_SYS_WL_EFUSE_CTRL) & B_BE_AUTOLOAD_SUS)
3516d67aabdSBjoern A. Zeeb 		rtwdev->efuse.valid = true;
3526d67aabdSBjoern A. Zeeb 	else
3536d67aabdSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to check efuse autoload\n");
3546d67aabdSBjoern A. Zeeb 
3556d67aabdSBjoern A. Zeeb 	phy_map = kmalloc(phy_size, GFP_KERNEL);
3566d67aabdSBjoern A. Zeeb 	if (dav_phy_size)
3576d67aabdSBjoern A. Zeeb 		dav_phy_map = kmalloc(dav_phy_size, GFP_KERNEL);
3586d67aabdSBjoern A. Zeeb 
3596d67aabdSBjoern A. Zeeb 	if (!phy_map || (dav_phy_size && !dav_phy_map)) {
3606d67aabdSBjoern A. Zeeb 		ret = -ENOMEM;
3616d67aabdSBjoern A. Zeeb 		goto out_free;
3626d67aabdSBjoern A. Zeeb 	}
3636d67aabdSBjoern A. Zeeb 
3646d67aabdSBjoern A. Zeeb 	ret = rtw89_dump_physical_efuse_map_be(rtwdev, phy_map, 0, phy_size, false);
3656d67aabdSBjoern A. Zeeb 	if (ret) {
3666d67aabdSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to dump efuse physical map\n");
3676d67aabdSBjoern A. Zeeb 		goto out_free;
3686d67aabdSBjoern A. Zeeb 	}
3696d67aabdSBjoern A. Zeeb 	ret = rtw89_dump_physical_efuse_map_be(rtwdev, dav_phy_map, 0, dav_phy_size, true);
3706d67aabdSBjoern A. Zeeb 	if (ret) {
3716d67aabdSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to dump efuse dav physical map\n");
3726d67aabdSBjoern A. Zeeb 		goto out_free;
3736d67aabdSBjoern A. Zeeb 	}
3746d67aabdSBjoern A. Zeeb 
3756d67aabdSBjoern A. Zeeb 	if (rtwdev->hci.type == RTW89_HCI_TYPE_USB)
3766d67aabdSBjoern A. Zeeb 		block = RTW89_EFUSE_BLOCK_HCI_DIG_USB;
3776d67aabdSBjoern A. Zeeb 	else
3786d67aabdSBjoern A. Zeeb 		block = RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO;
3796d67aabdSBjoern A. Zeeb 
3806d67aabdSBjoern A. Zeeb 	ret = rtw89_parse_logical_efuse_block_be(rtwdev, phy_map, phy_size, block);
3816d67aabdSBjoern A. Zeeb 	if (ret) {
3826d67aabdSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to parse efuse logic block %d\n",
3836d67aabdSBjoern A. Zeeb 			   RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO);
3846d67aabdSBjoern A. Zeeb 		goto out_free;
3856d67aabdSBjoern A. Zeeb 	}
3866d67aabdSBjoern A. Zeeb 
3876d67aabdSBjoern A. Zeeb 	ret = rtw89_parse_logical_efuse_block_be(rtwdev, phy_map, phy_size,
3886d67aabdSBjoern A. Zeeb 						 RTW89_EFUSE_BLOCK_RF);
3896d67aabdSBjoern A. Zeeb 	if (ret) {
3906d67aabdSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to parse efuse logic block %d\n",
3916d67aabdSBjoern A. Zeeb 			   RTW89_EFUSE_BLOCK_RF);
3926d67aabdSBjoern A. Zeeb 		goto out_free;
3936d67aabdSBjoern A. Zeeb 	}
3946d67aabdSBjoern A. Zeeb 
3956d67aabdSBjoern A. Zeeb out_free:
3966d67aabdSBjoern A. Zeeb 	kfree(dav_phy_map);
3976d67aabdSBjoern A. Zeeb 	kfree(phy_map);
3986d67aabdSBjoern A. Zeeb 
3996d67aabdSBjoern A. Zeeb 	return ret;
4006d67aabdSBjoern A. Zeeb }
4016d67aabdSBjoern A. Zeeb 
4026d67aabdSBjoern A. Zeeb int rtw89_parse_phycap_map_be(struct rtw89_dev *rtwdev)
4036d67aabdSBjoern A. Zeeb {
4046d67aabdSBjoern A. Zeeb 	u32 phycap_addr = rtwdev->chip->phycap_addr;
4056d67aabdSBjoern A. Zeeb 	u32 phycap_size = rtwdev->chip->phycap_size;
4066d67aabdSBjoern A. Zeeb 	u8 *phycap_map = NULL;
4076d67aabdSBjoern A. Zeeb 	int ret = 0;
4086d67aabdSBjoern A. Zeeb 
4096d67aabdSBjoern A. Zeeb 	if (!phycap_size)
4106d67aabdSBjoern A. Zeeb 		return 0;
4116d67aabdSBjoern A. Zeeb 
4126d67aabdSBjoern A. Zeeb 	phycap_map = kmalloc(phycap_size, GFP_KERNEL);
4136d67aabdSBjoern A. Zeeb 	if (!phycap_map)
4146d67aabdSBjoern A. Zeeb 		return -ENOMEM;
4156d67aabdSBjoern A. Zeeb 
4166d67aabdSBjoern A. Zeeb 	ret = rtw89_dump_physical_efuse_map_be(rtwdev, phycap_map,
4176d67aabdSBjoern A. Zeeb 					       phycap_addr, phycap_size, false);
4186d67aabdSBjoern A. Zeeb 	if (ret) {
4196d67aabdSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to dump phycap map\n");
4206d67aabdSBjoern A. Zeeb 		goto out_free;
4216d67aabdSBjoern A. Zeeb 	}
4226d67aabdSBjoern A. Zeeb 
4236d67aabdSBjoern A. Zeeb 	ret = rtwdev->chip->ops->read_phycap(rtwdev, phycap_map);
4246d67aabdSBjoern A. Zeeb 	if (ret) {
4256d67aabdSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to read phycap map\n");
4266d67aabdSBjoern A. Zeeb 		goto out_free;
4276d67aabdSBjoern A. Zeeb 	}
4286d67aabdSBjoern A. Zeeb 
4296d67aabdSBjoern A. Zeeb out_free:
4306d67aabdSBjoern A. Zeeb 	kfree(phycap_map);
4316d67aabdSBjoern A. Zeeb 
4326d67aabdSBjoern A. Zeeb 	return ret;
4336d67aabdSBjoern A. Zeeb }
4346d67aabdSBjoern A. Zeeb 
4356d67aabdSBjoern A. Zeeb static u16 get_sb_cryp_sel_idx(u16 sb_cryp_sel)
4366d67aabdSBjoern A. Zeeb {
4376d67aabdSBjoern A. Zeeb 	u8 low_bit, high_bit, cnt_zero = 0;
4386d67aabdSBjoern A. Zeeb 	u8 idx, sel_form_v, sel_idx_v;
4396d67aabdSBjoern A. Zeeb 	u16 sb_cryp_sel_v = 0x0;
4406d67aabdSBjoern A. Zeeb 
4416d67aabdSBjoern A. Zeeb 	sel_form_v = u16_get_bits(sb_cryp_sel, MASKBYTE0);
4426d67aabdSBjoern A. Zeeb 	sel_idx_v = u16_get_bits(sb_cryp_sel, MASKBYTE1);
4436d67aabdSBjoern A. Zeeb 
4446d67aabdSBjoern A. Zeeb 	for (idx = 0; idx < 4; idx++) {
4456d67aabdSBjoern A. Zeeb 		low_bit = !!(sel_form_v & BIT(idx));
4466d67aabdSBjoern A. Zeeb 		high_bit = !!(sel_form_v & BIT(7 - idx));
4476d67aabdSBjoern A. Zeeb 		if (low_bit != high_bit)
4486d67aabdSBjoern A. Zeeb 			return U16_MAX;
4496d67aabdSBjoern A. Zeeb 		if (low_bit)
4506d67aabdSBjoern A. Zeeb 			continue;
4516d67aabdSBjoern A. Zeeb 
4526d67aabdSBjoern A. Zeeb 		cnt_zero++;
4536d67aabdSBjoern A. Zeeb 		if (cnt_zero == 1)
4546d67aabdSBjoern A. Zeeb 			sb_cryp_sel_v = idx * 16;
4556d67aabdSBjoern A. Zeeb 		else if (cnt_zero > 1)
4566d67aabdSBjoern A. Zeeb 			return U16_MAX;
4576d67aabdSBjoern A. Zeeb 	}
4586d67aabdSBjoern A. Zeeb 
4596d67aabdSBjoern A. Zeeb 	low_bit = u8_get_bits(sel_idx_v, 0x0F);
4606d67aabdSBjoern A. Zeeb 	high_bit = u8_get_bits(sel_idx_v, 0xF0);
4616d67aabdSBjoern A. Zeeb 
4626d67aabdSBjoern A. Zeeb 	if ((low_bit ^ high_bit) != 0xF)
4636d67aabdSBjoern A. Zeeb 		return U16_MAX;
4646d67aabdSBjoern A. Zeeb 
4656d67aabdSBjoern A. Zeeb 	return sb_cryp_sel_v + low_bit;
4666d67aabdSBjoern A. Zeeb }
4676d67aabdSBjoern A. Zeeb 
4686d67aabdSBjoern A. Zeeb int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev)
4696d67aabdSBjoern A. Zeeb {
4706d67aabdSBjoern A. Zeeb 	struct rtw89_fw_secure *sec = &rtwdev->fw.sec;
4716d67aabdSBjoern A. Zeeb 	u32 sec_addr = EFUSE_SEC_BE_START;
4726d67aabdSBjoern A. Zeeb 	u32 sec_size = EFUSE_SEC_BE_SIZE;
4736d67aabdSBjoern A. Zeeb 	u16 sb_cryp_sel, sb_cryp_sel_idx;
4746d67aabdSBjoern A. Zeeb 	u8 sec_map[EFUSE_SEC_BE_SIZE];
4756d67aabdSBjoern A. Zeeb 	u8 b1, b2;
4766d67aabdSBjoern A. Zeeb 	int ret;
4776d67aabdSBjoern A. Zeeb 
4786d67aabdSBjoern A. Zeeb 	ret = rtw89_dump_physical_efuse_map_be(rtwdev, sec_map,
4796d67aabdSBjoern A. Zeeb 					       sec_addr, sec_size, false);
4806d67aabdSBjoern A. Zeeb 	if (ret) {
4816d67aabdSBjoern A. Zeeb 		rtw89_warn(rtwdev, "failed to dump secsel map\n");
4826d67aabdSBjoern A. Zeeb 		return ret;
4836d67aabdSBjoern A. Zeeb 	}
4846d67aabdSBjoern A. Zeeb 
4856d67aabdSBjoern A. Zeeb 	sb_cryp_sel = sec_map[EFUSE_SB_CRYP_SEL_ADDR - sec_addr] |
4866d67aabdSBjoern A. Zeeb 		      sec_map[EFUSE_SB_CRYP_SEL_ADDR - sec_addr + 1] << 8;
4876d67aabdSBjoern A. Zeeb 	if (sb_cryp_sel == EFUSE_SB_CRYP_SEL_DEFAULT)
4886d67aabdSBjoern A. Zeeb 		goto out;
4896d67aabdSBjoern A. Zeeb 
4906d67aabdSBjoern A. Zeeb 	sb_cryp_sel_idx = get_sb_cryp_sel_idx(sb_cryp_sel);
4916d67aabdSBjoern A. Zeeb 	if (sb_cryp_sel_idx >= SB_SEL_MGN_MAX_SIZE) {
4926d67aabdSBjoern A. Zeeb 		rtw89_warn(rtwdev, "invalid SB cryp sel idx %d\n", sb_cryp_sel_idx);
4936d67aabdSBjoern A. Zeeb 		goto out;
4946d67aabdSBjoern A. Zeeb 	}
4956d67aabdSBjoern A. Zeeb 
4966d67aabdSBjoern A. Zeeb 	sec->sb_sel_mgn = sb_sel_mgn[sb_cryp_sel_idx];
4976d67aabdSBjoern A. Zeeb 
4986d67aabdSBjoern A. Zeeb 	b1 = sec_map[EFUSE_EXTERNALPN_ADDR_BE - sec_addr];
4996d67aabdSBjoern A. Zeeb 	b2 = sec_map[EFUSE_SERIALNUM_ADDR_BE - sec_addr];
5006d67aabdSBjoern A. Zeeb 
501*df279a26SBjoern A. Zeeb 	ret = rtw89_efuse_recognize_mss_info_v1(rtwdev, b1, b2);
502*df279a26SBjoern A. Zeeb 	if (ret)
5036d67aabdSBjoern A. Zeeb 		goto out;
5046d67aabdSBjoern A. Zeeb 
5056d67aabdSBjoern A. Zeeb 	sec->secure_boot = true;
5066d67aabdSBjoern A. Zeeb 
5076d67aabdSBjoern A. Zeeb out:
5086d67aabdSBjoern A. Zeeb 	rtw89_debug(rtwdev, RTW89_DBG_FW,
5096d67aabdSBjoern A. Zeeb 		    "MSS secure_boot=%d dev_type=%d cust_idx=%d key_num=%d\n",
5106d67aabdSBjoern A. Zeeb 		    sec->secure_boot, sec->mss_dev_type, sec->mss_cust_idx,
5116d67aabdSBjoern A. Zeeb 		    sec->mss_key_num);
5126d67aabdSBjoern A. Zeeb 
5136d67aabdSBjoern A. Zeeb 	return 0;
5146d67aabdSBjoern A. Zeeb }
515