Commit bdfbf06c authored by Ping-Ke Shih's avatar Ping-Ke Shih Committed by Kalle Valo

rtw89: support DAV efuse reading operation

DAV is an another efuse region that new chip, like 8852C, has this region.
Extend the code to read it, and convert the physical map to logical map
followed by original logical map.
Signed-off-by: default avatarPing-Ke Shih <pkshih@realtek.com>
Signed-off-by: default avatarKalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20220307060457.56789-12-pkshih@realtek.com
parent 79d099e0
...@@ -2276,6 +2276,8 @@ struct rtw89_chip_info { ...@@ -2276,6 +2276,8 @@ struct rtw89_chip_info {
u32 physical_efuse_size; u32 physical_efuse_size;
u32 logical_efuse_size; u32 logical_efuse_size;
u32 limit_efuse_size; u32 limit_efuse_size;
u32 dav_phy_efuse_size;
u32 dav_log_efuse_size;
u32 phycap_addr; u32 phycap_addr;
u32 phycap_size; u32 phycap_size;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "debug.h" #include "debug.h"
#include "efuse.h" #include "efuse.h"
#include "mac.h"
#include "reg.h" #include "reg.h"
enum rtw89_efuse_bank { enum rtw89_efuse_bank {
...@@ -16,6 +17,9 @@ static int rtw89_switch_efuse_bank(struct rtw89_dev *rtwdev, ...@@ -16,6 +17,9 @@ static int rtw89_switch_efuse_bank(struct rtw89_dev *rtwdev,
{ {
u8 val; u8 val;
if (rtwdev->chip->chip_id != RTL8852A)
return 0;
val = rtw89_read32_mask(rtwdev, R_AX_EFUSE_CTRL_1, val = rtw89_read32_mask(rtwdev, R_AX_EFUSE_CTRL_1,
B_AX_EF_CELL_SEL_MASK); B_AX_EF_CELL_SEL_MASK);
if (bank == val) if (bank == val)
...@@ -32,14 +36,61 @@ static int rtw89_switch_efuse_bank(struct rtw89_dev *rtwdev, ...@@ -32,14 +36,61 @@ static int rtw89_switch_efuse_bank(struct rtw89_dev *rtwdev,
return -EBUSY; return -EBUSY;
} }
static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, static void rtw89_enable_otp_burst_mode(struct rtw89_dev *rtwdev, bool en)
u32 dump_addr, u32 dump_size) {
if (en)
rtw89_write32_set(rtwdev, R_AX_EFUSE_CTRL_1_V1, B_AX_EF_BURST);
else
rtw89_write32_clr(rtwdev, R_AX_EFUSE_CTRL_1_V1, B_AX_EF_BURST);
}
static void rtw89_enable_efuse_pwr_cut_ddv(struct rtw89_dev *rtwdev)
{
enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
struct rtw89_hal *hal = &rtwdev->hal;
if (chip_id == RTL8852A)
return;
rtw89_write8_set(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK);
rtw89_write16_set(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B14);
fsleep(1000);
rtw89_write16_set(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B15);
rtw89_write16_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_ISO_EB2CORE);
if (chip_id == RTL8852B && hal->cv == CHIP_CAV)
rtw89_enable_otp_burst_mode(rtwdev, true);
}
static void rtw89_disable_efuse_pwr_cut_ddv(struct rtw89_dev *rtwdev)
{
enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
struct rtw89_hal *hal = &rtwdev->hal;
if (chip_id == RTL8852A)
return;
if (chip_id == RTL8852B && hal->cv == CHIP_CAV)
rtw89_enable_otp_burst_mode(rtwdev, false);
rtw89_write16_set(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_ISO_EB2CORE);
rtw89_write16_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B15);
fsleep(1000);
rtw89_write16_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B14);
rtw89_write8_clr(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK);
}
static int rtw89_dump_physical_efuse_map_ddv(struct rtw89_dev *rtwdev, u8 *map,
u32 dump_addr, u32 dump_size)
{ {
u32 efuse_ctl; u32 efuse_ctl;
u32 addr; u32 addr;
int ret; int ret;
rtw89_switch_efuse_bank(rtwdev, RTW89_EFUSE_BANK_WIFI); rtw89_enable_efuse_pwr_cut_ddv(rtwdev);
for (addr = dump_addr; addr < dump_addr + dump_size; addr++) { for (addr = dump_addr; addr < dump_addr + dump_size; addr++) {
efuse_ctl = u32_encode_bits(addr, B_AX_EF_ADDR_MASK); efuse_ctl = u32_encode_bits(addr, B_AX_EF_ADDR_MASK);
...@@ -54,6 +105,74 @@ static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map, ...@@ -54,6 +105,74 @@ static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map,
*map++ = (u8)(efuse_ctl & 0xff); *map++ = (u8)(efuse_ctl & 0xff);
} }
rtw89_disable_efuse_pwr_cut_ddv(rtwdev);
return 0;
}
static int rtw89_dump_physical_efuse_map_dav(struct rtw89_dev *rtwdev, u8 *map,
u32 dump_addr, u32 dump_size)
{
u32 addr;
u8 val8;
int err;
int ret;
for (addr = dump_addr; addr < dump_addr + dump_size; addr++) {
ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0x40, FULL_BIT_MASK);
if (ret)
return ret;
ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_LOW_ADDR,
addr & 0xff, XTAL_SI_LOW_ADDR_MASK);
if (ret)
return ret;
ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, addr >> 8,
XTAL_SI_HIGH_ADDR_MASK);
if (ret)
return ret;
ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0,
XTAL_SI_MODE_SEL_MASK);
if (ret)
return ret;
ret = read_poll_timeout_atomic(rtw89_mac_read_xtal_si, err,
!err && (val8 & XTAL_SI_RDY),
1, 10000, false,
rtwdev, XTAL_SI_CTRL, &val8);
if (ret) {
rtw89_warn(rtwdev, "failed to read dav efuse\n");
return ret;
}
ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_READ_VAL, &val8);
if (ret)
return ret;
*map++ = val8;
}
return 0;
}
static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map,
u32 dump_addr, u32 dump_size, bool dav)
{
int ret;
if (!map || dump_size == 0)
return 0;
rtw89_switch_efuse_bank(rtwdev, RTW89_EFUSE_BANK_WIFI);
if (dav) {
ret = rtw89_dump_physical_efuse_map_dav(rtwdev, map, dump_addr, dump_size);
if (ret)
return ret;
} else {
ret = rtw89_dump_physical_efuse_map_ddv(rtwdev, map, dump_addr, dump_size);
if (ret)
return ret;
}
return 0; return 0;
} }
...@@ -78,6 +197,9 @@ static int rtw89_dump_logical_efuse_map(struct rtw89_dev *rtwdev, u8 *phy_map, ...@@ -78,6 +197,9 @@ static int rtw89_dump_logical_efuse_map(struct rtw89_dev *rtwdev, u8 *phy_map,
u8 word_en; u8 word_en;
int i; int i;
if (!phy_map)
return 0;
while (phy_idx < physical_size - sec_ctrl_size) { while (phy_idx < physical_size - sec_ctrl_size) {
hdr1 = phy_map[phy_idx]; hdr1 = phy_map[phy_idx];
hdr2 = phy_map[phy_idx + 1]; hdr2 = phy_map[phy_idx + 1];
...@@ -109,8 +231,13 @@ int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev) ...@@ -109,8 +231,13 @@ int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev)
{ {
u32 phy_size = rtwdev->chip->physical_efuse_size; u32 phy_size = rtwdev->chip->physical_efuse_size;
u32 log_size = rtwdev->chip->logical_efuse_size; u32 log_size = rtwdev->chip->logical_efuse_size;
u32 dav_phy_size = rtwdev->chip->dav_phy_efuse_size;
u32 dav_log_size = rtwdev->chip->dav_log_efuse_size;
u32 full_log_size = log_size + dav_log_size;
u8 *phy_map = NULL; u8 *phy_map = NULL;
u8 *log_map = NULL; u8 *log_map = NULL;
u8 *dav_phy_map = NULL;
u8 *dav_log_map = NULL;
int ret; int ret;
if (rtw89_read16(rtwdev, R_AX_SYS_WL_EFUSE_CTRL) & B_AX_AUTOLOAD_SUS) if (rtw89_read16(rtwdev, R_AX_SYS_WL_EFUSE_CTRL) & B_AX_AUTOLOAD_SUS)
...@@ -119,27 +246,41 @@ int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev) ...@@ -119,27 +246,41 @@ int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev)
rtw89_warn(rtwdev, "failed to check efuse autoload\n"); rtw89_warn(rtwdev, "failed to check efuse autoload\n");
phy_map = kmalloc(phy_size, GFP_KERNEL); phy_map = kmalloc(phy_size, GFP_KERNEL);
log_map = kmalloc(log_size, GFP_KERNEL); log_map = kmalloc(full_log_size, GFP_KERNEL);
if (dav_phy_size && dav_log_size) {
dav_phy_map = kmalloc(dav_phy_size, GFP_KERNEL);
dav_log_map = log_map + log_size;
}
if (!phy_map || !log_map) { if (!phy_map || !log_map || (dav_phy_size && !dav_phy_map)) {
ret = -ENOMEM; ret = -ENOMEM;
goto out_free; goto out_free;
} }
ret = rtw89_dump_physical_efuse_map(rtwdev, phy_map, 0, phy_size); ret = rtw89_dump_physical_efuse_map(rtwdev, phy_map, 0, phy_size, false);
if (ret) { if (ret) {
rtw89_warn(rtwdev, "failed to dump efuse physical map\n"); rtw89_warn(rtwdev, "failed to dump efuse physical map\n");
goto out_free; goto out_free;
} }
ret = rtw89_dump_physical_efuse_map(rtwdev, dav_phy_map, 0, dav_phy_size, true);
if (ret) {
rtw89_warn(rtwdev, "failed to dump efuse dav physical map\n");
goto out_free;
}
memset(log_map, 0xff, log_size); memset(log_map, 0xff, full_log_size);
ret = rtw89_dump_logical_efuse_map(rtwdev, phy_map, log_map); ret = rtw89_dump_logical_efuse_map(rtwdev, phy_map, log_map);
if (ret) { if (ret) {
rtw89_warn(rtwdev, "failed to dump efuse logical map\n"); rtw89_warn(rtwdev, "failed to dump efuse logical map\n");
goto out_free; goto out_free;
} }
ret = rtw89_dump_logical_efuse_map(rtwdev, dav_phy_map, dav_log_map);
if (ret) {
rtw89_warn(rtwdev, "failed to dump efuse dav logical map\n");
goto out_free;
}
rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "log_map: ", log_map, log_size); rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "log_map: ", log_map, full_log_size);
ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map); ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map);
if (ret) { if (ret) {
...@@ -148,6 +289,7 @@ int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev) ...@@ -148,6 +289,7 @@ int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev)
} }
out_free: out_free:
kfree(dav_phy_map);
kfree(log_map); kfree(log_map);
kfree(phy_map); kfree(phy_map);
...@@ -169,7 +311,7 @@ int rtw89_parse_phycap_map(struct rtw89_dev *rtwdev) ...@@ -169,7 +311,7 @@ int rtw89_parse_phycap_map(struct rtw89_dev *rtwdev)
return -ENOMEM; return -ENOMEM;
ret = rtw89_dump_physical_efuse_map(rtwdev, phycap_map, ret = rtw89_dump_physical_efuse_map(rtwdev, phycap_map,
phycap_addr, phycap_size); phycap_addr, phycap_size, false);
if (ret) { if (ret) {
rtw89_warn(rtwdev, "failed to dump phycap map\n"); rtw89_warn(rtwdev, "failed to dump phycap map\n");
goto out_free; goto out_free;
......
...@@ -4074,3 +4074,27 @@ int rtw89_mac_write_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask ...@@ -4074,3 +4074,27 @@ int rtw89_mac_write_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask
return 0; return 0;
} }
EXPORT_SYMBOL(rtw89_mac_write_xtal_si); EXPORT_SYMBOL(rtw89_mac_write_xtal_si);
int rtw89_mac_read_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 *val)
{
u32 val32;
int ret;
val32 = FIELD_PREP(B_AX_WL_XTAL_SI_ADDR_MASK, offset) |
FIELD_PREP(B_AX_WL_XTAL_SI_DATA_MASK, 0x00) |
FIELD_PREP(B_AX_WL_XTAL_SI_BITMASK_MASK, 0x00) |
FIELD_PREP(B_AX_WL_XTAL_SI_MODE_MASK, XTAL_SI_NORMAL_READ) |
FIELD_PREP(B_AX_WL_XTAL_SI_CMD_POLL, 1);
rtw89_write32(rtwdev, R_AX_WLAN_XTAL_SI_CTRL, val32);
ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_AX_WL_XTAL_SI_CMD_POLL),
50, 50000, false, rtwdev, R_AX_WLAN_XTAL_SI_CTRL);
if (ret) {
rtw89_warn(rtwdev, "xtal si not ready(R): offset=%x\n", offset);
return ret;
}
*val = rtw89_read8(rtwdev, R_AX_WLAN_XTAL_SI_CTRL + 1);
return 0;
}
...@@ -885,11 +885,21 @@ int rtw89_mac_get_tx_retry_limit(struct rtw89_dev *rtwdev, ...@@ -885,11 +885,21 @@ int rtw89_mac_get_tx_retry_limit(struct rtw89_dev *rtwdev,
enum rtw89_mac_xtal_si_offset { enum rtw89_mac_xtal_si_offset {
XTAL_SI_XTAL_SC_XI = 0x04, XTAL_SI_XTAL_SC_XI = 0x04,
XTAL_SI_XTAL_SC_XO = 0x05, XTAL_SI_XTAL_SC_XO = 0x05,
XTAL_SI_PWR_CUT = 0x10,
#define XTAL_SI_SMALL_PWR_CUT BIT(0)
#define XTAL_SI_BIG_PWR_CUT BIT(1)
XTAL_SI_XTAL_XMD_2 = 0x24, XTAL_SI_XTAL_XMD_2 = 0x24,
#define XTAL_SI_LDO_LPS GENMASK(6, 4) #define XTAL_SI_LDO_LPS GENMASK(6, 4)
XTAL_SI_XTAL_XMD_4 = 0x26, XTAL_SI_XTAL_XMD_4 = 0x26,
#define XTAL_SI_LPS_CAP GENMASK(3, 0) #define XTAL_SI_LPS_CAP GENMASK(3, 0)
XTAL_SI_CV = 0x41, XTAL_SI_CV = 0x41,
XTAL_SI_LOW_ADDR = 0x62,
#define XTAL_SI_LOW_ADDR_MASK GENMASK(7, 0)
XTAL_SI_CTRL = 0x63,
#define XTAL_SI_MODE_SEL_MASK GENMASK(7, 6)
#define XTAL_SI_RDY BIT(5)
#define XTAL_SI_HIGH_ADDR_MASK GENMASK(2, 0)
XTAL_SI_READ_VAL = 0x7A,
XTAL_SI_WL_RFC_S0 = 0x80, XTAL_SI_WL_RFC_S0 = 0x80,
#define XTAL_SI_RF00 BIT(0) #define XTAL_SI_RF00 BIT(0)
XTAL_SI_WL_RFC_S1 = 0x81, XTAL_SI_WL_RFC_S1 = 0x81,
...@@ -904,8 +914,10 @@ enum rtw89_mac_xtal_si_offset { ...@@ -904,8 +914,10 @@ enum rtw89_mac_xtal_si_offset {
#define XTAL_SI_PON_EI BIT(1) #define XTAL_SI_PON_EI BIT(1)
#define XTAL_SI_PON_WEI BIT(0) #define XTAL_SI_PON_WEI BIT(0)
XTAL_SI_SRAM_CTRL = 0xA1, XTAL_SI_SRAM_CTRL = 0xA1,
#define FULL_BIT_MASK GENMASK(7, 0)
}; };
int rtw89_mac_write_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask); int rtw89_mac_write_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask);
int rtw89_mac_read_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 *val);
#endif #endif
...@@ -61,6 +61,17 @@ ...@@ -61,6 +61,17 @@
#define B_AX_EF_ADDR_MASK GENMASK(26, 16) #define B_AX_EF_ADDR_MASK GENMASK(26, 16)
#define B_AX_EF_DATA_MASK GENMASK(15, 0) #define B_AX_EF_DATA_MASK GENMASK(15, 0)
#define R_AX_EFUSE_CTRL_1_V1 0x0038
#define B_AX_EF_ENT BIT(31)
#define B_AX_EF_BURST BIT(19)
#define B_AX_EF_TEST_SEL_MASK GENMASK(18, 16)
#define B_AX_EF_TROW_EN BIT(15)
#define B_AX_EF_ERR_FLAG BIT(14)
#define B_AX_EF_DSB_EN BIT(11)
#define B_AX_PCIE_CALIB_EN_V1 BIT(12)
#define B_AX_WDT_WAKE_PCIE_EN BIT(10)
#define B_AX_WDT_WAKE_USB_EN BIT(9)
#define R_AX_GPIO_MUXCFG 0x0040 #define R_AX_GPIO_MUXCFG 0x0040
#define B_AX_BOOT_MODE BIT(19) #define B_AX_BOOT_MODE BIT(19)
#define B_AX_WL_EECS_EXT_32K_SEL BIT(18) #define B_AX_WL_EECS_EXT_32K_SEL BIT(18)
......
...@@ -2063,6 +2063,8 @@ const struct rtw89_chip_info rtw8852a_chip_info = { ...@@ -2063,6 +2063,8 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
.physical_efuse_size = 1216, .physical_efuse_size = 1216,
.logical_efuse_size = 1536, .logical_efuse_size = 1536,
.limit_efuse_size = 1152, .limit_efuse_size = 1152,
.dav_phy_efuse_size = 0,
.dav_log_efuse_size = 0,
.phycap_addr = 0x580, .phycap_addr = 0x580,
.phycap_size = 128, .phycap_size = 128,
.para_ver = 0x05050864, .para_ver = 0x05050864,
......
...@@ -232,6 +232,12 @@ const struct rtw89_chip_info rtw8852c_chip_info = { ...@@ -232,6 +232,12 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
.dle_mem = rtw8852c_dle_mem_pcie, .dle_mem = rtw8852c_dle_mem_pcie,
.pwr_on_seq = NULL, .pwr_on_seq = NULL,
.pwr_off_seq = NULL, .pwr_off_seq = NULL,
.sec_ctrl_efuse_size = 4,
.physical_efuse_size = 1216,
.logical_efuse_size = 2048,
.limit_efuse_size = 1280,
.dav_phy_efuse_size = 96,
.dav_log_efuse_size = 16,
.hci_func_en_addr = R_AX_HCI_FUNC_EN_V1, .hci_func_en_addr = R_AX_HCI_FUNC_EN_V1,
.h2c_ctrl_reg = R_AX_H2CREG_CTRL_V1, .h2c_ctrl_reg = R_AX_H2CREG_CTRL_V1,
.h2c_regs = rtw8852c_h2c_regs, .h2c_regs = rtw8852c_h2c_regs,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment