rtw89: support DAV efuse reading operation
authorPing-Ke Shih <pkshih@realtek.com>
Mon, 7 Mar 2022 06:04:55 +0000 (14:04 +0800)
committerKalle Valo <kvalo@kernel.org>
Thu, 10 Mar 2022 16:43:40 +0000 (18:43 +0200)
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: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20220307060457.56789-12-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/efuse.c
drivers/net/wireless/realtek/rtw89/mac.c
drivers/net/wireless/realtek/rtw89/mac.h
drivers/net/wireless/realtek/rtw89/reg.h
drivers/net/wireless/realtek/rtw89/rtw8852a.c
drivers/net/wireless/realtek/rtw89/rtw8852c.c

index 348fbbca254c2ce3baf5d00e90d9d3ee99c04d64..6013f73ed7cae31fc9464f6e153ddd55b89b18d5 100644 (file)
@@ -2276,6 +2276,8 @@ struct rtw89_chip_info {
        u32 physical_efuse_size;
        u32 logical_efuse_size;
        u32 limit_efuse_size;
+       u32 dav_phy_efuse_size;
+       u32 dav_log_efuse_size;
        u32 phycap_addr;
        u32 phycap_size;
 
index c0b80f3da56c2cd5e760f0aef661911babcc5957..7bd4f8558e03b624b5f4da10c13c441e705e4f6c 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "debug.h"
 #include "efuse.h"
+#include "mac.h"
 #include "reg.h"
 
 enum rtw89_efuse_bank {
@@ -16,6 +17,9 @@ static int rtw89_switch_efuse_bank(struct rtw89_dev *rtwdev,
 {
        u8 val;
 
+       if (rtwdev->chip->chip_id != RTL8852A)
+               return 0;
+
        val = rtw89_read32_mask(rtwdev, R_AX_EFUSE_CTRL_1,
                                B_AX_EF_CELL_SEL_MASK);
        if (bank == val)
@@ -32,14 +36,61 @@ static int rtw89_switch_efuse_bank(struct rtw89_dev *rtwdev,
        return -EBUSY;
 }
 
-static int rtw89_dump_physical_efuse_map(struct rtw89_dev *rtwdev, u8 *map,
-                                        u32 dump_addr, u32 dump_size)
+static void rtw89_enable_otp_burst_mode(struct rtw89_dev *rtwdev, bool en)
+{
+       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 addr;
        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++) {
                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,
                *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;
 }
 
@@ -78,6 +197,9 @@ static int rtw89_dump_logical_efuse_map(struct rtw89_dev *rtwdev, u8 *phy_map,
        u8 word_en;
        int i;
 
+       if (!phy_map)
+               return 0;
+
        while (phy_idx < physical_size - sec_ctrl_size) {
                hdr1 = phy_map[phy_idx];
                hdr2 = phy_map[phy_idx + 1];
@@ -109,8 +231,13 @@ int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev)
 {
        u32 phy_size = rtwdev->chip->physical_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 *log_map = NULL;
+       u8 *dav_phy_map = NULL;
+       u8 *dav_log_map = NULL;
        int ret;
 
        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)
                rtw89_warn(rtwdev, "failed to check efuse autoload\n");
 
        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;
                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) {
                rtw89_warn(rtwdev, "failed to dump efuse physical map\n");
                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);
        if (ret) {
                rtw89_warn(rtwdev, "failed to dump efuse logical map\n");
                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);
        if (ret) {
@@ -148,6 +289,7 @@ int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev)
        }
 
 out_free:
+       kfree(dav_phy_map);
        kfree(log_map);
        kfree(phy_map);
 
@@ -169,7 +311,7 @@ int rtw89_parse_phycap_map(struct rtw89_dev *rtwdev)
                return -ENOMEM;
 
        ret = rtw89_dump_physical_efuse_map(rtwdev, phycap_map,
-                                           phycap_addr, phycap_size);
+                                           phycap_addr, phycap_size, false);
        if (ret) {
                rtw89_warn(rtwdev, "failed to dump phycap map\n");
                goto out_free;
index 0081cfbfea04213513faaacd0bb7dce0309d9311..8fbdfd983cc53dae65667d0616b77ce3a0a6f1a2 100644 (file)
@@ -4074,3 +4074,27 @@ int rtw89_mac_write_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask
        return 0;
 }
 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;
+}
index e74806d333079968c02bbb7c09d3af2a36551c07..2f707c817fa797b299b4f8584c1ba01ad27c2239 100644 (file)
@@ -885,11 +885,21 @@ int rtw89_mac_get_tx_retry_limit(struct rtw89_dev *rtwdev,
 enum rtw89_mac_xtal_si_offset {
        XTAL_SI_XTAL_SC_XI = 0x04,
        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,
 #define XTAL_SI_LDO_LPS                GENMASK(6, 4)
        XTAL_SI_XTAL_XMD_4 = 0x26,
 #define XTAL_SI_LPS_CAP                GENMASK(3, 0)
        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,
 #define XTAL_SI_RF00           BIT(0)
        XTAL_SI_WL_RFC_S1 = 0x81,
@@ -904,8 +914,10 @@ enum rtw89_mac_xtal_si_offset {
 #define XTAL_SI_PON_EI         BIT(1)
 #define XTAL_SI_PON_WEI                BIT(0)
        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_read_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 *val);
 
 #endif
index 222aaddbff6245cf0d1896f3872288f4d7f9b5e2..ec5e70b866009e0083bb92e4280d6d88d4968d4e 100644 (file)
 #define B_AX_EF_ADDR_MASK GENMASK(26, 16)
 #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 B_AX_BOOT_MODE BIT(19)
 #define B_AX_WL_EECS_EXT_32K_SEL BIT(18)
index 4eb03dde3413056b063146940c54f0ae81cb5884..c429eeae1b56712d91a718f4ff384c1eb28effee 100644 (file)
@@ -2063,6 +2063,8 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
        .physical_efuse_size    = 1216,
        .logical_efuse_size     = 1536,
        .limit_efuse_size       = 1152,
+       .dav_phy_efuse_size     = 0,
+       .dav_log_efuse_size     = 0,
        .phycap_addr            = 0x580,
        .phycap_size            = 128,
        .para_ver               = 0x05050864,
index 55dca693cb5abf8a8663e1a8120dc091bcef5461..e17e0ab75d0eb74182d1e8bdea88b71d4147873e 100644 (file)
@@ -232,6 +232,12 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
        .dle_mem                = rtw8852c_dle_mem_pcie,
        .pwr_on_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,
        .h2c_ctrl_reg           = R_AX_H2CREG_CTRL_V1,
        .h2c_regs               = rtw8852c_h2c_regs,