rtw88: 8822c: add CFO tracking

Add CFO tracking, which stands for central frequency offset tracking, to
adjust oscillator to align central frequency of connected AP. Then, it can
yield better performance.

Signed-off-by: Po-Hao Huang <phhuang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20210416030901.7099-1-pkshih@realtek.com
This commit is contained in:
Po-Hao Huang 2021-04-16 11:09:01 +08:00 committed by Kalle Valo
parent c544d89b0d
commit fb8517f4fa
8 changed files with 224 additions and 1 deletions

View File

@ -406,4 +406,12 @@ void rtw_coex_switchband_notify(struct rtw_dev *rtwdev, u8 type);
void rtw_coex_wl_status_change_notify(struct rtw_dev *rtwdev, u32 type);
void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m);
static inline bool rtw_coex_disabled(struct rtw_dev *rtwdev)
{
struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat;
return coex_stat->bt_disabled;
}
#endif

View File

@ -19,6 +19,7 @@ enum rtw_debug_mask {
RTW_DBG_PS = 0x00000400,
RTW_DBG_BF = 0x00000800,
RTW_DBG_WOW = 0x00001000,
RTW_DBG_CFO = 0x00002000,
RTW_DBG_ALL = 0xffffffff
};

View File

@ -625,6 +625,7 @@ struct rtw_rx_pkt_stat {
struct rtw_sta_info *si;
struct ieee80211_vif *vif;
struct ieee80211_hdr *hdr;
};
DECLARE_EWMA(tp, 10, 2);
@ -838,6 +839,8 @@ struct rtw_chip_ops {
struct ieee80211_bss_conf *conf);
void (*cfg_csi_rate)(struct rtw_dev *rtwdev, u8 rssi, u8 cur_rate,
u8 fixrate_en, u8 *new_rate);
void (*cfo_init)(struct rtw_dev *rtwdev);
void (*cfo_track)(struct rtw_dev *rtwdev);
/* for coex */
void (*coex_set_init)(struct rtw_dev *rtwdev);
@ -1499,6 +1502,15 @@ struct rtw_iqk_info {
} result;
};
struct rtw_cfo_track {
bool is_adjust;
u8 crystal_cap;
s32 cfo_tail[RTW_RF_PATH_MAX];
s32 cfo_cnt[RTW_RF_PATH_MAX];
u32 packet_count;
u32 packet_count_pre;
};
#define RRSR_INIT_2G 0x15f
#define RRSR_INIT_5G 0x150
@ -1552,6 +1564,7 @@ struct rtw_dm_info {
u8 dack_dck[RTW_RF_PATH_MAX][2][DACK_DCK_BACKUP_NUM];
struct rtw_dpk_info dpk_info;
struct rtw_cfo_track cfo_track;
/* [bandwidth 0:20M/1:40M][number of path] */
u8 cck_pd_lv[2][RTW_RF_PATH_MAX];

View File

@ -119,6 +119,14 @@ static void rtw_phy_cck_pd_init(struct rtw_dev *rtwdev)
dm_info->cck_fa_avg = CCK_FA_AVG_RESET;
}
static void rtw_phy_cfo_init(struct rtw_dev *rtwdev)
{
struct rtw_chip_info *chip = rtwdev->chip;
if (chip->ops->cfo_init)
chip->ops->cfo_init(rtwdev);
}
void rtw_phy_init(struct rtw_dev *rtwdev)
{
struct rtw_chip_info *chip = rtwdev->chip;
@ -140,6 +148,7 @@ void rtw_phy_init(struct rtw_dev *rtwdev)
rtw_phy_cck_pd_init(rtwdev);
dm_info->iqk.done = false;
rtw_phy_cfo_init(rtwdev);
}
EXPORT_SYMBOL(rtw_phy_init);
@ -528,6 +537,62 @@ static void rtw_phy_dpk_track(struct rtw_dev *rtwdev)
chip->ops->dpk_track(rtwdev);
}
struct rtw_rx_addr_match_data {
struct rtw_dev *rtwdev;
struct ieee80211_hdr *hdr;
struct rtw_rx_pkt_stat *pkt_stat;
u8 *bssid;
};
static void rtw_phy_parsing_cfo_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct rtw_rx_addr_match_data *iter_data = data;
struct rtw_dev *rtwdev = iter_data->rtwdev;
struct rtw_rx_pkt_stat *pkt_stat = iter_data->pkt_stat;
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
struct rtw_cfo_track *cfo = &dm_info->cfo_track;
u8 *bssid = iter_data->bssid;
u8 i;
if (!ether_addr_equal(vif->bss_conf.bssid, bssid))
return;
for (i = 0; i < rtwdev->hal.rf_path_num; i++) {
cfo->cfo_tail[i] += pkt_stat->cfo_tail[i];
cfo->cfo_cnt[i]++;
}
cfo->packet_count++;
}
void rtw_phy_parsing_cfo(struct rtw_dev *rtwdev,
struct rtw_rx_pkt_stat *pkt_stat)
{
struct ieee80211_hdr *hdr = pkt_stat->hdr;
struct rtw_rx_addr_match_data data = {};
if (pkt_stat->crc_err || pkt_stat->icv_err || !pkt_stat->phy_status ||
ieee80211_is_ctl(hdr->frame_control))
return;
data.rtwdev = rtwdev;
data.hdr = hdr;
data.pkt_stat = pkt_stat;
data.bssid = get_hdr_bssid(hdr);
rtw_iterate_vifs_atomic(rtwdev, rtw_phy_parsing_cfo_iter, &data);
}
EXPORT_SYMBOL(rtw_phy_parsing_cfo);
static void rtw_phy_cfo_track(struct rtw_dev *rtwdev)
{
struct rtw_chip_info *chip = rtwdev->chip;
if (chip->ops->cfo_track)
chip->ops->cfo_track(rtwdev);
}
#define CCK_PD_FA_LV1_MIN 1000
#define CCK_PD_FA_LV0_MAX 500
@ -630,6 +695,7 @@ void rtw_phy_dynamic_mechanism(struct rtw_dev *rtwdev)
rtw_phy_dig(rtwdev);
rtw_phy_cck_pd(rtwdev);
rtw_phy_ra_track(rtwdev);
rtw_phy_cfo_track(rtwdev);
rtw_phy_dpk_track(rtwdev);
rtw_phy_pwr_track(rtwdev);
}

