public inbox for linux-wireless@vger.kernel.org
 help / color / mirror / Atom feed
From: Ping-Ke Shih <pkshih@realtek.com>
To: <linux-wireless@vger.kernel.org>
Subject: [PATCH rtw-next 3/9] wifi: rtw89: 8922d: add RF calibration ops
Date: Mon, 30 Mar 2026 14:58:41 +0800	[thread overview]
Message-ID: <20260330065847.48946-4-pkshih@realtek.com> (raw)
In-Reply-To: <20260330065847.48946-1-pkshih@realtek.com>

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>
---
 drivers/net/wireless/realtek/rtw89/reg.h      |   4 +
 drivers/net/wireless/realtek/rtw89/rtw8922d.c | 154 ++++++++++++++++++
 .../net/wireless/realtek/rtw89/rtw8922d_rfk.c |  85 ++++++++++
 .../net/wireless/realtek/rtw89/rtw8922d_rfk.h |   1 +
 4 files changed, 244 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index 195d4806c4ef..1a5a5b30a28e 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -10531,6 +10531,10 @@
 #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)
 
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index a2dd504c99ed..2e6f4504caeb 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -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");
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
index d1eda19a39a9..147cf91d2cb0 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
@@ -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;
+		}
+	}
+}
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
index 4c505ae24261..8a5f4b56b8ce 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
@@ -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
-- 
2.25.1


  parent reply	other threads:[~2026-03-30  6:59 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-30  6:58 [PATCH rtw-next 0/9] wifi: rtw89: 8922d: add RTL8922DE part 2/2 Ping-Ke Shih
2026-03-30  6:58 ` [PATCH rtw-next 1/9] wifi: rtw89: 8922d: BB hardware pre-/post-init, TX/RX path and power settings Ping-Ke Shih
2026-03-30  6:58 ` [PATCH rtw-next 2/9] wifi: rtw89: 8922d: add set channel with pre-/post- helpers Ping-Ke Shih
2026-03-30  6:58 ` Ping-Ke Shih [this message]
2026-03-30  6:58 ` [PATCH rtw-next 4/9] wifi: rtw89: 8922d: add set TX power callback Ping-Ke Shih
2026-03-30  6:58 ` [PATCH rtw-next 5/9] wifi: rtw89: 8922d: configure TX/RX path assisting in BT coexistence Ping-Ke Shih
2026-03-30  6:58 ` [PATCH rtw-next 6/9] wifi: rtw89: 8922d: add RF ops of init hardware and get thermal Ping-Ke Shih
2026-03-30  6:58 ` [PATCH rtw-next 7/9] wifi: rtw89: 8922d: add ops related to BT coexistence mechanism Ping-Ke Shih
2026-03-30  6:58 ` [PATCH rtw-next 8/9] wifi: rtw89: 8922d: add chip_info and chip_ops struct Ping-Ke Shih
2026-03-30  6:58 ` [PATCH rtw-next 9/9] wifi: rtw89: 8922d: add PCI ID of RTL8922DE and RTL8922DE-VS Ping-Ke Shih

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260330065847.48946-4-pkshih@realtek.com \
    --to=pkshih@realtek.com \
    --cc=linux-wireless@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox