#include "debug.h"
 #include "efuse.h"
+#include "mac.h"
 #include "reg.h"
 
 enum rtw89_efuse_bank {
 {
        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)
        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);
                *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;
 }
 
        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];
 {
        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)
                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) {
        }
 
 out_free:
+       kfree(dav_phy_map);
        kfree(log_map);
        kfree(phy_map);
 
                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;
 
 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,
 #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