rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON);
rtw89_fw_h2c_fw_log(rtwdev, rtwdev->fw.log.enable);
rtw89_fw_h2c_init_ba_cam(rtwdev);
+ rtw89_tas_fw_timer_enable(rtwdev, true);
return 0;
}
if (!test_bit(RTW89_FLAG_RUNNING, rtwdev->flags))
return;
+ rtw89_tas_fw_timer_enable(rtwdev, false);
rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_OFF);
clear_bit(RTW89_FLAG_RUNNING, rtwdev->flags);
return ret;
}
+int rtw89_fw_h2c_rf_tas_trigger(struct rtw89_dev *rtwdev, bool enable)
+{
+ struct rtw89_h2c_rf_tas *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c RF TAS\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_rf_tas *)skb->data;
+
+ h2c->enable = cpu_to_le32(enable);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK,
+ H2C_FUNC_RFK_TAS_OFFLOAD, 0, 0, len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+
int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev,
u8 h2c_class, u8 h2c_func, u8 *buf, u16 len,
bool rack, bool dack)
H2C_FUNC_RFK_DACK_OFFLOAD = 0x5,
H2C_FUNC_RFK_RXDCK_OFFLOAD = 0x6,
H2C_FUNC_RFK_PRE_NOTIFY = 0x8,
+ H2C_FUNC_RFK_TAS_OFFLOAD = 0x9,
};
struct rtw89_fw_h2c_rf_get_mccch {
u8 rxdck_dbg_en;
} __packed;
+struct rtw89_h2c_rf_tas {
+ __le32 enable;
+} __packed;
+
struct rtw89_h2c_rf_rxdck {
struct rtw89_h2c_rf_rxdck_v0 v0;
u8 is_chl_k;
u8 version;
} __packed;
-struct rtw89_c2h_rf_tas_info {
- struct rtw89_c2h_hdr hdr;
+struct rtw89_c2h_rf_tas_rpt_log {
__le32 cur_idx;
__le16 txpwr_history[20];
} __packed;
+struct rtw89_c2h_rf_tas_info {
+ struct rtw89_c2h_hdr hdr;
+ struct rtw89_c2h_rf_tas_rpt_log content;
+} __packed;
+
#define RTW89_FW_RSVD_PLE_SIZE 0x800
#define RTW89_FW_BACKTRACE_INFO_SIZE 8
const struct rtw89_chan *chan);
int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
const struct rtw89_chan *chan, bool is_chl_k);
+int rtw89_fw_h2c_rf_tas_trigger(struct rtw89_dev *rtwdev, bool enable);
int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev,
u8 h2c_class, u8 h2c_func, u8 *buf, u16 len,
bool rack, bool dack);
[RTW89_PHY_C2H_DM_FUNC_FW_SCAN] = rtw89_phy_c2h_fw_scan_rpt,
};
+static
+void rtw89_phy_c2h_rfk_tas_pwr(struct rtw89_dev *rtwdev,
+ const struct rtw89_c2h_rf_tas_rpt_log *content)
+{
+ const enum rtw89_sar_sources src = rtwdev->sar.src;
+ struct rtw89_tas_info *tas = &rtwdev->tas;
+ u64 linear = 0;
+ u32 i, cur_idx;
+ s16 txpwr;
+
+ if (!tas->enable || src == RTW89_SAR_SOURCE_NONE)
+ return;
+
+ cur_idx = le32_to_cpu(content->cur_idx);
+ for (i = 0; i < cur_idx; i++) {
+ txpwr = le16_to_cpu(content->txpwr_history[i]);
+ linear += rtw89_db_quarter_to_linear(txpwr);
+
+ rtw89_debug(rtwdev, RTW89_DBG_SAR,
+ "tas: index: %u, txpwr: %d\n", i, txpwr);
+ }
+
+ if (cur_idx == 0)
+ tas->instant_txpwr = rtw89_db_to_linear(0);
+ else
+ tas->instant_txpwr = DIV_ROUND_DOWN_ULL(linear, cur_idx);
+}
+
static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev,
enum rtw89_phy_c2h_rfk_log_func func,
void *content, u16 len)
rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt power_d[1] = %*ph\n",
(int)sizeof(txgapk->power_d[1]), txgapk->power_d[1]);
return;
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_TAS_PWR:
+ if (len != sizeof(struct rtw89_c2h_rf_tas_rpt_log))
+ goto out;
+
+ rtw89_phy_c2h_rfk_tas_pwr(rtwdev, content);
+
+ return;
default:
break;
}
u16 chunk_len;
bool handled;
- if (!rtw89_debug_is_enabled(rtwdev, RTW89_DBG_RFK))
- return;
-
log_ptr += sizeof(*c2h_hdr);
len -= sizeof(*c2h_hdr);
RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK, "TXGAPK");
}
+static void
+rtw89_phy_c2h_rfk_log_tas_pwr(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ rtw89_phy_c2h_rfk_log(rtwdev, c2h, len,
+ RTW89_PHY_C2H_RFK_LOG_FUNC_TAS_PWR, "TAS");
+}
+
static
void (* const rtw89_phy_c2h_rfk_log_handler[])(struct rtw89_dev *rtwdev,
struct sk_buff *c2h, u32 len) = {
[RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK] = rtw89_phy_c2h_rfk_log_rxdck,
[RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI] = rtw89_phy_c2h_rfk_log_tssi,
[RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK] = rtw89_phy_c2h_rfk_log_txgapk,
+ [RTW89_PHY_C2H_RFK_LOG_FUNC_TAS_PWR] = rtw89_phy_c2h_rfk_log_tas_pwr,
};
static
}
static void
-rtw89_phy_c2h_rfk_log_tas_pwr(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+rtw89_phy_c2h_rfk_report_tas_pwr(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
{
- const struct rtw89_c2h_rf_tas_info *rf_tas =
+ const struct rtw89_c2h_rf_tas_info *report =
(const struct rtw89_c2h_rf_tas_info *)c2h->data;
- const enum rtw89_sar_sources src = rtwdev->sar.src;
- struct rtw89_tas_info *tas = &rtwdev->tas;
- u64 linear = 0;
- u32 i, cur_idx;
- s16 txpwr;
- if (!tas->enable || src == RTW89_SAR_SOURCE_NONE)
- return;
-
- cur_idx = le32_to_cpu(rf_tas->cur_idx);
- for (i = 0; i < cur_idx; i++) {
- txpwr = (s16)le16_to_cpu(rf_tas->txpwr_history[i]);
- linear += rtw89_db_quarter_to_linear(txpwr);
-
- rtw89_debug(rtwdev, RTW89_DBG_SAR,
- "tas: index: %u, txpwr: %d\n", i, txpwr);
- }
-
- if (cur_idx == 0)
- tas->instant_txpwr = rtw89_db_to_linear(0);
- else
- tas->instant_txpwr = DIV_ROUND_DOWN_ULL(linear, cur_idx);
+ rtw89_phy_c2h_rfk_tas_pwr(rtwdev, &report->content);
}
static
void (* const rtw89_phy_c2h_rfk_report_handler[])(struct rtw89_dev *rtwdev,
struct sk_buff *c2h, u32 len) = {
[RTW89_PHY_C2H_RFK_REPORT_FUNC_STATE] = rtw89_phy_c2h_rfk_report_state,
- [RTW89_PHY_C2H_RFK_LOG_TAS_PWR] = rtw89_phy_c2h_rfk_log_tas_pwr,
+ [RTW89_PHY_C2H_RFK_REPORT_FUNC_TAS_PWR] = rtw89_phy_c2h_rfk_report_tas_pwr,
};
bool rtw89_phy_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func)
RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK = 3,
RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI = 4,
RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK = 5,
+ RTW89_PHY_C2H_RFK_LOG_FUNC_TAS_PWR = 9,
RTW89_PHY_C2H_RFK_LOG_FUNC_NUM,
};
enum rtw89_phy_c2h_rfk_report_func {
RTW89_PHY_C2H_RFK_REPORT_FUNC_STATE = 0,
- RTW89_PHY_C2H_RFK_LOG_TAS_PWR = 6,
+ RTW89_PHY_C2H_RFK_REPORT_FUNC_TAS_PWR = 6,
};
enum rtw89_phy_c2h_dm_func {
return 0;
}
+static const struct rtw89_chanctx_listener rtw8922a_chanctx_listener = {
+ .callbacks[RTW89_CHANCTX_CALLBACK_TAS] = rtw89_tas_chanctx_cb,
+};
+
#ifdef CONFIG_PM
static const struct wiphy_wowlan_support rtw_wowlan_stub_8922a = {
.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT |
.nctl_post_table = NULL,
.dflt_parms = NULL, /* load parm from fw */
.rfe_parms_conf = NULL, /* load parm from fw */
+ .chanctx_listener = &rtw8922a_chanctx_listener,
.txpwr_factor_bb = 3,
.txpwr_factor_rf = 2,
.txpwr_factor_mac = 1,
BIT(NL80211_CHAN_WIDTH_160),
.support_unii4 = true,
.support_ant_gain = true,
- .support_tas = false,
+ .support_tas = true,
.support_sar_by_ant = true,
.support_noise = false,
.ul_tb_waveform_ctrl = false,
#include "acpi.h"
#include "debug.h"
+#include "fw.h"
#include "phy.h"
#include "reg.h"
#include "sar.h"
}
EXPORT_SYMBOL(rtw89_tas_chanctx_cb);
+void rtw89_tas_fw_timer_enable(struct rtw89_dev *rtwdev, bool enable)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_tas_info *tas = &rtwdev->tas;
+
+ if (!tas->enable)
+ return;
+
+ if (chip->chip_gen == RTW89_CHIP_AX)
+ return;
+
+ rtw89_fw_h2c_rf_tas_trigger(rtwdev, enable);
+}
+
void rtw89_sar_init(struct rtw89_dev *rtwdev)
{
rtw89_set_sar_from_acpi(rtwdev);
void rtw89_tas_scan(struct rtw89_dev *rtwdev, bool start);
void rtw89_tas_chanctx_cb(struct rtw89_dev *rtwdev,
enum rtw89_chanctx_state state);
+void rtw89_tas_fw_timer_enable(struct rtw89_dev *rtwdev, bool enable);
void rtw89_sar_init(struct rtw89_dev *rtwdev);
void rtw89_sar_track(struct rtw89_dev *rtwdev);