Files

238 lines
7.5 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Fiona Klute <[email protected]>
Date: Fri, 2 Feb 2024 22:29:41 +0100
Subject: Implement CFO tracking
This makes RX a lot more stable in my network. The chip still doesn't
really go beyond MCS 1.
Signed-off-by: Fiona Klute <[email protected]>
---
drivers/net/wireless/realtek/rtw88/main.h | 1 +
drivers/net/wireless/realtek/rtw88/rtw8703b.c | 148 +++++++++-
drivers/net/wireless/realtek/rtw88/rtw8703b.h | 3 +
drivers/net/wireless/realtek/rtw88/rtw8723x.h | 1 +
4 files changed, 150 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
index 111111111111..222222222222 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -1686,6 +1686,7 @@ enum rtw_edcca_mode {
struct rtw_cfo_track {
bool is_adjust;
+ bool atc_enable;
u8 crystal_cap;
s32 cfo_tail[RTW_RF_PATH_MAX];
s32 cfo_cnt[RTW_RF_PATH_MAX];
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8703b.c b/drivers/net/wireless/realtek/rtw88/rtw8703b.c
index 111111111111..222222222222 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8703b.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8703b.c
@@ -577,7 +577,7 @@ static void rtw8703b_pwrtrack_init(struct rtw_dev *rtwdev)
static void rtw8703b_phy_set_param(struct rtw_dev *rtwdev)
{
- u8 xtal_cap = rtwdev->efuse.crystal_cap & 0x3F;
+ u8 xtal_cap = rtwdev->efuse.crystal_cap & XCAP_MASK_8703B;
/* power on BB/RF domain */
rtw_write16_set(rtwdev, REG_SYS_FUNC_EN,
@@ -953,6 +953,8 @@ static void query_phy_status_ofdm(struct rtw_dev *rtwdev, u8 *phy_raw,
val_s8 = clamp_t(s8, -val_s8 >> 1, 0, 64);
val_s8 &= 0x3F; /* 64->0: second path of 1SS rate is 64 */
dm_info->rx_evm_dbm[RF_PATH_A] = val_s8;
+
+ rtw_phy_parsing_cfo(rtwdev, pkt_stat);
}
static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status,
@@ -1727,6 +1729,146 @@ static void rtw8703b_adaptivity(struct rtw_dev *rtwdev)
rtw_phy_set_edcca_th(rtwdev, l2h, h2l);
}
+static void rtw8703b_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;
+ cfo->atc_enable = rtw_read32_mask(rtwdev, REG_OFDM1_CFOTRK, BIT_EN_ATC);
+}
+
+#define XCAP_EXTEND(val) ({typeof(val) _v = (val); _v | _v << 6; })
+static void rtw8703b_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_AFE_CTRL3, BIT_MASK_XTAL, val);
+}
+
+static void rtw8703b_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;
+
+ rtw8703b_set_crystal_cap_reg(rtwdev, crystal_cap);
+ rtw_dbg(rtwdev, RTW_DBG_CFO, "[CFO] XTAL=0x%x\n", crystal_cap);
+}
+
+static void rtw8703b_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)
+ rtw8703b_set_crystal_cap(rtwdev, cfo->crystal_cap - 1);
+ else if (cfo->crystal_cap < rtwdev->efuse.crystal_cap)
+ rtw8703b_set_crystal_cap(rtwdev, cfo->crystal_cap + 1);
+}
+
+#define REPORT_TO_KHZ(val) ({typeof(val) _v = (val); (_v << 1) + (_v >> 1); })
+static s32 rtw8703b_cfo_calc_avg(struct rtw_dev *rtwdev)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ struct rtw_cfo_track *cfo = &dm_info->cfo_track;
+ s32 cfo_avg, cfo_rpt_sum;
+
+ cfo_rpt_sum = REPORT_TO_KHZ(cfo->cfo_tail[0]);
+
+ if (cfo->cfo_cnt[0])
+ cfo_avg = cfo_rpt_sum / cfo->cfo_cnt[0];
+ else
+ cfo_avg = 0;
+
+ cfo->cfo_tail[0] = 0;
+ cfo->cfo_cnt[0] = 0;
+
+ return cfo_avg;
+}
+
+#define CFO_TRK_ENABLE_TH 20
+#define CFO_TRK_STOP_TH 10
+#define CFO_TRK_ADJ_TH 10
+#define CFO_ATC_TH 80
+
+static void rtw8703b_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;
+ rtw8703b_set_crystal_cap(rtwdev, rtwdev->efuse.crystal_cap);
+ }
+}
+
+static void rtw8703b_cfo_set_atc(struct rtw_dev *rtwdev, bool enable)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ struct rtw_cfo_track *cfo = &dm_info->cfo_track;
+
+ if (cfo->atc_enable == enable)
+ return;
+
+ rtw_write32_mask(rtwdev, REG_OFDM1_CFOTRK, BIT_EN_ATC, enable);
+ cfo->atc_enable = enable;
+ rtw_dbg(rtwdev, RTW_DBG_CFO, "[CFO] ATC: %s\n",
+ enable ? "enabled" : "disabled");
+}
+
+static void rtw8703b_cfo_track(struct rtw_dev *rtwdev)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ struct rtw_cfo_track *cfo = &dm_info->cfo_track;
+ s8 crystal_cap = cfo->crystal_cap;
+ s32 cfo_avg = 0;
+
+ if (rtwdev->sta_cnt != 1) {
+ rtw8703b_cfo_tracking_reset(rtwdev);
+ return;
+ }
+
+ if (cfo->packet_count == cfo->packet_count_pre)
+ return;
+
+ cfo->packet_count_pre = cfo->packet_count;
+ cfo_avg = rtw8703b_cfo_calc_avg(rtwdev);
+ rtw8703b_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_8703B);
+ rtw8703b_set_crystal_cap(rtwdev, (u8)crystal_cap);
+ }
+
+ if (abs(cfo_avg) > CFO_ATC_TH)
+ rtw8703b_cfo_set_atc(rtwdev, true);
+ else
+ rtw8703b_cfo_set_atc(rtwdev, false);
+}
+
static const u8 rtw8703b_pwrtrk_2gb_n[] = {
0, 0, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6,
7, 7, 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11
@@ -1908,8 +2050,8 @@ static const struct rtw_chip_ops rtw8703b_ops = {
.cfg_csi_rate = NULL,
.adaptivity_init = rtw8703b_adaptivity_init,
.adaptivity = rtw8703b_adaptivity,
- .cfo_init = NULL,
- .cfo_track = NULL,
+ .cfo_init = rtw8703b_cfo_init,
+ .cfo_track = rtw8703b_cfo_track,
.config_tx_path = NULL,
.config_txrx_mode = NULL,
.fill_txdesc_checksum = rtw8723x_fill_txdesc_checksum,
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8703b.h b/drivers/net/wireless/realtek/rtw88/rtw8703b.h
index 111111111111..222222222222 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8703b.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8703b.h
@@ -70,6 +70,9 @@ struct phy_status_8703b {
#endif
} __packed;
+/* value mask (and maximum) for crystal cap setting */
+#define XCAP_MASK_8703B 0x3f
+
/* Baseband registers */
#define REG_BB_PWR_SAV5_11N 0x0818
/* BIT(11) should be 1 for 8703B *and* 8723D, which means LNA uses 4
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723x.h b/drivers/net/wireless/realtek/rtw88/rtw8723x.h
index 111111111111..222222222222 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8723x.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8723x.h
@@ -285,6 +285,7 @@ extern const struct rtw8723x_common rtw8723x_common;
#define REG_CTX 0x0d03
#define BIT_MASK_CTX_TYPE GENMASK(6, 4)
#define REG_OFDM1_CFOTRK 0x0d2c
+#define BIT_EN_ATC BIT(11)
#define BIT_EN_CFOTRK BIT(28)
#define REG_OFDM1_CSI1 0x0d40
#define REG_OFDM1_CSI2 0x0d44
--
Armbian