summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/realtek/rtw89/phy.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/realtek/rtw89/phy.c')
-rw-r--r--drivers/net/wireless/realtek/rtw89/phy.c5114
1 files changed, 4396 insertions, 718 deletions
diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
index c7e906123416..9f418b1fb7ed 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -2,6 +2,8 @@
/* Copyright(c) 2019-2020 Realtek Corporation
*/
+#include "acpi.h"
+#include "chan.h"
#include "coex.h"
#include "debug.h"
#include "fw.h"
@@ -10,8 +12,16 @@
#include "ps.h"
#include "reg.h"
#include "sar.h"
+#include "txrx.h"
#include "util.h"
+static u32 rtw89_phy0_phy1_offset(struct rtw89_dev *rtwdev, u32 addr)
+{
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+
+ return phy->phy0_phy1_offset(rtwdev, addr);
+}
+
static u16 get_max_amsdu_len(struct rtw89_dev *rtwdev,
const struct rtw89_ra_report *report)
{
@@ -66,12 +76,12 @@ static u64 get_mcs_ra_mask(u16 mcs_map, u8 highest_mcs, u8 gap)
return ra_mask;
}
-static u64 get_he_ra_mask(struct ieee80211_sta *sta)
+static u64 get_he_ra_mask(struct ieee80211_link_sta *link_sta)
{
- struct ieee80211_sta_he_cap cap = sta->deflink.he_cap;
+ struct ieee80211_sta_he_cap cap = link_sta->he_cap;
u16 mcs_map;
- switch (sta->deflink.bandwidth) {
+ switch (link_sta->bandwidth) {
case IEEE80211_STA_RX_BW_160:
if (cap.he_cap_elem.phy_cap_info[0] &
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
@@ -87,6 +97,62 @@ static u64 get_he_ra_mask(struct ieee80211_sta *sta)
return get_mcs_ra_mask(mcs_map, 11, 2);
}
+static u64 get_eht_mcs_ra_mask(u8 *max_nss, u8 start_mcs, u8 n_nss)
+{
+ u64 nss_mcs_shift;
+ u64 nss_mcs_val;
+ u64 mask = 0;
+ int i, j;
+ u8 nss;
+
+ for (i = 0; i < n_nss; i++) {
+ nss = u8_get_bits(max_nss[i], IEEE80211_EHT_MCS_NSS_RX);
+ if (!nss)
+ continue;
+
+ nss_mcs_val = GENMASK_ULL(start_mcs + i * 2, 0);
+
+ for (j = 0, nss_mcs_shift = 12; j < nss; j++, nss_mcs_shift += 16)
+ mask |= nss_mcs_val << nss_mcs_shift;
+ }
+
+ return mask;
+}
+
+static u64 get_eht_ra_mask(struct rtw89_vif_link *rtwvif_link,
+ struct ieee80211_link_sta *link_sta)
+{
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ struct ieee80211_eht_mcs_nss_supp_20mhz_only *mcs_nss_20mhz;
+ struct ieee80211_sta_eht_cap *eht_cap = &link_sta->eht_cap;
+ struct ieee80211_eht_mcs_nss_supp_bw *mcs_nss;
+ u8 *he_phy_cap = link_sta->he_cap.he_cap_elem.phy_cap_info;
+
+ switch (link_sta->bandwidth) {
+ case IEEE80211_STA_RX_BW_320:
+ mcs_nss = &eht_cap->eht_mcs_nss_supp.bw._320;
+ /* MCS 9, 11, 13 */
+ return get_eht_mcs_ra_mask(mcs_nss->rx_tx_max_nss, 9, 3);
+ case IEEE80211_STA_RX_BW_160:
+ mcs_nss = &eht_cap->eht_mcs_nss_supp.bw._160;
+ /* MCS 9, 11, 13 */
+ return get_eht_mcs_ra_mask(mcs_nss->rx_tx_max_nss, 9, 3);
+ case IEEE80211_STA_RX_BW_20:
+ if (vif->type == NL80211_IFTYPE_AP &&
+ !(he_phy_cap[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) {
+ mcs_nss_20mhz = &eht_cap->eht_mcs_nss_supp.only_20mhz;
+ /* MCS 7, 9, 11, 13 */
+ return get_eht_mcs_ra_mask(mcs_nss_20mhz->rx_tx_max_nss, 7, 4);
+ }
+ fallthrough;
+ case IEEE80211_STA_RX_BW_80:
+ default:
+ mcs_nss = &eht_cap->eht_mcs_nss_supp.bw._80;
+ /* MCS 9, 11, 13 */
+ return get_eht_mcs_ra_mask(mcs_nss->rx_tx_max_nss, 9, 3);
+ }
+}
+
#define RA_FLOOR_TABLE_SIZE 7
#define RA_FLOOR_UP_GAP 3
static u64 rtw89_phy_ra_mask_rssi(struct rtw89_dev *rtwdev, u8 rssi,
@@ -132,15 +198,16 @@ static u64 rtw89_phy_ra_mask_recover(u64 ra_mask, u64 ra_mask_bak)
return ra_mask;
}
-static u64 rtw89_phy_ra_mask_cfg(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta)
+static u64 rtw89_phy_ra_mask_cfg(struct rtw89_dev *rtwdev,
+ struct rtw89_sta_link *rtwsta_link,
+ struct ieee80211_link_sta *link_sta,
+ const struct rtw89_chan *chan)
{
- struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta);
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
- struct cfg80211_bitrate_mask *mask = &rtwsta->mask;
+ struct cfg80211_bitrate_mask *mask = &rtwsta_link->mask;
enum nl80211_band band;
u64 cfg_mask;
- if (!rtwsta->use_cfg_mask)
+ if (!rtwsta_link->use_cfg_mask)
return -1;
switch (chan->band_type) {
@@ -164,17 +231,22 @@ static u64 rtw89_phy_ra_mask_cfg(struct rtw89_dev *rtwdev, struct rtw89_sta *rtw
return -1;
}
- if (sta->deflink.he_cap.has_he) {
+ if (link_sta->eht_cap.has_eht) {
+ cfg_mask |= u64_encode_bits(mask->control[band].eht_mcs[0],
+ RA_MASK_EHT_1SS_RATES);
+ cfg_mask |= u64_encode_bits(mask->control[band].eht_mcs[1],
+ RA_MASK_EHT_2SS_RATES);
+ } else if (link_sta->he_cap.has_he) {
cfg_mask |= u64_encode_bits(mask->control[band].he_mcs[0],
RA_MASK_HE_1SS_RATES);
cfg_mask |= u64_encode_bits(mask->control[band].he_mcs[1],
RA_MASK_HE_2SS_RATES);
- } else if (sta->deflink.vht_cap.vht_supported) {
+ } else if (link_sta->vht_cap.vht_supported) {
cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[0],
RA_MASK_VHT_1SS_RATES);
cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[1],
RA_MASK_VHT_2SS_RATES);
- } else if (sta->deflink.ht_cap.ht_supported) {
+ } else if (link_sta->ht_cap.ht_supported) {
cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[0],
RA_MASK_HT_1SS_RATES);
cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[1],
@@ -193,19 +265,35 @@ rtw89_ra_mask_vht_rates[4] = {RA_MASK_VHT_1SS_RATES, RA_MASK_VHT_2SS_RATES,
static const u64
rtw89_ra_mask_he_rates[4] = {RA_MASK_HE_1SS_RATES, RA_MASK_HE_2SS_RATES,
RA_MASK_HE_3SS_RATES, RA_MASK_HE_4SS_RATES};
+static const u64
+rtw89_ra_mask_eht_rates[4] = {RA_MASK_EHT_1SS_RATES, RA_MASK_EHT_2SS_RATES,
+ RA_MASK_EHT_3SS_RATES, RA_MASK_EHT_4SS_RATES};
+static const u64
+rtw89_ra_mask_eht_mcs0_11[4] = {RA_MASK_EHT_1SS_MCS0_11, RA_MASK_EHT_2SS_MCS0_11,
+ RA_MASK_EHT_3SS_MCS0_11, RA_MASK_EHT_4SS_MCS0_11};
static void rtw89_phy_ra_gi_ltf(struct rtw89_dev *rtwdev,
- struct rtw89_sta *rtwsta,
+ struct rtw89_sta_link *rtwsta_link,
+ struct ieee80211_link_sta *link_sta,
+ const struct rtw89_chan *chan,
bool *fix_giltf_en, u8 *fix_giltf)
{
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
- struct cfg80211_bitrate_mask *mask = &rtwsta->mask;
+ struct cfg80211_bitrate_mask *mask = &rtwsta_link->mask;
u8 band = chan->band_type;
enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band);
- u8 he_gi = mask->control[nl_band].he_gi;
u8 he_ltf = mask->control[nl_band].he_ltf;
+ u8 he_gi = mask->control[nl_band].he_gi;
+
+ *fix_giltf_en = true;
+
+ if (rtwdev->chip->chip_id == RTL8852C &&
+ chan->band_width == RTW89_CHANNEL_WIDTH_160 &&
+ rtw89_sta_link_has_su_mu_4xhe08(link_sta))
+ *fix_giltf = RTW89_GILTF_SGI_4XHE08;
+ else
+ *fix_giltf = RTW89_GILTF_2XHE08;
- if (!rtwsta->use_cfg_mask)
+ if (!(rtwsta_link->use_cfg_mask && link_sta->he_cap.has_he))
return;
if (he_ltf == 2 && he_gi == 2) {
@@ -220,25 +308,21 @@ static void rtw89_phy_ra_gi_ltf(struct rtw89_dev *rtwdev,
*fix_giltf = RTW89_GILTF_1XHE16;
} else if (he_ltf == 0 && he_gi == 0) {
*fix_giltf = RTW89_GILTF_1XHE08;
- } else {
- *fix_giltf_en = false;
- return;
}
-
- *fix_giltf_en = true;
}
static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev,
- struct ieee80211_sta *sta, bool csi)
-{
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
- struct rtw89_vif *rtwvif = rtwsta->rtwvif;
- struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif->rate_pattern;
- struct rtw89_ra_info *ra = &rtwsta->ra;
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwsta->rtwvif);
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_sta_link *rtwsta_link,
+ struct ieee80211_link_sta *link_sta,
+ bool p2p, bool csi)
+{
+ struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif_link->rate_pattern;
+ struct rtw89_ra_info *ra = &rtwsta_link->ra;
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif_link->chanctx_idx);
const u64 *high_rate_masks = rtw89_ra_mask_ht_rates;
- u8 rssi = ewma_rssi_read(&rtwsta->avg_rssi);
+ u8 rssi = ewma_rssi_read(&rtwsta_link->avg_rssi);
u64 ra_mask = 0;
u64 ra_mask_bak;
u8 mode = 0;
@@ -253,58 +337,73 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev,
memset(ra, 0, sizeof(*ra));
/* Set the ra mask from sta's capability */
- if (sta->deflink.he_cap.has_he) {
+ if (link_sta->eht_cap.has_eht) {
+ mode |= RTW89_RA_MODE_EHT;
+ ra_mask |= get_eht_ra_mask(rtwvif_link, link_sta);
+
+ if (rtwdev->hal.no_mcs_12_13)
+ high_rate_masks = rtw89_ra_mask_eht_mcs0_11;
+ else
+ high_rate_masks = rtw89_ra_mask_eht_rates;
+
+ rtw89_phy_ra_gi_ltf(rtwdev, rtwsta_link, link_sta,
+ chan, &fix_giltf_en, &fix_giltf);
+ } else if (link_sta->he_cap.has_he) {
mode |= RTW89_RA_MODE_HE;
csi_mode = RTW89_RA_RPT_MODE_HE;
- ra_mask |= get_he_ra_mask(sta);
+ ra_mask |= get_he_ra_mask(link_sta);
high_rate_masks = rtw89_ra_mask_he_rates;
- if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[2] &
+ if (link_sta->he_cap.he_cap_elem.phy_cap_info[2] &
IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ)
stbc_en = 1;
- if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[1] &
+ if (link_sta->he_cap.he_cap_elem.phy_cap_info[1] &
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)
ldpc_en = 1;
- rtw89_phy_ra_gi_ltf(rtwdev, rtwsta, &fix_giltf_en, &fix_giltf);
- } else if (sta->deflink.vht_cap.vht_supported) {
- u16 mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map);
+ rtw89_phy_ra_gi_ltf(rtwdev, rtwsta_link, link_sta,
+ chan, &fix_giltf_en, &fix_giltf);
+ } else if (link_sta->vht_cap.vht_supported) {
+ u16 mcs_map = le16_to_cpu(link_sta->vht_cap.vht_mcs.rx_mcs_map);
mode |= RTW89_RA_MODE_VHT;
csi_mode = RTW89_RA_RPT_MODE_VHT;
- /* MCS9, MCS8, MCS7 */
- ra_mask |= get_mcs_ra_mask(mcs_map, 9, 1);
+ /* MCS9 (non-20MHz), MCS8, MCS7 */
+ if (link_sta->bandwidth == IEEE80211_STA_RX_BW_20)
+ ra_mask |= get_mcs_ra_mask(mcs_map, 8, 1);
+ else
+ ra_mask |= get_mcs_ra_mask(mcs_map, 9, 1);
high_rate_masks = rtw89_ra_mask_vht_rates;
- if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK)
+ if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK)
stbc_en = 1;
- if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC)
+ if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC)
ldpc_en = 1;
- } else if (sta->deflink.ht_cap.ht_supported) {
+ } else if (link_sta->ht_cap.ht_supported) {
mode |= RTW89_RA_MODE_HT;
csi_mode = RTW89_RA_RPT_MODE_HT;
- ra_mask |= ((u64)sta->deflink.ht_cap.mcs.rx_mask[3] << 48) |
- ((u64)sta->deflink.ht_cap.mcs.rx_mask[2] << 36) |
- (sta->deflink.ht_cap.mcs.rx_mask[1] << 24) |
- (sta->deflink.ht_cap.mcs.rx_mask[0] << 12);
+ ra_mask |= ((u64)link_sta->ht_cap.mcs.rx_mask[3] << 48) |
+ ((u64)link_sta->ht_cap.mcs.rx_mask[2] << 36) |
+ ((u64)link_sta->ht_cap.mcs.rx_mask[1] << 24) |
+ ((u64)link_sta->ht_cap.mcs.rx_mask[0] << 12);
high_rate_masks = rtw89_ra_mask_ht_rates;
- if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
+ if (link_sta->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
stbc_en = 1;
- if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)
+ if (link_sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)
ldpc_en = 1;
}
switch (chan->band_type) {
case RTW89_BAND_2G:
- ra_mask |= sta->deflink.supp_rates[NL80211_BAND_2GHZ];
- if (sta->deflink.supp_rates[NL80211_BAND_2GHZ] & 0xf)
+ ra_mask |= link_sta->supp_rates[NL80211_BAND_2GHZ];
+ if (link_sta->supp_rates[NL80211_BAND_2GHZ] & 0xf)
mode |= RTW89_RA_MODE_CCK;
- if (sta->deflink.supp_rates[NL80211_BAND_2GHZ] & 0xff0)
+ if (link_sta->supp_rates[NL80211_BAND_2GHZ] & 0xff0)
mode |= RTW89_RA_MODE_OFDM;
break;
case RTW89_BAND_5G:
- ra_mask |= (u64)sta->deflink.supp_rates[NL80211_BAND_5GHZ] << 4;
+ ra_mask |= (u64)link_sta->supp_rates[NL80211_BAND_5GHZ] << 4;
mode |= RTW89_RA_MODE_OFDM;
break;
case RTW89_BAND_6G:
- ra_mask |= (u64)sta->deflink.supp_rates[NL80211_BAND_6GHZ] << 4;
+ ra_mask |= (u64)link_sta->supp_rates[NL80211_BAND_6GHZ] << 4;
mode |= RTW89_RA_MODE_OFDM;
break;
default:
@@ -331,52 +430,56 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev,
ra_mask &= rtw89_phy_ra_mask_rssi(rtwdev, rssi, 0);
ra_mask = rtw89_phy_ra_mask_recover(ra_mask, ra_mask_bak);
- ra_mask &= rtw89_phy_ra_mask_cfg(rtwdev, rtwsta);
+ ra_mask &= rtw89_phy_ra_mask_cfg(rtwdev, rtwsta_link, link_sta, chan);
- switch (sta->deflink.bandwidth) {
+ switch (link_sta->bandwidth) {
case IEEE80211_STA_RX_BW_160:
bw_mode = RTW89_CHANNEL_WIDTH_160;
- sgi = sta->deflink.vht_cap.vht_supported &&
- (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160);
+ sgi = link_sta->vht_cap.vht_supported &&
+ (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160);
break;
case IEEE80211_STA_RX_BW_80:
bw_mode = RTW89_CHANNEL_WIDTH_80;
- sgi = sta->deflink.vht_cap.vht_supported &&
- (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80);
+ sgi = link_sta->vht_cap.vht_supported &&
+ (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80);
break;
case IEEE80211_STA_RX_BW_40:
bw_mode = RTW89_CHANNEL_WIDTH_40;
- sgi = sta->deflink.ht_cap.ht_supported &&
- (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40);
+ sgi = link_sta->ht_cap.ht_supported &&
+ (link_sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40);
break;
default:
bw_mode = RTW89_CHANNEL_WIDTH_20;
- sgi = sta->deflink.ht_cap.ht_supported &&
- (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20);
+ sgi = link_sta->ht_cap.ht_supported &&
+ (link_sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20);
break;
}
- if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[3] &
+ if (link_sta->he_cap.he_cap_elem.phy_cap_info[3] &
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM)
ra->dcm_cap = 1;
- if (rate_pattern->enable && !vif->p2p) {
- ra_mask = rtw89_phy_ra_mask_cfg(rtwdev, rtwsta);
+ if (rate_pattern->enable && !p2p) {
+ ra_mask = rtw89_phy_ra_mask_cfg(rtwdev, rtwsta_link, link_sta, chan);
ra_mask &= rate_pattern->ra_mask;
mode = rate_pattern->ra_mode;
}
ra->bw_cap = bw_mode;
- ra->er_cap = rtwsta->er_cap;
+ ra->er_cap = rtwsta_link->er_cap;
ra->mode_ctrl = mode;
- ra->macid = rtwsta->mac_id;
+ ra->macid = rtwsta_link->mac_id;
ra->stbc_cap = stbc_en;
ra->ldpc_cap = ldpc_en;
- ra->ss_num = min(sta->deflink.rx_nss, rtwdev->hal.tx_nss) - 1;
+ ra->ss_num = min(link_sta->rx_nss, rtwdev->hal.tx_nss) - 1;
ra->en_sgi = sgi;
ra->ra_mask = ra_mask;
ra->fix_giltf_en = fix_giltf_en;
ra->fix_giltf = fix_giltf;
+ ra->partial_bw_er = link_sta->he_cap.has_he ?
+ !!(link_sta->he_cap.he_cap_elem.phy_cap_info[6] &
+ IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE) : 0;
+ ra->band = chan->band_type;
if (!csi)
return;
@@ -384,20 +487,29 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev,
ra->fixed_csi_rate_en = false;
ra->ra_csi_rate_en = true;
ra->cr_tbl_sel = false;
- ra->band_num = rtwvif->phy_idx;
+ ra->band_num = rtwvif_link->phy_idx;
ra->csi_bw = bw_mode;
ra->csi_gi_ltf = RTW89_GILTF_LGI_4XHE32;
ra->csi_mcs_ss_idx = 5;
ra->csi_mode = csi_mode;
}
-void rtw89_phy_ra_updata_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta,
- u32 changed)
+void rtw89_phy_ra_update_sta_link(struct rtw89_dev *rtwdev,
+ struct rtw89_sta_link *rtwsta_link,
+ u32 changed)
{
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
- struct rtw89_ra_info *ra = &rtwsta->ra;
+ struct rtw89_vif_link *rtwvif_link = rtwsta_link->rtwvif_link;
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ struct rtw89_ra_info *ra = &rtwsta_link->ra;
+ struct ieee80211_link_sta *link_sta;
+
+ rcu_read_lock();
+
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false);
+ rtw89_phy_ra_sta_update(rtwdev, rtwvif_link, rtwsta_link,
+ link_sta, vif->p2p, false);
- rtw89_phy_ra_sta_update(rtwdev, sta, false);
+ rcu_read_unlock();
if (changed & IEEE80211_RC_SUPP_RATES_CHANGED)
ra->upd_mask = 1;
@@ -415,6 +527,17 @@ void rtw89_phy_ra_updata_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta
rtw89_fw_h2c_ra(rtwdev, ra, false);
}
+void rtw89_phy_ra_update_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta,
+ u32 changed)
+{
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_sta_link *rtwsta_link;
+ unsigned int link_id;
+
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id)
+ rtw89_phy_ra_update_sta_link(rtwdev, rtwsta_link, changed);
+}
+
static bool __check_rate_pattern(struct rtw89_phy_rate_pattern *next,
u16 rate_base, u64 ra_mask, u8 ra_mode,
u32 rate_ctrl, u32 ctrl_skip, bool force)
@@ -443,47 +566,86 @@ static bool __check_rate_pattern(struct rtw89_phy_rate_pattern *next,
return true;
}
-void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev,
- struct ieee80211_vif *vif,
- const struct cfg80211_bitrate_mask *mask)
+enum __rtw89_hw_rate_invalid_bases {
+ /* no EHT rate for ax chip */
+ RTW89_HW_RATE_EHT_NSS1_MCS0 = RTW89_HW_RATE_INVAL,
+ RTW89_HW_RATE_EHT_NSS2_MCS0 = RTW89_HW_RATE_INVAL,
+ RTW89_HW_RATE_EHT_NSS3_MCS0 = RTW89_HW_RATE_INVAL,
+ RTW89_HW_RATE_EHT_NSS4_MCS0 = RTW89_HW_RATE_INVAL,
+};
+
+#define RTW89_HW_RATE_BY_CHIP_GEN(rate) \
+ { \
+ [RTW89_CHIP_AX] = RTW89_HW_RATE_ ## rate, \
+ [RTW89_CHIP_BE] = RTW89_HW_RATE_V1_ ## rate, \
+ }
+
+static
+void __rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ const struct cfg80211_bitrate_mask *mask)
{
struct ieee80211_supported_band *sband;
- struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
struct rtw89_phy_rate_pattern next_pattern = {0};
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
- static const u16 hw_rate_he[] = {RTW89_HW_RATE_HE_NSS1_MCS0,
- RTW89_HW_RATE_HE_NSS2_MCS0,
- RTW89_HW_RATE_HE_NSS3_MCS0,
- RTW89_HW_RATE_HE_NSS4_MCS0};
- static const u16 hw_rate_vht[] = {RTW89_HW_RATE_VHT_NSS1_MCS0,
- RTW89_HW_RATE_VHT_NSS2_MCS0,
- RTW89_HW_RATE_VHT_NSS3_MCS0,
- RTW89_HW_RATE_VHT_NSS4_MCS0};
- static const u16 hw_rate_ht[] = {RTW89_HW_RATE_MCS0,
- RTW89_HW_RATE_MCS8,
- RTW89_HW_RATE_MCS16,
- RTW89_HW_RATE_MCS24};
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif_link->chanctx_idx);
+ static const u16 hw_rate_eht[][RTW89_CHIP_GEN_NUM] = {
+ RTW89_HW_RATE_BY_CHIP_GEN(EHT_NSS1_MCS0),
+ RTW89_HW_RATE_BY_CHIP_GEN(EHT_NSS2_MCS0),
+ RTW89_HW_RATE_BY_CHIP_GEN(EHT_NSS3_MCS0),
+ RTW89_HW_RATE_BY_CHIP_GEN(EHT_NSS4_MCS0),
+ };
+ static const u16 hw_rate_he[][RTW89_CHIP_GEN_NUM] = {
+ RTW89_HW_RATE_BY_CHIP_GEN(HE_NSS1_MCS0),
+ RTW89_HW_RATE_BY_CHIP_GEN(HE_NSS2_MCS0),
+ RTW89_HW_RATE_BY_CHIP_GEN(HE_NSS3_MCS0),
+ RTW89_HW_RATE_BY_CHIP_GEN(HE_NSS4_MCS0),
+ };
+ static const u16 hw_rate_vht[][RTW89_CHIP_GEN_NUM] = {
+ RTW89_HW_RATE_BY_CHIP_GEN(VHT_NSS1_MCS0),
+ RTW89_HW_RATE_BY_CHIP_GEN(VHT_NSS2_MCS0),
+ RTW89_HW_RATE_BY_CHIP_GEN(VHT_NSS3_MCS0),
+ RTW89_HW_RATE_BY_CHIP_GEN(VHT_NSS4_MCS0),
+ };
+ static const u16 hw_rate_ht[][RTW89_CHIP_GEN_NUM] = {
+ RTW89_HW_RATE_BY_CHIP_GEN(MCS0),
+ RTW89_HW_RATE_BY_CHIP_GEN(MCS8),
+ RTW89_HW_RATE_BY_CHIP_GEN(MCS16),
+ RTW89_HW_RATE_BY_CHIP_GEN(MCS24),
+ };
u8 band = chan->band_type;
enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band);
+ enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
u8 tx_nss = rtwdev->hal.tx_nss;
u8 i;
+ if (chip_gen == RTW89_CHIP_AX)
+ goto rs_11ax;
+
+ for (i = 0; i < tx_nss; i++)
+ if (!__check_rate_pattern(&next_pattern, hw_rate_eht[i][chip_gen],
+ RA_MASK_EHT_RATES, RTW89_RA_MODE_EHT,
+ mask->control[nl_band].eht_mcs[i],
+ 0, true))
+ goto out;
+
+rs_11ax:
for (i = 0; i < tx_nss; i++)
- if (!__check_rate_pattern(&next_pattern, hw_rate_he[i],
+ if (!__check_rate_pattern(&next_pattern, hw_rate_he[i][chip_gen],
RA_MASK_HE_RATES, RTW89_RA_MODE_HE,
mask->control[nl_band].he_mcs[i],
0, true))
goto out;
for (i = 0; i < tx_nss; i++)
- if (!__check_rate_pattern(&next_pattern, hw_rate_vht[i],
+ if (!__check_rate_pattern(&next_pattern, hw_rate_vht[i][chip_gen],
RA_MASK_VHT_RATES, RTW89_RA_MODE_VHT,
mask->control[nl_band].vht_mcs[i],
0, true))
goto out;
for (i = 0; i < tx_nss; i++)
- if (!__check_rate_pattern(&next_pattern, hw_rate_ht[i],
+ if (!__check_rate_pattern(&next_pattern, hw_rate_ht[i][chip_gen],
RA_MASK_HT_RATES, RTW89_RA_MODE_HT,
mask->control[nl_band].ht_mcs[i],
0, true))
@@ -512,7 +674,14 @@ void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev,
if (!next_pattern.enable)
goto out;
- rtwvif->rate_pattern = next_pattern;
+ if (unlikely(next_pattern.rate >= RTW89_HW_RATE_INVAL)) {
+ rtw89_debug(rtwdev, RTW89_DBG_RA,
+ "pattern invalid target: chip_gen %d, mode 0x%x\n",
+ chip_gen, next_pattern.ra_mode);
+ goto out;
+ }
+
+ rtwvif_link->rate_pattern = next_pattern;
rtw89_debug(rtwdev, RTW89_DBG_RA,
"configure pattern: rate 0x%x, mask 0x%llx, mode 0x%x\n",
next_pattern.rate,
@@ -521,32 +690,54 @@ void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev,
return;
out:
- rtwvif->rate_pattern.enable = false;
+ rtwvif_link->rate_pattern.enable = false;
rtw89_debug(rtwdev, RTW89_DBG_RA, "unset rate pattern\n");
}
-static void rtw89_phy_ra_updata_sta_iter(void *data, struct ieee80211_sta *sta)
+void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ const struct cfg80211_bitrate_mask *mask)
+{
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_vif_link *rtwvif_link;
+ unsigned int link_id;
+
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ __rtw89_phy_rate_pattern_vif(rtwdev, rtwvif_link, mask);
+}
+
+static void rtw89_phy_ra_update_sta_iter(void *data, struct ieee80211_sta *sta)
{
struct rtw89_dev *rtwdev = (struct rtw89_dev *)data;
- rtw89_phy_ra_updata_sta(rtwdev, sta, IEEE80211_RC_SUPP_RATES_CHANGED);
+ rtw89_phy_ra_update_sta(rtwdev, sta, IEEE80211_RC_SUPP_RATES_CHANGED);
}
void rtw89_phy_ra_update(struct rtw89_dev *rtwdev)
{
ieee80211_iterate_stations_atomic(rtwdev->hw,
- rtw89_phy_ra_updata_sta_iter,
+ rtw89_phy_ra_update_sta_iter,
rtwdev);
}
-void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta)
+void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link)
{
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
- struct rtw89_ra_info *ra = &rtwsta->ra;
- u8 rssi = ewma_rssi_read(&rtwsta->avg_rssi) >> RSSI_FACTOR;
- bool csi = rtw89_sta_has_beamformer_cap(sta);
+ struct rtw89_vif_link *rtwvif_link = rtwsta_link->rtwvif_link;
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ struct rtw89_ra_info *ra = &rtwsta_link->ra;
+ u8 rssi = ewma_rssi_read(&rtwsta_link->avg_rssi) >> RSSI_FACTOR;
+ struct ieee80211_link_sta *link_sta;
+ bool csi;
+
+ rcu_read_lock();
- rtw89_phy_ra_sta_update(rtwdev, sta, csi);
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true);
+ csi = rtw89_sta_has_beamformer_cap(link_sta);
+
+ rtw89_phy_ra_sta_update(rtwdev, rtwvif_link, rtwsta_link,
+ link_sta, vif->p2p, csi);
+
+ rcu_read_unlock();
if (rssi > 40)
ra->init_rate_lv = 1;
@@ -646,6 +837,53 @@ u8 rtw89_phy_get_txsc(struct rtw89_dev *rtwdev,
}
EXPORT_SYMBOL(rtw89_phy_get_txsc);
+u8 rtw89_phy_get_txsb(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan,
+ enum rtw89_bandwidth dbw)
+{
+ enum rtw89_bandwidth cbw = chan->band_width;
+ u8 pri_ch = chan->primary_channel;
+ u8 central_ch = chan->channel;
+ u8 txsb_idx = 0;
+
+ if (cbw == dbw || cbw == RTW89_CHANNEL_WIDTH_20)
+ return txsb_idx;
+
+ switch (cbw) {
+ case RTW89_CHANNEL_WIDTH_40:
+ txsb_idx = pri_ch > central_ch ? 1 : 0;
+ break;
+ case RTW89_CHANNEL_WIDTH_80:
+ if (dbw == RTW89_CHANNEL_WIDTH_20)
+ txsb_idx = (pri_ch - central_ch + 6) / 4;
+ else
+ txsb_idx = pri_ch > central_ch ? 1 : 0;
+ break;
+ case RTW89_CHANNEL_WIDTH_160:
+ if (dbw == RTW89_CHANNEL_WIDTH_20)
+ txsb_idx = (pri_ch - central_ch + 14) / 4;
+ else if (dbw == RTW89_CHANNEL_WIDTH_40)
+ txsb_idx = (pri_ch - central_ch + 12) / 8;
+ else
+ txsb_idx = pri_ch > central_ch ? 1 : 0;
+ break;
+ case RTW89_CHANNEL_WIDTH_320:
+ if (dbw == RTW89_CHANNEL_WIDTH_20)
+ txsb_idx = (pri_ch - central_ch + 30) / 4;
+ else if (dbw == RTW89_CHANNEL_WIDTH_40)
+ txsb_idx = (pri_ch - central_ch + 28) / 8;
+ else if (dbw == RTW89_CHANNEL_WIDTH_80)
+ txsb_idx = (pri_ch - central_ch + 24) / 16;
+ else
+ txsb_idx = pri_ch > central_ch ? 1 : 0;
+ break;
+ default:
+ break;
+ }
+
+ return txsb_idx;
+}
+EXPORT_SYMBOL(rtw89_phy_get_txsb);
+
static bool rtw89_phy_check_swsi_busy(struct rtw89_dev *rtwdev)
{
return !!rtw89_phy_read32_mask(rtwdev, R_SWSI_V1, B_SWSI_W_BUSY_V1) ||
@@ -700,7 +938,8 @@ static u32 rtw89_phy_read_rf_a(struct rtw89_dev *rtwdev,
30, false, rtwdev, R_SWSI_V1,
B_SWSI_R_DATA_DONE_V1);
if (ret) {
- rtw89_err(rtwdev, "read swsi busy\n");
+ if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags))
+ rtw89_err(rtwdev, "read swsi busy\n");
return INV_RF_DATA;
}
@@ -724,6 +963,71 @@ u32 rtw89_phy_read_rf_v1(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
}
EXPORT_SYMBOL(rtw89_phy_read_rf_v1);
+static u32 rtw89_phy_read_full_rf_v2_a(struct rtw89_dev *rtwdev,
+ enum rtw89_rf_path rf_path, u32 addr)
+{
+ static const u16 r_addr_ofst[2] = {0x2C24, 0x2D24};
+ static const u16 addr_ofst[2] = {0x2ADC, 0x2BDC};
+ bool busy, done;
+ int ret;
+ u32 val;
+
+ rtw89_phy_write32_mask(rtwdev, addr_ofst[rf_path], B_HWSI_ADD_CTL_MASK, 0x1);
+ ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, busy, !busy,
+ 1, 3800, false,
+ rtwdev, r_addr_ofst[rf_path], B_HWSI_VAL_BUSY);
+ if (ret) {
+ rtw89_warn(rtwdev, "poll HWSI is busy\n");
+ return INV_RF_DATA;
+ }
+
+ rtw89_phy_write32_mask(rtwdev, addr_ofst[rf_path], B_HWSI_ADD_MASK, addr);
+ rtw89_phy_write32_mask(rtwdev, addr_ofst[rf_path], B_HWSI_ADD_RD, 0x1);
+ udelay(2);
+
+ ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, done, done,
+ 1, 3800, false,
+ rtwdev, r_addr_ofst[rf_path], B_HWSI_VAL_RDONE);
+ if (ret) {
+ rtw89_warn(rtwdev, "read HWSI is busy\n");
+ val = INV_RF_DATA;
+ goto out;
+ }
+
+ val = rtw89_phy_read32_mask(rtwdev, r_addr_ofst[rf_path], RFREG_MASK);
+out:
+ rtw89_phy_write32_mask(rtwdev, addr_ofst[rf_path], B_HWSI_ADD_POLL_MASK, 0);
+
+ return val;
+}
+
+static u32 rtw89_phy_read_rf_v2_a(struct rtw89_dev *rtwdev,
+ enum rtw89_rf_path rf_path, u32 addr, u32 mask)
+{
+ u32 val;
+
+ val = rtw89_phy_read_full_rf_v2_a(rtwdev, rf_path, addr);
+
+ return (val & mask) >> __ffs(mask);
+}
+
+u32 rtw89_phy_read_rf_v2(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
+ u32 addr, u32 mask)
+{
+ bool ad_sel = u32_get_bits(addr, RTW89_RF_ADDR_ADSEL_MASK);
+
+ if (rf_path >= rtwdev->chip->rf_path_num) {
+ rtw89_err(rtwdev, "unsupported rf path (%d)\n", rf_path);
+ return INV_RF_DATA;
+ }
+
+ if (ad_sel)
+ return rtw89_phy_read_rf(rtwdev, rf_path, addr, mask);
+ else
+ return rtw89_phy_read_rf_v2_a(rtwdev, rf_path, addr, mask);
+}
+EXPORT_SYMBOL(rtw89_phy_read_rf_v2);
+
bool rtw89_phy_write_rf(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
u32 addr, u32 mask, u32 data)
{
@@ -803,38 +1107,115 @@ bool rtw89_phy_write_rf_v1(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
}
EXPORT_SYMBOL(rtw89_phy_write_rf_v1);
+static
+bool rtw89_phy_write_full_rf_v2_a(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
+ u32 addr, u32 data)
+{
+ static const u32 addr_is_idle[2] = {0x2C24, 0x2D24};
+ static const u32 addr_ofst[2] = {0x2AE0, 0x2BE0};
+ bool busy;
+ u32 val;
+ int ret;
+
+ ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, busy, !busy,
+ 1, 3800, false,
+ rtwdev, addr_is_idle[rf_path], BIT(29));
+ if (ret) {
+ rtw89_warn(rtwdev, "[%s] HWSI is busy\n", __func__);
+ return false;
+ }
+
+ val = u32_encode_bits(addr, B_HWSI_DATA_ADDR) |
+ u32_encode_bits(data, B_HWSI_DATA_VAL);
+
+ rtw89_phy_write32(rtwdev, addr_ofst[rf_path], val);
+
+ return true;
+}
+
+static
+bool rtw89_phy_write_rf_a_v2(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
+ u32 addr, u32 mask, u32 data)
+{
+ u32 val;
+
+ if (mask == RFREG_MASK) {
+ val = data;
+ } else {
+ val = rtw89_phy_read_full_rf_v2_a(rtwdev, rf_path, addr);
+ val &= ~mask;
+ val |= (data << __ffs(mask)) & mask;
+ }
+
+ return rtw89_phy_write_full_rf_v2_a(rtwdev, rf_path, addr, val);
+}
+
+bool rtw89_phy_write_rf_v2(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
+ u32 addr, u32 mask, u32 data)
+{
+ bool ad_sel = u32_get_bits(addr, RTW89_RF_ADDR_ADSEL_MASK);
+
+ if (rf_path >= rtwdev->chip->rf_path_num) {
+ rtw89_err(rtwdev, "unsupported rf path (%d)\n", rf_path);
+ return INV_RF_DATA;
+ }
+
+ if (ad_sel)
+ return rtw89_phy_write_rf(rtwdev, rf_path, addr, mask, data);
+ else
+ return rtw89_phy_write_rf_a_v2(rtwdev, rf_path, addr, mask, data);
+}
+EXPORT_SYMBOL(rtw89_phy_write_rf_v2);
+
static bool rtw89_chip_rf_v1(struct rtw89_dev *rtwdev)
{
return rtwdev->chip->ops->write_rf == rtw89_phy_write_rf_v1;
}
-static void rtw89_phy_bb_reset(struct rtw89_dev *rtwdev,
- enum rtw89_phy_idx phy_idx)
+static void __rtw89_phy_bb_reset(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
chip->ops->bb_reset(rtwdev, phy_idx);
}
+static void rtw89_phy_bb_reset(struct rtw89_dev *rtwdev)
+{
+ __rtw89_phy_bb_reset(rtwdev, RTW89_PHY_0);
+ if (rtwdev->dbcc_en)
+ __rtw89_phy_bb_reset(rtwdev, RTW89_PHY_1);
+}
+
static void rtw89_phy_config_bb_reg(struct rtw89_dev *rtwdev,
const struct rtw89_reg2_def *reg,
enum rtw89_rf_path rf_path,
void *extra_data)
{
- if (reg->addr == 0xfe)
+ u32 addr;
+
+ if (reg->addr == 0xfe) {
mdelay(50);
- else if (reg->addr == 0xfd)
+ } else if (reg->addr == 0xfd) {
mdelay(5);
- else if (reg->addr == 0xfc)
+ } else if (reg->addr == 0xfc) {
mdelay(1);
- else if (reg->addr == 0xfb)
+ } else if (reg->addr == 0xfb) {
udelay(50);
- else if (reg->addr == 0xfa)
+ } else if (reg->addr == 0xfa) {
udelay(5);
- else if (reg->addr == 0xf9)
+ } else if (reg->addr == 0xf9) {
udelay(1);
- else
- rtw89_phy_write32(rtwdev, reg->addr, reg->data);
+ } else if (reg->data == BYPASS_CR_DATA) {
+ rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK, "Bypass CR 0x%x\n", reg->addr);
+ } else {
+ addr = reg->addr;
+
+ if ((uintptr_t)extra_data == RTW89_PHY_1)
+ addr += rtw89_phy0_phy1_offset(rtwdev, reg->addr);
+
+ rtw89_phy_write32(rtwdev, addr, reg->data);
+ }
}
union rtw89_phy_bb_gain_arg {
@@ -857,7 +1238,7 @@ static void
rtw89_phy_cfg_bb_gain_error(struct rtw89_dev *rtwdev,
union rtw89_phy_bb_gain_arg arg, u32 data)
{
- struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain;
+ struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax;
u8 type = arg.type;
u8 path = arg.path;
u8 gband = arg.gain_band;
@@ -896,7 +1277,7 @@ static void
rtw89_phy_cfg_bb_rpl_ofst(struct rtw89_dev *rtwdev,
union rtw89_phy_bb_gain_arg arg, u32 data)
{
- struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain;
+ struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax;
u8 rxsc_start = arg.rxsc_start;
u8 bw = arg.bw;
u8 path = arg.path;
@@ -978,7 +1359,7 @@ static void
rtw89_phy_cfg_bb_gain_bypass(struct rtw89_dev *rtwdev,
union rtw89_phy_bb_gain_arg arg, u32 data)
{
- struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain;
+ struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax;
u8 type = arg.type;
u8 path = arg.path;
u8 gband = arg.gain_band;
@@ -1005,7 +1386,7 @@ static void
rtw89_phy_cfg_bb_gain_op1db(struct rtw89_dev *rtwdev,
union rtw89_phy_bb_gain_arg arg, u32 data)
{
- struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain;
+ struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax;
u8 type = arg.type;
u8 path = arg.path;
u8 gband = arg.gain_band;
@@ -1036,10 +1417,10 @@ rtw89_phy_cfg_bb_gain_op1db(struct rtw89_dev *rtwdev,
}
}
-static void rtw89_phy_config_bb_gain(struct rtw89_dev *rtwdev,
- const struct rtw89_reg2_def *reg,
- enum rtw89_rf_path rf_path,
- void *extra_data)
+static void rtw89_phy_config_bb_gain_ax(struct rtw89_dev *rtwdev,
+ const struct rtw89_reg2_def *reg,
+ enum rtw89_rf_path rf_path,
+ void *extra_data)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
union rtw89_phy_bb_gain_arg arg = { .addr = reg->addr };
@@ -1341,16 +1722,110 @@ 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);
+ if (rtwdev->dbcc_en)
+ rtw89_phy_init_reg(rtwdev, bb_table, rtw89_phy_config_bb_reg,
+ (void *)RTW89_PHY_1);
+
+ rtw89_chip_init_txpwr_unit(rtwdev);
+
+ 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);
- rtw89_phy_bb_reset(rtwdev, RTW89_PHY_0);
+ chip->phy_def->config_bb_gain, NULL);
+
+ rtw89_phy_bb_reset(rtwdev);
+}
+
+void rtw89_phy_init_bb_afe(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
+ const struct rtw89_fw_element_hdr *afe_elm = elm_info->afe;
+ const struct rtw89_phy_afe_info *info;
+ u32 action, cat, class;
+ u32 addr, mask, val;
+ u32 poll, rpt;
+ u32 n, i;
+
+ if (!afe_elm)
+ return;
+
+ n = le32_to_cpu(afe_elm->size) / sizeof(*info);
+
+ for (i = 0; i < n; i++) {
+ info = &afe_elm->u.afe.infos[i];
+
+ class = le32_to_cpu(info->class);
+ switch (class) {
+ case RTW89_FW_AFE_CLASS_P0:
+ case RTW89_FW_AFE_CLASS_P1:
+ case RTW89_FW_AFE_CLASS_CMN:
+ /* Currently support two paths */
+ break;
+ case RTW89_FW_AFE_CLASS_P2:
+ case RTW89_FW_AFE_CLASS_P3:
+ case RTW89_FW_AFE_CLASS_P4:
+ default:
+ rtw89_warn(rtwdev, "unexpected AFE class %u\n", class);
+ continue;
+ }
+
+ addr = le32_to_cpu(info->addr);
+ mask = le32_to_cpu(info->mask);
+ val = le32_to_cpu(info->val);
+ cat = le32_to_cpu(info->cat);
+ action = le32_to_cpu(info->action);
+
+ switch (action) {
+ case RTW89_FW_AFE_ACTION_WRITE:
+ switch (cat) {
+ case RTW89_FW_AFE_CAT_MAC:
+ case RTW89_FW_AFE_CAT_MAC1:
+ rtw89_write32_mask(rtwdev, addr, mask, val);
+ break;
+ case RTW89_FW_AFE_CAT_AFEDIG:
+ case RTW89_FW_AFE_CAT_AFEDIG1:
+ rtw89_write32_mask(rtwdev, addr, mask, val);
+ break;
+ case RTW89_FW_AFE_CAT_BB:
+ rtw89_phy_write32_idx(rtwdev, addr, mask, val, RTW89_PHY_0);
+ break;
+ case RTW89_FW_AFE_CAT_BB1:
+ rtw89_phy_write32_idx(rtwdev, addr, mask, val, RTW89_PHY_1);
+ break;
+ default:
+ rtw89_warn(rtwdev,
+ "unexpected AFE writing action %u\n", action);
+ break;
+ }
+ break;
+ case RTW89_FW_AFE_ACTION_POLL:
+ for (poll = 0; poll <= 10; poll++) {
+ /*
+ * For CAT_BB, AFE reads register with mcu_offset 0,
+ * so both CAT_MAC and CAT_BB use the same method.
+ */
+ rpt = rtw89_read32_mask(rtwdev, addr, mask);
+ if (rpt == val)
+ goto poll_done;
+
+ fsleep(1);
+ }
+ rtw89_warn(rtwdev, "failed to poll AFE cat=%u addr=0x%x mask=0x%x\n",
+ cat, addr, mask);
+poll_done:
+ break;
+ case RTW89_FW_AFE_ACTION_DELAY:
+ fsleep(addr);
+ break;
+ }
+ }
}
static u32 rtw89_phy_nctl_poll(struct rtw89_dev *rtwdev)
@@ -1364,6 +1839,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;
@@ -1374,7 +1850,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;
@@ -1389,10 +1866,9 @@ void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio)
kfree(rf_reg_info);
}
-static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev)
+static void rtw89_phy_preinit_rf_nctl_ax(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
- const struct rtw89_phy_table *nctl_table;
u32 val;
int ret;
@@ -1400,8 +1876,9 @@ static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev)
rtw89_phy_write32_set(rtwdev, R_IOQ_IQK_DPK, 0x3);
rtw89_phy_write32_set(rtwdev, R_GNT_BT_WGT_EN, 0x1);
rtw89_phy_write32_set(rtwdev, R_P0_PATH_RST, 0x8000000);
- rtw89_phy_write32_set(rtwdev, R_P1_PATH_RST, 0x8000000);
- if (chip->chip_id == RTL8852B)
+ if (chip->chip_id != RTL8851B)
+ rtw89_phy_write32_set(rtwdev, R_P1_PATH_RST, 0x8000000);
+ if (chip->chip_id == RTL8852B || chip->chip_id == RTL8852BT)
rtw89_phy_write32_set(rtwdev, R_IOQ_IQK_DPK, 0x2);
/* check 0x8080 */
@@ -1411,12 +1888,24 @@ static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev)
1000, false, rtwdev);
if (ret)
rtw89_err(rtwdev, "failed to poll nctl block\n");
+}
+
+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;
+
+ rtw89_phy_preinit_rf_nctl(rtwdev);
- 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)
+ rtw89_rfk_parser(rtwdev, chip->nctl_post_table);
}
-static u32 rtw89_phy0_phy1_offset(struct rtw89_dev *rtwdev, u32 addr)
+static u32 rtw89_phy0_phy1_offset_ax(struct rtw89_dev *rtwdev, u32 addr)
{
u32 phy_page = addr >> 8;
u32 ofst = 0;
@@ -1456,6 +1945,24 @@ void rtw89_phy_write32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask,
}
EXPORT_SYMBOL(rtw89_phy_write32_idx);
+void rtw89_phy_write32_idx_set(struct rtw89_dev *rtwdev, u32 addr, u32 bits,
+ enum rtw89_phy_idx phy_idx)
+{
+ if (rtwdev->dbcc_en && phy_idx == RTW89_PHY_1)
+ addr += rtw89_phy0_phy1_offset(rtwdev, addr);
+ rtw89_phy_write32_set(rtwdev, addr, bits);
+}
+EXPORT_SYMBOL(rtw89_phy_write32_idx_set);
+
+void rtw89_phy_write32_idx_clr(struct rtw89_dev *rtwdev, u32 addr, u32 bits,
+ enum rtw89_phy_idx phy_idx)
+{
+ if (rtwdev->dbcc_en && phy_idx == RTW89_PHY_1)
+ addr += rtw89_phy0_phy1_offset(rtwdev, addr);
+ rtw89_phy_write32_clr(rtwdev, addr, bits);
+}
+EXPORT_SYMBOL(rtw89_phy_write32_idx_clr);
+
u32 rtw89_phy_read32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask,
enum rtw89_phy_idx phy_idx)
{
@@ -1475,6 +1982,7 @@ void rtw89_phy_set_phy_regs(struct rtw89_dev *rtwdev, u32 addr, u32 mask,
rtw89_phy_write32_idx(rtwdev, addr, mask, val, RTW89_PHY_1);
}
+EXPORT_SYMBOL(rtw89_phy_set_phy_regs);
void rtw89_phy_write_reg3_tbl(struct rtw89_dev *rtwdev,
const struct rtw89_phy_reg3_tbl *tbl)
@@ -1489,84 +1997,342 @@ void rtw89_phy_write_reg3_tbl(struct rtw89_dev *rtwdev,
}
EXPORT_SYMBOL(rtw89_phy_write_reg3_tbl);
-static const u8 rtw89_rs_idx_max[] = {
- [RTW89_RS_CCK] = RTW89_RATE_CCK_MAX,
- [RTW89_RS_OFDM] = RTW89_RATE_OFDM_MAX,
- [RTW89_RS_MCS] = RTW89_RATE_MCS_MAX,
- [RTW89_RS_HEDCM] = RTW89_RATE_HEDCM_MAX,
- [RTW89_RS_OFFSET] = RTW89_RATE_OFFSET_MAX,
+static u8 rtw89_phy_ant_gain_domain_to_regd(struct rtw89_dev *rtwdev, u8 ant_gain_regd)
+{
+ switch (ant_gain_regd) {
+ case RTW89_ANT_GAIN_ETSI:
+ return RTW89_ETSI;
+ default:
+ rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
+ "unknown antenna gain domain: %d\n",
+ ant_gain_regd);
+ return RTW89_REGD_NUM;
+ }
+}
+
+/* antenna gain in unit of 0.25 dbm */
+#define RTW89_ANT_GAIN_2GHZ_MIN -8
+#define RTW89_ANT_GAIN_2GHZ_MAX 14
+#define RTW89_ANT_GAIN_5GHZ_MIN -8
+#define RTW89_ANT_GAIN_5GHZ_MAX 20
+#define RTW89_ANT_GAIN_6GHZ_MIN -8
+#define RTW89_ANT_GAIN_6GHZ_MAX 20
+
+#define RTW89_ANT_GAIN_REF_2GHZ 14
+#define RTW89_ANT_GAIN_REF_5GHZ 20
+#define RTW89_ANT_GAIN_REF_6GHZ 20
+
+void rtw89_phy_ant_gain_init(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_ant_gain_info *ant_gain = &rtwdev->ant_gain;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_acpi_rtag_result res = {};
+ u32 domain;
+ int ret;
+ u8 i, j;
+ u8 regd;
+ u8 val;
+
+ if (!chip->support_ant_gain)
+ return;
+
+ ret = rtw89_acpi_evaluate_rtag(rtwdev, &res);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
+ "acpi: cannot eval rtag: %d\n", ret);
+ return;
+ }
+
+ if (res.revision != 0) {
+ rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
+ "unknown rtag revision: %d\n", res.revision);
+ return;
+ }
+
+ domain = get_unaligned_le32(&res.domain);
+
+ for (i = 0; i < RTW89_ANT_GAIN_DOMAIN_NUM; i++) {
+ if (!(domain & BIT(i)))
+ continue;
+
+ regd = rtw89_phy_ant_gain_domain_to_regd(rtwdev, i);
+ if (regd >= RTW89_REGD_NUM)
+ continue;
+ ant_gain->regd_enabled |= BIT(regd);
+ }
+
+ for (i = 0; i < RTW89_ANT_GAIN_CHAIN_NUM; i++) {
+ for (j = 0; j < RTW89_ANT_GAIN_SUBBAND_NR; j++) {
+ val = res.ant_gain_table[i][j];
+ switch (j) {
+ default:
+ case RTW89_ANT_GAIN_2GHZ_SUBBAND:
+ val = RTW89_ANT_GAIN_REF_2GHZ -
+ clamp_t(s8, val,
+ RTW89_ANT_GAIN_2GHZ_MIN,
+ RTW89_ANT_GAIN_2GHZ_MAX);
+ break;
+ case RTW89_ANT_GAIN_5GHZ_SUBBAND_1:
+ case RTW89_ANT_GAIN_5GHZ_SUBBAND_2:
+ case RTW89_ANT_GAIN_5GHZ_SUBBAND_2E:
+ case RTW89_ANT_GAIN_5GHZ_SUBBAND_3_4:
+ val = RTW89_ANT_GAIN_REF_5GHZ -
+ clamp_t(s8, val,
+ RTW89_ANT_GAIN_5GHZ_MIN,
+ RTW89_ANT_GAIN_5GHZ_MAX);
+ break;
+ case RTW89_ANT_GAIN_6GHZ_SUBBAND_5_L:
+ case RTW89_ANT_GAIN_6GHZ_SUBBAND_5_H:
+ case RTW89_ANT_GAIN_6GHZ_SUBBAND_6:
+ case RTW89_ANT_GAIN_6GHZ_SUBBAND_7_L:
+ case RTW89_ANT_GAIN_6GHZ_SUBBAND_7_H:
+ case RTW89_ANT_GAIN_6GHZ_SUBBAND_8:
+ val = RTW89_ANT_GAIN_REF_6GHZ -
+ clamp_t(s8, val,
+ RTW89_ANT_GAIN_6GHZ_MIN,
+ RTW89_ANT_GAIN_6GHZ_MAX);
+ }
+ ant_gain->offset[i][j] = val;
+ }
+ }
+}
+
+static
+enum rtw89_ant_gain_subband rtw89_phy_ant_gain_get_subband(struct rtw89_dev *rtwdev,
+ u32 center_freq)
+{
+ switch (center_freq) {
+ default:
+ rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
+ "center freq: %u to antenna gain subband is unhandled\n",
+ center_freq);
+ fallthrough;
+ case 2412 ... 2484:
+ return RTW89_ANT_GAIN_2GHZ_SUBBAND;
+ case 5180 ... 5240:
+ return RTW89_ANT_GAIN_5GHZ_SUBBAND_1;
+ case 5250 ... 5320:
+ return RTW89_ANT_GAIN_5GHZ_SUBBAND_2;
+ case 5500 ... 5720:
+ return RTW89_ANT_GAIN_5GHZ_SUBBAND_2E;
+ case 5745 ... 5885:
+ return RTW89_ANT_GAIN_5GHZ_SUBBAND_3_4;
+ case 5955 ... 6155:
+ return RTW89_ANT_GAIN_6GHZ_SUBBAND_5_L;
+ case 6175 ... 6415:
+ return RTW89_ANT_GAIN_6GHZ_SUBBAND_5_H;
+ case 6435 ... 6515:
+ return RTW89_ANT_GAIN_6GHZ_SUBBAND_6;
+ case 6535 ... 6695:
+ return RTW89_ANT_GAIN_6GHZ_SUBBAND_7_L;
+ case 6715 ... 6855:
+ return RTW89_ANT_GAIN_6GHZ_SUBBAND_7_H;
+
+ /* freq 6875 (ch 185, 20MHz) spans RTW89_ANT_GAIN_6GHZ_SUBBAND_7_H
+ * and RTW89_ANT_GAIN_6GHZ_SUBBAND_8, so directly describe it with
+ * struct rtw89_6ghz_span.
+ */
+
+ case 6895 ... 7115:
+ return RTW89_ANT_GAIN_6GHZ_SUBBAND_8;
+ }
+}
+
+static s8 rtw89_phy_ant_gain_query(struct rtw89_dev *rtwdev,
+ enum rtw89_rf_path path, u32 center_freq)
+{
+ struct rtw89_ant_gain_info *ant_gain = &rtwdev->ant_gain;
+ enum rtw89_ant_gain_subband subband_l, subband_h;
+ const struct rtw89_6ghz_span *span;
+
+ span = rtw89_get_6ghz_span(rtwdev, center_freq);
+
+ if (span && RTW89_ANT_GAIN_SPAN_VALID(span)) {
+ subband_l = span->ant_gain_subband_low;
+ subband_h = span->ant_gain_subband_high;
+ } else {
+ subband_l = rtw89_phy_ant_gain_get_subband(rtwdev, center_freq);
+ subband_h = subband_l;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
+ "center_freq %u: antenna gain subband {%u, %u}\n",
+ center_freq, subband_l, subband_h);
+
+ return min(ant_gain->offset[path][subband_l],
+ ant_gain->offset[path][subband_h]);
+}
+
+static s8 rtw89_phy_ant_gain_offset(struct rtw89_dev *rtwdev, u32 center_freq)
+{
+ s8 offset_patha, offset_pathb;
+
+ offset_patha = rtw89_phy_ant_gain_query(rtwdev, RF_PATH_A, center_freq);
+ offset_pathb = rtw89_phy_ant_gain_query(rtwdev, RF_PATH_B, center_freq);
+
+ if (RTW89_CHK_FW_FEATURE(NO_POWER_DIFFERENCE, &rtwdev->fw))
+ return min(offset_patha, offset_pathb);
+
+ return max(offset_patha, offset_pathb);
+}
+
+static bool rtw89_can_apply_ant_gain(struct rtw89_dev *rtwdev, u8 band)
+{
+ const struct rtw89_rfe_parms *rfe_parms = rtwdev->rfe_parms;
+ struct rtw89_ant_gain_info *ant_gain = &rtwdev->ant_gain;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ u8 regd = rtw89_regd_get(rtwdev, band);
+
+ if (!chip->support_ant_gain)
+ return false;
+
+ if (ant_gain->block_country || !(ant_gain->regd_enabled & BIT(regd)))
+ return false;
+
+ if (!rfe_parms->has_da)
+ return false;
+
+ return true;
+}
+
+s16 rtw89_phy_ant_gain_pwr_offset(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan)
+{
+ s8 offset_patha, offset_pathb;
+
+ if (!rtw89_can_apply_ant_gain(rtwdev, chan->band_type))
+ return 0;
+
+ if (RTW89_CHK_FW_FEATURE(NO_POWER_DIFFERENCE, &rtwdev->fw))
+ return 0;
+
+ offset_patha = rtw89_phy_ant_gain_query(rtwdev, RF_PATH_A, chan->freq);
+ offset_pathb = rtw89_phy_ant_gain_query(rtwdev, RF_PATH_B, chan->freq);
+
+ return rtw89_phy_txpwr_rf_to_bb(rtwdev, offset_patha - offset_pathb);
+}
+EXPORT_SYMBOL(rtw89_phy_ant_gain_pwr_offset);
+
+int rtw89_print_ant_gain(struct rtw89_dev *rtwdev, char *buf, size_t bufsz,
+ const struct rtw89_chan *chan)
+{
+ char *p = buf, *end = buf + bufsz;
+ s8 offset_patha, offset_pathb;
+
+ if (!rtw89_can_apply_ant_gain(rtwdev, chan->band_type)) {
+ p += scnprintf(p, end - p, "no DAG is applied\n");
+ goto out;
+ }
+
+ offset_patha = rtw89_phy_ant_gain_query(rtwdev, RF_PATH_A, chan->freq);
+ offset_pathb = rtw89_phy_ant_gain_query(rtwdev, RF_PATH_B, chan->freq);
+
+ p += scnprintf(p, end - p, "ChainA offset: %d dBm\n", offset_patha);
+ p += scnprintf(p, end - p, "ChainB offset: %d dBm\n", offset_pathb);
+
+out:
+ return p - buf;
+}
+
+static const u8 rtw89_rs_idx_num_ax[] = {
+ [RTW89_RS_CCK] = RTW89_RATE_CCK_NUM,
+ [RTW89_RS_OFDM] = RTW89_RATE_OFDM_NUM,
+ [RTW89_RS_MCS] = RTW89_RATE_MCS_NUM_AX,
+ [RTW89_RS_HEDCM] = RTW89_RATE_HEDCM_NUM,
+ [RTW89_RS_OFFSET] = RTW89_RATE_OFFSET_NUM_AX,
};
-static const u8 rtw89_rs_nss_max[] = {
+static const u8 rtw89_rs_nss_num_ax[] = {
[RTW89_RS_CCK] = 1,
[RTW89_RS_OFDM] = 1,
- [RTW89_RS_MCS] = RTW89_NSS_MAX,
- [RTW89_RS_HEDCM] = RTW89_NSS_HEDCM_MAX,
+ [RTW89_RS_MCS] = RTW89_NSS_NUM,
+ [RTW89_RS_HEDCM] = RTW89_NSS_HEDCM_NUM,
[RTW89_RS_OFFSET] = 1,
};
-static const u8 _byr_of_rs[] = {
- [RTW89_RS_CCK] = offsetof(struct rtw89_txpwr_byrate, cck),
- [RTW89_RS_OFDM] = offsetof(struct rtw89_txpwr_byrate, ofdm),
- [RTW89_RS_MCS] = offsetof(struct rtw89_txpwr_byrate, mcs),
- [RTW89_RS_HEDCM] = offsetof(struct rtw89_txpwr_byrate, hedcm),
- [RTW89_RS_OFFSET] = offsetof(struct rtw89_txpwr_byrate, offset),
-};
-
-#define _byr_seek(rs, raw) ((s8 *)(raw) + _byr_of_rs[rs])
-#define _byr_idx(rs, nss, idx) ((nss) * rtw89_rs_idx_max[rs] + (idx))
-#define _byr_chk(rs, nss, idx) \
- ((nss) < rtw89_rs_nss_max[rs] && (idx) < rtw89_rs_idx_max[rs])
+s8 *rtw89_phy_raw_byr_seek(struct rtw89_dev *rtwdev,
+ struct rtw89_txpwr_byrate *head,
+ const struct rtw89_rate_desc *desc)
+{
+ switch (desc->rs) {
+ case RTW89_RS_CCK:
+ return &head->cck[desc->idx];
+ case RTW89_RS_OFDM:
+ return &head->ofdm[desc->idx];
+ case RTW89_RS_MCS:
+ return &head->mcs[desc->ofdma][desc->nss][desc->idx];
+ case RTW89_RS_HEDCM:
+ return &head->hedcm[desc->ofdma][desc->nss][desc->idx];
+ case RTW89_RS_OFFSET:
+ return &head->offset[desc->idx];
+ default:
+ rtw89_warn(rtwdev, "unrecognized byr rs: %d\n", desc->rs);
+ return &head->trap;
+ }
+}
void rtw89_phy_load_txpwr_byrate(struct rtw89_dev *rtwdev,
const struct rtw89_txpwr_table *tbl)
{
const struct rtw89_txpwr_byrate_cfg *cfg = tbl->data;
const struct rtw89_txpwr_byrate_cfg *end = cfg + tbl->size;
+ struct rtw89_txpwr_byrate *byr_head;
+ struct rtw89_rate_desc desc = {};
s8 *byr;
u32 data;
- u8 i, idx;
+ u8 i;
for (; cfg < end; cfg++) {
- byr = _byr_seek(cfg->rs, &rtwdev->byr[cfg->band]);
+ byr_head = &rtwdev->byr[cfg->band][0];
+ desc.rs = cfg->rs;
+ desc.nss = cfg->nss;
data = cfg->data;
for (i = 0; i < cfg->len; i++, data >>= 8) {
- idx = _byr_idx(cfg->rs, cfg->nss, (cfg->shf + i));
- byr[idx] = (s8)(data & 0xff);
+ desc.idx = cfg->shf + i;
+ byr = rtw89_phy_raw_byr_seek(rtwdev, byr_head, &desc);
+ *byr = data & 0xff;
}
}
}
EXPORT_SYMBOL(rtw89_phy_load_txpwr_byrate);
-#define _phy_txpwr_rf_to_mac(rtwdev, txpwr_rf) \
-({ \
- const struct rtw89_chip_info *__c = (rtwdev)->chip; \
- (txpwr_rf) >> (__c->txpwr_factor_rf - __c->txpwr_factor_mac); \
-})
+static s8 rtw89_phy_txpwr_dbm_without_tolerance(s8 dbm)
+{
+ const u8 tssi_deviation_point = 0;
+ const u8 tssi_max_deviation = 2;
-static
-s8 rtw89_phy_read_txpwr_byrate(struct rtw89_dev *rtwdev, u8 band,
+ if (dbm <= tssi_deviation_point)
+ dbm -= tssi_max_deviation;
+
+ return dbm;
+}
+
+static s8 rtw89_phy_get_tpe_constraint(struct rtw89_dev *rtwdev, u8 band)
+{
+ struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
+ const struct rtw89_reg_6ghz_tpe *tpe = &regulatory->reg_6ghz_tpe;
+ s8 cstr = S8_MAX;
+
+ if (band == RTW89_BAND_6G && tpe->valid)
+ cstr = rtw89_phy_txpwr_dbm_without_tolerance(tpe->constraint);
+
+ return rtw89_phy_txpwr_dbm_to_mac(rtwdev, cstr);
+}
+
+s8 rtw89_phy_read_txpwr_byrate(struct rtw89_dev *rtwdev, u8 band, u8 bw,
const struct rtw89_rate_desc *rate_desc)
{
+ struct rtw89_txpwr_byrate *byr_head;
s8 *byr;
- u8 idx;
if (rate_desc->rs == RTW89_RS_CCK)
band = RTW89_BAND_2G;
- if (!_byr_chk(rate_desc->rs, rate_desc->nss, rate_desc->idx)) {
- rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
- "[TXPWR] unknown byrate desc rs=%d nss=%d idx=%d\n",
- rate_desc->rs, rate_desc->nss, rate_desc->idx);
-
- return 0;
- }
+ byr_head = &rtwdev->byr[band][bw];
+ byr = rtw89_phy_raw_byr_seek(rtwdev, byr_head, rate_desc);
- byr = _byr_seek(rate_desc->rs, &rtwdev->byr[band]);
- idx = _byr_idx(rate_desc->rs, rate_desc->nss, rate_desc->idx);
-
- return _phy_txpwr_rf_to_mac(rtwdev, byr[idx]);
+ return rtw89_phy_txpwr_rf_to_mac(rtwdev, *byr);
}
static u8 rtw89_channel_6g_to_idx(struct rtw89_dev *rtwdev, u8 channel_6g)
@@ -1614,19 +2380,55 @@ static u8 rtw89_channel_to_idx(struct rtw89_dev *rtwdev, u8 band, u8 channel)
}
}
+static bool rtw89_phy_validate_txpwr_limit_bw(struct rtw89_dev *rtwdev,
+ u8 band, u8 bw)
+{
+ switch (band) {
+ case RTW89_BAND_2G:
+ return bw < RTW89_2G_BW_NUM;
+ case RTW89_BAND_5G:
+ return bw < RTW89_5G_BW_NUM;
+ case RTW89_BAND_6G:
+ return bw < RTW89_6G_BW_NUM;
+ default:
+ return false;
+ }
+}
+
s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band,
u8 bw, u8 ntx, u8 rs, u8 bf, u8 ch)
{
const struct rtw89_rfe_parms *rfe_parms = rtwdev->rfe_parms;
+ const struct rtw89_txpwr_rule_2ghz *rule_da_2ghz = &rfe_parms->rule_da_2ghz;
+ const struct rtw89_txpwr_rule_5ghz *rule_da_5ghz = &rfe_parms->rule_da_5ghz;
+ const struct rtw89_txpwr_rule_6ghz *rule_da_6ghz = &rfe_parms->rule_da_6ghz;
const struct rtw89_txpwr_rule_2ghz *rule_2ghz = &rfe_parms->rule_2ghz;
const struct rtw89_txpwr_rule_5ghz *rule_5ghz = &rfe_parms->rule_5ghz;
const struct rtw89_txpwr_rule_6ghz *rule_6ghz = &rfe_parms->rule_6ghz;
+ struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
+ enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band);
+ bool has_ant_gain = rtw89_can_apply_ant_gain(rtwdev, band);
+ u32 freq = ieee80211_channel_to_frequency(ch, nl_band);
u8 ch_idx = rtw89_channel_to_idx(rtwdev, band, ch);
+ s8 lmt = 0, da_lmt = S8_MAX, sar, offset = 0;
u8 regd = rtw89_regd_get(rtwdev, band);
- s8 lmt = 0, sar;
+ u8 reg6 = regulatory->reg_6ghz_power;
+ struct rtw89_sar_parm sar_parm = {
+ .center_freq = freq,
+ .ntx = ntx,
+ };
+ s8 cstr;
+
+ if (!rtw89_phy_validate_txpwr_limit_bw(rtwdev, band, bw)) {
+ rtw89_warn(rtwdev, "invalid band %u bandwidth %u\n", band, bw);
+ return 0;
+ }
switch (band) {
case RTW89_BAND_2G:
+ if (has_ant_gain)
+ da_lmt = (*rule_da_2ghz->lmt)[bw][ntx][rs][bf][regd][ch_idx];
+
lmt = (*rule_2ghz->lmt)[bw][ntx][rs][bf][regd][ch_idx];
if (lmt)
break;
@@ -1634,6 +2436,9 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band,
lmt = (*rule_2ghz->lmt)[bw][ntx][rs][bf][RTW89_WW][ch_idx];
break;
case RTW89_BAND_5G:
+ if (has_ant_gain)
+ da_lmt = (*rule_da_5ghz->lmt)[bw][ntx][rs][bf][regd][ch_idx];
+
lmt = (*rule_5ghz->lmt)[bw][ntx][rs][bf][regd][ch_idx];
if (lmt)
break;
@@ -1641,21 +2446,31 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band,
lmt = (*rule_5ghz->lmt)[bw][ntx][rs][bf][RTW89_WW][ch_idx];
break;
case RTW89_BAND_6G:
- lmt = (*rule_6ghz->lmt)[bw][ntx][rs][bf][regd][ch_idx];
+ if (has_ant_gain)
+ da_lmt = (*rule_da_6ghz->lmt)[bw][ntx][rs][bf][regd][reg6][ch_idx];
+
+ lmt = (*rule_6ghz->lmt)[bw][ntx][rs][bf][regd][reg6][ch_idx];
if (lmt)
break;
- lmt = (*rule_6ghz->lmt)[bw][ntx][rs][bf][RTW89_WW][ch_idx];
+ lmt = (*rule_6ghz->lmt)[bw][ntx][rs][bf][RTW89_WW]
+ [RTW89_REG_6GHZ_POWER_DFLT]
+ [ch_idx];
break;
default:
rtw89_warn(rtwdev, "unknown band type: %d\n", band);
return 0;
}
- lmt = _phy_txpwr_rf_to_mac(rtwdev, lmt);
- sar = rtw89_query_sar(rtwdev);
+ da_lmt = da_lmt ?: S8_MAX;
+ if (da_lmt != S8_MAX)
+ offset = rtw89_phy_ant_gain_offset(rtwdev, freq);
+
+ lmt = rtw89_phy_txpwr_rf_to_mac(rtwdev, min(lmt + offset, da_lmt));
+ sar = rtw89_query_sar(rtwdev, &sar_parm);
+ cstr = rtw89_phy_get_tpe_constraint(rtwdev, band);
- return min(lmt, sar);
+ return min3(lmt, sar, cstr);
}
EXPORT_SYMBOL(rtw89_phy_read_txpwr_limit);
@@ -1670,9 +2485,9 @@ EXPORT_SYMBOL(rtw89_phy_read_txpwr_limit);
(ch)); \
} while (0)
-static void rtw89_phy_fill_txpwr_limit_20m(struct rtw89_dev *rtwdev,
- struct rtw89_txpwr_limit *lmt,
- u8 band, u8 ntx, u8 ch)
+static void rtw89_phy_fill_txpwr_limit_20m_ax(struct rtw89_dev *rtwdev,
+ struct rtw89_txpwr_limit_ax *lmt,
+ u8 band, u8 ntx, u8 ch)
{
__fill_txpwr_limit_nonbf_bf(lmt->cck_20m, band, RTW89_CHANNEL_WIDTH_20,
ntx, RTW89_RS_CCK, ch);
@@ -1685,9 +2500,9 @@ static void rtw89_phy_fill_txpwr_limit_20m(struct rtw89_dev *rtwdev,
ntx, RTW89_RS_MCS, ch);
}
-static void rtw89_phy_fill_txpwr_limit_40m(struct rtw89_dev *rtwdev,
- struct rtw89_txpwr_limit *lmt,
- u8 band, u8 ntx, u8 ch, u8 pri_ch)
+static void rtw89_phy_fill_txpwr_limit_40m_ax(struct rtw89_dev *rtwdev,
+ struct rtw89_txpwr_limit_ax *lmt,
+ u8 band, u8 ntx, u8 ch, u8 pri_ch)
{
__fill_txpwr_limit_nonbf_bf(lmt->cck_20m, band, RTW89_CHANNEL_WIDTH_20,
ntx, RTW89_RS_CCK, ch - 2);
@@ -1706,9 +2521,9 @@ static void rtw89_phy_fill_txpwr_limit_40m(struct rtw89_dev *rtwdev,
ntx, RTW89_RS_MCS, ch);
}
-static void rtw89_phy_fill_txpwr_limit_80m(struct rtw89_dev *rtwdev,
- struct rtw89_txpwr_limit *lmt,
- u8 band, u8 ntx, u8 ch, u8 pri_ch)
+static void rtw89_phy_fill_txpwr_limit_80m_ax(struct rtw89_dev *rtwdev,
+ struct rtw89_txpwr_limit_ax *lmt,
+ u8 band, u8 ntx, u8 ch, u8 pri_ch)
{
s8 val_0p5_n[RTW89_BF_NUM];
s8 val_0p5_p[RTW89_BF_NUM];
@@ -1747,9 +2562,9 @@ static void rtw89_phy_fill_txpwr_limit_80m(struct rtw89_dev *rtwdev,
lmt->mcs_40m_0p5[i] = min_t(s8, val_0p5_n[i], val_0p5_p[i]);
}
-static void rtw89_phy_fill_txpwr_limit_160m(struct rtw89_dev *rtwdev,
- struct rtw89_txpwr_limit *lmt,
- u8 band, u8 ntx, u8 ch, u8 pri_ch)
+static void rtw89_phy_fill_txpwr_limit_160m_ax(struct rtw89_dev *rtwdev,
+ struct rtw89_txpwr_limit_ax *lmt,
+ u8 band, u8 ntx, u8 ch, u8 pri_ch)
{
s8 val_0p5_n[RTW89_BF_NUM];
s8 val_0p5_p[RTW89_BF_NUM];
@@ -1834,10 +2649,10 @@ static void rtw89_phy_fill_txpwr_limit_160m(struct rtw89_dev *rtwdev,
}
static
-void rtw89_phy_fill_txpwr_limit(struct rtw89_dev *rtwdev,
- const struct rtw89_chan *chan,
- struct rtw89_txpwr_limit *lmt,
- u8 ntx)
+void rtw89_phy_fill_txpwr_limit_ax(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ struct rtw89_txpwr_limit_ax *lmt,
+ u8 ntx)
{
u8 band = chan->band_type;
u8 pri_ch = chan->primary_channel;
@@ -1848,36 +2663,52 @@ void rtw89_phy_fill_txpwr_limit(struct rtw89_dev *rtwdev,
switch (bw) {
case RTW89_CHANNEL_WIDTH_20:
- rtw89_phy_fill_txpwr_limit_20m(rtwdev, lmt, band, ntx, ch);
+ rtw89_phy_fill_txpwr_limit_20m_ax(rtwdev, lmt, band, ntx, ch);
break;
case RTW89_CHANNEL_WIDTH_40:
- rtw89_phy_fill_txpwr_limit_40m(rtwdev, lmt, band, ntx, ch,
- pri_ch);
+ rtw89_phy_fill_txpwr_limit_40m_ax(rtwdev, lmt, band, ntx, ch,
+ pri_ch);
break;
case RTW89_CHANNEL_WIDTH_80:
- rtw89_phy_fill_txpwr_limit_80m(rtwdev, lmt, band, ntx, ch,
- pri_ch);
+ rtw89_phy_fill_txpwr_limit_80m_ax(rtwdev, lmt, band, ntx, ch,
+ pri_ch);
break;
case RTW89_CHANNEL_WIDTH_160:
- rtw89_phy_fill_txpwr_limit_160m(rtwdev, lmt, band, ntx, ch,
- pri_ch);
+ rtw89_phy_fill_txpwr_limit_160m_ax(rtwdev, lmt, band, ntx, ch,
+ pri_ch);
break;
}
}
-static s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band,
- u8 ru, u8 ntx, u8 ch)
+s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band,
+ u8 ru, u8 ntx, u8 ch)
{
const struct rtw89_rfe_parms *rfe_parms = rtwdev->rfe_parms;
+ const struct rtw89_txpwr_rule_2ghz *rule_da_2ghz = &rfe_parms->rule_da_2ghz;
+ const struct rtw89_txpwr_rule_5ghz *rule_da_5ghz = &rfe_parms->rule_da_5ghz;
+ const struct rtw89_txpwr_rule_6ghz *rule_da_6ghz = &rfe_parms->rule_da_6ghz;
const struct rtw89_txpwr_rule_2ghz *rule_2ghz = &rfe_parms->rule_2ghz;
const struct rtw89_txpwr_rule_5ghz *rule_5ghz = &rfe_parms->rule_5ghz;
const struct rtw89_txpwr_rule_6ghz *rule_6ghz = &rfe_parms->rule_6ghz;
+ struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
+ enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band);
+ bool has_ant_gain = rtw89_can_apply_ant_gain(rtwdev, band);
+ u32 freq = ieee80211_channel_to_frequency(ch, nl_band);
u8 ch_idx = rtw89_channel_to_idx(rtwdev, band, ch);
+ s8 lmt_ru = 0, da_lmt_ru = S8_MAX, sar, offset = 0;
u8 regd = rtw89_regd_get(rtwdev, band);
- s8 lmt_ru = 0, sar;
+ u8 reg6 = regulatory->reg_6ghz_power;
+ struct rtw89_sar_parm sar_parm = {
+ .center_freq = freq,
+ .ntx = ntx,
+ };
+ s8 cstr;
switch (band) {
case RTW89_BAND_2G:
+ if (has_ant_gain)
+ da_lmt_ru = (*rule_da_2ghz->lmt_ru)[ru][ntx][regd][ch_idx];
+
lmt_ru = (*rule_2ghz->lmt_ru)[ru][ntx][regd][ch_idx];
if (lmt_ru)
break;
@@ -1885,6 +2716,9 @@ static s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band,
lmt_ru = (*rule_2ghz->lmt_ru)[ru][ntx][RTW89_WW][ch_idx];
break;
case RTW89_BAND_5G:
+ if (has_ant_gain)
+ da_lmt_ru = (*rule_da_5ghz->lmt_ru)[ru][ntx][regd][ch_idx];
+
lmt_ru = (*rule_5ghz->lmt_ru)[ru][ntx][regd][ch_idx];
if (lmt_ru)
break;
@@ -1892,27 +2726,37 @@ static s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band,
lmt_ru = (*rule_5ghz->lmt_ru)[ru][ntx][RTW89_WW][ch_idx];
break;
case RTW89_BAND_6G:
- lmt_ru = (*rule_6ghz->lmt_ru)[ru][ntx][regd][ch_idx];
+ if (has_ant_gain)
+ da_lmt_ru = (*rule_da_6ghz->lmt_ru)[ru][ntx][regd][reg6][ch_idx];
+
+ lmt_ru = (*rule_6ghz->lmt_ru)[ru][ntx][regd][reg6][ch_idx];
if (lmt_ru)
break;
- lmt_ru = (*rule_6ghz->lmt_ru)[ru][ntx][RTW89_WW][ch_idx];
+ lmt_ru = (*rule_6ghz->lmt_ru)[ru][ntx][RTW89_WW]
+ [RTW89_REG_6GHZ_POWER_DFLT]
+ [ch_idx];
break;
default:
rtw89_warn(rtwdev, "unknown band type: %d\n", band);
return 0;
}
- lmt_ru = _phy_txpwr_rf_to_mac(rtwdev, lmt_ru);
- sar = rtw89_query_sar(rtwdev);
+ da_lmt_ru = da_lmt_ru ?: S8_MAX;
+ if (da_lmt_ru != S8_MAX)
+ offset = rtw89_phy_ant_gain_offset(rtwdev, freq);
- return min(lmt_ru, sar);
+ lmt_ru = rtw89_phy_txpwr_rf_to_mac(rtwdev, min(lmt_ru + offset, da_lmt_ru));
+ sar = rtw89_query_sar(rtwdev, &sar_parm);
+ cstr = rtw89_phy_get_tpe_constraint(rtwdev, band);
+
+ return min3(lmt_ru, sar, cstr);
}
static void
-rtw89_phy_fill_txpwr_limit_ru_20m(struct rtw89_dev *rtwdev,
- struct rtw89_txpwr_limit_ru *lmt_ru,
- u8 band, u8 ntx, u8 ch)
+rtw89_phy_fill_txpwr_limit_ru_20m_ax(struct rtw89_dev *rtwdev,
+ struct rtw89_txpwr_limit_ru_ax *lmt_ru,
+ u8 band, u8 ntx, u8 ch)
{
lmt_ru->ru26[0] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
RTW89_RU26,
@@ -1926,9 +2770,9 @@ rtw89_phy_fill_txpwr_limit_ru_20m(struct rtw89_dev *rtwdev,
}
static void
-rtw89_phy_fill_txpwr_limit_ru_40m(struct rtw89_dev *rtwdev,
- struct rtw89_txpwr_limit_ru *lmt_ru,
- u8 band, u8 ntx, u8 ch)
+rtw89_phy_fill_txpwr_limit_ru_40m_ax(struct rtw89_dev *rtwdev,
+ struct rtw89_txpwr_limit_ru_ax *lmt_ru,
+ u8 band, u8 ntx, u8 ch)
{
lmt_ru->ru26[0] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
RTW89_RU26,
@@ -1951,9 +2795,9 @@ rtw89_phy_fill_txpwr_limit_ru_40m(struct rtw89_dev *rtwdev,
}
static void
-rtw89_phy_fill_txpwr_limit_ru_80m(struct rtw89_dev *rtwdev,
- struct rtw89_txpwr_limit_ru *lmt_ru,
- u8 band, u8 ntx, u8 ch)
+rtw89_phy_fill_txpwr_limit_ru_80m_ax(struct rtw89_dev *rtwdev,
+ struct rtw89_txpwr_limit_ru_ax *lmt_ru,
+ u8 band, u8 ntx, u8 ch)
{
lmt_ru->ru26[0] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
RTW89_RU26,
@@ -1994,15 +2838,15 @@ rtw89_phy_fill_txpwr_limit_ru_80m(struct rtw89_dev *rtwdev,
}
static void
-rtw89_phy_fill_txpwr_limit_ru_160m(struct rtw89_dev *rtwdev,
- struct rtw89_txpwr_limit_ru *lmt_ru,
- u8 band, u8 ntx, u8 ch)
+rtw89_phy_fill_txpwr_limit_ru_160m_ax(struct rtw89_dev *rtwdev,
+ struct rtw89_txpwr_limit_ru_ax *lmt_ru,
+ u8 band, u8 ntx, u8 ch)
{
static const int ofst[] = { -14, -10, -6, -2, 2, 6, 10, 14 };
int i;
- static_assert(ARRAY_SIZE(ofst) == RTW89_RU_SEC_NUM);
- for (i = 0; i < RTW89_RU_SEC_NUM; i++) {
+ static_assert(ARRAY_SIZE(ofst) == RTW89_RU_SEC_NUM_AX);
+ for (i = 0; i < RTW89_RU_SEC_NUM_AX; i++) {
lmt_ru->ru26[i] = rtw89_phy_read_txpwr_limit_ru(rtwdev, band,
RTW89_RU26,
ntx,
@@ -2019,10 +2863,10 @@ rtw89_phy_fill_txpwr_limit_ru_160m(struct rtw89_dev *rtwdev,
}
static
-void rtw89_phy_fill_txpwr_limit_ru(struct rtw89_dev *rtwdev,
- const struct rtw89_chan *chan,
- struct rtw89_txpwr_limit_ru *lmt_ru,
- u8 ntx)
+void rtw89_phy_fill_txpwr_limit_ru_ax(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ struct rtw89_txpwr_limit_ru_ax *lmt_ru,
+ u8 ntx)
{
u8 band = chan->band_type;
u8 ch = chan->channel;
@@ -2032,27 +2876,27 @@ void rtw89_phy_fill_txpwr_limit_ru(struct rtw89_dev *rtwdev,
switch (bw) {
case RTW89_CHANNEL_WIDTH_20:
- rtw89_phy_fill_txpwr_limit_ru_20m(rtwdev, lmt_ru, band, ntx,
- ch);
+ rtw89_phy_fill_txpwr_limit_ru_20m_ax(rtwdev, lmt_ru, band, ntx,
+ ch);
break;
case RTW89_CHANNEL_WIDTH_40:
- rtw89_phy_fill_txpwr_limit_ru_40m(rtwdev, lmt_ru, band, ntx,
- ch);
+ rtw89_phy_fill_txpwr_limit_ru_40m_ax(rtwdev, lmt_ru, band, ntx,
+ ch);
break;
case RTW89_CHANNEL_WIDTH_80:
- rtw89_phy_fill_txpwr_limit_ru_80m(rtwdev, lmt_ru, band, ntx,
- ch);
+ rtw89_phy_fill_txpwr_limit_ru_80m_ax(rtwdev, lmt_ru, band, ntx,
+ ch);
break;
case RTW89_CHANNEL_WIDTH_160:
- rtw89_phy_fill_txpwr_limit_ru_160m(rtwdev, lmt_ru, band, ntx,
- ch);
+ rtw89_phy_fill_txpwr_limit_ru_160m_ax(rtwdev, lmt_ru, band, ntx,
+ ch);
break;
}
}
-void rtw89_phy_set_txpwr_byrate(struct rtw89_dev *rtwdev,
- const struct rtw89_chan *chan,
- enum rtw89_phy_idx phy_idx)
+static void rtw89_phy_set_txpwr_byrate_ax(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
{
u8 max_nss_num = rtwdev->chip->rf_path_num;
static const u8 rs[] = {
@@ -2061,7 +2905,7 @@ void rtw89_phy_set_txpwr_byrate(struct rtw89_dev *rtwdev,
RTW89_RS_MCS,
RTW89_RS_HEDCM,
};
- struct rtw89_rate_desc cur;
+ struct rtw89_rate_desc cur = {};
u8 band = chan->band_type;
u8 ch = chan->channel;
u32 addr, val;
@@ -2071,23 +2915,23 @@ void rtw89_phy_set_txpwr_byrate(struct rtw89_dev *rtwdev,
rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
"[TXPWR] set txpwr byrate with ch=%d\n", ch);
- BUILD_BUG_ON(rtw89_rs_idx_max[RTW89_RS_CCK] % 4);
- BUILD_BUG_ON(rtw89_rs_idx_max[RTW89_RS_OFDM] % 4);
- BUILD_BUG_ON(rtw89_rs_idx_max[RTW89_RS_MCS] % 4);
- BUILD_BUG_ON(rtw89_rs_idx_max[RTW89_RS_HEDCM] % 4);
+ BUILD_BUG_ON(rtw89_rs_idx_num_ax[RTW89_RS_CCK] % 4);
+ BUILD_BUG_ON(rtw89_rs_idx_num_ax[RTW89_RS_OFDM] % 4);
+ BUILD_BUG_ON(rtw89_rs_idx_num_ax[RTW89_RS_MCS] % 4);
+ BUILD_BUG_ON(rtw89_rs_idx_num_ax[RTW89_RS_HEDCM] % 4);
addr = R_AX_PWR_BY_RATE;
for (cur.nss = 0; cur.nss < max_nss_num; cur.nss++) {
for (i = 0; i < ARRAY_SIZE(rs); i++) {
- if (cur.nss >= rtw89_rs_nss_max[rs[i]])
+ if (cur.nss >= rtw89_rs_nss_num_ax[rs[i]])
continue;
cur.rs = rs[i];
- for (cur.idx = 0; cur.idx < rtw89_rs_idx_max[rs[i]];
+ for (cur.idx = 0; cur.idx < rtw89_rs_idx_num_ax[rs[i]];
cur.idx++) {
v[cur.idx % 4] =
rtw89_phy_read_txpwr_byrate(rtwdev,
- band,
+ band, 0,
&cur);
if ((cur.idx + 1) % 4)
@@ -2105,26 +2949,26 @@ void rtw89_phy_set_txpwr_byrate(struct rtw89_dev *rtwdev,
}
}
}
-EXPORT_SYMBOL(rtw89_phy_set_txpwr_byrate);
-void rtw89_phy_set_txpwr_offset(struct rtw89_dev *rtwdev,
- const struct rtw89_chan *chan,
- enum rtw89_phy_idx phy_idx)
+static
+void rtw89_phy_set_txpwr_offset_ax(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
{
struct rtw89_rate_desc desc = {
.nss = RTW89_NSS_1,
.rs = RTW89_RS_OFFSET,
};
u8 band = chan->band_type;
- s8 v[RTW89_RATE_OFFSET_MAX] = {};
+ s8 v[RTW89_RATE_OFFSET_NUM_AX] = {};
u32 val;
rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set txpwr offset\n");
- for (desc.idx = 0; desc.idx < RTW89_RATE_OFFSET_MAX; desc.idx++)
- v[desc.idx] = rtw89_phy_read_txpwr_byrate(rtwdev, band, &desc);
+ for (desc.idx = 0; desc.idx < RTW89_RATE_OFFSET_NUM_AX; desc.idx++)
+ v[desc.idx] = rtw89_phy_read_txpwr_byrate(rtwdev, band, 0, &desc);
- BUILD_BUG_ON(RTW89_RATE_OFFSET_MAX != 5);
+ BUILD_BUG_ON(RTW89_RATE_OFFSET_NUM_AX != 5);
val = FIELD_PREP(GENMASK(3, 0), v[0]) |
FIELD_PREP(GENMASK(7, 4), v[1]) |
FIELD_PREP(GENMASK(11, 8), v[2]) |
@@ -2134,14 +2978,13 @@ void rtw89_phy_set_txpwr_offset(struct rtw89_dev *rtwdev,
rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_AX_PWR_RATE_OFST_CTRL,
GENMASK(19, 0), val);
}
-EXPORT_SYMBOL(rtw89_phy_set_txpwr_offset);
-void rtw89_phy_set_txpwr_limit(struct rtw89_dev *rtwdev,
- const struct rtw89_chan *chan,
- enum rtw89_phy_idx phy_idx)
+static void rtw89_phy_set_txpwr_limit_ax(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
{
u8 max_ntx_num = rtwdev->chip->rf_path_num;
- struct rtw89_txpwr_limit lmt;
+ struct rtw89_txpwr_limit_ax lmt;
u8 ch = chan->channel;
u8 bw = chan->band_width;
const s8 *ptr;
@@ -2151,15 +2994,15 @@ void rtw89_phy_set_txpwr_limit(struct rtw89_dev *rtwdev,
rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
"[TXPWR] set txpwr limit with ch=%d bw=%d\n", ch, bw);
- BUILD_BUG_ON(sizeof(struct rtw89_txpwr_limit) !=
- RTW89_TXPWR_LMT_PAGE_SIZE);
+ BUILD_BUG_ON(sizeof(struct rtw89_txpwr_limit_ax) !=
+ RTW89_TXPWR_LMT_PAGE_SIZE_AX);
addr = R_AX_PWR_LMT;
for (i = 0; i < max_ntx_num; i++) {
- rtw89_phy_fill_txpwr_limit(rtwdev, chan, &lmt, i);
+ rtw89_phy_fill_txpwr_limit_ax(rtwdev, chan, &lmt, i);
ptr = (s8 *)&lmt;
- for (j = 0; j < RTW89_TXPWR_LMT_PAGE_SIZE;
+ for (j = 0; j < RTW89_TXPWR_LMT_PAGE_SIZE_AX;
j += 4, addr += 4, ptr += 4) {
val = FIELD_PREP(GENMASK(7, 0), ptr[0]) |
FIELD_PREP(GENMASK(15, 8), ptr[1]) |
@@ -2170,14 +3013,13 @@ void rtw89_phy_set_txpwr_limit(struct rtw89_dev *rtwdev,
}
}
}
-EXPORT_SYMBOL(rtw89_phy_set_txpwr_limit);
-void rtw89_phy_set_txpwr_limit_ru(struct rtw89_dev *rtwdev,
- const struct rtw89_chan *chan,
- enum rtw89_phy_idx phy_idx)
+static void rtw89_phy_set_txpwr_limit_ru_ax(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
{
u8 max_ntx_num = rtwdev->chip->rf_path_num;
- struct rtw89_txpwr_limit_ru lmt_ru;
+ struct rtw89_txpwr_limit_ru_ax lmt_ru;
u8 ch = chan->channel;
u8 bw = chan->band_width;
const s8 *ptr;
@@ -2187,15 +3029,15 @@ void rtw89_phy_set_txpwr_limit_ru(struct rtw89_dev *rtwdev,
rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
"[TXPWR] set txpwr limit ru with ch=%d bw=%d\n", ch, bw);
- BUILD_BUG_ON(sizeof(struct rtw89_txpwr_limit_ru) !=
- RTW89_TXPWR_LMT_RU_PAGE_SIZE);
+ BUILD_BUG_ON(sizeof(struct rtw89_txpwr_limit_ru_ax) !=
+ RTW89_TXPWR_LMT_RU_PAGE_SIZE_AX);
addr = R_AX_PWR_RU_LMT;
for (i = 0; i < max_ntx_num; i++) {
- rtw89_phy_fill_txpwr_limit_ru(rtwdev, chan, &lmt_ru, i);
+ rtw89_phy_fill_txpwr_limit_ru_ax(rtwdev, chan, &lmt_ru, i);
ptr = (s8 *)&lmt_ru;
- for (j = 0; j < RTW89_TXPWR_LMT_RU_PAGE_SIZE;
+ for (j = 0; j < RTW89_TXPWR_LMT_RU_PAGE_SIZE_AX;
j += 4, addr += 4, ptr += 4) {
val = FIELD_PREP(GENMASK(7, 0), ptr[0]) |
FIELD_PREP(GENMASK(15, 8), ptr[1]) |
@@ -2206,36 +3048,48 @@ void rtw89_phy_set_txpwr_limit_ru(struct rtw89_dev *rtwdev,
}
}
}
-EXPORT_SYMBOL(rtw89_phy_set_txpwr_limit_ru);
struct rtw89_phy_iter_ra_data {
struct rtw89_dev *rtwdev;
struct sk_buff *c2h;
};
-static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta)
+static void __rtw89_phy_c2h_ra_rpt_iter(struct rtw89_sta_link *rtwsta_link,
+ struct ieee80211_link_sta *link_sta,
+ struct rtw89_phy_iter_ra_data *ra_data)
{
- struct rtw89_phy_iter_ra_data *ra_data = (struct rtw89_phy_iter_ra_data *)data;
struct rtw89_dev *rtwdev = ra_data->rtwdev;
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
- struct rtw89_ra_report *ra_report = &rtwsta->ra_report;
- struct sk_buff *c2h = ra_data->c2h;
+ const struct rtw89_c2h_ra_rpt *c2h =
+ (const struct rtw89_c2h_ra_rpt *)ra_data->c2h->data;
+ struct rtw89_ra_report *ra_report = &rtwsta_link->ra_report;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ bool format_v1 = chip->chip_gen == RTW89_CHIP_BE;
u8 mode, rate, bw, giltf, mac_id;
u16 legacy_bitrate;
bool valid;
u8 mcs = 0;
+ u8 t;
- mac_id = RTW89_GET_PHY_C2H_RA_RPT_MACID(c2h->data);
- if (mac_id != rtwsta->mac_id)
+ mac_id = le32_get_bits(c2h->w2, RTW89_C2H_RA_RPT_W2_MACID);
+ if (mac_id != rtwsta_link->mac_id)
return;
- rate = RTW89_GET_PHY_C2H_RA_RPT_MCSNSS(c2h->data);
- bw = RTW89_GET_PHY_C2H_RA_RPT_BW(c2h->data);
- giltf = RTW89_GET_PHY_C2H_RA_RPT_GILTF(c2h->data);
- mode = RTW89_GET_PHY_C2H_RA_RPT_MD_SEL(c2h->data);
+ rate = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_MCSNSS);
+ bw = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_BW);
+ giltf = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_GILTF);
+ mode = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_MD_SEL);
+
+ if (format_v1) {
+ t = le32_get_bits(c2h->w2, RTW89_C2H_RA_RPT_W2_MCSNSS_B7);
+ rate |= u8_encode_bits(t, BIT(7));
+ t = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_BW_B2);
+ bw |= u8_encode_bits(t, BIT(2));
+ t = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_MD_SEL_B2);
+ mode |= u8_encode_bits(t, BIT(2));
+ }
if (mode == RTW89_RA_RPT_MODE_LEGACY) {
- valid = rtw89_ra_report_to_bitrate(rtwdev, rate, &legacy_bitrate);
+ valid = rtw89_legacy_rate_to_bitrate(rtwdev, rate, &legacy_bitrate);
if (!valid)
return;
}
@@ -2260,16 +3114,24 @@ static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta)
break;
case RTW89_RA_RPT_MODE_VHT:
ra_report->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
- ra_report->txrate.mcs = FIELD_GET(RTW89_RA_RATE_MASK_MCS, rate);
- ra_report->txrate.nss = FIELD_GET(RTW89_RA_RATE_MASK_NSS, rate) + 1;
+ ra_report->txrate.mcs = format_v1 ?
+ u8_get_bits(rate, RTW89_RA_RATE_MASK_MCS_V1) :
+ u8_get_bits(rate, RTW89_RA_RATE_MASK_MCS);
+ ra_report->txrate.nss = format_v1 ?
+ u8_get_bits(rate, RTW89_RA_RATE_MASK_NSS_V1) + 1 :
+ u8_get_bits(rate, RTW89_RA_RATE_MASK_NSS) + 1;
if (giltf)
ra_report->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
mcs = ra_report->txrate.mcs;
break;
case RTW89_RA_RPT_MODE_HE:
ra_report->txrate.flags |= RATE_INFO_FLAGS_HE_MCS;
- ra_report->txrate.mcs = FIELD_GET(RTW89_RA_RATE_MASK_MCS, rate);
- ra_report->txrate.nss = FIELD_GET(RTW89_RA_RATE_MASK_NSS, rate) + 1;
+ ra_report->txrate.mcs = format_v1 ?
+ u8_get_bits(rate, RTW89_RA_RATE_MASK_MCS_V1) :
+ u8_get_bits(rate, RTW89_RA_RATE_MASK_MCS);
+ ra_report->txrate.nss = format_v1 ?
+ u8_get_bits(rate, RTW89_RA_RATE_MASK_NSS_V1) + 1 :
+ u8_get_bits(rate, RTW89_RA_RATE_MASK_NSS) + 1;
if (giltf == RTW89_GILTF_2XHE08 || giltf == RTW89_GILTF_1XHE08)
ra_report->txrate.he_gi = NL80211_RATE_INFO_HE_GI_0_8;
else if (giltf == RTW89_GILTF_2XHE16 || giltf == RTW89_GILTF_1XHE16)
@@ -2278,15 +3140,48 @@ static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta)
ra_report->txrate.he_gi = NL80211_RATE_INFO_HE_GI_3_2;
mcs = ra_report->txrate.mcs;
break;
+ case RTW89_RA_RPT_MODE_EHT:
+ ra_report->txrate.flags |= RATE_INFO_FLAGS_EHT_MCS;
+ ra_report->txrate.mcs = u8_get_bits(rate, RTW89_RA_RATE_MASK_MCS_V1);
+ ra_report->txrate.nss = u8_get_bits(rate, RTW89_RA_RATE_MASK_NSS_V1) + 1;
+ if (giltf == RTW89_GILTF_2XHE08 || giltf == RTW89_GILTF_1XHE08)
+ ra_report->txrate.eht_gi = NL80211_RATE_INFO_EHT_GI_0_8;
+ else if (giltf == RTW89_GILTF_2XHE16 || giltf == RTW89_GILTF_1XHE16)
+ ra_report->txrate.eht_gi = NL80211_RATE_INFO_EHT_GI_1_6;
+ else
+ ra_report->txrate.eht_gi = NL80211_RATE_INFO_EHT_GI_3_2;
+ mcs = ra_report->txrate.mcs;
+ break;
}
ra_report->txrate.bw = rtw89_hw_to_rate_info_bw(bw);
ra_report->bit_rate = cfg80211_calculate_bitrate(&ra_report->txrate);
- ra_report->hw_rate = FIELD_PREP(RTW89_HW_RATE_MASK_MOD, mode) |
- FIELD_PREP(RTW89_HW_RATE_MASK_VAL, rate);
+ ra_report->hw_rate = format_v1 ?
+ u16_encode_bits(mode, RTW89_HW_RATE_V1_MASK_MOD) |
+ u16_encode_bits(rate, RTW89_HW_RATE_V1_MASK_VAL) :
+ u16_encode_bits(mode, RTW89_HW_RATE_MASK_MOD) |
+ u16_encode_bits(rate, RTW89_HW_RATE_MASK_VAL);
ra_report->might_fallback_legacy = mcs <= 2;
- sta->deflink.agg.max_rc_amsdu_len = get_max_amsdu_len(rtwdev, ra_report);
- rtwsta->max_agg_wait = sta->deflink.agg.max_rc_amsdu_len / 1500 - 1;
+ link_sta->agg.max_rc_amsdu_len = get_max_amsdu_len(rtwdev, ra_report);
+ rtwsta_link->max_agg_wait = link_sta->agg.max_rc_amsdu_len / 1500 - 1;
+}
+
+static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta)
+{
+ struct rtw89_phy_iter_ra_data *ra_data = (struct rtw89_phy_iter_ra_data *)data;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_sta_link *rtwsta_link;
+ struct ieee80211_link_sta *link_sta;
+ unsigned int link_id;
+
+ rcu_read_lock();
+
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
+ link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false);
+ __rtw89_phy_c2h_ra_rpt_iter(rtwsta_link, link_sta, ra_data);
+ }
+
+ rcu_read_unlock();
}
static void
@@ -2309,6 +3204,570 @@ void (* const rtw89_phy_c2h_ra_handler[])(struct rtw89_dev *rtwdev,
[RTW89_PHY_C2H_FUNC_TXSTS] = NULL,
};
+static void
+rtw89_phy_c2h_lowrt_rty(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+}
+
+static void
+rtw89_phy_c2h_fw_scan_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ const struct rtw89_c2h_fw_scan_rpt *c2h_rpt =
+ (const struct rtw89_c2h_fw_scan_rpt *)c2h->data;
+
+ rtw89_debug(rtwdev, RTW89_DBG_DIG,
+ "%s: band: %u, op_chan: %u, PD_low_bd(ofdm, cck): (-%d, %d), phy_idx: %u\n",
+ __func__, c2h_rpt->band, c2h_rpt->center_ch,
+ PD_LOWER_BOUND_BASE - (c2h_rpt->ofdm_pd_idx << 1),
+ c2h_rpt->cck_pd_idx, c2h_rpt->phy_idx);
+}
+
+static
+void (* const rtw89_phy_c2h_dm_handler[])(struct rtw89_dev *rtwdev,
+ struct sk_buff *c2h, u32 len) = {
+ [RTW89_PHY_C2H_DM_FUNC_FW_TEST] = NULL,
+ [RTW89_PHY_C2H_DM_FUNC_FW_TRIG_TX_RPT] = NULL,
+ [RTW89_PHY_C2H_DM_FUNC_SIGB] = NULL,
+ [RTW89_PHY_C2H_DM_FUNC_LOWRT_RTY] = rtw89_phy_c2h_lowrt_rty,
+ [RTW89_PHY_C2H_DM_FUNC_MCC_DIG] = NULL,
+ [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)
+{
+ struct rtw89_c2h_rf_txgapk_rpt_log *txgapk;
+ struct rtw89_c2h_rf_rxdck_rpt_log *rxdck;
+ struct rtw89_c2h_rf_dack_rpt_log *dack;
+ struct rtw89_c2h_rf_tssi_rpt_log *tssi;
+ struct rtw89_c2h_rf_dpk_rpt_log *dpk;
+ struct rtw89_c2h_rf_iqk_rpt_log *iqk;
+ int i, j, k;
+
+ switch (func) {
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_IQK:
+ if (len != sizeof(*iqk))
+ goto out;
+
+ iqk = content;
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->is_iqk_init = %x\n", iqk->is_iqk_init);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->is_reload = %x\n", iqk->is_reload);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->is_nbiqk = %x\n", iqk->is_nbiqk);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->txiqk_en = %x\n", iqk->txiqk_en);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->rxiqk_en = %x\n", iqk->rxiqk_en);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->lok_en = %x\n", iqk->lok_en);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->iqk_xym_en = %x\n", iqk->iqk_xym_en);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->iqk_sram_en = %x\n", iqk->iqk_sram_en);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->iqk_fft_en = %x\n", iqk->iqk_fft_en);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->is_fw_iqk = %x\n", iqk->is_fw_iqk);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->is_iqk_enable = %x\n", iqk->is_iqk_enable);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->iqk_cfir_en = %x\n", iqk->iqk_cfir_en);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->thermal_rek_en = %x\n", iqk->thermal_rek_en);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->version = %x\n", iqk->version);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->phy = %x\n", iqk->phy);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->fwk_status = %x\n", iqk->fwk_status);
+
+ for (i = 0; i < 2; i++) {
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] ======== Path %x ========\n", i);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_band[%d] = %x\n",
+ i, iqk->iqk_band[i]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_ch[%d] = %x\n",
+ i, iqk->iqk_ch[i]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_bw[%d] = %x\n",
+ i, iqk->iqk_bw[i]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->lok_idac[%d] = %x\n",
+ i, le32_to_cpu(iqk->lok_idac[i]));
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->lok_vbuf[%d] = %x\n",
+ i, le32_to_cpu(iqk->lok_vbuf[i]));
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_tx_fail[%d] = %x\n",
+ i, iqk->iqk_tx_fail[i]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_rx_fail[%d] = %x\n",
+ i, iqk->iqk_rx_fail[i]);
+ for (j = 0; j < 4; j++)
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->rftxgain[%d][%d] = %x\n",
+ i, j, le32_to_cpu(iqk->rftxgain[i][j]));
+ for (j = 0; j < 4; j++)
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->tx_xym[%d][%d] = %x\n",
+ i, j, le32_to_cpu(iqk->tx_xym[i][j]));
+ for (j = 0; j < 4; j++)
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->rfrxgain[%d][%d] = %x\n",
+ i, j, le32_to_cpu(iqk->rfrxgain[i][j]));
+ for (j = 0; j < 4; j++)
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[IQK] iqk->rx_xym[%d][%d] = %x\n",
+ i, j, le32_to_cpu(iqk->rx_xym[i][j]));
+ }
+ return;
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_DPK:
+ if (len != sizeof(*dpk))
+ goto out;
+
+ dpk = content;
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "DPK ver:%d idx:%2ph band:%2ph bw:%2ph ch:%2ph path:%2ph\n",
+ dpk->ver, dpk->idx, dpk->band, dpk->bw, dpk->ch, dpk->path_ok);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "DPK txagc:%2ph ther:%2ph gs:%2ph dc_i:%4ph dc_q:%4ph\n",
+ dpk->txagc, dpk->ther, dpk->gs, dpk->dc_i, dpk->dc_q);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "DPK corr_v:%2ph corr_i:%2ph to:%2ph ov:%2ph\n",
+ dpk->corr_val, dpk->corr_idx, dpk->is_timeout, dpk->rxbb_ov);
+ return;
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_DACK:
+ if (len != sizeof(*dack))
+ goto out;
+
+ dack = content;
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]FWDACK SUMMARY!!!!!\n");
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[DACK]FWDACK ver = 0x%x, FWDACK rpt_ver = 0x%x, driver rpt_ver = 0x%x\n",
+ dack->fwdack_ver, dack->fwdack_info_ver, 0x2);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[DACK]timeout code = [0x%x 0x%x 0x%x 0x%x 0x%x]\n",
+ dack->addck_timeout, dack->cdack_timeout, dack->dadck_timeout,
+ dack->adgaink_timeout, dack->msbk_timeout);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[DACK]DACK fail = 0x%x\n", dack->dack_fail);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[DACK]S0 WBADCK = [0x%x]\n", dack->wbdck_d[0]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[DACK]S1 WBADCK = [0x%x]\n", dack->wbdck_d[1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[DACK]DRCK = [0x%x]\n", dack->rck_d);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 CDACK ic = [0x%x, 0x%x]\n",
+ dack->cdack_d[0][0][0], dack->cdack_d[0][0][1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 CDACK qc = [0x%x, 0x%x]\n",
+ dack->cdack_d[0][1][0], dack->cdack_d[0][1][1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 CDACK ic = [0x%x, 0x%x]\n",
+ dack->cdack_d[1][0][0], dack->cdack_d[1][0][1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 CDACK qc = [0x%x, 0x%x]\n",
+ dack->cdack_d[1][1][0], dack->cdack_d[1][1][1]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 ADC_DCK ic = [0x%x, 0x%x]\n",
+ ((u32)dack->addck2_hd[0][0][0] << 8) | dack->addck2_ld[0][0][0],
+ ((u32)dack->addck2_hd[0][0][1] << 8) | dack->addck2_ld[0][0][1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 ADC_DCK qc = [0x%x, 0x%x]\n",
+ ((u32)dack->addck2_hd[0][1][0] << 8) | dack->addck2_ld[0][1][0],
+ ((u32)dack->addck2_hd[0][1][1] << 8) | dack->addck2_ld[0][1][1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 ADC_DCK ic = [0x%x, 0x%x]\n",
+ ((u32)dack->addck2_hd[1][0][0] << 8) | dack->addck2_ld[1][0][0],
+ ((u32)dack->addck2_hd[1][0][1] << 8) | dack->addck2_ld[1][0][1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 ADC_DCK qc = [0x%x, 0x%x]\n",
+ ((u32)dack->addck2_hd[1][1][0] << 8) | dack->addck2_ld[1][1][0],
+ ((u32)dack->addck2_hd[1][1][1] << 8) | dack->addck2_ld[1][1][1]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 ADC_GAINK ic = 0x%x, qc = 0x%x\n",
+ dack->adgaink_d[0][0], dack->adgaink_d[0][1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 ADC_GAINK ic = 0x%x, qc = 0x%x\n",
+ dack->adgaink_d[1][0], dack->adgaink_d[1][1]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 DAC_DCK ic = 0x%x, qc = 0x%x\n",
+ dack->dadck_d[0][0], dack->dadck_d[0][1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 DAC_DCK ic = 0x%x, qc = 0x%x\n",
+ dack->dadck_d[1][0], dack->dadck_d[1][1]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 biask iqc = 0x%x\n",
+ ((u32)dack->biask_hd[0][0] << 8) | dack->biask_ld[0][0]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 biask iqc = 0x%x\n",
+ ((u32)dack->biask_hd[1][0] << 8) | dack->biask_ld[1][0]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK ic:\n");
+ for (i = 0; i < 0x10; i++)
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n",
+ dack->msbk_d[0][0][i]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK qc:\n");
+ for (i = 0; i < 0x10; i++)
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n",
+ dack->msbk_d[0][1][i]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK ic:\n");
+ for (i = 0; i < 0x10; i++)
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n",
+ dack->msbk_d[1][0][i]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK qc:\n");
+ for (i = 0; i < 0x10; i++)
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n",
+ dack->msbk_d[1][1][i]);
+ return;
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK:
+ if (len != sizeof(*rxdck))
+ goto out;
+
+ rxdck = content;
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "RXDCK ver:%d band:%2ph bw:%2ph ch:%2ph to:%2ph\n",
+ rxdck->ver, rxdck->band, rxdck->bw, rxdck->ch,
+ rxdck->timeout);
+ return;
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI:
+ if (len != sizeof(*tssi))
+ goto out;
+
+ tssi = content;
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 2; j++) {
+ for (k = 0; k < 4; k++) {
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[TSSI] alignment_power_cw_h[%d][%d][%d]=%d\n",
+ i, j, k, tssi->alignment_power_cw_h[i][j][k]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[TSSI] alignment_power_cw_l[%d][%d][%d]=%d\n",
+ i, j, k, tssi->alignment_power_cw_l[i][j][k]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[TSSI] alignment_power[%d][%d][%d]=%d\n",
+ i, j, k, tssi->alignment_power[i][j][k]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[TSSI] alignment_power_cw[%d][%d][%d]=%d\n",
+ i, j, k,
+ (tssi->alignment_power_cw_h[i][j][k] << 8) +
+ tssi->alignment_power_cw_l[i][j][k]);
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[TSSI] tssi_alimk_state[%d][%d]=%d\n",
+ i, j, tssi->tssi_alimk_state[i][j]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[TSSI] default_txagc_offset[%d]=%d\n",
+ j, tssi->default_txagc_offset[0][j]);
+ }
+ }
+ return;
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK:
+ if (len != sizeof(*txgapk))
+ goto out;
+
+ txgapk = content;
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[TXGAPK]rpt r0x8010[0]=0x%x, r0x8010[1]=0x%x\n",
+ le32_to_cpu(txgapk->r0x8010[0]),
+ le32_to_cpu(txgapk->r0x8010[1]));
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt chk_id = %d\n",
+ txgapk->chk_id);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt chk_cnt = %d\n",
+ le32_to_cpu(txgapk->chk_cnt));
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt ver = 0x%x\n",
+ txgapk->ver);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt rsv1 = %d\n",
+ txgapk->rsv1);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt track_d[0] = %*ph\n",
+ (int)sizeof(txgapk->track_d[0]), txgapk->track_d[0]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt power_d[0] = %*ph\n",
+ (int)sizeof(txgapk->power_d[0]), txgapk->power_d[0]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt track_d[1] = %*ph\n",
+ (int)sizeof(txgapk->track_d[1]), txgapk->track_d[1]);
+ 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;
+ }
+
+out:
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "unexpected RFK func %d report log with length %d\n", func, len);
+}
+
+static bool rtw89_phy_c2h_rfk_run_log(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_c2h_rfk_log_func func,
+ void *content, u16 len)
+{
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
+ const struct rtw89_c2h_rf_run_log *log = content;
+ const struct rtw89_fw_element_hdr *elm;
+ u32 fmt_idx;
+ u16 offset;
+
+ if (sizeof(*log) != len)
+ return false;
+
+ if (!elm_info->rfk_log_fmt)
+ return false;
+
+ elm = elm_info->rfk_log_fmt->elm[func];
+ fmt_idx = le32_to_cpu(log->fmt_idx);
+ if (!elm || fmt_idx >= elm->u.rfk_log_fmt.nr)
+ return false;
+
+ offset = le16_to_cpu(elm->u.rfk_log_fmt.offset[fmt_idx]);
+ if (offset == 0)
+ return false;
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, &elm->u.common.contents[offset],
+ le32_to_cpu(log->arg[0]), le32_to_cpu(log->arg[1]),
+ le32_to_cpu(log->arg[2]), le32_to_cpu(log->arg[3]));
+
+ return true;
+}
+
+static void rtw89_phy_c2h_rfk_log(struct rtw89_dev *rtwdev, struct sk_buff *c2h,
+ u32 len, enum rtw89_phy_c2h_rfk_log_func func,
+ const char *rfk_name)
+{
+ struct rtw89_c2h_hdr *c2h_hdr = (struct rtw89_c2h_hdr *)c2h->data;
+ struct rtw89_c2h_rf_log_hdr *log_hdr;
+ void *log_ptr = c2h_hdr;
+ u16 content_len;
+ u16 chunk_len;
+ bool handled;
+
+ log_ptr += sizeof(*c2h_hdr);
+ len -= sizeof(*c2h_hdr);
+
+ while (len > sizeof(*log_hdr)) {
+ log_hdr = log_ptr;
+ content_len = le16_to_cpu(log_hdr->len);
+ chunk_len = content_len + sizeof(*log_hdr);
+
+ if (chunk_len > len)
+ break;
+
+ switch (log_hdr->type) {
+ case RTW89_RF_RUN_LOG:
+ handled = rtw89_phy_c2h_rfk_run_log(rtwdev, func,
+ log_hdr->content, content_len);
+ if (handled)
+ break;
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "%s run: %*ph\n",
+ rfk_name, content_len, log_hdr->content);
+ break;
+ case RTW89_RF_RPT_LOG:
+ rtw89_phy_c2h_rfk_rpt_log(rtwdev, func,
+ log_hdr->content, content_len);
+ break;
+ default:
+ return;
+ }
+
+ log_ptr += chunk_len;
+ len -= chunk_len;
+ }
+}
+
+static void
+rtw89_phy_c2h_rfk_log_iqk(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ rtw89_phy_c2h_rfk_log(rtwdev, c2h, len,
+ RTW89_PHY_C2H_RFK_LOG_FUNC_IQK, "IQK");
+}
+
+static void
+rtw89_phy_c2h_rfk_log_dpk(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ rtw89_phy_c2h_rfk_log(rtwdev, c2h, len,
+ RTW89_PHY_C2H_RFK_LOG_FUNC_DPK, "DPK");
+}
+
+static void
+rtw89_phy_c2h_rfk_log_dack(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ rtw89_phy_c2h_rfk_log(rtwdev, c2h, len,
+ RTW89_PHY_C2H_RFK_LOG_FUNC_DACK, "DACK");
+}
+
+static void
+rtw89_phy_c2h_rfk_log_rxdck(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ rtw89_phy_c2h_rfk_log(rtwdev, c2h, len,
+ RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK, "RX_DCK");
+}
+
+static void
+rtw89_phy_c2h_rfk_log_tssi(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ rtw89_phy_c2h_rfk_log(rtwdev, c2h, len,
+ RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI, "TSSI");
+}
+
+static void
+rtw89_phy_c2h_rfk_log_txgapk(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ rtw89_phy_c2h_rfk_log(rtwdev, c2h, len,
+ 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_IQK] = rtw89_phy_c2h_rfk_log_iqk,
+ [RTW89_PHY_C2H_RFK_LOG_FUNC_DPK] = rtw89_phy_c2h_rfk_log_dpk,
+ [RTW89_PHY_C2H_RFK_LOG_FUNC_DACK] = rtw89_phy_c2h_rfk_log_dack,
+ [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
+void rtw89_phy_rfk_report_prep(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_rfk_wait_info *wait = &rtwdev->rfk_wait;
+
+ wait->state = RTW89_RFK_STATE_START;
+ wait->start_time = ktime_get();
+ reinit_completion(&wait->completion);
+}
+
+static
+int rtw89_phy_rfk_report_wait(struct rtw89_dev *rtwdev, const char *rfk_name,
+ unsigned int ms)
+{
+ struct rtw89_rfk_wait_info *wait = &rtwdev->rfk_wait;
+ unsigned long time_left;
+
+ /* Since we can't receive C2H event during SER, use a fixed delay. */
+ if (test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags)) {
+ fsleep(1000 * ms / 2);
+ goto out;
+ }
+
+ time_left = wait_for_completion_timeout(&wait->completion,
+ msecs_to_jiffies(ms));
+ if (time_left == 0) {
+ rtw89_warn(rtwdev, "failed to wait RF %s\n", rfk_name);
+ return -ETIMEDOUT;
+ } else if (wait->state != RTW89_RFK_STATE_OK) {
+ rtw89_warn(rtwdev, "failed to do RF %s result from state %d\n",
+ rfk_name, wait->state);
+ return -EFAULT;
+ }
+
+out:
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "RF %s takes %lld ms to complete\n",
+ rfk_name, ktime_ms_delta(ktime_get(), wait->start_time));
+
+ return 0;
+}
+
+static void
+rtw89_phy_c2h_rfk_report_state(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ const struct rtw89_c2h_rfk_report *report =
+ (const struct rtw89_c2h_rfk_report *)c2h->data;
+ struct rtw89_rfk_wait_info *wait = &rtwdev->rfk_wait;
+
+ wait->state = report->state;
+ wait->version = report->version;
+
+ complete(&wait->completion);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "RFK report state %d with version %d (%*ph)\n",
+ wait->state, wait->version,
+ (int)(len - sizeof(report->hdr)), &report->state);
+}
+
+static void
+rtw89_phy_c2h_rfk_report_tas_pwr(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ const struct rtw89_c2h_rf_tas_info *report =
+ (const struct rtw89_c2h_rf_tas_info *)c2h->data;
+
+ 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_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)
+{
+ switch (class) {
+ case RTW89_PHY_C2H_RFK_LOG:
+ switch (func) {
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_IQK:
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_DPK:
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_DACK:
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK:
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI:
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK:
+ return true;
+ default:
+ return false;
+ }
+ case RTW89_PHY_C2H_RFK_REPORT:
+ switch (func) {
+ case RTW89_PHY_C2H_RFK_REPORT_FUNC_STATE:
+ return true;
+ default:
+ return false;
+ }
+ default:
+ return false;
+ }
+}
+
void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
u32 len, u8 class, u8 func)
{
@@ -2320,45 +3779,780 @@ void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
if (func < RTW89_PHY_C2H_FUNC_RA_MAX)
handler = rtw89_phy_c2h_ra_handler[func];
break;
+ case RTW89_PHY_C2H_RFK_LOG:
+ if (func < ARRAY_SIZE(rtw89_phy_c2h_rfk_log_handler))
+ handler = rtw89_phy_c2h_rfk_log_handler[func];
+ break;
+ case RTW89_PHY_C2H_RFK_REPORT:
+ if (func < ARRAY_SIZE(rtw89_phy_c2h_rfk_report_handler))
+ handler = rtw89_phy_c2h_rfk_report_handler[func];
+ break;
case RTW89_PHY_C2H_CLASS_DM:
- if (func == RTW89_PHY_C2H_DM_FUNC_LOWRT_RTY)
- return;
- fallthrough;
+ if (func < ARRAY_SIZE(rtw89_phy_c2h_dm_handler))
+ handler = rtw89_phy_c2h_dm_handler[func];
+ break;
default:
- rtw89_info(rtwdev, "c2h class %d not support\n", class);
- return;
+ break;
}
if (!handler) {
- rtw89_info(rtwdev, "c2h class %d func %d not support\n", class,
- func);
+ rtw89_info_once(rtwdev, "PHY c2h class %d func %d not support\n",
+ class, func);
return;
}
handler(rtwdev, skb, len);
}
+int rtw89_phy_rfk_pre_ntfy_and_wait(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx,
+ unsigned int ms)
+{
+ int ret;
+
+ rtw89_phy_rfk_report_prep(rtwdev);
+
+ ret = rtw89_fw_h2c_rf_pre_ntfy(rtwdev, phy_idx);
+ if (ret)
+ return ret;
+
+ return rtw89_phy_rfk_report_wait(rtwdev, "PRE_NTFY", ms);
+}
+EXPORT_SYMBOL(rtw89_phy_rfk_pre_ntfy_and_wait);
+
+int rtw89_phy_rfk_tssi_and_wait(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx,
+ const struct rtw89_chan *chan,
+ enum rtw89_tssi_mode tssi_mode,
+ unsigned int ms)
+{
+ int ret;
+
+ rtw89_phy_rfk_report_prep(rtwdev);
+
+ ret = rtw89_fw_h2c_rf_tssi(rtwdev, phy_idx, chan, tssi_mode);
+ if (ret)
+ return ret;
+
+ return rtw89_phy_rfk_report_wait(rtwdev, "TSSI", ms);
+}
+EXPORT_SYMBOL(rtw89_phy_rfk_tssi_and_wait);
+
+int rtw89_phy_rfk_iqk_and_wait(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx,
+ const struct rtw89_chan *chan,
+ unsigned int ms)
+{
+ int ret;
+
+ rtw89_phy_rfk_report_prep(rtwdev);
+
+ ret = rtw89_fw_h2c_rf_iqk(rtwdev, phy_idx, chan);
+ if (ret)
+ return ret;
+
+ return rtw89_phy_rfk_report_wait(rtwdev, "IQK", ms);
+}
+EXPORT_SYMBOL(rtw89_phy_rfk_iqk_and_wait);
+
+int rtw89_phy_rfk_dpk_and_wait(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx,
+ const struct rtw89_chan *chan,
+ unsigned int ms)
+{
+ int ret;
+
+ rtw89_phy_rfk_report_prep(rtwdev);
+
+ ret = rtw89_fw_h2c_rf_dpk(rtwdev, phy_idx, chan);
+ if (ret)
+ return ret;
+
+ return rtw89_phy_rfk_report_wait(rtwdev, "DPK", ms);
+}
+EXPORT_SYMBOL(rtw89_phy_rfk_dpk_and_wait);
+
+int rtw89_phy_rfk_txgapk_and_wait(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx,
+ const struct rtw89_chan *chan,
+ unsigned int ms)
+{
+ int ret;
+
+ rtw89_phy_rfk_report_prep(rtwdev);
+
+ ret = rtw89_fw_h2c_rf_txgapk(rtwdev, phy_idx, chan);
+ if (ret)
+ return ret;
+
+ return rtw89_phy_rfk_report_wait(rtwdev, "TXGAPK", ms);
+}
+EXPORT_SYMBOL(rtw89_phy_rfk_txgapk_and_wait);
+
+int rtw89_phy_rfk_dack_and_wait(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx,
+ const struct rtw89_chan *chan,
+ unsigned int ms)
+{
+ int ret;
+
+ rtw89_phy_rfk_report_prep(rtwdev);
+
+ ret = rtw89_fw_h2c_rf_dack(rtwdev, phy_idx, chan);
+ if (ret)
+ return ret;
+
+ return rtw89_phy_rfk_report_wait(rtwdev, "DACK", ms);
+}
+EXPORT_SYMBOL(rtw89_phy_rfk_dack_and_wait);
+
+int rtw89_phy_rfk_rxdck_and_wait(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx,
+ const struct rtw89_chan *chan,
+ bool is_chl_k, unsigned int ms)
+{
+ int ret;
+
+ rtw89_phy_rfk_report_prep(rtwdev);
+
+ ret = rtw89_fw_h2c_rf_rxdck(rtwdev, phy_idx, chan, is_chl_k);
+ if (ret)
+ return ret;
+
+ return rtw89_phy_rfk_report_wait(rtwdev, "RX_DCK", ms);
+}
+EXPORT_SYMBOL(rtw89_phy_rfk_rxdck_and_wait);
+
+static u32 phy_tssi_get_cck_group(u8 ch)
+{
+ switch (ch) {
+ case 1 ... 2:
+ return 0;
+ case 3 ... 5:
+ return 1;
+ case 6 ... 8:
+ return 2;
+ case 9 ... 11:
+ return 3;
+ case 12 ... 13:
+ return 4;
+ case 14:
+ return 5;
+ }
+
+ return 0;
+}
+
+#define PHY_TSSI_EXTRA_GROUP_BIT BIT(31)
+#define PHY_TSSI_EXTRA_GROUP(idx) (PHY_TSSI_EXTRA_GROUP_BIT | (idx))
+#define PHY_IS_TSSI_EXTRA_GROUP(group) ((group) & PHY_TSSI_EXTRA_GROUP_BIT)
+#define PHY_TSSI_EXTRA_GET_GROUP_IDX1(group) \
+ ((group) & ~PHY_TSSI_EXTRA_GROUP_BIT)
+#define PHY_TSSI_EXTRA_GET_GROUP_IDX2(group) \
+ (PHY_TSSI_EXTRA_GET_GROUP_IDX1(group) + 1)
+
+static u32 phy_tssi_get_ofdm_group(u8 ch)
+{
+ switch (ch) {
+ case 1 ... 2:
+ return 0;
+ case 3 ... 5:
+ return 1;
+ case 6 ... 8:
+ return 2;
+ case 9 ... 11:
+ return 3;
+ case 12 ... 14:
+ return 4;
+ case 36 ... 40:
+ return 5;
+ case 41 ... 43:
+ return PHY_TSSI_EXTRA_GROUP(5);
+ case 44 ... 48:
+ return 6;
+ case 49 ... 51:
+ return PHY_TSSI_EXTRA_GROUP(6);
+ case 52 ... 56:
+ return 7;
+ case 57 ... 59:
+ return PHY_TSSI_EXTRA_GROUP(7);
+ case 60 ... 64:
+ return 8;
+ case 100 ... 104:
+ return 9;
+ case 105 ... 107:
+ return PHY_TSSI_EXTRA_GROUP(9);
+ case 108 ... 112:
+ return 10;
+ case 113 ... 115:
+ return PHY_TSSI_EXTRA_GROUP(10);
+ case 116 ... 120:
+ return 11;
+ case 121 ... 123:
+ return PHY_TSSI_EXTRA_GROUP(11);
+ case 124 ... 128:
+ return 12;
+ case 129 ... 131:
+ return PHY_TSSI_EXTRA_GROUP(12);
+ case 132 ... 136:
+ return 13;
+ case 137 ... 139:
+ return PHY_TSSI_EXTRA_GROUP(13);
+ case 140 ... 144:
+ return 14;
+ case 149 ... 153:
+ return 15;
+ case 154 ... 156:
+ return PHY_TSSI_EXTRA_GROUP(15);
+ case 157 ... 161:
+ return 16;
+ case 162 ... 164:
+ return PHY_TSSI_EXTRA_GROUP(16);
+ case 165 ... 169:
+ return 17;
+ case 170 ... 172:
+ return PHY_TSSI_EXTRA_GROUP(17);
+ case 173 ... 177:
+ return 18;
+ }
+
+ return 0;
+}
+
+static u32 phy_tssi_get_6g_ofdm_group(u8 ch)
+{
+ switch (ch) {
+ case 1 ... 5:
+ return 0;
+ case 6 ... 8:
+ return PHY_TSSI_EXTRA_GROUP(0);
+ case 9 ... 13:
+ return 1;
+ case 14 ... 16:
+ return PHY_TSSI_EXTRA_GROUP(1);
+ case 17 ... 21:
+ return 2;
+ case 22 ... 24:
+ return PHY_TSSI_EXTRA_GROUP(2);
+ case 25 ... 29:
+ return 3;
+ case 33 ... 37:
+ return 4;
+ case 38 ... 40:
+ return PHY_TSSI_EXTRA_GROUP(4);
+ case 41 ... 45:
+ return 5;
+ case 46 ... 48:
+ return PHY_TSSI_EXTRA_GROUP(5);
+ case 49 ... 53:
+ return 6;
+ case 54 ... 56:
+ return PHY_TSSI_EXTRA_GROUP(6);
+ case 57 ... 61:
+ return 7;
+ case 65 ... 69:
+ return 8;
+ case 70 ... 72:
+ return PHY_TSSI_EXTRA_GROUP(8);
+ case 73 ... 77:
+ return 9;
+ case 78 ... 80:
+ return PHY_TSSI_EXTRA_GROUP(9);
+ case 81 ... 85:
+ return 10;
+ case 86 ... 88:
+ return PHY_TSSI_EXTRA_GROUP(10);
+ case 89 ... 93:
+ return 11;
+ case 97 ... 101:
+ return 12;
+ case 102 ... 104:
+ return PHY_TSSI_EXTRA_GROUP(12);
+ case 105 ... 109:
+ return 13;
+ case 110 ... 112:
+ return PHY_TSSI_EXTRA_GROUP(13);
+ case 113 ... 117:
+ return 14;
+ case 118 ... 120:
+ return PHY_TSSI_EXTRA_GROUP(14);
+ case 121 ... 125:
+ return 15;
+ case 129 ... 133:
+ return 16;
+ case 134 ... 136:
+ return PHY_TSSI_EXTRA_GROUP(16);
+ case 137 ... 141:
+ return 17;
+ case 142 ... 144:
+ return PHY_TSSI_EXTRA_GROUP(17);
+ case 145 ... 149:
+ return 18;
+ case 150 ... 152:
+ return PHY_TSSI_EXTRA_GROUP(18);
+ case 153 ... 157:
+ return 19;
+ case 161 ... 165:
+ return 20;
+ case 166 ... 168:
+ return PHY_TSSI_EXTRA_GROUP(20);
+ case 169 ... 173:
+ return 21;
+ case 174 ... 176:
+ return PHY_TSSI_EXTRA_GROUP(21);
+ case 177 ... 181:
+ return 22;
+ case 182 ... 184:
+ return PHY_TSSI_EXTRA_GROUP(22);
+ case 185 ... 189:
+ return 23;
+ case 193 ... 197:
+ return 24;
+ case 198 ... 200:
+ return PHY_TSSI_EXTRA_GROUP(24);
+ case 201 ... 205:
+ return 25;
+ case 206 ... 208:
+ return PHY_TSSI_EXTRA_GROUP(25);
+ case 209 ... 213:
+ return 26;
+ case 214 ... 216:
+ return PHY_TSSI_EXTRA_GROUP(26);
+ case 217 ... 221:
+ return 27;
+ case 225 ... 229:
+ return 28;
+ case 230 ... 232:
+ return PHY_TSSI_EXTRA_GROUP(28);
+ case 233 ... 237:
+ return 29;
+ case 238 ... 240:
+ return PHY_TSSI_EXTRA_GROUP(29);
+ case 241 ... 245:
+ return 30;
+ case 246 ... 248:
+ return PHY_TSSI_EXTRA_GROUP(30);
+ case 249 ... 253:
+ return 31;
+ }
+
+ return 0;
+}
+
+static u32 phy_tssi_get_trim_group(u8 ch)
+{
+ switch (ch) {
+ case 1 ... 8:
+ return 0;
+ case 9 ... 14:
+ return 1;
+ case 36 ... 48:
+ return 2;
+ case 49 ... 51:
+ return PHY_TSSI_EXTRA_GROUP(2);
+ case 52 ... 64:
+ return 3;
+ case 100 ... 112:
+ return 4;
+ case 113 ... 115:
+ return PHY_TSSI_EXTRA_GROUP(4);
+ case 116 ... 128:
+ return 5;
+ case 132 ... 144:
+ return 6;
+ case 149 ... 177:
+ return 7;
+ }
+
+ return 0;
+}
+
+static u32 phy_tssi_get_6g_trim_group(u8 ch)
+{
+ switch (ch) {
+ case 1 ... 13:
+ return 0;
+ case 14 ... 16:
+ return PHY_TSSI_EXTRA_GROUP(0);
+ case 17 ... 29:
+ return 1;
+ case 33 ... 45:
+ return 2;
+ case 46 ... 48:
+ return PHY_TSSI_EXTRA_GROUP(2);
+ case 49 ... 61:
+ return 3;
+ case 65 ... 77:
+ return 4;
+ case 78 ... 80:
+ return PHY_TSSI_EXTRA_GROUP(4);
+ case 81 ... 93:
+ return 5;
+ case 97 ... 109:
+ return 6;
+ case 110 ... 112:
+ return PHY_TSSI_EXTRA_GROUP(6);
+ case 113 ... 125:
+ return 7;
+ case 129 ... 141:
+ return 8;
+ case 142 ... 144:
+ return PHY_TSSI_EXTRA_GROUP(8);
+ case 145 ... 157:
+ return 9;
+ case 161 ... 173:
+ return 10;
+ case 174 ... 176:
+ return PHY_TSSI_EXTRA_GROUP(10);
+ case 177 ... 189:
+ return 11;
+ case 193 ... 205:
+ return 12;
+ case 206 ... 208:
+ return PHY_TSSI_EXTRA_GROUP(12);
+ case 209 ... 221:
+ return 13;
+ case 225 ... 237:
+ return 14;
+ case 238 ... 240:
+ return PHY_TSSI_EXTRA_GROUP(14);
+ case 241 ... 253:
+ return 15;
+ }
+
+ return 0;
+}
+
+static s8 phy_tssi_get_ofdm_de(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy,
+ const struct rtw89_chan *chan,
+ enum rtw89_rf_path path)
+{
+ struct rtw89_tssi_info *tssi_info = &rtwdev->tssi;
+ enum rtw89_band band = chan->band_type;
+ u8 ch = chan->channel;
+ u32 gidx_1st;
+ u32 gidx_2nd;
+ s8 de_1st;
+ s8 de_2nd;
+ u32 gidx;
+ s8 val;
+
+ if (band == RTW89_BAND_6G)
+ goto calc_6g;
+
+ gidx = phy_tssi_get_ofdm_group(ch);
+
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][TRIM]: path=%d mcs group_idx=0x%x\n",
+ path, gidx);
+
+ if (PHY_IS_TSSI_EXTRA_GROUP(gidx)) {
+ gidx_1st = PHY_TSSI_EXTRA_GET_GROUP_IDX1(gidx);
+ gidx_2nd = PHY_TSSI_EXTRA_GET_GROUP_IDX2(gidx);
+ de_1st = tssi_info->tssi_mcs[path][gidx_1st];
+ de_2nd = tssi_info->tssi_mcs[path][gidx_2nd];
+ val = (de_1st + de_2nd) / 2;
+
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][TRIM]: path=%d mcs de=%d 1st=%d 2nd=%d\n",
+ path, val, de_1st, de_2nd);
+ } else {
+ val = tssi_info->tssi_mcs[path][gidx];
+
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][TRIM]: path=%d mcs de=%d\n", path, val);
+ }
+
+ return val;
+
+calc_6g:
+ gidx = phy_tssi_get_6g_ofdm_group(ch);
+
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][TRIM]: path=%d mcs group_idx=0x%x\n",
+ path, gidx);
+
+ if (PHY_IS_TSSI_EXTRA_GROUP(gidx)) {
+ gidx_1st = PHY_TSSI_EXTRA_GET_GROUP_IDX1(gidx);
+ gidx_2nd = PHY_TSSI_EXTRA_GET_GROUP_IDX2(gidx);
+ de_1st = tssi_info->tssi_6g_mcs[path][gidx_1st];
+ de_2nd = tssi_info->tssi_6g_mcs[path][gidx_2nd];
+ val = (de_1st + de_2nd) / 2;
+
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][TRIM]: path=%d mcs de=%d 1st=%d 2nd=%d\n",
+ path, val, de_1st, de_2nd);
+ } else {
+ val = tssi_info->tssi_6g_mcs[path][gidx];
+
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][TRIM]: path=%d mcs de=%d\n", path, val);
+ }
+
+ return val;
+}
+
+static s8 phy_tssi_get_ofdm_trim_de(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy,
+ const struct rtw89_chan *chan,
+ enum rtw89_rf_path path)
+{
+ struct rtw89_tssi_info *tssi_info = &rtwdev->tssi;
+ enum rtw89_band band = chan->band_type;
+ u8 ch = chan->channel;
+ u32 tgidx_1st;
+ u32 tgidx_2nd;
+ s8 tde_1st;
+ s8 tde_2nd;
+ u32 tgidx;
+ s8 val;
+
+ if (band == RTW89_BAND_6G)
+ goto calc_6g;
+
+ tgidx = phy_tssi_get_trim_group(ch);
+
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][TRIM]: path=%d mcs trim_group_idx=0x%x\n",
+ path, tgidx);
+
+ if (PHY_IS_TSSI_EXTRA_GROUP(tgidx)) {
+ tgidx_1st = PHY_TSSI_EXTRA_GET_GROUP_IDX1(tgidx);
+ tgidx_2nd = PHY_TSSI_EXTRA_GET_GROUP_IDX2(tgidx);
+ tde_1st = tssi_info->tssi_trim[path][tgidx_1st];
+ tde_2nd = tssi_info->tssi_trim[path][tgidx_2nd];
+ val = (tde_1st + tde_2nd) / 2;
+
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][TRIM]: path=%d mcs trim_de=%d 1st=%d 2nd=%d\n",
+ path, val, tde_1st, tde_2nd);
+ } else {
+ val = tssi_info->tssi_trim[path][tgidx];
+
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][TRIM]: path=%d mcs trim_de=%d\n",
+ path, val);
+ }
+
+ return val;
+
+calc_6g:
+ tgidx = phy_tssi_get_6g_trim_group(ch);
+
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][TRIM]: path=%d mcs trim_group_idx=0x%x\n",
+ path, tgidx);
+
+ if (PHY_IS_TSSI_EXTRA_GROUP(tgidx)) {
+ tgidx_1st = PHY_TSSI_EXTRA_GET_GROUP_IDX1(tgidx);
+ tgidx_2nd = PHY_TSSI_EXTRA_GET_GROUP_IDX2(tgidx);
+ tde_1st = tssi_info->tssi_trim_6g[path][tgidx_1st];
+ tde_2nd = tssi_info->tssi_trim_6g[path][tgidx_2nd];
+ val = (tde_1st + tde_2nd) / 2;
+
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][TRIM]: path=%d mcs trim_de=%d 1st=%d 2nd=%d\n",
+ path, val, tde_1st, tde_2nd);
+ } else {
+ val = tssi_info->tssi_trim_6g[path][tgidx];
+
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][TRIM]: path=%d mcs trim_de=%d\n",
+ path, val);
+ }
+
+ return val;
+}
+
+void rtw89_phy_rfk_tssi_fill_fwcmd_efuse_to_de(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy,
+ const struct rtw89_chan *chan,
+ struct rtw89_h2c_rf_tssi *h2c)
+{
+ struct rtw89_tssi_info *tssi_info = &rtwdev->tssi;
+ u8 ch = chan->channel;
+ s8 trim_de;
+ s8 ofdm_de;
+ s8 cck_de;
+ u8 gidx;
+ s8 val;
+ int i;
+
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI, "[TSSI][TRIM]: phy=%d ch=%d\n",
+ phy, ch);
+
+ for (i = RF_PATH_A; i <= RF_PATH_B; i++) {
+ trim_de = phy_tssi_get_ofdm_trim_de(rtwdev, phy, chan, i);
+ h2c->curr_tssi_trim_de[i] = trim_de;
+
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][TRIM]: path=%d trim_de=0x%x\n", i, trim_de);
+
+ gidx = phy_tssi_get_cck_group(ch);
+ cck_de = tssi_info->tssi_cck[i][gidx];
+ val = u32_get_bits(cck_de + trim_de, 0xff);
+
+ h2c->curr_tssi_cck_de[i] = 0x0;
+ h2c->curr_tssi_cck_de_20m[i] = val;
+ h2c->curr_tssi_cck_de_40m[i] = val;
+ h2c->curr_tssi_efuse_cck_de[i] = cck_de;
+
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][TRIM]: path=%d cck_de=0x%x\n", i, cck_de);
+
+ ofdm_de = phy_tssi_get_ofdm_de(rtwdev, phy, chan, i);
+ val = u32_get_bits(ofdm_de + trim_de, 0xff);
+
+ h2c->curr_tssi_ofdm_de[i] = 0x0;
+ h2c->curr_tssi_ofdm_de_20m[i] = val;
+ h2c->curr_tssi_ofdm_de_40m[i] = val;
+ h2c->curr_tssi_ofdm_de_80m[i] = val;
+ h2c->curr_tssi_ofdm_de_160m[i] = val;
+ h2c->curr_tssi_ofdm_de_320m[i] = val;
+ h2c->curr_tssi_efuse_ofdm_de[i] = ofdm_de;
+
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][TRIM]: path=%d ofdm_de=0x%x\n", i, ofdm_de);
+ }
+}
+
+void rtw89_phy_rfk_tssi_fill_fwcmd_tmeter_tbl(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy,
+ const struct rtw89_chan *chan,
+ struct rtw89_h2c_rf_tssi *h2c)
+{
+ struct rtw89_fw_txpwr_track_cfg *trk = rtwdev->fw.elm_info.txpwr_trk;
+ struct rtw89_tssi_info *tssi_info = &rtwdev->tssi;
+ const s8 *thm_up[RF_PATH_B + 1] = {};
+ const s8 *thm_down[RF_PATH_B + 1] = {};
+ u8 subband = chan->subband_type;
+ s8 thm_ofst[128] = {0};
+ u8 thermal;
+ u8 path;
+ u8 i, j;
+
+ switch (subband) {
+ default:
+ case RTW89_CH_2G:
+ thm_up[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_2GA_P][0];
+ thm_down[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_2GA_N][0];
+ thm_up[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_2GB_P][0];
+ thm_down[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_2GB_N][0];
+ break;
+ case RTW89_CH_5G_BAND_1:
+ thm_up[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GA_P][0];
+ thm_down[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GA_N][0];
+ thm_up[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GB_P][0];
+ thm_down[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GB_N][0];
+ break;
+ case RTW89_CH_5G_BAND_3:
+ thm_up[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GA_P][1];
+ thm_down[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GA_N][1];
+ thm_up[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GB_P][1];
+ thm_down[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GB_N][1];
+ break;
+ case RTW89_CH_5G_BAND_4:
+ thm_up[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GA_P][2];
+ thm_down[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GA_N][2];
+ thm_up[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GB_P][2];
+ thm_down[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_5GB_N][2];
+ break;
+ case RTW89_CH_6G_BAND_IDX0:
+ case RTW89_CH_6G_BAND_IDX1:
+ thm_up[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GA_P][0];
+ thm_down[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GA_N][0];
+ thm_up[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GB_P][0];
+ thm_down[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GB_N][0];
+ break;
+ case RTW89_CH_6G_BAND_IDX2:
+ case RTW89_CH_6G_BAND_IDX3:
+ thm_up[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GA_P][1];
+ thm_down[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GA_N][1];
+ thm_up[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GB_P][1];
+ thm_down[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GB_N][1];
+ break;
+ case RTW89_CH_6G_BAND_IDX4:
+ case RTW89_CH_6G_BAND_IDX5:
+ thm_up[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GA_P][2];
+ thm_down[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GA_N][2];
+ thm_up[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GB_P][2];
+ thm_down[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GB_N][2];
+ break;
+ case RTW89_CH_6G_BAND_IDX6:
+ case RTW89_CH_6G_BAND_IDX7:
+ thm_up[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GA_P][3];
+ thm_down[RF_PATH_A] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GA_N][3];
+ thm_up[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GB_P][3];
+ thm_down[RF_PATH_B] = trk->delta[RTW89_FW_TXPWR_TRK_TYPE_6GB_N][3];
+ break;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI] tmeter tbl on subband: %u\n", subband);
+
+ for (path = RF_PATH_A; path <= RF_PATH_B; path++) {
+ thermal = tssi_info->thermal[path];
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "path: %u, pg thermal: 0x%x\n", path, thermal);
+
+ if (thermal == 0xff) {
+ h2c->pg_thermal[path] = 0x38;
+ memset(h2c->ftable[path], 0, sizeof(h2c->ftable[path]));
+ continue;
+ }
+
+ h2c->pg_thermal[path] = thermal;
+
+ i = 0;
+ for (j = 0; j < 64; j++)
+ thm_ofst[j] = i < DELTA_SWINGIDX_SIZE ?
+ thm_up[path][i++] :
+ thm_up[path][DELTA_SWINGIDX_SIZE - 1];
+
+ i = 1;
+ for (j = 127; j >= 64; j--)
+ thm_ofst[j] = i < DELTA_SWINGIDX_SIZE ?
+ -thm_down[path][i++] :
+ -thm_down[path][DELTA_SWINGIDX_SIZE - 1];
+
+ for (i = 0; i < 128; i += 4) {
+ h2c->ftable[path][i + 0] = thm_ofst[i + 3];
+ h2c->ftable[path][i + 1] = thm_ofst[i + 2];
+ h2c->ftable[path][i + 2] = thm_ofst[i + 1];
+ h2c->ftable[path][i + 3] = thm_ofst[i + 0];
+
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "thm ofst [%x]: %02x %02x %02x %02x\n",
+ i, thm_ofst[i], thm_ofst[i + 1],
+ thm_ofst[i + 2], thm_ofst[i + 3]);
+ }
+ }
+}
+
static u8 rtw89_phy_cfo_get_xcap_reg(struct rtw89_dev *rtwdev, bool sc_xo)
{
+ const struct rtw89_xtal_info *xtal = rtwdev->chip->xtal_info;
u32 reg_mask;
if (sc_xo)
- reg_mask = B_AX_XTAL_SC_XO_MASK;
+ reg_mask = xtal->sc_xo_mask;
else
- reg_mask = B_AX_XTAL_SC_XI_MASK;
+ reg_mask = xtal->sc_xi_mask;
- return (u8)rtw89_read32_mask(rtwdev, R_AX_XTAL_ON_CTRL0, reg_mask);
+ return (u8)rtw89_read32_mask(rtwdev, xtal->xcap_reg, reg_mask);
}
static void rtw89_phy_cfo_set_xcap_reg(struct rtw89_dev *rtwdev, bool sc_xo,
u8 val)
{
+ const struct rtw89_xtal_info *xtal = rtwdev->chip->xtal_info;
u32 reg_mask;
if (sc_xo)
- reg_mask = B_AX_XTAL_SC_XO_MASK;
+ reg_mask = xtal->sc_xo_mask;
else
- reg_mask = B_AX_XTAL_SC_XI_MASK;
+ reg_mask = xtal->sc_xi_mask;
- rtw89_write32_mask(rtwdev, R_AX_XTAL_ON_CTRL0, reg_mask, val);
+ rtw89_write32_mask(rtwdev, xtal->xcap_reg, reg_mask, val);
}
static void rtw89_phy_cfo_set_crystal_cap(struct rtw89_dev *rtwdev,
@@ -2370,8 +4564,7 @@ static void rtw89_phy_cfo_set_crystal_cap(struct rtw89_dev *rtwdev,
if (!force && cfo->crystal_cap == crystal_cap)
return;
- crystal_cap = clamp_t(u8, crystal_cap, 0, 127);
- if (chip->chip_id == RTL8852A) {
+ if (chip->chip_id == RTL8852A || chip->chip_id == RTL8851B) {
rtw89_phy_cfo_set_xcap_reg(rtwdev, true, crystal_cap);
rtw89_phy_cfo_set_xcap_reg(rtwdev, false, crystal_cap);
sc_xo_val = rtw89_phy_cfo_get_xcap_reg(rtwdev, true);
@@ -2419,6 +4612,9 @@ static void rtw89_dcfo_comp(struct rtw89_dev *rtwdev, s32 curr_cfo)
s32 dcfo_comp_val;
int sign;
+ if (!dcfo_comp)
+ return;
+
if (!is_linked) {
rtw89_debug(rtwdev, RTW89_DBG_CFO, "DCFO: is_linked=%d\n",
is_linked);
@@ -2439,16 +4635,23 @@ static void rtw89_dcfo_comp(struct rtw89_dev *rtwdev, s32 curr_cfo)
static void rtw89_dcfo_comp_init(struct rtw89_dev *rtwdev)
{
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_cfo_regs *cfo = phy->cfo;
- rtw89_phy_set_phy_regs(rtwdev, R_DCFO_OPT, B_DCFO_OPT_EN, 1);
- rtw89_phy_set_phy_regs(rtwdev, R_DCFO_WEIGHT, B_DCFO_WEIGHT_MSK, 8);
+ rtw89_phy_set_phy_regs(rtwdev, cfo->comp_seg0, cfo->valid_0_mask, 1);
+ rtw89_phy_set_phy_regs(rtwdev, cfo->comp, cfo->weighting_mask, 8);
- if (chip->cfo_hw_comp)
- rtw89_write32_mask(rtwdev, R_AX_PWR_UL_CTRL2,
- B_AX_PWR_UL_CFO_MASK, 0x6);
- else
- rtw89_write32_clr(rtwdev, R_AX_PWR_UL_CTRL2, B_AX_PWR_UL_CFO_MASK);
+ if (chip->chip_gen == RTW89_CHIP_AX) {
+ if (chip->cfo_hw_comp) {
+ rtw89_write32_mask(rtwdev, R_AX_PWR_UL_CTRL2,
+ B_AX_PWR_UL_CFO_MASK, 0x6);
+ } else {
+ rtw89_phy_set_phy_regs(rtwdev, R_DCFO, B_DCFO, 1);
+ rtw89_write32_clr(rtwdev, R_AX_PWR_UL_CTRL2,
+ B_AX_PWR_UL_CFO_MASK);
+ }
+ }
}
static void rtw89_phy_cfo_init(struct rtw89_dev *rtwdev)
@@ -2471,7 +4674,6 @@ static void rtw89_phy_cfo_init(struct rtw89_dev *rtwdev)
rtw89_debug(rtwdev, RTW89_DBG_CFO, "Default xcap=%0x\n",
cfo->crystal_cap_default);
rtw89_phy_cfo_set_crystal_cap(rtwdev, cfo->crystal_cap_default, true);
- rtw89_phy_set_phy_regs(rtwdev, R_DCFO, B_DCFO, 1);
rtw89_dcfo_comp_init(rtwdev);
cfo->cfo_timer_ms = 2000;
cfo->cfo_trig_by_timer_en = false;
@@ -2484,15 +4686,19 @@ static void rtw89_phy_cfo_crystal_cap_adjust(struct rtw89_dev *rtwdev,
s32 curr_cfo)
{
struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking;
- s8 crystal_cap = cfo->crystal_cap;
+ int crystal_cap = cfo->crystal_cap;
s32 cfo_abs = abs(curr_cfo);
int sign;
+ if (curr_cfo == 0) {
+ rtw89_debug(rtwdev, RTW89_DBG_CFO, "curr_cfo=0\n");
+ return;
+ }
if (!cfo->is_adjust) {
if (cfo_abs > CFO_TRK_ENABLE_TH)
cfo->is_adjust = true;
} else {
- if (cfo_abs < CFO_TRK_STOP_TH)
+ if (cfo_abs <= CFO_TRK_STOP_TH)
cfo->is_adjust = false;
}
if (!cfo->is_adjust) {
@@ -2501,15 +4707,17 @@ static void rtw89_phy_cfo_crystal_cap_adjust(struct rtw89_dev *rtwdev,
}
sign = curr_cfo > 0 ? 1 : -1;
if (cfo_abs > CFO_TRK_STOP_TH_4)
- crystal_cap += 7 * sign;
+ crystal_cap += 3 * sign;
else if (cfo_abs > CFO_TRK_STOP_TH_3)
- crystal_cap += 5 * sign;
- else if (cfo_abs > CFO_TRK_STOP_TH_2)
crystal_cap += 3 * sign;
+ else if (cfo_abs > CFO_TRK_STOP_TH_2)
+ crystal_cap += 1 * sign;
else if (cfo_abs > CFO_TRK_STOP_TH_1)
crystal_cap += 1 * sign;
else
return;
+
+ crystal_cap = clamp(crystal_cap, 0, 127);
rtw89_phy_cfo_set_crystal_cap(rtwdev, (u8)crystal_cap, false);
rtw89_debug(rtwdev, RTW89_DBG_CFO,
"X_cap{Curr,Default}={0x%x,0x%x}\n",
@@ -2668,7 +4876,7 @@ static void rtw89_phy_cfo_dm(struct rtw89_dev *rtwdev)
cfo->dcfo_avg = 0;
rtw89_debug(rtwdev, RTW89_DBG_CFO, "CFO:total_sta_assoc=%d\n",
rtwdev->total_sta_assoc);
- if (rtwdev->total_sta_assoc == 0) {
+ if (rtwdev->total_sta_assoc == 0 || rtw89_is_mlo_1_1(rtwdev)) {
rtw89_phy_cfo_reset(rtwdev);
return;
}
@@ -2684,10 +4892,6 @@ static void rtw89_phy_cfo_dm(struct rtw89_dev *rtwdev)
new_cfo = rtw89_phy_average_cfo_calc(rtwdev);
else
new_cfo = rtw89_phy_multi_sta_cfo_calc(rtwdev);
- if (new_cfo == 0) {
- rtw89_debug(rtwdev, RTW89_DBG_CFO, "curr_cfo=0\n");
- return;
- }
if (cfo->divergence_lock_en) {
cfo->lock_cnt++;
if (cfo->lock_cnt > CFO_PERIOD_CNT) {
@@ -2723,29 +4927,28 @@ static void rtw89_phy_cfo_dm(struct rtw89_dev *rtwdev)
rtw89_phy_cfo_statistics_reset(rtwdev);
}
-void rtw89_phy_cfo_track_work(struct work_struct *work)
+void rtw89_phy_cfo_track_work(struct wiphy *wiphy, struct wiphy_work *work)
{
struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
cfo_track_work.work);
struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking;
- mutex_lock(&rtwdev->mutex);
+ lockdep_assert_wiphy(wiphy);
+
if (!cfo->cfo_trig_by_timer_en)
- goto out;
+ return;
rtw89_leave_ps_mode(rtwdev);
rtw89_phy_cfo_dm(rtwdev);
- ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->cfo_track_work,
- msecs_to_jiffies(cfo->cfo_timer_ms));
-out:
- mutex_unlock(&rtwdev->mutex);
+ wiphy_delayed_work_queue(wiphy, &rtwdev->cfo_track_work,
+ msecs_to_jiffies(cfo->cfo_timer_ms));
}
static void rtw89_phy_cfo_start_work(struct rtw89_dev *rtwdev)
{
struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking;
- ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->cfo_track_work,
- msecs_to_jiffies(cfo->cfo_timer_ms));
+ wiphy_delayed_work_queue(rtwdev->hw->wiphy, &rtwdev->cfo_track_work,
+ msecs_to_jiffies(cfo->cfo_timer_ms));
}
void rtw89_phy_cfo_track(struct rtw89_dev *rtwdev)
@@ -2823,32 +5026,33 @@ void rtw89_phy_cfo_parse(struct rtw89_dev *rtwdev, s16 cfo_val,
cfo->packet_count++;
}
-void rtw89_phy_ul_tb_assoc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+void rtw89_phy_ul_tb_assoc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif_link->chanctx_idx);
struct rtw89_phy_ul_tb_info *ul_tb_info = &rtwdev->ul_tb_info;
- if (!chip->support_ul_tb_ctrl)
+ if (!chip->ul_tb_waveform_ctrl)
return;
- rtwvif->def_tri_idx =
+ rtwvif_link->def_tri_idx =
rtw89_phy_read32_mask(rtwdev, R_DCFO_OPT, B_TXSHAPE_TRIANGULAR_CFG);
if (chip->chip_id == RTL8852B && rtwdev->hal.cv > CHIP_CBV)
- rtwvif->dyn_tb_bedge_en = false;
+ rtwvif_link->dyn_tb_bedge_en = false;
else if (chan->band_type >= RTW89_BAND_5G &&
chan->band_width >= RTW89_CHANNEL_WIDTH_40)
- rtwvif->dyn_tb_bedge_en = true;
+ rtwvif_link->dyn_tb_bedge_en = true;
else
- rtwvif->dyn_tb_bedge_en = false;
+ rtwvif_link->dyn_tb_bedge_en = false;
rtw89_debug(rtwdev, RTW89_DBG_UL_TB,
"[ULTB] def_if_bandedge=%d, def_tri_idx=%d\n",
- ul_tb_info->def_if_bandedge, rtwvif->def_tri_idx);
+ ul_tb_info->def_if_bandedge, rtwvif_link->def_tri_idx);
rtw89_debug(rtwdev, RTW89_DBG_UL_TB,
"[ULTB] dyn_tb_begde_en=%d, dyn_tb_tri_en=%d\n",
- rtwvif->dyn_tb_bedge_en, ul_tb_info->dyn_tb_tri_en);
+ rtwvif_link->dyn_tb_bedge_en, ul_tb_info->dyn_tb_tri_en);
}
struct rtw89_phy_ul_tb_check_data {
@@ -2859,55 +5063,103 @@ struct rtw89_phy_ul_tb_check_data {
u8 def_tri_idx;
};
+struct rtw89_phy_power_diff {
+ u32 q_00;
+ u32 q_11;
+ u32 q_matrix_en;
+ u32 ultb_1t_norm_160;
+ u32 ultb_2t_norm_160;
+ u32 com1_norm_1sts;
+ u32 com2_resp_1sts_path;
+};
+
+static void rtw89_phy_ofdma_power_diff(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
+{
+ static const struct rtw89_phy_power_diff table[2] = {
+ {0x0, 0x0, 0x0, 0x0, 0xf4, 0x3, 0x3},
+ {0xb50, 0xb50, 0x1, 0xc, 0x0, 0x1, 0x1},
+ };
+ const struct rtw89_phy_power_diff *param;
+ u32 reg;
+
+ if (!rtwdev->chip->ul_tb_pwr_diff)
+ return;
+
+ if (rtwvif_link->pwr_diff_en == rtwvif_link->pre_pwr_diff_en) {
+ rtwvif_link->pwr_diff_en = false;
+ return;
+ }
+
+ rtwvif_link->pre_pwr_diff_en = rtwvif_link->pwr_diff_en;
+ param = &table[rtwvif_link->pwr_diff_en];
+
+ rtw89_phy_write32_mask(rtwdev, R_Q_MATRIX_00, B_Q_MATRIX_00_REAL,
+ param->q_00);
+ rtw89_phy_write32_mask(rtwdev, R_Q_MATRIX_11, B_Q_MATRIX_11_REAL,
+ param->q_11);
+ rtw89_phy_write32_mask(rtwdev, R_CUSTOMIZE_Q_MATRIX,
+ B_CUSTOMIZE_Q_MATRIX_EN, param->q_matrix_en);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_1T, rtwvif_link->mac_idx);
+ rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_1T_NORM_BW160,
+ param->ultb_1t_norm_160);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_2T, rtwvif_link->mac_idx);
+ rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_2T_NORM_BW160,
+ param->ultb_2t_norm_160);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PATH_COM1, rtwvif_link->mac_idx);
+ rtw89_write32_mask(rtwdev, reg, B_AX_PATH_COM1_NORM_1STS,
+ param->com1_norm_1sts);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PATH_COM2, rtwvif_link->mac_idx);
+ rtw89_write32_mask(rtwdev, reg, B_AX_PATH_COM2_RESP_1STS_PATH,
+ param->com2_resp_1sts_path);
+}
+
static
void rtw89_phy_ul_tb_ctrl_check(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif,
+ struct rtw89_vif_link *rtwvif_link,
struct rtw89_phy_ul_tb_check_data *ul_tb_data)
{
struct rtw89_traffic_stats *stats = &rtwdev->stats;
- struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
- if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION)
+ if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION)
return;
if (!vif->cfg.assoc)
return;
- if (stats->rx_tf_periodic > UL_TB_TF_CNT_L2H_TH)
- ul_tb_data->high_tf_client = true;
- else if (stats->rx_tf_periodic < UL_TB_TF_CNT_H2L_TH)
- ul_tb_data->low_tf_client = true;
+ if (rtwdev->chip->ul_tb_waveform_ctrl) {
+ if (stats->rx_tf_periodic > UL_TB_TF_CNT_L2H_TH)
+ ul_tb_data->high_tf_client = true;
+ else if (stats->rx_tf_periodic < UL_TB_TF_CNT_H2L_TH)
+ ul_tb_data->low_tf_client = true;
+
+ ul_tb_data->valid = true;
+ ul_tb_data->def_tri_idx = rtwvif_link->def_tri_idx;
+ ul_tb_data->dyn_tb_bedge_en = rtwvif_link->dyn_tb_bedge_en;
+ }
- ul_tb_data->valid = true;
- ul_tb_data->def_tri_idx = rtwvif->def_tri_idx;
- ul_tb_data->dyn_tb_bedge_en = rtwvif->dyn_tb_bedge_en;
+ rtw89_phy_ofdma_power_diff(rtwdev, rtwvif_link);
}
-void rtw89_phy_ul_tb_ctrl_track(struct rtw89_dev *rtwdev)
+static void rtw89_phy_ul_tb_waveform_ctrl(struct rtw89_dev *rtwdev,
+ struct rtw89_phy_ul_tb_check_data *ul_tb_data)
{
- const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_phy_ul_tb_info *ul_tb_info = &rtwdev->ul_tb_info;
- struct rtw89_phy_ul_tb_check_data ul_tb_data = {};
- struct rtw89_vif *rtwvif;
-
- if (!chip->support_ul_tb_ctrl)
- return;
- if (rtwdev->total_sta_assoc != 1)
+ if (!rtwdev->chip->ul_tb_waveform_ctrl)
return;
- rtw89_for_each_rtwvif(rtwdev, rtwvif)
- rtw89_phy_ul_tb_ctrl_check(rtwdev, rtwvif, &ul_tb_data);
-
- if (!ul_tb_data.valid)
- return;
-
- if (ul_tb_data.dyn_tb_bedge_en) {
- if (ul_tb_data.high_tf_client) {
+ if (ul_tb_data->dyn_tb_bedge_en) {
+ if (ul_tb_data->high_tf_client) {
rtw89_phy_write32_mask(rtwdev, R_BANDEDGE, B_BANDEDGE_EN, 0);
rtw89_debug(rtwdev, RTW89_DBG_UL_TB,
"[ULTB] Turn off if_bandedge\n");
- } else if (ul_tb_data.low_tf_client) {
+ } else if (ul_tb_data->low_tf_client) {
rtw89_phy_write32_mask(rtwdev, R_BANDEDGE, B_BANDEDGE_EN,
ul_tb_info->def_if_bandedge);
rtw89_debug(rtwdev, RTW89_DBG_UL_TB,
@@ -2917,28 +5169,52 @@ void rtw89_phy_ul_tb_ctrl_track(struct rtw89_dev *rtwdev)
}
if (ul_tb_info->dyn_tb_tri_en) {
- if (ul_tb_data.high_tf_client) {
+ if (ul_tb_data->high_tf_client) {
rtw89_phy_write32_mask(rtwdev, R_DCFO_OPT,
B_TXSHAPE_TRIANGULAR_CFG, 0);
rtw89_debug(rtwdev, RTW89_DBG_UL_TB,
"[ULTB] Turn off Tx triangle\n");
- } else if (ul_tb_data.low_tf_client) {
+ } else if (ul_tb_data->low_tf_client) {
rtw89_phy_write32_mask(rtwdev, R_DCFO_OPT,
B_TXSHAPE_TRIANGULAR_CFG,
- ul_tb_data.def_tri_idx);
+ ul_tb_data->def_tri_idx);
rtw89_debug(rtwdev, RTW89_DBG_UL_TB,
"[ULTB] Set to default tx_shap_idx = %d\n",
- ul_tb_data.def_tri_idx);
+ ul_tb_data->def_tri_idx);
}
}
}
+void rtw89_phy_ul_tb_ctrl_track(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_phy_ul_tb_check_data ul_tb_data = {};
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_vif *rtwvif;
+ unsigned int link_id;
+
+ if (!chip->ul_tb_waveform_ctrl && !chip->ul_tb_pwr_diff)
+ return;
+
+ if (rtwdev->total_sta_assoc != 1)
+ return;
+
+ rtw89_for_each_rtwvif(rtwdev, rtwvif)
+ rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
+ rtw89_phy_ul_tb_ctrl_check(rtwdev, rtwvif_link, &ul_tb_data);
+
+ if (!ul_tb_data.valid)
+ return;
+
+ rtw89_phy_ul_tb_waveform_ctrl(rtwdev, &ul_tb_data);
+}
+
static void rtw89_phy_ul_tb_info_init(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_phy_ul_tb_info *ul_tb_info = &rtwdev->ul_tb_info;
- if (!chip->support_ul_tb_ctrl)
+ if (!chip->ul_tb_waveform_ctrl)
return;
ul_tb_info->dyn_tb_tri_en = true;
@@ -2946,11 +5222,156 @@ static void rtw89_phy_ul_tb_info_init(struct rtw89_dev *rtwdev)
rtw89_phy_read32_mask(rtwdev, R_BANDEDGE, B_BANDEDGE_EN);
}
+static
+void rtw89_phy_antdiv_sts_instance_reset(struct rtw89_antdiv_stats *antdiv_sts)
+{
+ ewma_rssi_init(&antdiv_sts->cck_rssi_avg);
+ ewma_rssi_init(&antdiv_sts->ofdm_rssi_avg);
+ ewma_rssi_init(&antdiv_sts->non_legacy_rssi_avg);
+ antdiv_sts->pkt_cnt_cck = 0;
+ antdiv_sts->pkt_cnt_ofdm = 0;
+ antdiv_sts->pkt_cnt_non_legacy = 0;
+ antdiv_sts->evm = 0;
+}
+
+static void rtw89_phy_antdiv_sts_instance_add(struct rtw89_dev *rtwdev,
+ struct rtw89_rx_phy_ppdu *phy_ppdu,
+ struct rtw89_antdiv_stats *stats)
+{
+ if (rtw89_get_data_rate_mode(rtwdev, phy_ppdu->rate) == DATA_RATE_MODE_NON_HT) {
+ if (phy_ppdu->rate < RTW89_HW_RATE_OFDM6) {
+ ewma_rssi_add(&stats->cck_rssi_avg, phy_ppdu->rssi_avg);
+ stats->pkt_cnt_cck++;
+ } else {
+ ewma_rssi_add(&stats->ofdm_rssi_avg, phy_ppdu->rssi_avg);
+ stats->pkt_cnt_ofdm++;
+ stats->evm += phy_ppdu->ofdm.evm_min;
+ }
+ } else {
+ ewma_rssi_add(&stats->non_legacy_rssi_avg, phy_ppdu->rssi_avg);
+ stats->pkt_cnt_non_legacy++;
+ stats->evm += phy_ppdu->ofdm.evm_min;
+ }
+}
+
+static u8 rtw89_phy_antdiv_sts_instance_get_rssi(struct rtw89_antdiv_stats *stats)
+{
+ if (stats->pkt_cnt_non_legacy >= stats->pkt_cnt_cck &&
+ stats->pkt_cnt_non_legacy >= stats->pkt_cnt_ofdm)
+ return ewma_rssi_read(&stats->non_legacy_rssi_avg);
+ else if (stats->pkt_cnt_ofdm >= stats->pkt_cnt_cck &&
+ stats->pkt_cnt_ofdm >= stats->pkt_cnt_non_legacy)
+ return ewma_rssi_read(&stats->ofdm_rssi_avg);
+ else
+ return ewma_rssi_read(&stats->cck_rssi_avg);
+}
+
+static u8 rtw89_phy_antdiv_sts_instance_get_evm(struct rtw89_antdiv_stats *stats)
+{
+ return phy_div(stats->evm, stats->pkt_cnt_non_legacy + stats->pkt_cnt_ofdm);
+}
+
+void rtw89_phy_antdiv_parse(struct rtw89_dev *rtwdev,
+ struct rtw89_rx_phy_ppdu *phy_ppdu)
+{
+ struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv;
+ struct rtw89_hal *hal = &rtwdev->hal;
+
+ if (!hal->ant_diversity || hal->ant_diversity_fixed)
+ return;
+
+ rtw89_phy_antdiv_sts_instance_add(rtwdev, phy_ppdu, &antdiv->target_stats);
+
+ if (!antdiv->get_stats)
+ return;
+
+ if (hal->antenna_rx == RF_A)
+ rtw89_phy_antdiv_sts_instance_add(rtwdev, phy_ppdu, &antdiv->main_stats);
+ else if (hal->antenna_rx == RF_B)
+ rtw89_phy_antdiv_sts_instance_add(rtwdev, phy_ppdu, &antdiv->aux_stats);
+}
+
+static void rtw89_phy_antdiv_reg_init(struct rtw89_dev *rtwdev)
+{
+ rtw89_phy_write32_idx(rtwdev, R_P0_TRSW, B_P0_ANT_TRAIN_EN,
+ 0x0, RTW89_PHY_0);
+ rtw89_phy_write32_idx(rtwdev, R_P0_TRSW, B_P0_TX_ANT_SEL,
+ 0x0, RTW89_PHY_0);
+
+ rtw89_phy_write32_idx(rtwdev, R_P0_ANT_SW, B_P0_TRSW_TX_EXTEND,
+ 0x0, RTW89_PHY_0);
+ rtw89_phy_write32_idx(rtwdev, R_P0_ANT_SW, B_P0_HW_ANTSW_DIS_BY_GNT_BT,
+ 0x0, RTW89_PHY_0);
+
+ rtw89_phy_write32_idx(rtwdev, R_P0_TRSW, B_P0_BT_FORCE_ANTIDX_EN,
+ 0x0, RTW89_PHY_0);
+
+ rtw89_phy_write32_idx(rtwdev, R_RFSW_CTRL_ANT0_BASE, B_RFSW_CTRL_ANT_MAPPING,
+ 0x0100, RTW89_PHY_0);
+
+ rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_BTG_TRX,
+ 0x1, RTW89_PHY_0);
+ rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_HW_CTRL,
+ 0x0, RTW89_PHY_0);
+ rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_SW_2G,
+ 0x0, RTW89_PHY_0);
+ rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_SW_5G,
+ 0x0, RTW89_PHY_0);
+}
+
+static void rtw89_phy_antdiv_sts_reset(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv;
+
+ rtw89_phy_antdiv_sts_instance_reset(&antdiv->target_stats);
+ rtw89_phy_antdiv_sts_instance_reset(&antdiv->main_stats);
+ rtw89_phy_antdiv_sts_instance_reset(&antdiv->aux_stats);
+}
+
+static void rtw89_phy_antdiv_init(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv;
+ struct rtw89_hal *hal = &rtwdev->hal;
+
+ if (!hal->ant_diversity)
+ return;
+
+ antdiv->get_stats = false;
+ antdiv->rssi_pre = 0;
+ rtw89_phy_antdiv_sts_reset(rtwdev);
+ rtw89_phy_antdiv_reg_init(rtwdev);
+}
+
+static void rtw89_phy_thermal_protect(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_phy_stat *phystat = &rtwdev->phystat;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u8 th_max = phystat->last_thermal_max;
+ u8 lv = hal->thermal_prot_lv;
+
+ if (!hal->thermal_prot_th ||
+ (hal->disabled_dm_bitmap & BIT(RTW89_DM_THERMAL_PROTECT)))
+ return;
+
+ if (th_max > hal->thermal_prot_th && lv < RTW89_THERMAL_PROT_LV_MAX)
+ lv++;
+ else if (th_max < hal->thermal_prot_th - 2 && lv > 0)
+ lv--;
+ else
+ return;
+
+ hal->thermal_prot_lv = lv;
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, "thermal protection lv=%d\n", lv);
+
+ rtw89_fw_h2c_tx_duty(rtwdev, hal->thermal_prot_lv);
+}
+
static void rtw89_phy_stat_thermal_update(struct rtw89_dev *rtwdev)
{
struct rtw89_phy_stat *phystat = &rtwdev->phystat;
+ u8 th, th_max = 0;
int i;
- u8 th;
for (i = 0; i < rtwdev->chip->rf_path_num; i++) {
th = rtw89_chip_get_thermal(rtwdev, i);
@@ -2960,46 +5381,68 @@ static void rtw89_phy_stat_thermal_update(struct rtw89_dev *rtwdev)
rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK,
"path(%d) thermal cur=%u avg=%ld", i, th,
ewma_thermal_read(&phystat->avg_thermal[i]));
+
+ th_max = max(th_max, th);
}
+
+ phystat->last_thermal_max = th_max;
}
struct rtw89_phy_iter_rssi_data {
struct rtw89_dev *rtwdev;
- struct rtw89_phy_ch_info *ch_info;
bool rssi_changed;
};
-static void rtw89_phy_stat_rssi_update_iter(void *data,
- struct ieee80211_sta *sta)
+static
+void __rtw89_phy_stat_rssi_update_iter(struct rtw89_sta_link *rtwsta_link,
+ struct rtw89_phy_iter_rssi_data *rssi_data)
{
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
- struct rtw89_phy_iter_rssi_data *rssi_data =
- (struct rtw89_phy_iter_rssi_data *)data;
- struct rtw89_phy_ch_info *ch_info = rssi_data->ch_info;
+ struct rtw89_vif_link *rtwvif_link = rtwsta_link->rtwvif_link;
+ struct rtw89_dev *rtwdev = rssi_data->rtwdev;
+ struct rtw89_phy_ch_info *ch_info;
+ struct rtw89_bb_ctx *bb;
unsigned long rssi_curr;
- rssi_curr = ewma_rssi_read(&rtwsta->avg_rssi);
+ rssi_curr = ewma_rssi_read(&rtwsta_link->avg_rssi);
+ bb = rtw89_get_bb_ctx(rtwdev, rtwvif_link->phy_idx);
+ ch_info = &bb->ch_info;
if (rssi_curr < ch_info->rssi_min) {
ch_info->rssi_min = rssi_curr;
- ch_info->rssi_min_macid = rtwsta->mac_id;
+ ch_info->rssi_min_macid = rtwsta_link->mac_id;
}
- if (rtwsta->prev_rssi == 0) {
- rtwsta->prev_rssi = rssi_curr;
- } else if (abs((int)rtwsta->prev_rssi - (int)rssi_curr) > (3 << RSSI_FACTOR)) {
- rtwsta->prev_rssi = rssi_curr;
+ if (rtwsta_link->prev_rssi == 0) {
+ rtwsta_link->prev_rssi = rssi_curr;
+ } else if (abs((int)rtwsta_link->prev_rssi - (int)rssi_curr) >
+ (3 << RSSI_FACTOR)) {
+ rtwsta_link->prev_rssi = rssi_curr;
rssi_data->rssi_changed = true;
}
}
+static void rtw89_phy_stat_rssi_update_iter(void *data,
+ struct ieee80211_sta *sta)
+{
+ struct rtw89_phy_iter_rssi_data *rssi_data =
+ (struct rtw89_phy_iter_rssi_data *)data;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_sta_link *rtwsta_link;
+ unsigned int link_id;
+
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id)
+ __rtw89_phy_stat_rssi_update_iter(rtwsta_link, rssi_data);
+}
+
static void rtw89_phy_stat_rssi_update(struct rtw89_dev *rtwdev)
{
- struct rtw89_phy_iter_rssi_data rssi_data = {0};
+ struct rtw89_phy_iter_rssi_data rssi_data = {};
+ struct rtw89_bb_ctx *bb;
rssi_data.rtwdev = rtwdev;
- rssi_data.ch_info = &rtwdev->ch_info;
- rssi_data.ch_info->rssi_min = U8_MAX;
+ rtw89_for_each_active_bb(rtwdev, bb)
+ bb->ch_info.rssi_min = U8_MAX;
+
ieee80211_iterate_stations_atomic(rtwdev->hw,
rtw89_phy_stat_rssi_update_iter,
&rssi_data);
@@ -3019,6 +5462,10 @@ static void rtw89_phy_stat_init(struct rtw89_dev *rtwdev)
memset(&phystat->cur_pkt_stat, 0, sizeof(phystat->cur_pkt_stat));
memset(&phystat->last_pkt_stat, 0, sizeof(phystat->last_pkt_stat));
+
+ ewma_rssi_init(&phystat->bcn_rssi);
+
+ rtwdev->hal.thermal_prot_lv = 0;
}
void rtw89_phy_stat_track(struct rtw89_dev *rtwdev)
@@ -3026,50 +5473,56 @@ void rtw89_phy_stat_track(struct rtw89_dev *rtwdev)
struct rtw89_phy_stat *phystat = &rtwdev->phystat;
rtw89_phy_stat_thermal_update(rtwdev);
+ rtw89_phy_thermal_protect(rtwdev);
rtw89_phy_stat_rssi_update(rtwdev);
phystat->last_pkt_stat = phystat->cur_pkt_stat;
memset(&phystat->cur_pkt_stat, 0, sizeof(phystat->cur_pkt_stat));
}
-static u16 rtw89_phy_ccx_us_to_idx(struct rtw89_dev *rtwdev, u32 time_us)
+static u16 rtw89_phy_ccx_us_to_idx(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb, u32 time_us)
{
- struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
return time_us >> (ilog2(CCX_US_BASE_RATIO) + env->ccx_unit_idx);
}
-static u32 rtw89_phy_ccx_idx_to_us(struct rtw89_dev *rtwdev, u16 idx)
+static u32 rtw89_phy_ccx_idx_to_us(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb, u16 idx)
{
- struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
return idx << (ilog2(CCX_US_BASE_RATIO) + env->ccx_unit_idx);
}
-static void rtw89_phy_ccx_top_setting_init(struct rtw89_dev *rtwdev)
+static void rtw89_phy_ccx_top_setting_init(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
{
- struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
+ const struct rtw89_ccx_regs *ccx = phy->ccx;
env->ccx_manual_ctrl = false;
env->ccx_ongoing = false;
env->ccx_rac_lv = RTW89_RAC_RELEASE;
- env->ccx_rpt_stamp = 0;
env->ccx_period = 0;
env->ccx_unit_idx = RTW89_CCX_32_US;
- env->ccx_trigger_time = 0;
- env->ccx_edcca_opt_bw_idx = RTW89_CCX_EDCCA_BW20_0;
- rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_CCX_EN_MSK, 1);
- rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_CCX_TRIG_OPT_MSK, 1);
- rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_MEASUREMENT_TRIG_MSK, 1);
- rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_CCX_EDCCA_OPT_MSK,
- RTW89_CCX_EDCCA_BW20_0);
+ rtw89_phy_write32_idx(rtwdev, ccx->setting_addr, ccx->en_mask, 1, bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, ccx->setting_addr, ccx->trig_opt_mask, 1,
+ bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, ccx->setting_addr, ccx->measurement_trig_mask, 1,
+ bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, ccx->setting_addr, ccx->edcca_opt_mask,
+ RTW89_CCX_EDCCA_BW20_0, bb->phy_idx);
}
-static u16 rtw89_phy_ccx_get_report(struct rtw89_dev *rtwdev, u16 report,
- u16 score)
+static u16 rtw89_phy_ccx_get_report(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb,
+ u16 report, u16 score)
{
- struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
u32 numer = 0;
u16 ret = 0;
@@ -3109,9 +5562,10 @@ static void rtw89_phy_ccx_ms_to_period_unit(struct rtw89_dev *rtwdev,
*period, *unit_idx);
}
-static void rtw89_phy_ccx_racing_release(struct rtw89_dev *rtwdev)
+static void rtw89_phy_ccx_racing_release(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
{
- struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
"lv:(%d)->(0)\n", env->ccx_rac_lv);
@@ -3122,9 +5576,10 @@ static void rtw89_phy_ccx_racing_release(struct rtw89_dev *rtwdev)
}
static bool rtw89_phy_ifs_clm_th_update_check(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb,
struct rtw89_ccx_para_info *para)
{
- struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
bool is_update = env->ifs_clm_app != para->ifs_clm_app;
u8 i = 0;
u16 *ifs_th_l = env->ifs_clm_th_l;
@@ -3159,12 +5614,12 @@ static bool rtw89_phy_ifs_clm_th_update_check(struct rtw89_dev *rtwdev,
*/
ifs_th_l[IFS_CLM_TH_START_IDX] = 0;
ifs_th_h_us[IFS_CLM_TH_START_IDX] = ifs_th0_us;
- ifs_th_h[IFS_CLM_TH_START_IDX] = rtw89_phy_ccx_us_to_idx(rtwdev,
+ ifs_th_h[IFS_CLM_TH_START_IDX] = rtw89_phy_ccx_us_to_idx(rtwdev, bb,
ifs_th0_us);
for (i = 1; i < RTW89_IFS_CLM_NUM; i++) {
ifs_th_l[i] = ifs_th_h[i - 1] + 1;
ifs_th_h_us[i] = ifs_th_h_us[i - 1] * ifs_th_times;
- ifs_th_h[i] = rtw89_phy_ccx_us_to_idx(rtwdev, ifs_th_h_us[i]);
+ ifs_th_h[i] = rtw89_phy_ccx_us_to_idx(rtwdev, bb, ifs_th_h_us[i]);
}
ifs_update_finished:
@@ -3175,28 +5630,31 @@ ifs_update_finished:
return is_update;
}
-static void rtw89_phy_ifs_clm_set_th_reg(struct rtw89_dev *rtwdev)
+static void rtw89_phy_ifs_clm_set_th_reg(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
{
- struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
+ const struct rtw89_ccx_regs *ccx = phy->ccx;
u8 i = 0;
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T1, B_IFS_T1_TH_LOW_MSK,
- env->ifs_clm_th_l[0]);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T2, B_IFS_T2_TH_LOW_MSK,
- env->ifs_clm_th_l[1]);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T3, B_IFS_T3_TH_LOW_MSK,
- env->ifs_clm_th_l[2]);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T4, B_IFS_T4_TH_LOW_MSK,
- env->ifs_clm_th_l[3]);
-
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T1, B_IFS_T1_TH_HIGH_MSK,
- env->ifs_clm_th_h[0]);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T2, B_IFS_T2_TH_HIGH_MSK,
- env->ifs_clm_th_h[1]);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T3, B_IFS_T3_TH_HIGH_MSK,
- env->ifs_clm_th_h[2]);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T4, B_IFS_T4_TH_HIGH_MSK,
- env->ifs_clm_th_h[3]);
+ rtw89_phy_write32_idx(rtwdev, ccx->ifs_t1_addr, ccx->ifs_t1_th_l_mask,
+ env->ifs_clm_th_l[0], bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, ccx->ifs_t2_addr, ccx->ifs_t2_th_l_mask,
+ env->ifs_clm_th_l[1], bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, ccx->ifs_t3_addr, ccx->ifs_t3_th_l_mask,
+ env->ifs_clm_th_l[2], bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, ccx->ifs_t4_addr, ccx->ifs_t4_th_l_mask,
+ env->ifs_clm_th_l[3], bb->phy_idx);
+
+ rtw89_phy_write32_idx(rtwdev, ccx->ifs_t1_addr, ccx->ifs_t1_th_h_mask,
+ env->ifs_clm_th_h[0], bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, ccx->ifs_t2_addr, ccx->ifs_t2_th_h_mask,
+ env->ifs_clm_th_h[1], bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, ccx->ifs_t3_addr, ccx->ifs_t3_th_h_mask,
+ env->ifs_clm_th_h[2], bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, ccx->ifs_t4_addr, ccx->ifs_t4_th_h_mask,
+ env->ifs_clm_th_h[3], bb->phy_idx);
for (i = 0; i < RTW89_IFS_CLM_NUM; i++)
rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
@@ -3204,30 +5662,66 @@ static void rtw89_phy_ifs_clm_set_th_reg(struct rtw89_dev *rtwdev)
i + 1, env->ifs_clm_th_l[i], env->ifs_clm_th_h[i]);
}
-static void rtw89_phy_ifs_clm_setting_init(struct rtw89_dev *rtwdev)
+static void __rtw89_phy_nhm_setting_init(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
+{
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
+ const struct rtw89_ccx_regs *ccx = phy->ccx;
+
+ env->nhm_include_cca = false;
+ env->nhm_mntr_time = 0;
+ env->nhm_sum = 0;
+
+ rtw89_phy_write32_idx_set(rtwdev, ccx->nhm_config, ccx->nhm_en_mask, bb->phy_idx);
+ rtw89_phy_write32_idx_set(rtwdev, ccx->nhm_method, ccx->nhm_pwr_method_msk,
+ bb->phy_idx);
+}
+
+void rtw89_phy_nhm_setting_init(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_bb_ctx *bb;
+
+ if (!chip->support_noise)
+ return;
+
+ rtw89_for_each_active_bb(rtwdev, bb)
+ __rtw89_phy_nhm_setting_init(rtwdev, bb);
+}
+
+static void rtw89_phy_ifs_clm_setting_init(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
{
- struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
- struct rtw89_ccx_para_info para = {0};
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
+ const struct rtw89_ccx_regs *ccx = phy->ccx;
+ struct rtw89_ccx_para_info para = {};
env->ifs_clm_app = RTW89_IFS_CLM_BACKGROUND;
env->ifs_clm_mntr_time = 0;
para.ifs_clm_app = RTW89_IFS_CLM_INIT;
- if (rtw89_phy_ifs_clm_th_update_check(rtwdev, &para))
- rtw89_phy_ifs_clm_set_th_reg(rtwdev);
+ if (rtw89_phy_ifs_clm_th_update_check(rtwdev, bb, &para))
+ rtw89_phy_ifs_clm_set_th_reg(rtwdev, bb);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_COUNTER, B_IFS_COLLECT_EN,
- true);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T1, B_IFS_T1_EN_MSK, true);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T2, B_IFS_T2_EN_MSK, true);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T3, B_IFS_T3_EN_MSK, true);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_T4, B_IFS_T4_EN_MSK, true);
+ rtw89_phy_write32_idx(rtwdev, ccx->ifs_cnt_addr, ccx->ifs_collect_en_mask, true,
+ bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, ccx->ifs_t1_addr, ccx->ifs_t1_en_mask, true,
+ bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, ccx->ifs_t2_addr, ccx->ifs_t2_en_mask, true,
+ bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, ccx->ifs_t3_addr, ccx->ifs_t3_en_mask, true,
+ bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, ccx->ifs_t4_addr, ccx->ifs_t4_en_mask, true,
+ bb->phy_idx);
}
static int rtw89_phy_ccx_racing_ctrl(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb,
enum rtw89_env_racing_lv level)
{
- struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
int ret = 0;
if (level >= RTW89_RAC_MAX_NUM) {
@@ -3256,55 +5750,69 @@ static int rtw89_phy_ccx_racing_ctrl(struct rtw89_dev *rtwdev,
return ret;
}
-static void rtw89_phy_ccx_trigger(struct rtw89_dev *rtwdev)
+static void rtw89_phy_ccx_trigger(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb, u8 sel)
{
- struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
+ const struct rtw89_ccx_regs *ccx = phy->ccx;
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_COUNTER, B_IFS_COUNTER_CLR_MSK, 0);
- rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_MEASUREMENT_TRIG_MSK, 0);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_COUNTER, B_IFS_COUNTER_CLR_MSK, 1);
- rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_MEASUREMENT_TRIG_MSK, 1);
+ rtw89_phy_write32_idx(rtwdev, ccx->ifs_cnt_addr, ccx->ifs_clm_cnt_clear_mask, 0,
+ bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, ccx->setting_addr, ccx->measurement_trig_mask, 0,
+ bb->phy_idx);
+ if (sel & RTW89_PHY_ENV_MON_NHM)
+ rtw89_phy_write32_idx_clr(rtwdev, ccx->nhm_config,
+ ccx->nhm_en_mask, bb->phy_idx);
+
+ rtw89_phy_write32_idx(rtwdev, ccx->ifs_cnt_addr, ccx->ifs_clm_cnt_clear_mask, 1,
+ bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, ccx->setting_addr, ccx->measurement_trig_mask, 1,
+ bb->phy_idx);
+ if (sel & RTW89_PHY_ENV_MON_NHM)
+ rtw89_phy_write32_idx_set(rtwdev, ccx->nhm_config,
+ ccx->nhm_en_mask, bb->phy_idx);
- env->ccx_rpt_stamp++;
env->ccx_ongoing = true;
}
-static void rtw89_phy_ifs_clm_get_utility(struct rtw89_dev *rtwdev)
+static void rtw89_phy_ifs_clm_get_utility(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
{
- struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
u8 i = 0;
u32 res = 0;
env->ifs_clm_tx_ratio =
- rtw89_phy_ccx_get_report(rtwdev, env->ifs_clm_tx, PERCENT);
+ rtw89_phy_ccx_get_report(rtwdev, bb, env->ifs_clm_tx, PERCENT);
env->ifs_clm_edcca_excl_cca_ratio =
- rtw89_phy_ccx_get_report(rtwdev, env->ifs_clm_edcca_excl_cca,
+ rtw89_phy_ccx_get_report(rtwdev, bb, env->ifs_clm_edcca_excl_cca,
PERCENT);
env->ifs_clm_cck_fa_ratio =
- rtw89_phy_ccx_get_report(rtwdev, env->ifs_clm_cckfa, PERCENT);
+ rtw89_phy_ccx_get_report(rtwdev, bb, env->ifs_clm_cckfa, PERCENT);
env->ifs_clm_ofdm_fa_ratio =
- rtw89_phy_ccx_get_report(rtwdev, env->ifs_clm_ofdmfa, PERCENT);
+ rtw89_phy_ccx_get_report(rtwdev, bb, env->ifs_clm_ofdmfa, PERCENT);
env->ifs_clm_cck_cca_excl_fa_ratio =
- rtw89_phy_ccx_get_report(rtwdev, env->ifs_clm_cckcca_excl_fa,
+ rtw89_phy_ccx_get_report(rtwdev, bb, env->ifs_clm_cckcca_excl_fa,
PERCENT);
env->ifs_clm_ofdm_cca_excl_fa_ratio =
- rtw89_phy_ccx_get_report(rtwdev, env->ifs_clm_ofdmcca_excl_fa,
+ rtw89_phy_ccx_get_report(rtwdev, bb, env->ifs_clm_ofdmcca_excl_fa,
PERCENT);
env->ifs_clm_cck_fa_permil =
- rtw89_phy_ccx_get_report(rtwdev, env->ifs_clm_cckfa, PERMIL);
+ rtw89_phy_ccx_get_report(rtwdev, bb, env->ifs_clm_cckfa, PERMIL);
env->ifs_clm_ofdm_fa_permil =
- rtw89_phy_ccx_get_report(rtwdev, env->ifs_clm_ofdmfa, PERMIL);
+ rtw89_phy_ccx_get_report(rtwdev, bb, env->ifs_clm_ofdmfa, PERMIL);
for (i = 0; i < RTW89_IFS_CLM_NUM; i++) {
if (env->ifs_clm_his[i] > ENV_MNTR_IFSCLM_HIS_MAX) {
env->ifs_clm_ifs_avg[i] = ENV_MNTR_FAIL_DWORD;
} else {
env->ifs_clm_ifs_avg[i] =
- rtw89_phy_ccx_idx_to_us(rtwdev,
+ rtw89_phy_ccx_idx_to_us(rtwdev, bb,
env->ifs_clm_avg[i]);
}
- res = rtw89_phy_ccx_idx_to_us(rtwdev, env->ifs_clm_cca[i]);
+ res = rtw89_phy_ccx_idx_to_us(rtwdev, bb, env->ifs_clm_cca[i]);
res += env->ifs_clm_his[i] >> 1;
if (env->ifs_clm_his[i])
res /= env->ifs_clm_his[i];
@@ -3334,65 +5842,201 @@ static void rtw89_phy_ifs_clm_get_utility(struct rtw89_dev *rtwdev)
env->ifs_clm_cca_avg[i]);
}
-static bool rtw89_phy_ifs_clm_get_result(struct rtw89_dev *rtwdev)
+static u8 rtw89_nhm_weighted_avg(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
+{
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
+ u8 nhm_weight[RTW89_NHM_RPT_NUM];
+ u32 nhm_weighted_sum = 0;
+ u8 weight_zero;
+ u8 i;
+
+ if (env->nhm_sum == 0)
+ return 0;
+
+ weight_zero = clamp_t(u16, env->nhm_th[0] - RTW89_NHM_WEIGHT_OFFSET, 0, U8_MAX);
+
+ for (i = 0; i < RTW89_NHM_RPT_NUM; i++) {
+ if (i == 0)
+ nhm_weight[i] = weight_zero;
+ else if (i == (RTW89_NHM_RPT_NUM - 1))
+ nhm_weight[i] = env->nhm_th[i - 1] + RTW89_NHM_WEIGHT_OFFSET;
+ else
+ nhm_weight[i] = (env->nhm_th[i - 1] + env->nhm_th[i]) / 2;
+ }
+
+ if (rtwdev->chip->chip_id == RTL8852A || rtwdev->chip->chip_id == RTL8852B ||
+ rtwdev->chip->chip_id == RTL8852C) {
+ if (env->nhm_th[RTW89_NHM_TH_NUM - 1] == RTW89_NHM_WA_TH) {
+ nhm_weight[RTW89_NHM_RPT_NUM - 1] =
+ env->nhm_th[RTW89_NHM_TH_NUM - 2] +
+ RTW89_NHM_WEIGHT_OFFSET;
+ nhm_weight[RTW89_NHM_RPT_NUM - 2] =
+ nhm_weight[RTW89_NHM_RPT_NUM - 1];
+ }
+
+ env->nhm_result[0] += env->nhm_result[RTW89_NHM_RPT_NUM - 1];
+ env->nhm_result[RTW89_NHM_RPT_NUM - 1] = 0;
+ }
+
+ for (i = 0; i < RTW89_NHM_RPT_NUM; i++)
+ nhm_weighted_sum += env->nhm_result[i] * nhm_weight[i];
+
+ return (nhm_weighted_sum / env->nhm_sum) >> RTW89_NHM_TH_FACTOR;
+}
+
+static void __rtw89_phy_nhm_get_result(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb, enum rtw89_band hw_band,
+ u16 ch_hw_value)
+{
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_ccx_regs *ccx = phy->ccx;
+ struct ieee80211_supported_band *sband;
+ const struct rtw89_reg_def *nhm_rpt;
+ enum nl80211_band band;
+ u32 sum = 0;
+ u8 chan_idx;
+ u8 nhm_pwr;
+ u8 i;
+
+ if (!rtw89_phy_read32_idx(rtwdev, ccx->nhm, ccx->nhm_ready, bb->phy_idx)) {
+ rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK, "[NHM] Get NHM report Fail\n");
+ return;
+ }
+
+ for (i = 0; i < RTW89_NHM_RPT_NUM; i++) {
+ nhm_rpt = &(*chip->nhm_report)[i];
+
+ env->nhm_result[i] =
+ rtw89_phy_read32_idx(rtwdev, nhm_rpt->addr,
+ nhm_rpt->mask, bb->phy_idx);
+ sum += env->nhm_result[i];
+ }
+ env->nhm_sum = sum;
+ nhm_pwr = rtw89_nhm_weighted_avg(rtwdev, bb);
+
+ if (!ch_hw_value)
+ return;
+
+ band = rtw89_hw_to_nl80211_band(hw_band);
+ sband = rtwdev->hw->wiphy->bands[band];
+ if (!sband)
+ return;
+
+ for (chan_idx = 0; chan_idx < sband->n_channels; chan_idx++) {
+ struct ieee80211_channel *channel;
+ struct rtw89_nhm_report *rpt;
+ struct list_head *nhm_list;
+
+ channel = &sband->channels[chan_idx];
+ if (channel->hw_value != ch_hw_value)
+ continue;
+
+ rpt = &env->nhm_his[hw_band][chan_idx];
+ nhm_list = &env->nhm_rpt_list;
+
+ rpt->channel = channel;
+ rpt->noise = nhm_pwr;
+
+ if (list_empty(&rpt->list))
+ list_add_tail(&rpt->list, nhm_list);
+
+ return;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK, "[NHM] channel not found\n");
+}
+
+void rtw89_phy_nhm_get_result(struct rtw89_dev *rtwdev, enum rtw89_band hw_band,
+ u16 ch_hw_value)
{
- struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_bb_ctx *bb;
+
+ if (!chip->support_noise)
+ return;
+
+ rtw89_for_each_active_bb(rtwdev, bb)
+ __rtw89_phy_nhm_get_result(rtwdev, bb, hw_band, ch_hw_value);
+}
+
+static bool rtw89_phy_ifs_clm_get_result(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
+{
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
+ const struct rtw89_ccx_regs *ccx = phy->ccx;
u8 i = 0;
- if (rtw89_phy_read32_mask(rtwdev, R_IFSCNT, B_IFSCNT_DONE_MSK) == 0) {
+ if (rtw89_phy_read32_idx(rtwdev, ccx->ifs_total_addr,
+ ccx->ifs_cnt_done_mask, bb->phy_idx) == 0) {
rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
"Get IFS_CLM report Fail\n");
return false;
}
env->ifs_clm_tx =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CLM_TX_CNT,
- B_IFS_CLM_TX_CNT_MSK);
+ rtw89_phy_read32_idx(rtwdev, ccx->ifs_clm_tx_cnt_addr,
+ ccx->ifs_clm_tx_cnt_msk, bb->phy_idx);
env->ifs_clm_edcca_excl_cca =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CLM_TX_CNT,
- B_IFS_CLM_EDCCA_EXCLUDE_CCA_FA_MSK);
+ rtw89_phy_read32_idx(rtwdev, ccx->ifs_clm_tx_cnt_addr,
+ ccx->ifs_clm_edcca_excl_cca_fa_mask, bb->phy_idx);
env->ifs_clm_cckcca_excl_fa =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CLM_CCA,
- B_IFS_CLM_CCKCCA_EXCLUDE_FA_MSK);
+ rtw89_phy_read32_idx(rtwdev, ccx->ifs_clm_cca_addr,
+ ccx->ifs_clm_cckcca_excl_fa_mask, bb->phy_idx);
env->ifs_clm_ofdmcca_excl_fa =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CLM_CCA,
- B_IFS_CLM_OFDMCCA_EXCLUDE_FA_MSK);
+ rtw89_phy_read32_idx(rtwdev, ccx->ifs_clm_cca_addr,
+ ccx->ifs_clm_ofdmcca_excl_fa_mask, bb->phy_idx);
env->ifs_clm_cckfa =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CLM_FA,
- B_IFS_CLM_CCK_FA_MSK);
+ rtw89_phy_read32_idx(rtwdev, ccx->ifs_clm_fa_addr,
+ ccx->ifs_clm_cck_fa_mask, bb->phy_idx);
env->ifs_clm_ofdmfa =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CLM_FA,
- B_IFS_CLM_OFDM_FA_MSK);
+ rtw89_phy_read32_idx(rtwdev, ccx->ifs_clm_fa_addr,
+ ccx->ifs_clm_ofdm_fa_mask, bb->phy_idx);
env->ifs_clm_his[0] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_HIS, B_IFS_T1_HIS_MSK);
+ rtw89_phy_read32_idx(rtwdev, ccx->ifs_his_addr,
+ ccx->ifs_t1_his_mask, bb->phy_idx);
env->ifs_clm_his[1] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_HIS, B_IFS_T2_HIS_MSK);
+ rtw89_phy_read32_idx(rtwdev, ccx->ifs_his_addr,
+ ccx->ifs_t2_his_mask, bb->phy_idx);
env->ifs_clm_his[2] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_HIS, B_IFS_T3_HIS_MSK);
+ rtw89_phy_read32_idx(rtwdev, ccx->ifs_his_addr,
+ ccx->ifs_t3_his_mask, bb->phy_idx);
env->ifs_clm_his[3] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_HIS, B_IFS_T4_HIS_MSK);
+ rtw89_phy_read32_idx(rtwdev, ccx->ifs_his_addr,
+ ccx->ifs_t4_his_mask, bb->phy_idx);
env->ifs_clm_avg[0] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_AVG_L, B_IFS_T1_AVG_MSK);
+ rtw89_phy_read32_idx(rtwdev, ccx->ifs_avg_l_addr,
+ ccx->ifs_t1_avg_mask, bb->phy_idx);
env->ifs_clm_avg[1] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_AVG_L, B_IFS_T2_AVG_MSK);
+ rtw89_phy_read32_idx(rtwdev, ccx->ifs_avg_l_addr,
+ ccx->ifs_t2_avg_mask, bb->phy_idx);
env->ifs_clm_avg[2] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_AVG_H, B_IFS_T3_AVG_MSK);
+ rtw89_phy_read32_idx(rtwdev, ccx->ifs_avg_h_addr,
+ ccx->ifs_t3_avg_mask, bb->phy_idx);
env->ifs_clm_avg[3] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_AVG_H, B_IFS_T4_AVG_MSK);
+ rtw89_phy_read32_idx(rtwdev, ccx->ifs_avg_h_addr,
+ ccx->ifs_t4_avg_mask, bb->phy_idx);
env->ifs_clm_cca[0] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CCA_L, B_IFS_T1_CCA_MSK);
+ rtw89_phy_read32_idx(rtwdev, ccx->ifs_cca_l_addr,
+ ccx->ifs_t1_cca_mask, bb->phy_idx);
env->ifs_clm_cca[1] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CCA_L, B_IFS_T2_CCA_MSK);
+ rtw89_phy_read32_idx(rtwdev, ccx->ifs_cca_l_addr,
+ ccx->ifs_t2_cca_mask, bb->phy_idx);
env->ifs_clm_cca[2] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CCA_H, B_IFS_T3_CCA_MSK);
+ rtw89_phy_read32_idx(rtwdev, ccx->ifs_cca_h_addr,
+ ccx->ifs_t3_cca_mask, bb->phy_idx);
env->ifs_clm_cca[3] =
- rtw89_phy_read32_mask(rtwdev, R_IFS_CCA_H, B_IFS_T4_CCA_MSK);
+ rtw89_phy_read32_idx(rtwdev, ccx->ifs_cca_h_addr,
+ ccx->ifs_t4_cca_mask, bb->phy_idx);
env->ifs_clm_total_ifs =
- rtw89_phy_read32_mask(rtwdev, R_IFSCNT, B_IFSCNT_TOTAL_CNT_MSK);
+ rtw89_phy_read32_idx(rtwdev, ccx->ifs_total_addr,
+ ccx->ifs_total_mask, bb->phy_idx);
rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK, "IFS-CLM total_ifs = %d\n",
env->ifs_clm_total_ifs);
@@ -3412,15 +6056,119 @@ static bool rtw89_phy_ifs_clm_get_result(struct rtw89_dev *rtwdev)
"T%d:[%d, %d, %d]\n", i + 1, env->ifs_clm_his[i],
env->ifs_clm_avg[i], env->ifs_clm_cca[i]);
- rtw89_phy_ifs_clm_get_utility(rtwdev);
+ rtw89_phy_ifs_clm_get_utility(rtwdev, bb);
return true;
}
+static void rtw89_phy_nhm_th_update(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
+{
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
+ static const u8 nhm_th_11k[RTW89_NHM_RPT_NUM] = {
+ 18, 21, 24, 27, 30, 35, 40, 45, 50, 55, 60, 0
+ };
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_reg_def *nhm_th;
+ u8 i;
+
+ for (i = 0; i < RTW89_NHM_RPT_NUM; i++)
+ env->nhm_th[i] = nhm_th_11k[i] << RTW89_NHM_TH_FACTOR;
+
+ if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B ||
+ chip->chip_id == RTL8852C)
+ env->nhm_th[RTW89_NHM_TH_NUM - 1] = RTW89_NHM_WA_TH;
+
+ for (i = 0; i < RTW89_NHM_TH_NUM; i++) {
+ nhm_th = &(*chip->nhm_th)[i];
+
+ rtw89_phy_write32_idx(rtwdev, nhm_th->addr, nhm_th->mask,
+ env->nhm_th[i], bb->phy_idx);
+ }
+}
+
+static int rtw89_phy_nhm_set(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb,
+ struct rtw89_ccx_para_info *para)
+{
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
+ const struct rtw89_ccx_regs *ccx = phy->ccx;
+ u32 unit_idx = 0;
+ u32 period = 0;
+
+ if (para->mntr_time == 0) {
+ rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
+ "[NHM] MNTR_TIME is 0\n");
+ return -EINVAL;
+ }
+
+ if (rtw89_phy_ccx_racing_ctrl(rtwdev, bb, para->rac_lv))
+ return -EINVAL;
+
+ rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
+ "[NHM]nhm_incld_cca=%d, mntr_time=%d ms\n",
+ para->nhm_incld_cca, para->mntr_time);
+
+ if (para->mntr_time != env->nhm_mntr_time) {
+ rtw89_phy_ccx_ms_to_period_unit(rtwdev, para->mntr_time,
+ &period, &unit_idx);
+ rtw89_phy_write32_idx(rtwdev, ccx->nhm_config,
+ ccx->nhm_period_mask, period, bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, ccx->nhm_config,
+ ccx->nhm_unit_mask, period, bb->phy_idx);
+
+ env->nhm_mntr_time = para->mntr_time;
+ env->ccx_period = period;
+ env->ccx_unit_idx = unit_idx;
+ }
+
+ if (para->nhm_incld_cca != env->nhm_include_cca) {
+ rtw89_phy_write32_idx(rtwdev, ccx->nhm_config,
+ ccx->nhm_include_cca_mask, para->nhm_incld_cca,
+ bb->phy_idx);
+
+ env->nhm_include_cca = para->nhm_incld_cca;
+ }
+
+ rtw89_phy_nhm_th_update(rtwdev, bb);
+
+ return 0;
+}
+
+static void __rtw89_phy_nhm_trigger(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
+{
+ struct rtw89_ccx_para_info para = {
+ .mntr_time = RTW89_NHM_MNTR_TIME,
+ .rac_lv = RTW89_RAC_LV_1,
+ .nhm_incld_cca = true,
+ };
+
+ rtw89_phy_ccx_racing_release(rtwdev, bb);
+
+ rtw89_phy_nhm_set(rtwdev, bb, &para);
+ rtw89_phy_ccx_trigger(rtwdev, bb, RTW89_PHY_ENV_MON_NHM);
+}
+
+void rtw89_phy_nhm_trigger(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_bb_ctx *bb;
+
+ if (!chip->support_noise)
+ return;
+
+ rtw89_for_each_active_bb(rtwdev, bb)
+ __rtw89_phy_nhm_trigger(rtwdev, bb);
+}
+
static int rtw89_phy_ifs_clm_set(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb,
struct rtw89_ccx_para_info *para)
{
- struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
+ const struct rtw89_ccx_regs *ccx = phy->ccx;
u32 period = 0;
u32 unit_idx = 0;
@@ -3430,16 +6178,17 @@ static int rtw89_phy_ifs_clm_set(struct rtw89_dev *rtwdev,
return -EINVAL;
}
- if (rtw89_phy_ccx_racing_ctrl(rtwdev, para->rac_lv))
+ if (rtw89_phy_ccx_racing_ctrl(rtwdev, bb, para->rac_lv))
return -EINVAL;
if (para->mntr_time != env->ifs_clm_mntr_time) {
rtw89_phy_ccx_ms_to_period_unit(rtwdev, para->mntr_time,
&period, &unit_idx);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_COUNTER,
- B_IFS_CLM_PERIOD_MSK, period);
- rtw89_phy_set_phy_regs(rtwdev, R_IFS_COUNTER,
- B_IFS_CLM_COUNTER_UNIT_MSK, unit_idx);
+ rtw89_phy_write32_idx(rtwdev, ccx->ifs_cnt_addr,
+ ccx->ifs_clm_period_mask, period, bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, ccx->ifs_cnt_addr,
+ ccx->ifs_clm_cnt_unit_mask,
+ unit_idx, bb->phy_idx);
rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
"Update IFS-CLM time ((%d)) -> ((%d))\n",
@@ -3450,18 +6199,19 @@ static int rtw89_phy_ifs_clm_set(struct rtw89_dev *rtwdev,
env->ccx_unit_idx = (u8)unit_idx;
}
- if (rtw89_phy_ifs_clm_th_update_check(rtwdev, para)) {
+ if (rtw89_phy_ifs_clm_th_update_check(rtwdev, bb, para)) {
env->ifs_clm_app = para->ifs_clm_app;
- rtw89_phy_ifs_clm_set_th_reg(rtwdev);
+ rtw89_phy_ifs_clm_set_th_reg(rtwdev, bb);
}
return 0;
}
-void rtw89_phy_env_monitor_track(struct rtw89_dev *rtwdev)
+static void __rtw89_phy_env_monitor_track(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
{
- struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
- struct rtw89_ccx_para_info para = {0};
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
+ struct rtw89_ccx_para_info para = {};
u8 chk_result = RTW89_PHY_ENV_MON_CCX_FAIL;
env->ccx_watchdog_result = RTW89_PHY_ENV_MON_CCX_FAIL;
@@ -3471,33 +6221,50 @@ void rtw89_phy_env_monitor_track(struct rtw89_dev *rtwdev)
return;
}
+ rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
+ "BB-%d env_monitor track\n", bb->phy_idx);
+
/* only ifs_clm for now */
- if (rtw89_phy_ifs_clm_get_result(rtwdev))
+ if (rtw89_phy_ifs_clm_get_result(rtwdev, bb))
env->ccx_watchdog_result |= RTW89_PHY_ENV_MON_IFS_CLM;
- rtw89_phy_ccx_racing_release(rtwdev);
+ rtw89_phy_ccx_racing_release(rtwdev, bb);
para.mntr_time = 1900;
para.rac_lv = RTW89_RAC_LV_1;
para.ifs_clm_app = RTW89_IFS_CLM_BACKGROUND;
- if (rtw89_phy_ifs_clm_set(rtwdev, &para) == 0)
+ if (rtw89_phy_ifs_clm_set(rtwdev, bb, &para) == 0)
chk_result |= RTW89_PHY_ENV_MON_IFS_CLM;
if (chk_result)
- rtw89_phy_ccx_trigger(rtwdev);
+ rtw89_phy_ccx_trigger(rtwdev, bb, chk_result);
rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
"get_result=0x%x, chk_result:0x%x\n",
env->ccx_watchdog_result, chk_result);
}
-static bool rtw89_physts_ie_page_valid(enum rtw89_phy_status_bitmap *ie_page)
+void rtw89_phy_env_monitor_track(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_bb_ctx *bb;
+
+ rtw89_for_each_active_bb(rtwdev, bb)
+ __rtw89_phy_env_monitor_track(rtwdev, bb);
+}
+
+static bool rtw89_physts_ie_page_valid(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_status_bitmap *ie_page)
{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+
if (*ie_page >= RTW89_PHYSTS_BITMAP_NUM ||
*ie_page == RTW89_RSVD_9)
return false;
- else if (*ie_page > RTW89_RSVD_9)
+ else if (*ie_page > RTW89_RSVD_9 && *ie_page < RTW89_EHT_PKT)
*ie_page -= 1;
+ if (*ie_page == RTW89_EHT_PKT && chip->chip_gen == RTW89_CHIP_AX)
+ return false;
+
return true;
}
@@ -3505,104 +6272,110 @@ static u32 rtw89_phy_get_ie_bitmap_addr(enum rtw89_phy_status_bitmap ie_page)
{
static const u8 ie_page_shift = 2;
+ if (ie_page == RTW89_EHT_PKT)
+ return R_PHY_STS_BITMAP_EHT;
+
return R_PHY_STS_BITMAP_ADDR_START + (ie_page << ie_page_shift);
}
static u32 rtw89_physts_get_ie_bitmap(struct rtw89_dev *rtwdev,
- enum rtw89_phy_status_bitmap ie_page)
+ enum rtw89_phy_status_bitmap ie_page,
+ enum rtw89_phy_idx phy_idx)
{
u32 addr;
- if (!rtw89_physts_ie_page_valid(&ie_page))
+ if (!rtw89_physts_ie_page_valid(rtwdev, &ie_page))
return 0;
addr = rtw89_phy_get_ie_bitmap_addr(ie_page);
- return rtw89_phy_read32(rtwdev, addr);
+ return rtw89_phy_read32_idx(rtwdev, addr, MASKDWORD, phy_idx);
}
static void rtw89_physts_set_ie_bitmap(struct rtw89_dev *rtwdev,
enum rtw89_phy_status_bitmap ie_page,
- u32 val)
+ u32 val, enum rtw89_phy_idx phy_idx)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
u32 addr;
- if (!rtw89_physts_ie_page_valid(&ie_page))
+ if (!rtw89_physts_ie_page_valid(rtwdev, &ie_page))
return;
if (chip->chip_id == RTL8852A)
val &= B_PHY_STS_BITMAP_MSK_52A;
addr = rtw89_phy_get_ie_bitmap_addr(ie_page);
- rtw89_phy_write32(rtwdev, addr, val);
-}
-
-static void rtw89_physts_enable_ie_bitmap(struct rtw89_dev *rtwdev,
- enum rtw89_phy_status_bitmap bitmap,
- enum rtw89_phy_status_ie_type ie,
- bool enable)
-{
- u32 val = rtw89_physts_get_ie_bitmap(rtwdev, bitmap);
-
- if (enable)
- val |= BIT(ie);
- else
- val &= ~BIT(ie);
-
- rtw89_physts_set_ie_bitmap(rtwdev, bitmap, val);
+ rtw89_phy_write32_idx(rtwdev, addr, MASKDWORD, val, phy_idx);
}
static void rtw89_physts_enable_fail_report(struct rtw89_dev *rtwdev,
bool enable,
enum rtw89_phy_idx phy_idx)
{
+ const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def;
+ const struct rtw89_physts_regs *physts = phy->physts;
+
if (enable) {
- rtw89_phy_write32_clr(rtwdev, R_PLCP_HISTOGRAM,
- B_STS_DIS_TRIG_BY_FAIL);
- rtw89_phy_write32_clr(rtwdev, R_PLCP_HISTOGRAM,
- B_STS_DIS_TRIG_BY_BRK);
+ rtw89_phy_write32_idx_clr(rtwdev, physts->setting_addr,
+ physts->dis_trigger_fail_mask, phy_idx);
+ rtw89_phy_write32_idx_clr(rtwdev, physts->setting_addr,
+ physts->dis_trigger_brk_mask, phy_idx);
} else {
- rtw89_phy_write32_set(rtwdev, R_PLCP_HISTOGRAM,
- B_STS_DIS_TRIG_BY_FAIL);
- rtw89_phy_write32_set(rtwdev, R_PLCP_HISTOGRAM,
- B_STS_DIS_TRIG_BY_BRK);
+ rtw89_phy_write32_idx_set(rtwdev, physts->setting_addr,
+ physts->dis_trigger_fail_mask, phy_idx);
+ rtw89_phy_write32_idx_set(rtwdev, physts->setting_addr,
+ physts->dis_trigger_brk_mask, phy_idx);
}
}
-static void rtw89_physts_parsing_init(struct rtw89_dev *rtwdev)
+static void __rtw89_physts_parsing_init(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ u32 val;
u8 i;
- rtw89_physts_enable_fail_report(rtwdev, false, RTW89_PHY_0);
+ rtw89_physts_enable_fail_report(rtwdev, false, phy_idx);
for (i = 0; i < RTW89_PHYSTS_BITMAP_NUM; i++) {
- if (i >= RTW89_CCK_PKT)
- rtw89_physts_enable_ie_bitmap(rtwdev, i,
- RTW89_PHYSTS_IE09_FTR_0,
- true);
- if ((i >= RTW89_CCK_BRK && i <= RTW89_VHT_MU) ||
- (i >= RTW89_RSVD_9 && i <= RTW89_CCK_PKT))
+ if (i == RTW89_RSVD_9 ||
+ (i == RTW89_EHT_PKT && chip->chip_gen == RTW89_CHIP_AX))
continue;
- rtw89_physts_enable_ie_bitmap(rtwdev, i,
- RTW89_PHYSTS_IE24_OFDM_TD_PATH_A,
- true);
+
+ val = rtw89_physts_get_ie_bitmap(rtwdev, i, phy_idx);
+ if (i == RTW89_HE_MU || i == RTW89_VHT_MU) {
+ val |= BIT(RTW89_PHYSTS_IE13_DL_MU_DEF);
+ } else if (i == RTW89_TRIG_BASE_PPDU) {
+ val |= BIT(RTW89_PHYSTS_IE13_DL_MU_DEF) |
+ BIT(RTW89_PHYSTS_IE01_CMN_OFDM);
+ } else if (i >= RTW89_CCK_PKT) {
+ val &= ~(GENMASK(RTW89_PHYSTS_IE07_CMN_EXT_PATH_D,
+ RTW89_PHYSTS_IE04_CMN_EXT_PATH_A));
+
+ if (i == RTW89_CCK_PKT)
+ val |= BIT(RTW89_PHYSTS_IE01_CMN_OFDM);
+ else if (i >= RTW89_HT_PKT)
+ val |= BIT(RTW89_PHYSTS_IE20_DBG_OFDM_FD_USER_SEG_0);
+ }
+
+ rtw89_physts_set_ie_bitmap(rtwdev, i, val, phy_idx);
}
- rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_VHT_PKT,
- RTW89_PHYSTS_IE13_DL_MU_DEF, true);
- rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_HE_PKT,
- RTW89_PHYSTS_IE13_DL_MU_DEF, true);
+}
- /* force IE01 for channel index, only channel field is valid */
- rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_CCK_PKT,
- RTW89_PHYSTS_IE01_CMN_OFDM, true);
+static void rtw89_physts_parsing_init(struct rtw89_dev *rtwdev)
+{
+ __rtw89_physts_parsing_init(rtwdev, RTW89_PHY_0);
+ if (rtwdev->dbcc_en)
+ __rtw89_physts_parsing_init(rtwdev, RTW89_PHY_1);
}
-static void rtw89_phy_dig_read_gain_table(struct rtw89_dev *rtwdev, int type)
+static void rtw89_phy_dig_read_gain_table(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb, int type)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
- struct rtw89_dig_info *dig = &rtwdev->dig;
const struct rtw89_phy_dig_gain_cfg *cfg;
+ struct rtw89_dig_info *dig = &bb->dig;
const char *msg;
u8 i;
s8 gain_base;
@@ -3639,8 +6412,8 @@ static void rtw89_phy_dig_read_gain_table(struct rtw89_dev *rtwdev, int type)
}
for (i = 0; i < cfg->size; i++) {
- tmp = rtw89_phy_read32_mask(rtwdev, cfg->table[i].addr,
- cfg->table[i].mask);
+ tmp = rtw89_phy_read32_idx(rtwdev, cfg->table[i].addr,
+ cfg->table[i].mask, bb->phy_idx);
tmp >>= DIG_GAIN_SHIFT;
gain_arr[i] = sign_extend32(tmp, U4_MAX_BIT) + gain_base;
gain_base += DIG_GAIN;
@@ -3650,25 +6423,26 @@ static void rtw89_phy_dig_read_gain_table(struct rtw89_dev *rtwdev, int type)
}
}
-static void rtw89_phy_dig_update_gain_para(struct rtw89_dev *rtwdev)
+static void rtw89_phy_dig_update_gain_para(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
{
- struct rtw89_dig_info *dig = &rtwdev->dig;
+ struct rtw89_dig_info *dig = &bb->dig;
u32 tmp;
u8 i;
if (!rtwdev->hal.support_igi)
return;
- tmp = rtw89_phy_read32_mask(rtwdev, R_PATH0_IB_PKPW,
- B_PATH0_IB_PKPW_MSK);
+ tmp = rtw89_phy_read32_idx(rtwdev, R_PATH0_IB_PKPW,
+ B_PATH0_IB_PKPW_MSK, bb->phy_idx);
dig->ib_pkpwr = sign_extend32(tmp >> DIG_GAIN_SHIFT, U8_MAX_BIT);
- dig->ib_pbk = rtw89_phy_read32_mask(rtwdev, R_PATH0_IB_PBK,
- B_PATH0_IB_PBK_MSK);
+ dig->ib_pbk = rtw89_phy_read32_idx(rtwdev, R_PATH0_IB_PBK,
+ B_PATH0_IB_PBK_MSK, bb->phy_idx);
rtw89_debug(rtwdev, RTW89_DBG_DIG, "ib_pkpwr=%d, ib_pbk=%d\n",
dig->ib_pkpwr, dig->ib_pbk);
for (i = RTW89_DIG_GAIN_LNA_G; i < RTW89_DIG_GAIN_MAX; i++)
- rtw89_phy_dig_read_gain_table(rtwdev, i);
+ rtw89_phy_dig_read_gain_table(rtwdev, bb, i);
}
static const u8 rssi_nolink = 22;
@@ -3677,10 +6451,11 @@ static const u16 fa_th_2g[FA_TH_NUM] = {22, 44, 66, 88};
static const u16 fa_th_5g[FA_TH_NUM] = {4, 8, 12, 16};
static const u16 fa_th_nolink[FA_TH_NUM] = {196, 352, 440, 528};
-static void rtw89_phy_dig_update_rssi_info(struct rtw89_dev *rtwdev)
+static void rtw89_phy_dig_update_rssi_info(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
{
- struct rtw89_phy_ch_info *ch_info = &rtwdev->ch_info;
- struct rtw89_dig_info *dig = &rtwdev->dig;
+ struct rtw89_phy_ch_info *ch_info = &bb->ch_info;
+ struct rtw89_dig_info *dig = &bb->dig;
bool is_linked = rtwdev->total_sta_assoc > 0;
if (is_linked) {
@@ -3691,10 +6466,11 @@ static void rtw89_phy_dig_update_rssi_info(struct rtw89_dev *rtwdev)
}
}
-static void rtw89_phy_dig_update_para(struct rtw89_dev *rtwdev)
+static void rtw89_phy_dig_update_para(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
{
- struct rtw89_dig_info *dig = &rtwdev->dig;
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
+ const struct rtw89_chan *chan = rtw89_mgnt_chan_get(rtwdev, bb->phy_idx);
+ struct rtw89_dig_info *dig = &bb->dig;
bool is_linked = rtwdev->total_sta_assoc > 0;
const u16 *fa_th_src = NULL;
@@ -3719,13 +6495,14 @@ static void rtw89_phy_dig_update_para(struct rtw89_dev *rtwdev)
memcpy(dig->igi_rssi_th, igi_rssi_th, sizeof(dig->igi_rssi_th));
}
-static const u8 pd_low_th_offset = 20, dynamic_igi_min = 0x20;
+static const u8 pd_low_th_offset = 16, dynamic_igi_min = 0x20;
static const u8 igi_max_performance_mode = 0x5a;
static const u8 dynamic_pd_threshold_max;
-static void rtw89_phy_dig_para_reset(struct rtw89_dev *rtwdev)
+static void rtw89_phy_dig_para_reset(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
{
- struct rtw89_dig_info *dig = &rtwdev->dig;
+ struct rtw89_dig_info *dig = &bb->dig;
dig->cur_gaincode.lna_idx = LNA_IDX_MAX;
dig->cur_gaincode.tia_idx = TIA_IDX_MAX;
@@ -3741,15 +6518,27 @@ static void rtw89_phy_dig_para_reset(struct rtw89_dev *rtwdev)
dig->is_linked_pre = false;
}
+static void __rtw89_phy_dig_init(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
+{
+ rtw89_debug(rtwdev, RTW89_DBG_DIG, "BB-%d dig_init\n", bb->phy_idx);
+
+ rtw89_phy_dig_update_gain_para(rtwdev, bb);
+ rtw89_phy_dig_reset(rtwdev, bb);
+}
+
static void rtw89_phy_dig_init(struct rtw89_dev *rtwdev)
{
- rtw89_phy_dig_update_gain_para(rtwdev);
- rtw89_phy_dig_reset(rtwdev);
+ struct rtw89_bb_ctx *bb;
+
+ rtw89_for_each_capab_bb(rtwdev, bb)
+ __rtw89_phy_dig_init(rtwdev, bb);
}
-static u8 rtw89_phy_dig_lna_idx_by_rssi(struct rtw89_dev *rtwdev, u8 rssi)
+static u8 rtw89_phy_dig_lna_idx_by_rssi(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb, u8 rssi)
{
- struct rtw89_dig_info *dig = &rtwdev->dig;
+ struct rtw89_dig_info *dig = &bb->dig;
u8 lna_idx;
if (rssi < dig->igi_rssi_th[0])
@@ -3768,9 +6557,10 @@ static u8 rtw89_phy_dig_lna_idx_by_rssi(struct rtw89_dev *rtwdev, u8 rssi)
return lna_idx;
}
-static u8 rtw89_phy_dig_tia_idx_by_rssi(struct rtw89_dev *rtwdev, u8 rssi)
+static u8 rtw89_phy_dig_tia_idx_by_rssi(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb, u8 rssi)
{
- struct rtw89_dig_info *dig = &rtwdev->dig;
+ struct rtw89_dig_info *dig = &bb->dig;
u8 tia_idx;
if (rssi < dig->igi_rssi_th[0])
@@ -3783,10 +6573,11 @@ static u8 rtw89_phy_dig_tia_idx_by_rssi(struct rtw89_dev *rtwdev, u8 rssi)
#define IB_PBK_BASE 110
#define WB_RSSI_BASE 10
-static u8 rtw89_phy_dig_rxb_idx_by_rssi(struct rtw89_dev *rtwdev, u8 rssi,
+static u8 rtw89_phy_dig_rxb_idx_by_rssi(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb, u8 rssi,
struct rtw89_agc_gaincode_set *set)
{
- struct rtw89_dig_info *dig = &rtwdev->dig;
+ struct rtw89_dig_info *dig = &bb->dig;
s8 lna_gain = dig->lna_gain[set->lna_idx];
s8 tia_gain = dig->tia_gain[set->tia_idx];
s32 wb_rssi = rssi + lna_gain + tia_gain;
@@ -3802,12 +6593,13 @@ static u8 rtw89_phy_dig_rxb_idx_by_rssi(struct rtw89_dev *rtwdev, u8 rssi,
return rxb_idx;
}
-static void rtw89_phy_dig_gaincode_by_rssi(struct rtw89_dev *rtwdev, u8 rssi,
+static void rtw89_phy_dig_gaincode_by_rssi(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb, u8 rssi,
struct rtw89_agc_gaincode_set *set)
{
- set->lna_idx = rtw89_phy_dig_lna_idx_by_rssi(rtwdev, rssi);
- set->tia_idx = rtw89_phy_dig_tia_idx_by_rssi(rtwdev, rssi);
- set->rxb_idx = rtw89_phy_dig_rxb_idx_by_rssi(rtwdev, rssi, set);
+ set->lna_idx = rtw89_phy_dig_lna_idx_by_rssi(rtwdev, bb, rssi);
+ set->tia_idx = rtw89_phy_dig_tia_idx_by_rssi(rtwdev, bb, rssi);
+ set->rxb_idx = rtw89_phy_dig_rxb_idx_by_rssi(rtwdev, bb, rssi, set);
rtw89_debug(rtwdev, RTW89_DBG_DIG,
"final_rssi=%03d, (lna,tia,rab)=(%d,%d,%02d)\n",
@@ -3816,10 +6608,11 @@ static void rtw89_phy_dig_gaincode_by_rssi(struct rtw89_dev *rtwdev, u8 rssi,
#define IGI_OFFSET_MAX 25
#define IGI_OFFSET_MUL 2
-static void rtw89_phy_dig_igi_offset_by_env(struct rtw89_dev *rtwdev)
+static void rtw89_phy_dig_igi_offset_by_env(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
{
- struct rtw89_dig_info *dig = &rtwdev->dig;
- struct rtw89_env_monitor_info *env = &rtwdev->env_monitor;
+ struct rtw89_dig_info *dig = &bb->dig;
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
enum rtw89_dig_noisy_level noisy_lv;
u8 igi_offset = dig->fa_rssi_ofst;
u16 fa_ratio = 0;
@@ -3856,95 +6649,101 @@ static void rtw89_phy_dig_igi_offset_by_env(struct rtw89_dev *rtwdev)
noisy_lv, igi_offset);
}
-static void rtw89_phy_dig_set_lna_idx(struct rtw89_dev *rtwdev, u8 lna_idx)
+static void rtw89_phy_dig_set_lna_idx(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb, u8 lna_idx)
{
const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs;
- rtw89_phy_write32_mask(rtwdev, dig_regs->p0_lna_init.addr,
- dig_regs->p0_lna_init.mask, lna_idx);
- rtw89_phy_write32_mask(rtwdev, dig_regs->p1_lna_init.addr,
- dig_regs->p1_lna_init.mask, lna_idx);
+ rtw89_phy_write32_idx(rtwdev, dig_regs->p0_lna_init.addr,
+ dig_regs->p0_lna_init.mask, lna_idx, bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, dig_regs->p1_lna_init.addr,
+ dig_regs->p1_lna_init.mask, lna_idx, bb->phy_idx);
}
-static void rtw89_phy_dig_set_tia_idx(struct rtw89_dev *rtwdev, u8 tia_idx)
+static void rtw89_phy_dig_set_tia_idx(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb, u8 tia_idx)
{
const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs;
- rtw89_phy_write32_mask(rtwdev, dig_regs->p0_tia_init.addr,
- dig_regs->p0_tia_init.mask, tia_idx);
- rtw89_phy_write32_mask(rtwdev, dig_regs->p1_tia_init.addr,
- dig_regs->p1_tia_init.mask, tia_idx);
+ rtw89_phy_write32_idx(rtwdev, dig_regs->p0_tia_init.addr,
+ dig_regs->p0_tia_init.mask, tia_idx, bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, dig_regs->p1_tia_init.addr,
+ dig_regs->p1_tia_init.mask, tia_idx, bb->phy_idx);
}
-static void rtw89_phy_dig_set_rxb_idx(struct rtw89_dev *rtwdev, u8 rxb_idx)
+static void rtw89_phy_dig_set_rxb_idx(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb, u8 rxb_idx)
{
const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs;
- rtw89_phy_write32_mask(rtwdev, dig_regs->p0_rxb_init.addr,
- dig_regs->p0_rxb_init.mask, rxb_idx);
- rtw89_phy_write32_mask(rtwdev, dig_regs->p1_rxb_init.addr,
- dig_regs->p1_rxb_init.mask, rxb_idx);
+ rtw89_phy_write32_idx(rtwdev, dig_regs->p0_rxb_init.addr,
+ dig_regs->p0_rxb_init.mask, rxb_idx, bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, dig_regs->p1_rxb_init.addr,
+ dig_regs->p1_rxb_init.mask, rxb_idx, bb->phy_idx);
}
static void rtw89_phy_dig_set_igi_cr(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb,
const struct rtw89_agc_gaincode_set set)
{
- rtw89_phy_dig_set_lna_idx(rtwdev, set.lna_idx);
- rtw89_phy_dig_set_tia_idx(rtwdev, set.tia_idx);
- rtw89_phy_dig_set_rxb_idx(rtwdev, set.rxb_idx);
+ if (!rtwdev->hal.support_igi)
+ return;
+
+ rtw89_phy_dig_set_lna_idx(rtwdev, bb, set.lna_idx);
+ rtw89_phy_dig_set_tia_idx(rtwdev, bb, set.tia_idx);
+ rtw89_phy_dig_set_rxb_idx(rtwdev, bb, set.rxb_idx);
rtw89_debug(rtwdev, RTW89_DBG_DIG, "Set (lna,tia,rxb)=((%d,%d,%02d))\n",
set.lna_idx, set.tia_idx, set.rxb_idx);
}
static void rtw89_phy_dig_sdagc_follow_pagc_config(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb,
bool enable)
{
const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs;
- rtw89_phy_write32_mask(rtwdev, dig_regs->p0_p20_pagcugc_en.addr,
- dig_regs->p0_p20_pagcugc_en.mask, enable);
- rtw89_phy_write32_mask(rtwdev, dig_regs->p0_s20_pagcugc_en.addr,
- dig_regs->p0_s20_pagcugc_en.mask, enable);
- rtw89_phy_write32_mask(rtwdev, dig_regs->p1_p20_pagcugc_en.addr,
- dig_regs->p1_p20_pagcugc_en.mask, enable);
- rtw89_phy_write32_mask(rtwdev, dig_regs->p1_s20_pagcugc_en.addr,
- dig_regs->p1_s20_pagcugc_en.mask, enable);
+ rtw89_phy_write32_idx(rtwdev, dig_regs->p0_p20_pagcugc_en.addr,
+ dig_regs->p0_p20_pagcugc_en.mask, enable, bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, dig_regs->p0_s20_pagcugc_en.addr,
+ dig_regs->p0_s20_pagcugc_en.mask, enable, bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, dig_regs->p1_p20_pagcugc_en.addr,
+ dig_regs->p1_p20_pagcugc_en.mask, enable, bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, dig_regs->p1_s20_pagcugc_en.addr,
+ dig_regs->p1_s20_pagcugc_en.mask, enable, bb->phy_idx);
rtw89_debug(rtwdev, RTW89_DBG_DIG, "sdagc_follow_pagc=%d\n", enable);
}
-static void rtw89_phy_dig_config_igi(struct rtw89_dev *rtwdev)
+static void rtw89_phy_dig_config_igi(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
{
- struct rtw89_dig_info *dig = &rtwdev->dig;
+ struct rtw89_dig_info *dig = &bb->dig;
if (!rtwdev->hal.support_igi)
return;
if (dig->force_gaincode_idx_en) {
- rtw89_phy_dig_set_igi_cr(rtwdev, dig->force_gaincode);
+ rtw89_phy_dig_set_igi_cr(rtwdev, bb, dig->force_gaincode);
rtw89_debug(rtwdev, RTW89_DBG_DIG,
"Force gaincode index enabled.\n");
} else {
- rtw89_phy_dig_gaincode_by_rssi(rtwdev, dig->igi_fa_rssi,
+ rtw89_phy_dig_gaincode_by_rssi(rtwdev, bb, dig->igi_fa_rssi,
&dig->cur_gaincode);
- rtw89_phy_dig_set_igi_cr(rtwdev, dig->cur_gaincode);
+ rtw89_phy_dig_set_igi_cr(rtwdev, bb, dig->cur_gaincode);
}
}
-static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, u8 rssi,
- bool enable)
+static u8 rtw89_phy_dig_cal_under_region(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb,
+ const struct rtw89_chan *chan)
{
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
- const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs;
enum rtw89_bandwidth cbw = chan->band_width;
- struct rtw89_dig_info *dig = &rtwdev->dig;
- u8 final_rssi = 0, under_region = dig->pd_low_th_ofst;
- u8 ofdm_cca_th;
- s8 cck_cca_th;
- u32 pd_val = 0;
+ struct rtw89_dig_info *dig = &bb->dig;
+ u8 under_region = dig->pd_low_th_ofst;
- under_region += PD_TH_SB_FLTR_CMP_VAL;
+ if (rtwdev->chip->chip_gen == RTW89_CHIP_AX)
+ under_region += PD_TH_SB_FLTR_CMP_VAL;
switch (cbw) {
case RTW89_CHANNEL_WIDTH_40:
@@ -3963,6 +6762,20 @@ static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, u8 rssi,
break;
}
+ return under_region;
+}
+
+static u32 __rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb,
+ u8 rssi, bool enable,
+ const struct rtw89_chan *chan)
+{
+ struct rtw89_dig_info *dig = &bb->dig;
+ u8 ofdm_cca_th, under_region;
+ u8 final_rssi;
+ u32 pd_val;
+
+ under_region = rtw89_phy_dig_cal_under_region(rtwdev, bb, chan);
dig->dyn_pd_th_max = dig->igi_rssi;
final_rssi = min_t(u8, rssi, dig->igi_rssi);
@@ -3975,18 +6788,38 @@ static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, u8 rssi,
"igi=%d, ofdm_ccaTH=%d, backoff=%d, PD_low=%d\n",
final_rssi, ofdm_cca_th, under_region, pd_val);
} else {
+ pd_val = 0;
rtw89_debug(rtwdev, RTW89_DBG_DIG,
"Dynamic PD th disabled, Set PD_low_bd=0\n");
}
- rtw89_phy_write32_mask(rtwdev, dig_regs->seg0_pd_reg,
- dig_regs->pd_lower_bound_mask, pd_val);
- rtw89_phy_write32_mask(rtwdev, dig_regs->seg0_pd_reg,
- dig_regs->pd_spatial_reuse_en, enable);
+ return pd_val;
+}
+
+static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb,
+ u8 rssi, bool enable)
+{
+ const struct rtw89_chan *chan = rtw89_mgnt_chan_get(rtwdev, bb->phy_idx);
+ const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs;
+ struct rtw89_dig_info *dig = &bb->dig;
+ u8 final_rssi, under_region = dig->pd_low_th_ofst;
+ s8 cck_cca_th;
+ u32 pd_val;
+
+ pd_val = __rtw89_phy_dig_dyn_pd_th(rtwdev, bb, rssi, enable, chan);
+ dig->bak_dig = pd_val;
+
+ rtw89_phy_write32_idx(rtwdev, dig_regs->seg0_pd_reg,
+ dig_regs->pd_lower_bound_mask, pd_val, bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, dig_regs->seg0_pd_reg,
+ dig_regs->pd_spatial_reuse_en, enable, bb->phy_idx);
if (!rtwdev->hal.support_cckpd)
return;
+ final_rssi = min_t(u8, rssi, dig->igi_rssi);
+ under_region = rtw89_phy_dig_cal_under_region(rtwdev, bb, chan);
cck_cca_th = max_t(s8, final_rssi - under_region, CCKPD_TH_MIN_RSSI);
pd_val = (u32)(cck_cca_th - IGI_RSSI_MAX);
@@ -3994,90 +6827,245 @@ static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, u8 rssi,
"igi=%d, cck_ccaTH=%d, backoff=%d, cck_PD_low=((%d))dB\n",
final_rssi, cck_cca_th, under_region, pd_val);
- rtw89_phy_write32_mask(rtwdev, R_BMODE_PDTH_EN_V1,
- B_BMODE_PDTH_LIMIT_EN_MSK_V1, enable);
- rtw89_phy_write32_mask(rtwdev, R_BMODE_PDTH_V1,
- B_BMODE_PDTH_LOWER_BOUND_MSK_V1, pd_val);
+ rtw89_phy_write32_idx(rtwdev, dig_regs->bmode_pd_reg,
+ dig_regs->bmode_cca_rssi_limit_en, enable, bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, dig_regs->bmode_pd_lower_bound_reg,
+ dig_regs->bmode_rssi_nocca_low_th_mask, pd_val, bb->phy_idx);
}
-void rtw89_phy_dig_reset(struct rtw89_dev *rtwdev)
+void rtw89_phy_dig_reset(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
{
- struct rtw89_dig_info *dig = &rtwdev->dig;
+ struct rtw89_dig_info *dig = &bb->dig;
dig->bypass_dig = false;
- rtw89_phy_dig_para_reset(rtwdev);
- rtw89_phy_dig_set_igi_cr(rtwdev, dig->force_gaincode);
- rtw89_phy_dig_dyn_pd_th(rtwdev, rssi_nolink, false);
- rtw89_phy_dig_sdagc_follow_pagc_config(rtwdev, false);
- rtw89_phy_dig_update_para(rtwdev);
+ rtw89_phy_dig_para_reset(rtwdev, bb);
+ rtw89_phy_dig_set_igi_cr(rtwdev, bb, dig->force_gaincode);
+ rtw89_phy_dig_dyn_pd_th(rtwdev, bb, rssi_nolink, false);
+ rtw89_phy_dig_sdagc_follow_pagc_config(rtwdev, bb, false);
+ rtw89_phy_dig_update_para(rtwdev, bb);
}
#define IGI_RSSI_MIN 10
-void rtw89_phy_dig(struct rtw89_dev *rtwdev)
+#define ABS_IGI_MIN 0xc
+static
+void rtw89_phy_cal_igi_fa_rssi(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
+{
+ struct rtw89_dig_info *dig = &bb->dig;
+ u8 igi_min;
+
+ rtw89_phy_dig_igi_offset_by_env(rtwdev, bb);
+
+ igi_min = max_t(int, dig->igi_rssi - IGI_RSSI_MIN, 0);
+ dig->dyn_igi_max = min(igi_min + IGI_OFFSET_MAX, igi_max_performance_mode);
+ dig->dyn_igi_min = max(igi_min, ABS_IGI_MIN);
+
+ if (dig->dyn_igi_max >= dig->dyn_igi_min) {
+ dig->igi_fa_rssi += dig->fa_rssi_ofst;
+ dig->igi_fa_rssi = clamp(dig->igi_fa_rssi, dig->dyn_igi_min,
+ dig->dyn_igi_max);
+ } else {
+ dig->igi_fa_rssi = dig->dyn_igi_max;
+ }
+}
+
+struct rtw89_phy_iter_mcc_dig {
+ struct rtw89_vif_link *rtwvif_link;
+ bool has_sta;
+ u8 rssi_min;
+};
+
+static void rtw89_phy_set_mcc_dig(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link,
+ struct rtw89_bb_ctx *bb,
+ u8 rssi_min, u8 mcc_role_idx,
+ bool is_linked)
+{
+ struct rtw89_dig_info *dig = &bb->dig;
+ const struct rtw89_chan *chan;
+ u8 pd_val;
+
+ if (is_linked) {
+ dig->igi_rssi = rssi_min >> 1;
+ dig->igi_fa_rssi = dig->igi_rssi;
+ } else {
+ rtw89_debug(rtwdev, RTW89_DBG_DIG, "RSSI update : NO Link\n");
+ dig->igi_rssi = rssi_nolink;
+ dig->igi_fa_rssi = dig->igi_rssi;
+ }
+
+ chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx);
+ rtw89_phy_cal_igi_fa_rssi(rtwdev, bb);
+ pd_val = __rtw89_phy_dig_dyn_pd_th(rtwdev, bb, dig->igi_fa_rssi,
+ is_linked, chan);
+ rtw89_fw_h2c_mcc_dig(rtwdev, rtwvif_link->chanctx_idx,
+ mcc_role_idx, pd_val, true);
+
+ rtw89_debug(rtwdev, RTW89_DBG_DIG,
+ "MCC chanctx_idx %d chan %d rssi %d pd_val %d",
+ rtwvif_link->chanctx_idx, chan->primary_channel,
+ dig->igi_rssi, pd_val);
+}
+
+static void rtw89_phy_set_mcc_dig_iter(void *data, struct ieee80211_sta *sta)
+{
+ struct rtw89_phy_iter_mcc_dig *mcc_dig = (struct rtw89_phy_iter_mcc_dig *)data;
+ unsigned int link_id = mcc_dig->rtwvif_link->link_id;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_sta_link *rtwsta_link;
+
+ if (rtwsta->rtwvif != mcc_dig->rtwvif_link->rtwvif)
+ return;
+
+ rtwsta_link = rtwsta->links[link_id];
+ if (!rtwsta_link)
+ return;
+
+ mcc_dig->has_sta = true;
+ if (ewma_rssi_read(&rtwsta_link->avg_rssi) < mcc_dig->rssi_min)
+ mcc_dig->rssi_min = ewma_rssi_read(&rtwsta_link->avg_rssi);
+}
+
+static void rtw89_phy_dig_mcc(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
+{
+ struct rtw89_phy_iter_mcc_dig mcc_dig;
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_mcc_links_info info;
+ int i;
+
+ rtw89_mcc_get_links(rtwdev, &info);
+ for (i = 0; i < ARRAY_SIZE(info.links); i++) {
+ rtwvif_link = info.links[i];
+ if (!rtwvif_link)
+ continue;
+
+ memset(&mcc_dig, 0, sizeof(mcc_dig));
+ mcc_dig.rtwvif_link = rtwvif_link;
+ mcc_dig.has_sta = false;
+ mcc_dig.rssi_min = U8_MAX;
+ ieee80211_iterate_stations_atomic(rtwdev->hw,
+ rtw89_phy_set_mcc_dig_iter,
+ &mcc_dig);
+
+ rtw89_phy_set_mcc_dig(rtwdev, rtwvif_link, bb,
+ mcc_dig.rssi_min, i, mcc_dig.has_sta);
+ }
+}
+
+static void rtw89_phy_dig_ctrl(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb,
+ bool pause_dig, bool restore)
+{
+ const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs;
+ struct rtw89_dig_info *dig = &bb->dig;
+ bool en_dig;
+ u32 pd_val;
+
+ if (dig->pause_dig == pause_dig)
+ return;
+
+ if (pause_dig) {
+ en_dig = false;
+ pd_val = 0;
+ } else {
+ en_dig = rtwdev->total_sta_assoc > 0;
+ pd_val = restore ? dig->bak_dig : 0;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_DIG, "%s <%s> PD_low=%d", __func__,
+ pause_dig ? "suspend" : "resume", pd_val);
+
+ rtw89_phy_write32_idx(rtwdev, dig_regs->seg0_pd_reg,
+ dig_regs->pd_lower_bound_mask, pd_val, bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, dig_regs->seg0_pd_reg,
+ dig_regs->pd_spatial_reuse_en, en_dig, bb->phy_idx);
+
+ dig->pause_dig = pause_dig;
+}
+
+void rtw89_phy_dig_suspend(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_bb_ctx *bb;
+
+ rtw89_for_each_active_bb(rtwdev, bb)
+ rtw89_phy_dig_ctrl(rtwdev, bb, true, false);
+}
+
+void rtw89_phy_dig_resume(struct rtw89_dev *rtwdev, bool restore)
+{
+ struct rtw89_bb_ctx *bb;
+
+ rtw89_for_each_active_bb(rtwdev, bb)
+ rtw89_phy_dig_ctrl(rtwdev, bb, false, restore);
+}
+
+static void __rtw89_phy_dig(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
{
- struct rtw89_dig_info *dig = &rtwdev->dig;
+ struct rtw89_dig_info *dig = &bb->dig;
bool is_linked = rtwdev->total_sta_assoc > 0;
+ enum rtw89_entity_mode mode;
if (unlikely(dig->bypass_dig)) {
dig->bypass_dig = false;
return;
}
+ rtw89_debug(rtwdev, RTW89_DBG_DIG, "BB-%d dig track\n", bb->phy_idx);
+
+ rtw89_phy_dig_update_rssi_info(rtwdev, bb);
+
+ mode = rtw89_get_entity_mode(rtwdev);
+ if (mode == RTW89_ENTITY_MODE_MCC) {
+ rtw89_phy_dig_mcc(rtwdev, bb);
+ return;
+ }
+
+ if (unlikely(dig->pause_dig))
+ return;
+
if (!dig->is_linked_pre && is_linked) {
rtw89_debug(rtwdev, RTW89_DBG_DIG, "First connected\n");
- rtw89_phy_dig_update_para(rtwdev);
+ rtw89_phy_dig_update_para(rtwdev, bb);
+ dig->igi_fa_rssi = dig->igi_rssi;
} else if (dig->is_linked_pre && !is_linked) {
rtw89_debug(rtwdev, RTW89_DBG_DIG, "First disconnected\n");
- rtw89_phy_dig_update_para(rtwdev);
+ rtw89_phy_dig_update_para(rtwdev, bb);
+ dig->igi_fa_rssi = dig->igi_rssi;
}
dig->is_linked_pre = is_linked;
- rtw89_phy_dig_igi_offset_by_env(rtwdev);
- rtw89_phy_dig_update_rssi_info(rtwdev);
-
- dig->dyn_igi_min = (dig->igi_rssi > IGI_RSSI_MIN) ?
- dig->igi_rssi - IGI_RSSI_MIN : 0;
- dig->dyn_igi_max = dig->dyn_igi_min + IGI_OFFSET_MAX;
- dig->igi_fa_rssi = dig->dyn_igi_min + dig->fa_rssi_ofst;
-
- dig->igi_fa_rssi = clamp(dig->igi_fa_rssi, dig->dyn_igi_min,
- dig->dyn_igi_max);
+ rtw89_phy_cal_igi_fa_rssi(rtwdev, bb);
rtw89_debug(rtwdev, RTW89_DBG_DIG,
- "rssi=%03d, dyn(max,min)=(%d,%d), final_rssi=%d\n",
+ "rssi=%03d, dyn_joint(max,min)=(%d,%d), final_rssi=%d\n",
dig->igi_rssi, dig->dyn_igi_max, dig->dyn_igi_min,
dig->igi_fa_rssi);
- rtw89_phy_dig_config_igi(rtwdev);
+ rtw89_phy_dig_config_igi(rtwdev, bb);
- rtw89_phy_dig_dyn_pd_th(rtwdev, dig->igi_fa_rssi, dig->dyn_pd_th_en);
+ rtw89_phy_dig_dyn_pd_th(rtwdev, bb, dig->igi_fa_rssi, dig->dyn_pd_th_en);
if (dig->dyn_pd_th_en && dig->igi_fa_rssi > dig->dyn_pd_th_max)
- rtw89_phy_dig_sdagc_follow_pagc_config(rtwdev, true);
+ rtw89_phy_dig_sdagc_follow_pagc_config(rtwdev, bb, true);
else
- rtw89_phy_dig_sdagc_follow_pagc_config(rtwdev, false);
+ rtw89_phy_dig_sdagc_follow_pagc_config(rtwdev, bb, false);
}
-static void rtw89_phy_tx_path_div_sta_iter(void *data, struct ieee80211_sta *sta)
+void rtw89_phy_dig(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_bb_ctx *bb;
+
+ rtw89_for_each_active_bb(rtwdev, bb)
+ __rtw89_phy_dig(rtwdev, bb);
+}
+
+static void __rtw89_phy_tx_path_div_sta_iter(struct rtw89_dev *rtwdev,
+ struct rtw89_sta_link *rtwsta_link)
{
- struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
- struct rtw89_dev *rtwdev = rtwsta->rtwdev;
- struct rtw89_vif *rtwvif = rtwsta->rtwvif;
struct rtw89_hal *hal = &rtwdev->hal;
- bool *done = data;
u8 rssi_a, rssi_b;
u32 candidate;
- if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION || sta->tdls)
- return;
-
- if (*done)
- return;
-
- *done = true;
-
- rssi_a = ewma_rssi_read(&rtwsta->rssi[RF_PATH_A]);
- rssi_b = ewma_rssi_read(&rtwsta->rssi[RF_PATH_B]);
+ rssi_a = ewma_rssi_read(&rtwsta_link->rssi[RF_PATH_A]);
+ rssi_b = ewma_rssi_read(&rtwsta_link->rssi[RF_PATH_B]);
if (rssi_a > rssi_b + RTW89_TX_DIV_RSSI_RAW_TH)
candidate = RF_A;
@@ -4090,7 +7078,7 @@ static void rtw89_phy_tx_path_div_sta_iter(void *data, struct ieee80211_sta *sta
return;
hal->antenna_tx = candidate;
- rtw89_fw_h2c_txpath_cmac_tbl(rtwdev, rtwsta);
+ rtw89_fw_h2c_txpath_cmac_tbl(rtwdev, rtwsta_link);
if (hal->antenna_tx == RF_A) {
rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE, B_P0_RFMODE_MUX, 0x12);
@@ -4101,6 +7089,37 @@ static void rtw89_phy_tx_path_div_sta_iter(void *data, struct ieee80211_sta *sta
}
}
+static void rtw89_phy_tx_path_div_sta_iter(void *data, struct ieee80211_sta *sta)
+{
+ struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
+ struct rtw89_dev *rtwdev = rtwsta->rtwdev;
+ struct rtw89_vif *rtwvif = rtwsta->rtwvif;
+ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ struct rtw89_vif_link *rtwvif_link;
+ struct rtw89_sta_link *rtwsta_link;
+ unsigned int link_id;
+ bool *done = data;
+
+ if (WARN(ieee80211_vif_is_mld(vif), "MLD mix path_div\n"))
+ return;
+
+ if (sta->tdls)
+ return;
+
+ if (*done)
+ return;
+
+ rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) {
+ rtwvif_link = rtwsta_link->rtwvif_link;
+ if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION)
+ continue;
+
+ *done = true;
+ __rtw89_phy_tx_path_div_sta_iter(rtwdev, rtwsta_link);
+ return;
+ }
+}
+
void rtw89_phy_tx_path_div_track(struct rtw89_dev *rtwdev)
{
struct rtw89_hal *hal = &rtwdev->hal;
@@ -4114,46 +7133,287 @@ void rtw89_phy_tx_path_div_track(struct rtw89_dev *rtwdev)
&done);
}
+#define ANTDIV_MAIN 0
+#define ANTDIV_AUX 1
+
+static void rtw89_phy_antdiv_set_ant(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u8 default_ant, optional_ant;
+
+ if (!hal->ant_diversity || hal->antenna_tx == 0)
+ return;
+
+ if (hal->antenna_tx == RF_B) {
+ default_ant = ANTDIV_AUX;
+ optional_ant = ANTDIV_MAIN;
+ } else {
+ default_ant = ANTDIV_MAIN;
+ optional_ant = ANTDIV_AUX;
+ }
+
+ rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_CGCS_CTRL,
+ default_ant, RTW89_PHY_0);
+ rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_RX_ORI,
+ default_ant, RTW89_PHY_0);
+ rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_RX_ALT,
+ optional_ant, RTW89_PHY_0);
+ rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_TX_ORI,
+ default_ant, RTW89_PHY_0);
+}
+
+static void rtw89_phy_swap_hal_antenna(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+
+ hal->antenna_rx = hal->antenna_rx == RF_A ? RF_B : RF_A;
+ hal->antenna_tx = hal->antenna_rx;
+}
+
+static void rtw89_phy_antdiv_decision_state(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ bool no_change = false;
+ u8 main_rssi, aux_rssi;
+ u8 main_evm, aux_evm;
+ u32 candidate;
+
+ antdiv->get_stats = false;
+ antdiv->training_count = 0;
+
+ main_rssi = rtw89_phy_antdiv_sts_instance_get_rssi(&antdiv->main_stats);
+ main_evm = rtw89_phy_antdiv_sts_instance_get_evm(&antdiv->main_stats);
+ aux_rssi = rtw89_phy_antdiv_sts_instance_get_rssi(&antdiv->aux_stats);
+ aux_evm = rtw89_phy_antdiv_sts_instance_get_evm(&antdiv->aux_stats);
+
+ if (main_evm > aux_evm + ANTDIV_EVM_DIFF_TH)
+ candidate = RF_A;
+ else if (aux_evm > main_evm + ANTDIV_EVM_DIFF_TH)
+ candidate = RF_B;
+ else if (main_rssi > aux_rssi + RTW89_TX_DIV_RSSI_RAW_TH)
+ candidate = RF_A;
+ else if (aux_rssi > main_rssi + RTW89_TX_DIV_RSSI_RAW_TH)
+ candidate = RF_B;
+ else
+ no_change = true;
+
+ if (no_change) {
+ /* swap back from training antenna to original */
+ rtw89_phy_swap_hal_antenna(rtwdev);
+ return;
+ }
+
+ hal->antenna_tx = candidate;
+ hal->antenna_rx = candidate;
+}
+
+static void rtw89_phy_antdiv_training_state(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv;
+ u64 state_period;
+
+ if (antdiv->training_count % 2 == 0) {
+ if (antdiv->training_count == 0)
+ rtw89_phy_antdiv_sts_reset(rtwdev);
+
+ antdiv->get_stats = true;
+ state_period = msecs_to_jiffies(ANTDIV_TRAINNING_INTVL);
+ } else {
+ antdiv->get_stats = false;
+ state_period = msecs_to_jiffies(ANTDIV_DELAY);
+
+ rtw89_phy_swap_hal_antenna(rtwdev);
+ rtw89_phy_antdiv_set_ant(rtwdev);
+ }
+
+ antdiv->training_count++;
+ wiphy_delayed_work_queue(rtwdev->hw->wiphy, &rtwdev->antdiv_work,
+ state_period);
+}
+
+void rtw89_phy_antdiv_work(struct wiphy *wiphy, struct wiphy_work *work)
+{
+ struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
+ antdiv_work.work);
+ struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv;
+
+ lockdep_assert_wiphy(wiphy);
+
+ if (antdiv->training_count <= ANTDIV_TRAINNING_CNT) {
+ rtw89_phy_antdiv_training_state(rtwdev);
+ } else {
+ rtw89_phy_antdiv_decision_state(rtwdev);
+ rtw89_phy_antdiv_set_ant(rtwdev);
+ }
+}
+
+void rtw89_phy_antdiv_track(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u8 rssi, rssi_pre;
+
+ if (!hal->ant_diversity || hal->ant_diversity_fixed)
+ return;
+
+ rssi = rtw89_phy_antdiv_sts_instance_get_rssi(&antdiv->target_stats);
+ rssi_pre = antdiv->rssi_pre;
+ antdiv->rssi_pre = rssi;
+ rtw89_phy_antdiv_sts_instance_reset(&antdiv->target_stats);
+
+ if (abs((int)rssi - (int)rssi_pre) < ANTDIV_RSSI_DIFF_TH)
+ return;
+
+ antdiv->training_count = 0;
+ wiphy_delayed_work_queue(rtwdev->hw->wiphy, &rtwdev->antdiv_work, 0);
+}
+
+static void __rtw89_phy_env_monitor_init(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
+{
+ rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK,
+ "BB-%d env_monitor init\n", bb->phy_idx);
+
+ rtw89_phy_ccx_top_setting_init(rtwdev, bb);
+ rtw89_phy_ifs_clm_setting_init(rtwdev, bb);
+}
+
static void rtw89_phy_env_monitor_init(struct rtw89_dev *rtwdev)
{
- rtw89_phy_ccx_top_setting_init(rtwdev);
- rtw89_phy_ifs_clm_setting_init(rtwdev);
+ struct rtw89_bb_ctx *bb;
+
+ rtw89_for_each_capab_bb(rtwdev, bb)
+ __rtw89_phy_env_monitor_init(rtwdev, bb);
}
-void rtw89_phy_dm_init(struct rtw89_dev *rtwdev)
+static void __rtw89_phy_edcca_init(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
{
- const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs;
+ struct rtw89_edcca_bak *edcca_bak = &bb->edcca_bak;
+
+ rtw89_debug(rtwdev, RTW89_DBG_EDCCA, "BB-%d edcca init\n", bb->phy_idx);
+
+ memset(edcca_bak, 0, sizeof(*edcca_bak));
+
+ if (rtwdev->chip->chip_id == RTL8922A && rtwdev->hal.cv == CHIP_CAV) {
+ rtw89_phy_set_phy_regs(rtwdev, R_TXGATING, B_TXGATING_EN, 0);
+ rtw89_phy_set_phy_regs(rtwdev, R_CTLTOP, B_CTLTOP_VAL, 2);
+ rtw89_phy_set_phy_regs(rtwdev, R_CTLTOP, B_CTLTOP_ON, 1);
+ rtw89_phy_set_phy_regs(rtwdev, R_SPOOF_CG, B_SPOOF_CG_EN, 0);
+ rtw89_phy_set_phy_regs(rtwdev, R_DFS_FFT_CG, B_DFS_CG_EN, 0);
+ rtw89_phy_set_phy_regs(rtwdev, R_DFS_FFT_CG, B_DFS_FFT_EN, 0);
+ rtw89_phy_set_phy_regs(rtwdev, R_SEGSND, B_SEGSND_EN, 0);
+ rtw89_phy_set_phy_regs(rtwdev, R_SEGSND, B_SEGSND_EN, 1);
+ rtw89_phy_set_phy_regs(rtwdev, R_DFS_FFT_CG, B_DFS_FFT_EN, 1);
+ }
+
+ rtw89_phy_write32_idx(rtwdev, edcca_regs->tx_collision_t2r_st,
+ edcca_regs->tx_collision_t2r_st_mask, 0x29, bb->phy_idx);
+}
+static void rtw89_phy_edcca_init(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_bb_ctx *bb;
+
+ rtw89_for_each_capab_bb(rtwdev, bb)
+ __rtw89_phy_edcca_init(rtwdev, bb);
+}
+
+void rtw89_phy_dm_init(struct rtw89_dev *rtwdev)
+{
rtw89_phy_stat_init(rtwdev);
rtw89_chip_bb_sethw(rtwdev);
rtw89_phy_env_monitor_init(rtwdev);
+ rtw89_phy_nhm_setting_init(rtwdev);
rtw89_physts_parsing_init(rtwdev);
rtw89_phy_dig_init(rtwdev);
rtw89_phy_cfo_init(rtwdev);
+ rtw89_phy_bb_wrap_init(rtwdev);
+ rtw89_phy_edcca_init(rtwdev);
+ rtw89_phy_ch_info_init(rtwdev);
rtw89_phy_ul_tb_info_init(rtwdev);
+ rtw89_phy_antdiv_init(rtwdev);
+ rtw89_chip_rfe_gpio(rtwdev);
+ rtw89_phy_antdiv_set_ant(rtwdev);
+ rtw89_chip_rfk_hw_init(rtwdev);
rtw89_phy_init_rf_nctl(rtwdev);
rtw89_chip_rfk_init(rtwdev);
- rtw89_load_txpwr_table(rtwdev, chip->byr_table);
rtw89_chip_set_txpwr_ctrl(rtwdev);
rtw89_chip_power_trim(rtwdev);
rtw89_chip_cfg_txrx_path(rtwdev);
}
-void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif)
+void rtw89_phy_dm_reinit(struct rtw89_dev *rtwdev)
{
+ rtw89_phy_env_monitor_init(rtwdev);
+ rtw89_physts_parsing_init(rtwdev);
+}
+
+static void __rtw89_phy_dm_init_data(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
+{
+ struct rtw89_env_monitor_info *env = &bb->env_monitor;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct ieee80211_supported_band *sband;
+ enum rtw89_band hw_band;
+ enum nl80211_band band;
+ u8 idx;
+
+ if (!chip->support_noise)
+ return;
+
+ for (band = 0; band < NUM_NL80211_BANDS; band++) {
+ sband = rtwdev->hw->wiphy->bands[band];
+ if (!sband)
+ continue;
+
+ hw_band = rtw89_nl80211_to_hw_band(band);
+ env->nhm_his[hw_band] =
+ devm_kcalloc(rtwdev->dev, sband->n_channels,
+ sizeof(*env->nhm_his[0]), GFP_KERNEL);
+
+ for (idx = 0; idx < sband->n_channels; idx++)
+ INIT_LIST_HEAD(&env->nhm_his[hw_band][idx].list);
+
+ INIT_LIST_HEAD(&env->nhm_rpt_list);
+ }
+}
+
+void rtw89_phy_dm_init_data(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_bb_ctx *bb;
+
+ rtw89_for_each_capab_bb(rtwdev, bb)
+ __rtw89_phy_dm_init_data(rtwdev, bb);
+}
+
+void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev,
+ struct rtw89_vif_link *rtwvif_link)
+{
+ struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
const struct rtw89_chip_info *chip = rtwdev->chip;
- enum rtw89_phy_idx phy_idx = RTW89_PHY_0;
+ const struct rtw89_reg_def *bss_clr_vld = &chip->bss_clr_vld;
+ enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx;
+ struct ieee80211_bss_conf *bss_conf;
u8 bss_color;
- if (!vif->bss_conf.he_support || !vif->cfg.assoc)
+ rcu_read_lock();
+
+ bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
+ if (!bss_conf->he_support || !vif->cfg.assoc) {
+ rcu_read_unlock();
return;
+ }
+
+ bss_color = bss_conf->he_bss_color.color;
- bss_color = vif->bss_conf.he_bss_color.color;
+ rcu_read_unlock();
- rtw89_phy_write32_idx(rtwdev, chip->bss_clr_map_reg, B_BSS_CLR_MAP_VLD0, 0x1,
+ rtw89_phy_write32_idx(rtwdev, bss_clr_vld->addr, bss_clr_vld->mask, 0x1,
phy_idx);
rtw89_phy_write32_idx(rtwdev, chip->bss_clr_map_reg, B_BSS_CLR_MAP_TGT,
bss_color, phy_idx);
@@ -4161,6 +7421,74 @@ void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif
vif->cfg.aid, phy_idx);
}
+static bool rfk_chan_validate_desc(const struct rtw89_rfk_chan_desc *desc)
+{
+ return desc->ch != 0;
+}
+
+static bool rfk_chan_is_equivalent(const struct rtw89_rfk_chan_desc *desc,
+ const struct rtw89_chan *chan)
+{
+ if (!rfk_chan_validate_desc(desc))
+ return false;
+
+ if (desc->ch != chan->channel)
+ return false;
+
+ if (desc->has_band && desc->band != chan->band_type)
+ return false;
+
+ if (desc->has_bw && desc->bw != chan->band_width)
+ return false;
+
+ return true;
+}
+
+struct rfk_chan_iter_data {
+ const struct rtw89_rfk_chan_desc desc;
+ unsigned int found;
+};
+
+static int rfk_chan_iter_search(const struct rtw89_chan *chan, void *data)
+{
+ struct rfk_chan_iter_data *iter_data = data;
+
+ if (rfk_chan_is_equivalent(&iter_data->desc, chan))
+ iter_data->found++;
+
+ return 0;
+}
+
+u8 rtw89_rfk_chan_lookup(struct rtw89_dev *rtwdev,
+ const struct rtw89_rfk_chan_desc *desc, u8 desc_nr,
+ const struct rtw89_chan *target_chan)
+{
+ int sel = -1;
+ u8 i;
+
+ for (i = 0; i < desc_nr; i++) {
+ struct rfk_chan_iter_data iter_data = {
+ .desc = desc[i],
+ };
+
+ if (rfk_chan_is_equivalent(&desc[i], target_chan))
+ return i;
+
+ rtw89_iterate_entity_chan(rtwdev, rfk_chan_iter_search, &iter_data);
+ if (!iter_data.found && sel == -1)
+ sel = i;
+ }
+
+ if (sel == -1) {
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "no idle rfk entry; force replace the first\n");
+ sel = 0;
+ }
+
+ return sel;
+}
+EXPORT_SYMBOL(rtw89_rfk_chan_lookup);
+
static void
_rfk_write_rf(struct rtw89_dev *rtwdev, const struct rtw89_reg5_def *def)
{
@@ -4245,7 +7573,7 @@ void rtw89_phy_tssi_ctrl_set_fast_mode_cfg(struct rtw89_dev *rtwdev,
regs = rtw89_tssi_fastmode_regs_level;
for (i = 0; i < RTW89_TSSI_FAST_MODE_NUM; i++) {
- reg = rtw89_mac_reg_by_idx(regs[i].addr, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, regs[i].addr, mac_idx);
rtw89_write32_mask(rtwdev, reg, regs[i].mask, val);
}
}
@@ -4307,11 +7635,11 @@ void rtw89_phy_tssi_ctrl_set_bandedge_cfg(struct rtw89_dev *rtwdev,
data = chip->tssi_dbw_table->data[bandedge_cfg];
for (i = 0; i < RTW89_TSSI_SBW_NUM; i++) {
- reg = rtw89_mac_reg_by_idx(regs[i].addr, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, regs[i].addr, mac_idx);
rtw89_write32_mask(rtwdev, reg, regs[i].mask, data[i]);
}
- reg = rtw89_mac_reg_by_idx(R_AX_BANDEDGE_CFG, mac_idx);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_BANDEDGE_CFG, mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_BANDEDGE_CFG_IDX_MASK, bandedge_cfg);
rtw89_phy_tssi_ctrl_set_fast_mode_cfg(rtwdev, mac_idx, bandedge_cfg,
@@ -4391,21 +7719,371 @@ void rtw89_decode_chan_idx(struct rtw89_dev *rtwdev, u8 chan_idx,
}
EXPORT_SYMBOL(rtw89_decode_chan_idx);
-#define EDCCA_DEFAULT 249
-void rtw89_phy_config_edcca(struct rtw89_dev *rtwdev, bool scan)
+void rtw89_phy_config_edcca(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb, bool scan)
{
- u32 reg = rtwdev->chip->edcca_lvl_reg;
- struct rtw89_hal *hal = &rtwdev->hal;
- u32 val;
+ const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs;
+ struct rtw89_edcca_bak *edcca_bak = &bb->edcca_bak;
if (scan) {
- hal->edcca_bak = rtw89_phy_read32(rtwdev, reg);
- val = hal->edcca_bak;
- u32p_replace_bits(&val, EDCCA_DEFAULT, B_SEG0R_EDCCA_LVL_A_MSK);
- u32p_replace_bits(&val, EDCCA_DEFAULT, B_SEG0R_EDCCA_LVL_P_MSK);
- u32p_replace_bits(&val, EDCCA_DEFAULT, B_SEG0R_PPDU_LVL_MSK);
- rtw89_phy_write32(rtwdev, reg, val);
+ edcca_bak->a =
+ rtw89_phy_read32_idx(rtwdev, edcca_regs->edcca_level,
+ edcca_regs->edcca_mask, bb->phy_idx);
+ edcca_bak->p =
+ rtw89_phy_read32_idx(rtwdev, edcca_regs->edcca_level,
+ edcca_regs->edcca_p_mask, bb->phy_idx);
+ edcca_bak->ppdu =
+ rtw89_phy_read32_idx(rtwdev, edcca_regs->ppdu_level,
+ edcca_regs->ppdu_mask, bb->phy_idx);
+
+ rtw89_phy_write32_idx(rtwdev, edcca_regs->edcca_level,
+ edcca_regs->edcca_mask, EDCCA_MAX, bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, edcca_regs->edcca_level,
+ edcca_regs->edcca_p_mask, EDCCA_MAX, bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, edcca_regs->ppdu_level,
+ edcca_regs->ppdu_mask, EDCCA_MAX, bb->phy_idx);
+ } else {
+ rtw89_phy_write32_idx(rtwdev, edcca_regs->edcca_level,
+ edcca_regs->edcca_mask,
+ edcca_bak->a, bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, edcca_regs->edcca_level,
+ edcca_regs->edcca_p_mask,
+ edcca_bak->p, bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, edcca_regs->ppdu_level,
+ edcca_regs->ppdu_mask,
+ edcca_bak->ppdu, bb->phy_idx);
+ }
+}
+
+static void rtw89_phy_edcca_log(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
+{
+ const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs;
+ const struct rtw89_edcca_p_regs *edcca_p_regs;
+ bool flag_fb, flag_p20, flag_s20, flag_s40, flag_s80;
+ s8 pwdb_fb, pwdb_p20, pwdb_s20, pwdb_s40, pwdb_s80;
+ u8 path, per20_bitmap = 0;
+ u8 pwdb[8];
+ u32 tmp;
+
+ if (!rtw89_debug_is_enabled(rtwdev, RTW89_DBG_EDCCA))
+ return;
+
+ if (bb->phy_idx == RTW89_PHY_1)
+ edcca_p_regs = &edcca_regs->p[RTW89_PHY_1];
+ else
+ edcca_p_regs = &edcca_regs->p[RTW89_PHY_0];
+
+ if (rtwdev->chip->chip_id == RTL8922A)
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel_be,
+ edcca_regs->rpt_sel_be_mask, 0);
+
+ rtw89_phy_write32_mask(rtwdev, edcca_p_regs->rpt_sel,
+ edcca_p_regs->rpt_sel_mask, 0);
+ tmp = rtw89_phy_read32(rtwdev, edcca_p_regs->rpt_b);
+ path = u32_get_bits(tmp, B_EDCCA_RPT_B_PATH_MASK);
+ flag_s80 = u32_get_bits(tmp, B_EDCCA_RPT_B_S80);
+ flag_s40 = u32_get_bits(tmp, B_EDCCA_RPT_B_S40);
+ flag_s20 = u32_get_bits(tmp, B_EDCCA_RPT_B_S20);
+ flag_p20 = u32_get_bits(tmp, B_EDCCA_RPT_B_P20);
+ flag_fb = u32_get_bits(tmp, B_EDCCA_RPT_B_FB);
+ pwdb_s20 = u32_get_bits(tmp, MASKBYTE1);
+ pwdb_p20 = u32_get_bits(tmp, MASKBYTE2);
+ pwdb_fb = u32_get_bits(tmp, MASKBYTE3);
+
+ rtw89_phy_write32_mask(rtwdev, edcca_p_regs->rpt_sel,
+ edcca_p_regs->rpt_sel_mask, 5);
+ tmp = rtw89_phy_read32(rtwdev, edcca_p_regs->rpt_b);
+ pwdb_s80 = u32_get_bits(tmp, MASKBYTE1);
+ pwdb_s40 = u32_get_bits(tmp, MASKBYTE2);
+
+ if (rtwdev->chip->chip_id == RTL8922A) {
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel_be,
+ edcca_regs->rpt_sel_be_mask, 4);
+ tmp = rtw89_phy_read32(rtwdev, edcca_p_regs->rpt_b);
+ pwdb[0] = u32_get_bits(tmp, MASKBYTE3);
+ pwdb[1] = u32_get_bits(tmp, MASKBYTE2);
+ pwdb[2] = u32_get_bits(tmp, MASKBYTE1);
+ pwdb[3] = u32_get_bits(tmp, MASKBYTE0);
+ per20_bitmap = rtw89_phy_read32_mask(rtwdev, edcca_p_regs->rpt_a,
+ MASKBYTE0);
+
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel_be,
+ edcca_regs->rpt_sel_be_mask, 5);
+ tmp = rtw89_phy_read32(rtwdev, edcca_p_regs->rpt_b);
+ pwdb[4] = u32_get_bits(tmp, MASKBYTE3);
+ pwdb[5] = u32_get_bits(tmp, MASKBYTE2);
+ pwdb[6] = u32_get_bits(tmp, MASKBYTE1);
+ pwdb[7] = u32_get_bits(tmp, MASKBYTE0);
+ } else {
+ rtw89_phy_write32_mask(rtwdev, edcca_p_regs->rpt_sel,
+ edcca_p_regs->rpt_sel_mask, 0);
+ tmp = rtw89_phy_read32(rtwdev, edcca_p_regs->rpt_a);
+ pwdb[0] = u32_get_bits(tmp, MASKBYTE3);
+ pwdb[1] = u32_get_bits(tmp, MASKBYTE2);
+
+ rtw89_phy_write32_mask(rtwdev, edcca_p_regs->rpt_sel,
+ edcca_p_regs->rpt_sel_mask, 5);
+ tmp = rtw89_phy_read32(rtwdev, edcca_p_regs->rpt_a);
+ pwdb[2] = u32_get_bits(tmp, MASKBYTE3);
+ pwdb[3] = u32_get_bits(tmp, MASKBYTE2);
+
+ rtw89_phy_write32_mask(rtwdev, edcca_p_regs->rpt_sel,
+ edcca_p_regs->rpt_sel_mask, 2);
+ tmp = rtw89_phy_read32(rtwdev, edcca_p_regs->rpt_a);
+ pwdb[4] = u32_get_bits(tmp, MASKBYTE3);
+ pwdb[5] = u32_get_bits(tmp, MASKBYTE2);
+
+ rtw89_phy_write32_mask(rtwdev, edcca_p_regs->rpt_sel,
+ edcca_p_regs->rpt_sel_mask, 3);
+ tmp = rtw89_phy_read32(rtwdev, edcca_p_regs->rpt_a);
+ pwdb[6] = u32_get_bits(tmp, MASKBYTE3);
+ pwdb[7] = u32_get_bits(tmp, MASKBYTE2);
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_EDCCA,
+ "[EDCCA]: edcca_bitmap = %04x\n", per20_bitmap);
+
+ rtw89_debug(rtwdev, RTW89_DBG_EDCCA,
+ "[EDCCA]: pwdb per20{0,1,2,3,4,5,6,7} = {%d,%d,%d,%d,%d,%d,%d,%d}(dBm)\n",
+ pwdb[0], pwdb[1], pwdb[2], pwdb[3], pwdb[4], pwdb[5],
+ pwdb[6], pwdb[7]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_EDCCA,
+ "[EDCCA]: path=%d, flag {FB,p20,s20,s40,s80} = {%d,%d,%d,%d,%d}\n",
+ path, flag_fb, flag_p20, flag_s20, flag_s40, flag_s80);
+
+ rtw89_debug(rtwdev, RTW89_DBG_EDCCA,
+ "[EDCCA]: pwdb {FB,p20,s20,s40,s80} = {%d,%d,%d,%d,%d}(dBm)\n",
+ pwdb_fb, pwdb_p20, pwdb_s20, pwdb_s40, pwdb_s80);
+}
+
+static u8 rtw89_phy_edcca_get_thre_by_rssi(struct rtw89_dev *rtwdev,
+ struct rtw89_bb_ctx *bb)
+{
+ struct rtw89_phy_ch_info *ch_info = &bb->ch_info;
+ bool is_linked = rtwdev->total_sta_assoc > 0;
+ u8 rssi_min = ch_info->rssi_min >> 1;
+ u8 edcca_thre;
+
+ if (!is_linked) {
+ edcca_thre = EDCCA_MAX;
} else {
- rtw89_phy_write32(rtwdev, reg, hal->edcca_bak);
+ edcca_thre = rssi_min - RSSI_UNIT_CONVER + EDCCA_UNIT_CONVER -
+ EDCCA_TH_REF;
+ edcca_thre = max_t(u8, edcca_thre, EDCCA_TH_L2H_LB);
+ }
+
+ return edcca_thre;
+}
+
+void rtw89_phy_edcca_thre_calc(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
+{
+ const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs;
+ struct rtw89_edcca_bak *edcca_bak = &bb->edcca_bak;
+ u8 th;
+
+ th = rtw89_phy_edcca_get_thre_by_rssi(rtwdev, bb);
+ if (th == edcca_bak->th_old)
+ return;
+
+ edcca_bak->th_old = th;
+
+ rtw89_debug(rtwdev, RTW89_DBG_EDCCA,
+ "[EDCCA]: Normal Mode, EDCCA_th = %d\n", th);
+
+ rtw89_phy_write32_idx(rtwdev, edcca_regs->edcca_level,
+ edcca_regs->edcca_mask, th, bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, edcca_regs->edcca_level,
+ edcca_regs->edcca_p_mask, th, bb->phy_idx);
+ rtw89_phy_write32_idx(rtwdev, edcca_regs->ppdu_level,
+ edcca_regs->ppdu_mask, th, bb->phy_idx);
+}
+
+static
+void __rtw89_phy_edcca_track(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb)
+{
+ rtw89_debug(rtwdev, RTW89_DBG_EDCCA, "BB-%d edcca track\n", bb->phy_idx);
+
+ rtw89_phy_edcca_thre_calc(rtwdev, bb);
+ rtw89_phy_edcca_log(rtwdev, bb);
+}
+
+void rtw89_phy_edcca_track(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ struct rtw89_bb_ctx *bb;
+
+ if (hal->disabled_dm_bitmap & BIT(RTW89_DM_DYNAMIC_EDCCA))
+ return;
+
+ rtw89_for_each_active_bb(rtwdev, bb)
+ __rtw89_phy_edcca_track(rtwdev, bb);
+}
+
+enum rtw89_rf_path_bit rtw89_phy_get_kpath(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
+{
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[RFK] kpath dbcc_en: 0x%x, mode=0x%x, PHY%d\n",
+ rtwdev->dbcc_en, rtwdev->mlo_dbcc_mode, phy_idx);
+
+ switch (rtwdev->mlo_dbcc_mode) {
+ case MLO_1_PLUS_1_1RF:
+ if (phy_idx == RTW89_PHY_0)
+ return RF_A;
+ else
+ return RF_B;
+ case MLO_1_PLUS_1_2RF:
+ if (phy_idx == RTW89_PHY_0)
+ return RF_A;
+ else
+ return RF_D;
+ case MLO_0_PLUS_2_1RF:
+ case MLO_2_PLUS_0_1RF:
+ /* for both PHY 0/1 */
+ return RF_AB;
+ case MLO_0_PLUS_2_2RF:
+ case MLO_2_PLUS_0_2RF:
+ case MLO_2_PLUS_2_2RF:
+ default:
+ if (phy_idx == RTW89_PHY_0)
+ return RF_AB;
+ else
+ return RF_CD;
+ }
+}
+EXPORT_SYMBOL(rtw89_phy_get_kpath);
+
+enum rtw89_rf_path rtw89_phy_get_syn_sel(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
+{
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[RFK] kpath dbcc_en: 0x%x, mode=0x%x, PHY%d\n",
+ rtwdev->dbcc_en, rtwdev->mlo_dbcc_mode, phy_idx);
+
+ switch (rtwdev->mlo_dbcc_mode) {
+ case MLO_1_PLUS_1_1RF:
+ if (phy_idx == RTW89_PHY_0)
+ return RF_PATH_A;
+ else
+ return RF_PATH_B;
+ case MLO_1_PLUS_1_2RF:
+ if (phy_idx == RTW89_PHY_0)
+ return RF_PATH_A;
+ else
+ return RF_PATH_D;
+ case MLO_0_PLUS_2_1RF:
+ case MLO_2_PLUS_0_1RF:
+ if (phy_idx == RTW89_PHY_0)
+ return RF_PATH_A;
+ else
+ return RF_PATH_B;
+ case MLO_0_PLUS_2_2RF:
+ case MLO_2_PLUS_0_2RF:
+ case MLO_2_PLUS_2_2RF:
+ default:
+ if (phy_idx == RTW89_PHY_0)
+ return RF_PATH_A;
+ else
+ return RF_PATH_C;
}
}
+EXPORT_SYMBOL(rtw89_phy_get_syn_sel);
+
+static const struct rtw89_ccx_regs rtw89_ccx_regs_ax = {
+ .setting_addr = R_CCX,
+ .edcca_opt_mask = B_CCX_EDCCA_OPT_MSK,
+ .measurement_trig_mask = B_MEASUREMENT_TRIG_MSK,
+ .trig_opt_mask = B_CCX_TRIG_OPT_MSK,
+ .en_mask = B_CCX_EN_MSK,
+ .ifs_cnt_addr = R_IFS_COUNTER,
+ .ifs_clm_period_mask = B_IFS_CLM_PERIOD_MSK,
+ .ifs_clm_cnt_unit_mask = B_IFS_CLM_COUNTER_UNIT_MSK,
+ .ifs_clm_cnt_clear_mask = B_IFS_COUNTER_CLR_MSK,
+ .ifs_collect_en_mask = B_IFS_COLLECT_EN,
+ .ifs_t1_addr = R_IFS_T1,
+ .ifs_t1_th_h_mask = B_IFS_T1_TH_HIGH_MSK,
+ .ifs_t1_en_mask = B_IFS_T1_EN_MSK,
+ .ifs_t1_th_l_mask = B_IFS_T1_TH_LOW_MSK,
+ .ifs_t2_addr = R_IFS_T2,
+ .ifs_t2_th_h_mask = B_IFS_T2_TH_HIGH_MSK,
+ .ifs_t2_en_mask = B_IFS_T2_EN_MSK,
+ .ifs_t2_th_l_mask = B_IFS_T2_TH_LOW_MSK,
+ .ifs_t3_addr = R_IFS_T3,
+ .ifs_t3_th_h_mask = B_IFS_T3_TH_HIGH_MSK,
+ .ifs_t3_en_mask = B_IFS_T3_EN_MSK,
+ .ifs_t3_th_l_mask = B_IFS_T3_TH_LOW_MSK,
+ .ifs_t4_addr = R_IFS_T4,
+ .ifs_t4_th_h_mask = B_IFS_T4_TH_HIGH_MSK,
+ .ifs_t4_en_mask = B_IFS_T4_EN_MSK,
+ .ifs_t4_th_l_mask = B_IFS_T4_TH_LOW_MSK,
+ .ifs_clm_tx_cnt_addr = R_IFS_CLM_TX_CNT,
+ .ifs_clm_edcca_excl_cca_fa_mask = B_IFS_CLM_EDCCA_EXCLUDE_CCA_FA_MSK,
+ .ifs_clm_tx_cnt_msk = B_IFS_CLM_TX_CNT_MSK,
+ .ifs_clm_cca_addr = R_IFS_CLM_CCA,
+ .ifs_clm_ofdmcca_excl_fa_mask = B_IFS_CLM_OFDMCCA_EXCLUDE_FA_MSK,
+ .ifs_clm_cckcca_excl_fa_mask = B_IFS_CLM_CCKCCA_EXCLUDE_FA_MSK,
+ .ifs_clm_fa_addr = R_IFS_CLM_FA,
+ .ifs_clm_ofdm_fa_mask = B_IFS_CLM_OFDM_FA_MSK,
+ .ifs_clm_cck_fa_mask = B_IFS_CLM_CCK_FA_MSK,
+ .ifs_his_addr = R_IFS_HIS,
+ .ifs_t4_his_mask = B_IFS_T4_HIS_MSK,
+ .ifs_t3_his_mask = B_IFS_T3_HIS_MSK,
+ .ifs_t2_his_mask = B_IFS_T2_HIS_MSK,
+ .ifs_t1_his_mask = B_IFS_T1_HIS_MSK,
+ .ifs_avg_l_addr = R_IFS_AVG_L,
+ .ifs_t2_avg_mask = B_IFS_T2_AVG_MSK,
+ .ifs_t1_avg_mask = B_IFS_T1_AVG_MSK,
+ .ifs_avg_h_addr = R_IFS_AVG_H,
+ .ifs_t4_avg_mask = B_IFS_T4_AVG_MSK,
+ .ifs_t3_avg_mask = B_IFS_T3_AVG_MSK,
+ .ifs_cca_l_addr = R_IFS_CCA_L,
+ .ifs_t2_cca_mask = B_IFS_T2_CCA_MSK,
+ .ifs_t1_cca_mask = B_IFS_T1_CCA_MSK,
+ .ifs_cca_h_addr = R_IFS_CCA_H,
+ .ifs_t4_cca_mask = B_IFS_T4_CCA_MSK,
+ .ifs_t3_cca_mask = B_IFS_T3_CCA_MSK,
+ .ifs_total_addr = R_IFSCNT,
+ .ifs_cnt_done_mask = B_IFSCNT_DONE_MSK,
+ .ifs_total_mask = B_IFSCNT_TOTAL_CNT_MSK,
+ .nhm = R_NHM_AX,
+ .nhm_ready = B_NHM_READY_MSK,
+ .nhm_config = R_NHM_CFG,
+ .nhm_period_mask = B_NHM_PERIOD_MSK,
+ .nhm_unit_mask = B_NHM_COUNTER_MSK,
+ .nhm_include_cca_mask = B_NHM_INCLUDE_CCA_MSK,
+ .nhm_en_mask = B_NHM_EN_MSK,
+ .nhm_method = R_NHM_TH9,
+ .nhm_pwr_method_msk = B_NHM_PWDB_METHOD_MSK,
+};
+
+static const struct rtw89_physts_regs rtw89_physts_regs_ax = {
+ .setting_addr = R_PLCP_HISTOGRAM,
+ .dis_trigger_fail_mask = B_STS_DIS_TRIG_BY_FAIL,
+ .dis_trigger_brk_mask = B_STS_DIS_TRIG_BY_BRK,
+};
+
+static const struct rtw89_cfo_regs rtw89_cfo_regs_ax = {
+ .comp = R_DCFO_WEIGHT,
+ .weighting_mask = B_DCFO_WEIGHT_MSK,
+ .comp_seg0 = R_DCFO_OPT,
+ .valid_0_mask = B_DCFO_OPT_EN,
+};
+
+const struct rtw89_phy_gen_def rtw89_phy_gen_ax = {
+ .cr_base = 0x10000,
+ .ccx = &rtw89_ccx_regs_ax,
+ .physts = &rtw89_physts_regs_ax,
+ .cfo = &rtw89_cfo_regs_ax,
+ .phy0_phy1_offset = rtw89_phy0_phy1_offset_ax,
+ .config_bb_gain = rtw89_phy_config_bb_gain_ax,
+ .preinit_rf_nctl = rtw89_phy_preinit_rf_nctl_ax,
+ .bb_wrap_init = NULL,
+ .ch_info_init = NULL,
+
+ .set_txpwr_byrate = rtw89_phy_set_txpwr_byrate_ax,
+ .set_txpwr_offset = rtw89_phy_set_txpwr_offset_ax,
+ .set_txpwr_limit = rtw89_phy_set_txpwr_limit_ax,
+ .set_txpwr_limit_ru = rtw89_phy_set_txpwr_limit_ru_ax,
+};
+EXPORT_SYMBOL(rtw89_phy_gen_ax);