View File

@ -59,6 +59,8 @@ bool rtw_phy_pwrtrack_need_lck(struct rtw_dev *rtwdev);
bool rtw_phy_pwrtrack_need_iqk(struct rtw_dev *rtwdev);
void rtw_phy_config_swing_table(struct rtw_dev *rtwdev,
struct rtw_swing_table *swing_table);
void rtw_phy_parsing_cfo(struct rtw_dev *rtwdev,
struct rtw_rx_pkt_stat *pkt_stat);
struct rtw_txpwr_lmt_cfg_pair {
u8 regd;

View File

@ -516,6 +516,7 @@
#define BIT_RFE_BUF_EN BIT(3)
#define REG_ANAPAR_XTAL_0 0x1040
#define BIT_XCAP_0 GENMASK(23, 10)
#define REG_CPU_DMEM_CON 0x1080
#define BIT_WL_PLATFORM_RST BIT(16)
#define BIT_WL_SECURITY_CLK BIT(15)

View File

@ -17,6 +17,7 @@
#include "util.h"
#include "bf.h"
#include "efuse.h"
#include "coex.h"
#define IQK_DONE_8822C 0xaa
@ -39,7 +40,7 @@ static int rtw8822c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
efuse->rfe_option = map->rfe_option;
efuse->rf_board_option = map->rf_board_option;
efuse->crystal_cap = map->xtal_k;
efuse->crystal_cap = map->xtal_k & XCAP_MASK;
efuse->channel_plan = map->channel_plan;
efuse->country_code[0] = map->country_code[0];
efuse->country_code[1] = map->country_code[1];
@ -1866,6 +1867,7 @@ static void query_phy_status_page1(struct rtw_dev *rtwdev, u8 *phy_status,
}
dm_info->rx_evm_dbm[path] = evm_dbm;
}
rtw_phy_parsing_cfo(rtwdev, pkt_stat);
}
static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status,
@ -1921,6 +1923,7 @@ static void rtw8822c_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc,
hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift +
pkt_stat->drv_info_sz);
pkt_stat->hdr = hdr;
if (pkt_stat->phy_status) {
phy_status = rx_desc + desc_sz + pkt_stat->shift;
query_phy_status(rtwdev, phy_status, pkt_stat);
@ -3436,6 +3439,128 @@ static void rtw8822c_dpk_track(struct rtw_dev *rtwdev)
}
}
#define XCAP_EXTEND(val) ({typeof(val) _v = (val); _v | _v << 7; })
static void rtw8822c_set_crystal_cap_reg(struct rtw_dev *rtwdev, u8 crystal_cap)
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
struct rtw_cfo_track *cfo = &dm_info->cfo_track;
u32 val = 0;
val = XCAP_EXTEND(crystal_cap);
cfo->crystal_cap = crystal_cap;
rtw_write32_mask(rtwdev, REG_ANAPAR_XTAL_0, BIT_XCAP_0, val);
}
static void rtw8822c_set_crystal_cap(struct rtw_dev *rtwdev, u8 crystal_cap)
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
struct rtw_cfo_track *cfo = &dm_info->cfo_track;
if (cfo->crystal_cap == crystal_cap)
return;
rtw8822c_set_crystal_cap_reg(rtwdev, crystal_cap);
}
static void rtw8822c_cfo_tracking_reset(struct rtw_dev *rtwdev)
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
struct rtw_cfo_track *cfo = &dm_info->cfo_track;
cfo->is_adjust = true;
if (cfo->crystal_cap > rtwdev->efuse.crystal_cap)
rtw8822c_set_crystal_cap(rtwdev, cfo->crystal_cap - 1);
else if (cfo->crystal_cap < rtwdev->efuse.crystal_cap)
rtw8822c_set_crystal_cap(rtwdev, cfo->crystal_cap + 1);
}
static void rtw8822c_cfo_init(struct rtw_dev *rtwdev)
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
struct rtw_cfo_track *cfo = &dm_info->cfo_track;
cfo->crystal_cap = rtwdev->efuse.crystal_cap;
cfo->is_adjust = true;
}
#define REPORT_TO_KHZ(val) ({typeof(val) _v = (val); (_v << 1) + (_v >> 1); })
static s32 rtw8822c_cfo_calc_avg(struct rtw_dev *rtwdev, u8 path_num)
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
struct rtw_cfo_track *cfo = &dm_info->cfo_track;
s32 cfo_avg, cfo_path_sum = 0, cfo_rpt_sum;
u8 i;
for (i = 0; i < path_num; i++) {
cfo_rpt_sum = REPORT_TO_KHZ(cfo->cfo_tail[i]);
if (cfo->cfo_cnt[i])
cfo_avg = cfo_rpt_sum / cfo->cfo_cnt[i];
else
cfo_avg = 0;
cfo_path_sum += cfo_avg;
}
for (i = 0; i < path_num; i++) {
cfo->cfo_tail[i] = 0;
cfo->cfo_cnt[i] = 0;
}
return cfo_path_sum / path_num;
}
static void rtw8822c_cfo_need_adjust(struct rtw_dev *rtwdev, s32 cfo_avg)
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
struct rtw_cfo_track *cfo = &dm_info->cfo_track;
if (!cfo->is_adjust) {
if (abs(cfo_avg) > CFO_TRK_ENABLE_TH)
cfo->is_adjust = true;
} else {
if (abs(cfo_avg) <= CFO_TRK_STOP_TH)
cfo->is_adjust = false;
}
if (!rtw_coex_disabled(rtwdev)) {
cfo->is_adjust = false;
rtw8822c_set_crystal_cap(rtwdev, rtwdev->efuse.crystal_cap);
}
}
static void rtw8822c_cfo_track(struct rtw_dev *rtwdev)
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
struct rtw_cfo_track *cfo = &dm_info->cfo_track;
u8 path_num = rtwdev->hal.rf_path_num;
s8 crystal_cap = cfo->crystal_cap;
s32 cfo_avg = 0;
if (rtwdev->sta_cnt != 1) {
rtw8822c_cfo_tracking_reset(rtwdev);
return;
}
if (cfo->packet_count == cfo->packet_count_pre)
return;
cfo->packet_count_pre = cfo->packet_count;
cfo_avg = rtw8822c_cfo_calc_avg(rtwdev, path_num);
rtw8822c_cfo_need_adjust(rtwdev, cfo_avg);
if (cfo->is_adjust) {
if (cfo_avg > CFO_TRK_ADJ_TH)
crystal_cap++;
else if (cfo_avg < -CFO_TRK_ADJ_TH)
crystal_cap--;
crystal_cap = clamp_t(s8, crystal_cap, 0, XCAP_MASK);
rtw8822c_set_crystal_cap(rtwdev, (u8)crystal_cap);
}
}
static const struct rtw_phy_cck_pd_reg
rtw8822c_cck_pd_reg[RTW_CHANNEL_WIDTH_40 + 1][RTW_RF_PATH_MAX] = {
{
@ -4016,6 +4141,8 @@ static struct rtw_chip_ops rtw8822c_ops = {
.config_bfee = rtw8822c_bf_config_bfee,
.set_gid_table = rtw_bf_set_gid_table,
.cfg_csi_rate = rtw_bf_cfg_csi_rate,
.cfo_init = rtw8822c_cfo_init,
.cfo_track = rtw8822c_cfo_track,
.coex_set_init = rtw8822c_coex_cfg_init,
.coex_set_ant_switch = NULL,

View File

@ -165,6 +165,11 @@ const struct rtw_table name ## _tbl = { \
#define REG_ANAPARLDO_POW_MAC 0x0029
#define BIT_LDOE25_PON BIT(0)
#define XCAP_MASK GENMASK(6, 0)
#define CFO_TRK_ENABLE_TH 20
#define CFO_TRK_STOP_TH 10
#define CFO_TRK_ADJ_TH 10
#define REG_TXDFIR0 0x808
#define REG_DFIRBW 0x810
#define REG_ANTMAP0 0x820