wifi: rtw89: fw: read firmware secure information from efuse
To support firmware secure boot, read secure information from efuse to know if current hardware module can support secure boot with certain cryptography method. This information should be prepared before downloading firmware, so read efuse right after power on at probe stage. The secure information includes secure cryptography method and secure key index that are used to choose proper key material when downloading firmware. Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Signed-off-by: Kalle Valo <kvalo@kernel.org> Link: https://msgid.link/20240204012627.9647-3-pkshih@realtek.com
This commit is contained in:
parent
dedf78efd2
commit
5462b8505f
|
@ -4033,6 +4033,19 @@ struct rtw89_fw_elm_info {
|
|||
struct rtw89_phy_rfk_log_fmt *rfk_log_fmt;
|
||||
};
|
||||
|
||||
enum rtw89_fw_mss_dev_type {
|
||||
RTW89_FW_MSS_DEV_TYPE_FWSEC_DEF = 0xF,
|
||||
RTW89_FW_MSS_DEV_TYPE_FWSEC_INV = 0xFF,
|
||||
};
|
||||
|
||||
struct rtw89_fw_secure {
|
||||
bool secure_boot;
|
||||
u32 sb_sel_mgn;
|
||||
u8 mss_dev_type;
|
||||
u8 mss_cust_idx;
|
||||
u8 mss_key_num;
|
||||
};
|
||||
|
||||
struct rtw89_fw_info {
|
||||
struct rtw89_fw_req_info req;
|
||||
int fw_format;
|
||||
|
@ -4047,6 +4060,7 @@ struct rtw89_fw_info {
|
|||
struct rtw89_fw_log log;
|
||||
u32 feature_map;
|
||||
struct rtw89_fw_elm_info elm_info;
|
||||
struct rtw89_fw_secure sec;
|
||||
};
|
||||
|
||||
#define RTW89_CHK_FW_FEATURE(_feat, _fw) \
|
||||
|
@ -4199,6 +4213,7 @@ enum rtw89_flags {
|
|||
RTW89_FLAG_CMAC1_FUNC,
|
||||
RTW89_FLAG_FW_RDY,
|
||||
RTW89_FLAG_RUNNING,
|
||||
RTW89_FLAG_PROBE_DONE,
|
||||
RTW89_FLAG_BFEE_MON,
|
||||
RTW89_FLAG_BFEE_EN,
|
||||
RTW89_FLAG_BFEE_TIMER_KEEP,
|
||||
|
|
|
@ -23,5 +23,6 @@ int rtw89_parse_efuse_map_be(struct rtw89_dev *rtwdev);
|
|||
int rtw89_parse_phycap_map_be(struct rtw89_dev *rtwdev);
|
||||
int rtw89_cnv_efuse_state_be(struct rtw89_dev *rtwdev, bool idle);
|
||||
int rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *efv);
|
||||
int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,6 +7,31 @@
|
|||
#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;
|
||||
|
@ -418,3 +443,120 @@ out_free:
|
|||
|
||||
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);
|
||||
|
|
|
@ -4180,6 +4180,8 @@ int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
goto err_free_irq;
|
||||
}
|
||||
|
||||
set_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
|
|
|
@ -377,6 +377,9 @@ static int rtw8922a_pwr_on_func(struct rtw89_dev *rtwdev)
|
|||
rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_FEN_BB_IP_RSTN |
|
||||
B_BE_FEN_BBPLAT_RSTB);
|
||||
|
||||
if (!test_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags))
|
||||
rtw89_efuse_read_fw_secure_be(rtwdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue