]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: rtw89: 8922d: add RF calibration ops
authorPing-Ke Shih <pkshih@realtek.com>
Mon, 30 Mar 2026 06:58:41 +0000 (14:58 +0800)
committerPing-Ke Shih <pkshih@realtek.com>
Thu, 2 Apr 2026 03:14:20 +0000 (11:14 +0800)
The chips ops related to RF calibration include init, init_late, channel,
band_change, scan, and track. The init_late is similar to init, but HCI
is ready, so receiving C2H event is possible. The ops channel is the main
function that do all RF calibration on operating channel.

The ops band_change and scan are to reset RF calibration because channel is
switching at these moment, we need to reset RF state. The ops track is to
monitor temperature to check if re-calibrate RF again.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20260330065847.48946-4-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/reg.h
drivers/net/wireless/realtek/rtw89/rtw8922d.c
drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h

index 195d4806c4efe054e9c4f117edf1d250ab770534..1a5a5b30a28e92c9c7bd2548772eac19cf0245df 100644 (file)
 #define B_TXPWR_RSTB0_BE4 BIT(16)
 #define R_TSSI_EN_P0_BE4 0x22510
 #define B_TSSI_EN_P0_BE4 GENMASK(3, 0)
+#define R_USED_TSSI_TRK_ON_P0_BE4 0x22534
+#define B_USED_TSSI_TRK_ON_P0_BE4 BIT(22)
+#define R_TSSI_DCK_MOV_AVG_LEN_P0_BE4 0x225CC
+#define B_TSSI_DCK_MOV_AVG_LEN_P0_BE4 GENMASK(8, 6)
 #define R_TXPWR_RSTB1_BE4 0x2260C
 #define B_TXPWR_RSTB1_BE4 BIT(16)
 
index a2dd504c99ed4c0ec09962efde9d461f5ee5e603..2e6f4504caebdfcd78727cdadf8fbb7550e94104 100644 (file)
@@ -3,6 +3,7 @@
  */
 
 #include "chan.h"
+#include "coex.h"
 #include "debug.h"
 #include "efuse.h"
 #include "mac.h"
@@ -2168,6 +2169,159 @@ static void rtw8922d_set_channel_help(struct rtw89_dev *rtwdev, bool enter,
        }
 }
 
+static void rtw8922d_rfk_init(struct rtw89_dev *rtwdev)
+{
+       struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc;
+       struct rtw89_lck_info *lck = &rtwdev->lck;
+
+       rtwdev->is_tssi_mode[RF_PATH_A] = false;
+       rtwdev->is_tssi_mode[RF_PATH_B] = false;
+       memset(rfk_mcc, 0, sizeof(*rfk_mcc));
+       memset(lck, 0, sizeof(*lck));
+}
+
+static void __rtw8922d_rfk_init_late(struct rtw89_dev *rtwdev,
+                                    enum rtw89_phy_idx phy_idx,
+                                    const struct rtw89_chan *chan)
+{
+       rtw8922d_rfk_mlo_ctrl(rtwdev);
+
+       rtw89_phy_rfk_pre_ntfy_and_wait(rtwdev, phy_idx, 5);
+       if (!test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags))
+               rtw89_phy_rfk_rxdck_and_wait(rtwdev, phy_idx, chan, false, 128);
+       if (phy_idx == RTW89_PHY_0)
+               rtw89_phy_rfk_dack_and_wait(rtwdev, phy_idx, chan, 58);
+}
+
+static void rtw8922d_rfk_init_late(struct rtw89_dev *rtwdev)
+{
+       const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_CHANCTX_0);
+
+       __rtw8922d_rfk_init_late(rtwdev, RTW89_PHY_0, chan);
+       if (rtwdev->dbcc_en)
+               __rtw8922d_rfk_init_late(rtwdev, RTW89_PHY_1, chan);
+}
+
+static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath)
+{
+       u32 rf_mode;
+       u8 path;
+       int ret;
+
+       for (path = 0; path < RF_PATH_NUM_8922D; path++) {
+               if (!(kpath & BIT(path)))
+                       continue;
+
+               ret = read_poll_timeout_atomic(rtw89_read_rf, rf_mode, rf_mode != 2,
+                                              2, 5000, false, rtwdev, path, 0x00,
+                                              RR_MOD_MASK);
+               rtw89_debug(rtwdev, RTW89_DBG_RFK,
+                           "[RFK] Wait S%d to Rx mode!! (ret = %d)\n",
+                           path, ret);
+       }
+}
+
+static void __rtw8922d_tssi_enable(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+       u8 path;
+
+       for (path = RF_PATH_A; path <= RF_PATH_B; path++) {
+               u32 addr_ofst = (phy_idx << 12) + (path << 8);
+
+               rtw89_phy_write32_mask(rtwdev, R_TSSI_DCK_MOV_AVG_LEN_P0_BE4 + addr_ofst,
+                                      B_TSSI_DCK_MOV_AVG_LEN_P0_BE4, 0x4);
+               rtw89_phy_write32_clr(rtwdev, R_USED_TSSI_TRK_ON_P0_BE4 + addr_ofst,
+                                     B_USED_TSSI_TRK_ON_P0_BE4);
+               rtw89_phy_write32_set(rtwdev, R_USED_TSSI_TRK_ON_P0_BE4 + addr_ofst,
+                                     B_USED_TSSI_TRK_ON_P0_BE4);
+               rtw89_phy_write32_clr(rtwdev, R_TSSI_EN_P0_BE4 + addr_ofst,
+                                     B_TSSI_EN_P0_BE4);
+               rtw89_phy_write32_mask(rtwdev, R_TSSI_EN_P0_BE4 + addr_ofst,
+                                      B_TSSI_EN_P0_BE4, 0x3);
+       }
+}
+
+static void __rtw8922d_tssi_disable(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+       u8 path;
+
+       for (path = RF_PATH_A; path <= RF_PATH_B; path++) {
+               u32 addr_ofst = (phy_idx << 12) + (path << 8);
+
+               rtw89_phy_write32_clr(rtwdev, R_TSSI_DCK_MOV_AVG_LEN_P0_BE4 + addr_ofst,
+                                     B_TSSI_DCK_MOV_AVG_LEN_P0_BE4);
+               rtw89_phy_write32_clr(rtwdev, R_USED_TSSI_TRK_ON_P0_BE4 + addr_ofst,
+                                     B_USED_TSSI_TRK_ON_P0_BE4);
+               rtw89_phy_write32_clr(rtwdev, R_TSSI_EN_P0_BE4 + addr_ofst,
+                                     B_TSSI_EN_P0_BE4);
+       }
+}
+
+static void rtw8922d_rfk_tssi(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;
+
+       ret = rtw89_phy_rfk_tssi_and_wait(rtwdev, phy_idx, chan, tssi_mode, ms);
+       if (ret) {
+               rtwdev->is_tssi_mode[RF_PATH_A] = false;
+               rtwdev->is_tssi_mode[RF_PATH_B] = false;
+       } else {
+               rtwdev->is_tssi_mode[RF_PATH_A] = true;
+               rtwdev->is_tssi_mode[RF_PATH_B] = true;
+       }
+}
+
+static void rtw8922d_rfk_channel(struct rtw89_dev *rtwdev,
+                                struct rtw89_vif_link *rtwvif_link)
+{
+       enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx;
+       const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, chanctx_idx);
+       enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx;
+       u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, RF_AB, chanctx_idx);
+       u32 tx_en;
+
+       rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_CHLK, BTC_WRFK_START);
+       rtw89_chip_stop_sch_tx(rtwdev, phy_idx, &tx_en, RTW89_SCH_TX_SEL_ALL);
+       _wait_rx_mode(rtwdev, RF_AB);
+
+       rtw89_phy_rfk_pre_ntfy_and_wait(rtwdev, phy_idx, 5);
+       rtw89_phy_rfk_txgapk_and_wait(rtwdev, phy_idx, chan, 54);
+       rtw89_phy_rfk_txiqk_and_wait(rtwdev, phy_idx, chan, 45);
+       rtw89_phy_rfk_iqk_and_wait(rtwdev, phy_idx, chan, 84);
+       rtw8922d_rfk_tssi(rtwdev, phy_idx, chan, RTW89_TSSI_NORMAL, 20);
+       rtw89_phy_rfk_cim3k_and_wait(rtwdev, phy_idx, chan, 44);
+       rtw89_phy_rfk_dpk_and_wait(rtwdev, phy_idx, chan, 68);
+       rtw89_phy_rfk_rxdck_and_wait(rtwdev, RTW89_PHY_0, chan, true, 32);
+
+       rtw89_chip_resume_sch_tx(rtwdev, phy_idx, tx_en);
+       rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_CHLK, BTC_WRFK_STOP);
+}
+
+static void rtw8922d_rfk_band_changed(struct rtw89_dev *rtwdev,
+                                     enum rtw89_phy_idx phy_idx,
+                                     const struct rtw89_chan *chan)
+{
+}
+
+static void rtw8922d_rfk_scan(struct rtw89_dev *rtwdev,
+                             struct rtw89_vif_link *rtwvif_link,
+                             bool start)
+{
+       if (start)
+               __rtw8922d_tssi_disable(rtwdev, rtwvif_link->phy_idx);
+       else
+               __rtw8922d_tssi_enable(rtwdev, rtwvif_link->phy_idx);
+}
+
+static void rtw8922d_rfk_track(struct rtw89_dev *rtwdev)
+{
+       rtw8922d_lck_track(rtwdev);
+}
+
 MODULE_FIRMWARE(RTW8922D_MODULE_FIRMWARE);
 MODULE_FIRMWARE(RTW8922DS_MODULE_FIRMWARE);
 MODULE_AUTHOR("Realtek Corporation");
index d1eda19a39a947109cffe403568b81e02ce99235..147cf91d2cb043ae681874b4c231434bb7cade94 100644 (file)
@@ -261,3 +261,88 @@ void rtw8922d_post_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx p
 {
        rtw8922d_rfk_mlo_ctrl(rtwdev);
 }
+
+static u8 _get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path path)
+{
+       rtw89_write_rf(rtwdev, path, RR_TM, RR_TM_TRI, 0x1);
+       rtw89_write_rf(rtwdev, path, RR_TM, RR_TM_TRI, 0x0);
+       rtw89_write_rf(rtwdev, path, RR_TM, RR_TM_TRI, 0x1);
+
+       fsleep(200);
+
+       return rtw89_read_rf(rtwdev, path, RR_TM, RR_TM_VAL_V1);
+}
+
+static void _lck_keep_thermal(struct rtw89_dev *rtwdev)
+{
+       struct rtw89_lck_info *lck = &rtwdev->lck;
+       int path;
+
+       for (path = 0; path < rtwdev->chip->rf_path_num; path++) {
+               lck->thermal[path] = _get_thermal(rtwdev, path);
+               rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK,
+                           "[LCK] path=%d thermal=0x%x", path, lck->thermal[path]);
+       }
+}
+
+static void _lck(struct rtw89_dev *rtwdev)
+{
+       enum _rf_syn_pow syn_pow = rtw8922d_get_syn_pow(rtwdev);
+       u8 path_mask = 0;
+       u32 tmp18, tmp5;
+       int path;
+
+       rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, "[LCK] DO LCK\n");
+
+       if (syn_pow == RF_SYN_ALLON)
+               path_mask = BIT(RF_PATH_A) | BIT(RF_PATH_B);
+       else if (syn_pow == RF_SYN_ON_OFF)
+               path_mask = BIT(RF_PATH_A);
+       else if (syn_pow == RF_SYN_OFF_ON)
+               path_mask = BIT(RF_PATH_B);
+       else
+               return;
+
+       for (path = 0; path < rtwdev->chip->rf_path_num; path++) {
+               if (!(path_mask & BIT(path)))
+                       continue;
+
+               tmp18 = rtw89_read_rf(rtwdev, path, RR_CFGCH, MASKDWORD);
+               tmp5 = rtw89_read_rf(rtwdev, path, RR_RSV1, MASKDWORD);
+
+               rtw89_write_rf(rtwdev, path, RR_MOD, MASKDWORD, 0x10000);
+               rtw89_write_rf(rtwdev, path, RR_RSV1, MASKDWORD, 0x0);
+               rtw89_write_rf(rtwdev, path, RR_LCK_TRG, RR_LCK_TRGSEL, 0x1);
+               rtw89_write_rf(rtwdev, path, RR_CFGCH, MASKDWORD, tmp18);
+               rtw89_write_rf(rtwdev, path, RR_LCK_TRG, RR_LCK_TRGSEL, 0x0);
+
+               fsleep(400);
+
+               rtw89_write_rf(rtwdev, path, RR_RSV1, MASKDWORD, tmp5);
+       }
+
+       _lck_keep_thermal(rtwdev);
+}
+
+#define RTW8922D_LCK_TH 16
+void rtw8922d_lck_track(struct rtw89_dev *rtwdev)
+{
+       struct rtw89_lck_info *lck = &rtwdev->lck;
+       u8 cur_thermal;
+       int delta;
+       int path;
+
+       for (path = 0; path < rtwdev->chip->rf_path_num; path++) {
+               cur_thermal = _get_thermal(rtwdev, path);
+               delta = abs((int)cur_thermal - lck->thermal[path]);
+
+               rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK,
+                           "[LCK] path=%d current thermal=0x%x delta=0x%x\n",
+                           path, cur_thermal, delta);
+
+               if (delta >= RTW8922D_LCK_TH) {
+                       _lck(rtwdev);
+                       return;
+               }
+       }
+}
index 4c505ae24261b50a7b878550cb0c22855d018038..8a5f4b56b8ce3fbf4f6debdf7fdca30c1755201b 100644 (file)
@@ -14,5 +14,6 @@ void rtw8922d_set_channel_rf(struct rtw89_dev *rtwdev,
 void rtw8922d_rfk_mlo_ctrl(struct rtw89_dev *rtwdev);
 void rtw8922d_pre_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx);
 void rtw8922d_post_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx);
+void rtw8922d_lck_track(struct rtw89_dev *rtwdev);
 
 #endif