#include "mac.h"
 #include "reg.h"
 
+#define EFUSE_EXTERNALPN_ADDR_BE 0x1580
+#define EFUSE_B1_MSSDEVTYPE_MASK GENMASK(3, 0)
+#define EFUSE_B1_MSSCUSTIDX0_MASK GENMASK(7, 4)
+#define EFUSE_SERIALNUM_ADDR_BE 0x1581
+#define EFUSE_B2_MSSKEYNUM_MASK GENMASK(3, 0)
+#define EFUSE_B2_MSSCUSTIDX1_MASK BIT(6)
+#define EFUSE_SB_CRYP_SEL_ADDR 0x1582
+#define EFUSE_SB_CRYP_SEL_SIZE 2
+#define EFUSE_SB_CRYP_SEL_DEFAULT 0xFFFF
+#define SB_SEL_MGN_MAX_SIZE 2
+#define EFUSE_SEC_BE_START 0x1580
+#define EFUSE_SEC_BE_SIZE 4
+
+enum rtw89_efuse_mss_dev_type {
+       MSS_DEV_TYPE_FWSEC_DEF = 0xF,
+       MSS_DEV_TYPE_FWSEC_WINLIN_INBOX = 0xC,
+       MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB = 0xA,
+       MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB = 0x9,
+       MSS_DEV_TYPE_FWSEC_NONWIN_INBOX = 0x6,
+};
+
+static const u32 sb_sel_mgn[SB_SEL_MGN_MAX_SIZE] = {
+       0x8000100, 0xC000180
+};
+
 static void rtw89_enable_efuse_pwr_cut_ddv_be(struct rtw89_dev *rtwdev)
 {
        const struct rtw89_chip_info *chip = rtwdev->chip;
 
        return ret;
 }
+
+static u16 get_sb_cryp_sel_idx(u16 sb_cryp_sel)
+{
+       u8 low_bit, high_bit, cnt_zero = 0;
+       u8 idx, sel_form_v, sel_idx_v;
+       u16 sb_cryp_sel_v = 0x0;
+
+       sel_form_v = u16_get_bits(sb_cryp_sel, MASKBYTE0);
+       sel_idx_v = u16_get_bits(sb_cryp_sel, MASKBYTE1);
+
+       for (idx = 0; idx < 4; idx++) {
+               low_bit = !!(sel_form_v & BIT(idx));
+               high_bit = !!(sel_form_v & BIT(7 - idx));
+               if (low_bit != high_bit)
+                       return U16_MAX;
+               if (low_bit)
+                       continue;
+
+               cnt_zero++;
+               if (cnt_zero == 1)
+                       sb_cryp_sel_v = idx * 16;
+               else if (cnt_zero > 1)
+                       return U16_MAX;
+       }
+
+       low_bit = u8_get_bits(sel_idx_v, 0x0F);
+       high_bit = u8_get_bits(sel_idx_v, 0xF0);
+
+       if ((low_bit ^ high_bit) != 0xF)
+               return U16_MAX;
+
+       return sb_cryp_sel_v + low_bit;
+}
+
+static u8 get_mss_dev_type_idx(struct rtw89_dev *rtwdev, u8 mss_dev_type)
+{
+       switch (mss_dev_type) {
+       case MSS_DEV_TYPE_FWSEC_WINLIN_INBOX:
+               mss_dev_type = 0x0;
+               break;
+       case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB:
+               mss_dev_type = 0x1;
+               break;
+       case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB:
+               mss_dev_type = 0x2;
+               break;
+       case MSS_DEV_TYPE_FWSEC_NONWIN_INBOX:
+               mss_dev_type = 0x3;
+               break;
+       case MSS_DEV_TYPE_FWSEC_DEF:
+               mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_DEF;
+               break;
+       default:
+               rtw89_warn(rtwdev, "unknown mss_dev_type %d", mss_dev_type);
+               mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_INV;
+               break;
+       }
+
+       return mss_dev_type;
+}
+
+int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev)
+{
+       struct rtw89_fw_secure *sec = &rtwdev->fw.sec;
+       u32 sec_addr = EFUSE_SEC_BE_START;
+       u32 sec_size = EFUSE_SEC_BE_SIZE;
+       u16 sb_cryp_sel, sb_cryp_sel_idx;
+       u8 sec_map[EFUSE_SEC_BE_SIZE];
+       u8 mss_dev_type;
+       u8 b1, b2;
+       int ret;
+
+       ret = rtw89_dump_physical_efuse_map_be(rtwdev, sec_map,
+                                              sec_addr, sec_size, false);
+       if (ret) {
+               rtw89_warn(rtwdev, "failed to dump secsel map\n");
+               return ret;
+       }
+
+       sb_cryp_sel = sec_map[EFUSE_SB_CRYP_SEL_ADDR - sec_addr] |
+                     sec_map[EFUSE_SB_CRYP_SEL_ADDR - sec_addr + 1] << 8;
+       if (sb_cryp_sel == EFUSE_SB_CRYP_SEL_DEFAULT)
+               goto out;
+
+       sb_cryp_sel_idx = get_sb_cryp_sel_idx(sb_cryp_sel);
+       if (sb_cryp_sel_idx >= SB_SEL_MGN_MAX_SIZE) {
+               rtw89_warn(rtwdev, "invalid SB cryp sel idx %d\n", sb_cryp_sel_idx);
+               goto out;
+       }
+
+       sec->sb_sel_mgn = sb_sel_mgn[sb_cryp_sel_idx];
+
+       b1 = sec_map[EFUSE_EXTERNALPN_ADDR_BE - sec_addr];
+       b2 = sec_map[EFUSE_SERIALNUM_ADDR_BE - sec_addr];
+
+       mss_dev_type = u8_get_bits(b1, EFUSE_B1_MSSDEVTYPE_MASK);
+       sec->mss_cust_idx = 0x1F - (u8_get_bits(b1, EFUSE_B1_MSSCUSTIDX0_MASK) |
+                                   u8_get_bits(b2, EFUSE_B2_MSSCUSTIDX1_MASK) << 4);
+       sec->mss_key_num = 0xF - u8_get_bits(b2, EFUSE_B2_MSSKEYNUM_MASK);
+
+       sec->mss_dev_type = get_mss_dev_type_idx(rtwdev, mss_dev_type);
+       if (sec->mss_dev_type == RTW89_FW_MSS_DEV_TYPE_FWSEC_INV) {
+               rtw89_warn(rtwdev, "invalid mss_dev_type %d\n", mss_dev_type);
+               goto out;
+       }
+
+       sec->secure_boot = true;
+
+out:
+       rtw89_debug(rtwdev, RTW89_DBG_FW,
+                   "MSS secure_boot=%d dev_type=%d cust_idx=%d key_num=%d\n",
+                   sec->secure_boot, sec->mss_dev_type, sec->mss_cust_idx,
+                   sec->mss_key_num);
+
+       return 0;
+}
+EXPORT_SYMBOL(rtw89_efuse_read_fw_secure_be);