return 0;
}
+static
+int rtw89_build_phy_tbl_from_elm(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_element_hdr *elm,
+ const void *data)
+{
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
+ struct rtw89_phy_table *tbl;
+ struct rtw89_reg2_def *regs;
+ enum rtw89_rf_path rf_path;
+ u32 n_regs, i;
+ u8 idx;
+
+ tbl = kzalloc(sizeof(*tbl), GFP_KERNEL);
+ if (!tbl)
+ return -ENOMEM;
+
+ switch (le32_to_cpu(elm->id)) {
+ case RTW89_FW_ELEMENT_ID_BB_REG:
+ elm_info->bb_tbl = tbl;
+ break;
+ case RTW89_FW_ELEMENT_ID_BB_GAIN:
+ elm_info->bb_gain = tbl;
+ break;
+ case RTW89_FW_ELEMENT_ID_RADIO_A:
+ case RTW89_FW_ELEMENT_ID_RADIO_B:
+ case RTW89_FW_ELEMENT_ID_RADIO_C:
+ case RTW89_FW_ELEMENT_ID_RADIO_D:
+ rf_path = (enum rtw89_rf_path)data;
+ idx = elm->u.reg2.idx;
+
+ elm_info->rf_radio[idx] = tbl;
+ tbl->rf_path = rf_path;
+ tbl->config = rtw89_phy_config_rf_reg_v1;
+ break;
+ case RTW89_FW_ELEMENT_ID_RF_NCTL:
+ elm_info->rf_nctl = tbl;
+ break;
+ default:
+ kfree(tbl);
+ return -ENOENT;
+ }
+
+ n_regs = le32_to_cpu(elm->size) / sizeof(tbl->regs[0]);
+ regs = kcalloc(n_regs, sizeof(tbl->regs[0]), GFP_KERNEL);
+ if (!regs)
+ goto out;
+
+ for (i = 0; i < n_regs; i++) {
+ regs[i].addr = le32_to_cpu(elm->u.reg2.regs[i].addr);
+ regs[i].data = le32_to_cpu(elm->u.reg2.regs[i].data);
+ }
+
+ tbl->n_regs = n_regs;
+ tbl->regs = regs;
+
+ return 0;
+
+out:
+ kfree(tbl);
+ return -ENOMEM;
+}
+
struct rtw89_fw_element_handler {
int (*fn)(struct rtw89_dev *rtwdev,
const struct rtw89_fw_element_hdr *elm, const void *data);
(const void *)RTW89_FW_BBMCU0, NULL},
[RTW89_FW_ELEMENT_ID_BBMCU1] = {__rtw89_fw_recognize_from_elm,
(const void *)RTW89_FW_BBMCU1, NULL},
+ [RTW89_FW_ELEMENT_ID_BB_REG] = {rtw89_build_phy_tbl_from_elm, NULL, "BB"},
+ [RTW89_FW_ELEMENT_ID_BB_GAIN] = {rtw89_build_phy_tbl_from_elm, NULL, NULL},
+ [RTW89_FW_ELEMENT_ID_RADIO_A] = {rtw89_build_phy_tbl_from_elm,
+ (const void *)RF_PATH_A, "radio A"},
+ [RTW89_FW_ELEMENT_ID_RADIO_B] = {rtw89_build_phy_tbl_from_elm,
+ (const void *)RF_PATH_B, NULL},
+ [RTW89_FW_ELEMENT_ID_RADIO_C] = {rtw89_build_phy_tbl_from_elm,
+ (const void *)RF_PATH_C, NULL},
+ [RTW89_FW_ELEMENT_ID_RADIO_D] = {rtw89_build_phy_tbl_from_elm,
+ (const void *)RF_PATH_D, NULL},
+ [RTW89_FW_ELEMENT_ID_RF_NCTL] = {rtw89_build_phy_tbl_from_elm, NULL, "NCTL"},
};
int rtw89_fw_recognize_elements(struct rtw89_dev *rtwdev)
rtw89_load_firmware_req(rtwdev, &rtwdev->fw.req, fw_name, false);
}
+static void rtw89_free_phy_tbl_from_elm(struct rtw89_phy_table *tbl)
+{
+ if (!tbl)
+ return;
+
+ kfree(tbl->regs);
+ kfree(tbl);
+}
+
+static void rtw89_unload_firmware_elements(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
+ int i;
+
+ rtw89_free_phy_tbl_from_elm(elm_info->bb_tbl);
+ rtw89_free_phy_tbl_from_elm(elm_info->bb_gain);
+ for (i = 0; i < ARRAY_SIZE(elm_info->rf_radio); i++)
+ rtw89_free_phy_tbl_from_elm(elm_info->rf_radio[i]);
+ rtw89_free_phy_tbl_from_elm(elm_info->rf_nctl);
+}
+
void rtw89_unload_firmware(struct rtw89_dev *rtwdev)
{
struct rtw89_fw_info *fw = &rtwdev->fw;
}
kfree(fw->log.fmts);
+ rtw89_unload_firmware_elements(rtwdev);
}
static u32 rtw89_fw_log_get_fmt_idx(struct rtw89_dev *rtwdev, u32 fmt_id)
void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev)
{
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
const struct rtw89_chip_info *chip = rtwdev->chip;
- const struct rtw89_phy_table *bb_table = chip->bb_table;
- const struct rtw89_phy_table *bb_gain_table = chip->bb_gain_table;
+ const struct rtw89_phy_table *bb_table;
+ const struct rtw89_phy_table *bb_gain_table;
+ bb_table = elm_info->bb_tbl ? elm_info->bb_tbl : chip->bb_table;
rtw89_phy_init_reg(rtwdev, bb_table, rtw89_phy_config_bb_reg, NULL);
rtw89_chip_init_txpwr_unit(rtwdev, RTW89_PHY_0);
+
+ bb_gain_table = elm_info->bb_gain ? elm_info->bb_gain : chip->bb_gain_table;
if (bb_gain_table)
rtw89_phy_init_reg(rtwdev, bb_gain_table,
rtw89_phy_config_bb_gain, NULL);
{
void (*config)(struct rtw89_dev *rtwdev, const struct rtw89_reg2_def *reg,
enum rtw89_rf_path rf_path, void *data);
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_phy_table *rf_table;
struct rtw89_fw_h2c_rf_reg_info *rf_reg_info;
return;
for (path = RF_PATH_A; path < chip->rf_path_num; path++) {
- rf_table = chip->rf_table[path];
+ rf_table = elm_info->rf_radio[path] ?
+ elm_info->rf_radio[path] : chip->rf_table[path];
rf_reg_info->rf_path = rf_table->rf_path;
if (noio)
config = rtw89_phy_config_rf_reg_noio;
static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev)
{
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_phy_table *nctl_table;
u32 val;
if (ret)
rtw89_err(rtwdev, "failed to poll nctl block\n");
- nctl_table = chip->nctl_table;
+ nctl_table = elm_info->rf_nctl ? elm_info->rf_nctl : chip->nctl_table;
rtw89_phy_init_reg(rtwdev, nctl_table, rtw89_phy_config_bb_reg, NULL);
if (chip->nctl_post_table)