cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

efuse.c (8322B)


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