Skip to content

Commit

Permalink
wifi: rtw89: add to parse firmware elements of BB and RF tables
Browse files Browse the repository at this point in the history
The tables of BB and RF parameters are pairs of {addr, value}. Load them
and convert from little-endian to CPU order, and show the version to clear
which version we are using.

  rtw89_8922ae 0000:03:00.0: Firmware element BB version: 00 04 00 00
  rtw89_8922ae 0000:03:00.0: Firmware element radio A version: 00 13 00 00
  rtw89_8922ae 0000:03:00.0: Firmware element NCTL version: 00 05 00 00

We use tables defined in firmware elements with higher priority than
original static const tables defined in driver, because WiFi 7 chips will
not define the tables in driver, and existing chips can possibly migrate to
the new design one by one.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20230801021127.15919-8-pkshih@realtek.com
  • Loading branch information
Ping-Ke Shih authored and Kalle Valo committed Aug 3, 2023
1 parent a337d43 commit 8947472
Showing 4 changed files with 121 additions and 4 deletions.
8 changes: 8 additions & 0 deletions drivers/net/wireless/realtek/rtw89/core.h
Original file line number Diff line number Diff line change
@@ -3613,6 +3613,13 @@ struct rtw89_fw_log {
const char *(*fmts)[];
};

struct rtw89_fw_elm_info {
struct rtw89_phy_table *bb_tbl;
struct rtw89_phy_table *bb_gain;
struct rtw89_phy_table *rf_radio[RF_PATH_MAX];
struct rtw89_phy_table *rf_nctl;
};

struct rtw89_fw_info {
struct rtw89_fw_req_info req;
int fw_format;
@@ -3626,6 +3633,7 @@ struct rtw89_fw_info {
struct rtw89_fw_suit bbmcu1;
struct rtw89_fw_log log;
u32 feature_map;
struct rtw89_fw_elm_info elm_info;
};

#define RTW89_CHK_FW_FEATURE(_feat, _fw) \
95 changes: 95 additions & 0 deletions drivers/net/wireless/realtek/rtw89/fw.c
Original file line number Diff line number Diff line change
@@ -544,6 +544,68 @@ int rtw89_fw_recognize(struct rtw89_dev *rtwdev)
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);
@@ -556,6 +618,17 @@ static const struct rtw89_fw_element_handler __fw_element_handlers[] = {
(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)
@@ -903,6 +976,27 @@ void rtw89_load_firmware_work(struct work_struct *work)
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;
@@ -919,6 +1013,7 @@ void rtw89_unload_firmware(struct rtw89_dev *rtwdev)
}

kfree(fw->log.fmts);
rtw89_unload_firmware_elements(rtwdev);
}

static u32 rtw89_fw_log_get_fmt_idx(struct rtw89_dev *rtwdev, u32 fmt_id)
7 changes: 7 additions & 0 deletions drivers/net/wireless/realtek/rtw89/fw.h
Original file line number Diff line number Diff line change
@@ -3405,6 +3405,13 @@ struct rtw89_fw_logsuit_hdr {
enum rtw89_fw_element_id {
RTW89_FW_ELEMENT_ID_BBMCU0 = 0,
RTW89_FW_ELEMENT_ID_BBMCU1 = 1,
RTW89_FW_ELEMENT_ID_BB_REG = 2,
RTW89_FW_ELEMENT_ID_BB_GAIN = 3,
RTW89_FW_ELEMENT_ID_RADIO_A = 4,
RTW89_FW_ELEMENT_ID_RADIO_B = 5,
RTW89_FW_ELEMENT_ID_RADIO_C = 6,
RTW89_FW_ELEMENT_ID_RADIO_D = 7,
RTW89_FW_ELEMENT_ID_RF_NCTL = 8,
};

struct rtw89_fw_element_hdr {
15 changes: 11 additions & 4 deletions drivers/net/wireless/realtek/rtw89/phy.c
Original file line number Diff line number Diff line change
@@ -1355,12 +1355,16 @@ static void rtw89_phy_init_reg(struct rtw89_dev *rtwdev,

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);
@@ -1378,6 +1382,7 @@ void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio)
{
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;
@@ -1388,7 +1393,8 @@ void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio)
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;
@@ -1405,6 +1411,7 @@ void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool 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;
@@ -1427,7 +1434,7 @@ static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev)
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)

0 comments on commit 8947472

Please sign in to comment.