* [PATCH rtw-next 1/9] wifi: rtw89: 8922d: BB hardware pre-/post-init, TX/RX path and power settings
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 ` 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
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ping-Ke Shih @ 2026-03-30 6:58 UTC (permalink / raw)
To: linux-wireless
More settings related to BB pre-/post-initial settings, the TX/RX path
settings, and digital power compensation.
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/reg.h | 64 ++++
drivers/net/wireless/realtek/rtw89/rtw8922d.c | 318 ++++++++++++++++++
2 files changed, 382 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index 5d284f310069..e64bd74db83a 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -8384,6 +8384,9 @@
#define B_BE_PWR_BT_VAL GENMASK(8, 0)
#define B_BE_PWR_FORCE_COEX_ON GENMASK(29, 27)
+#define R_PWR_BOOST_BE4 0x11A64
+#define B_PWR_BOOST_BE4 BIT(8)
+
#define R_BE_PWR_TH 0x11A78
#define R_BE_PWR_RSSI_TARGET_LMT 0x11A84
@@ -10248,6 +10251,8 @@
#define R_TSSI_K_P1 0xE7A0
#define B_TSSI_K_OFDM_P1 GENMASK(29, 20)
+#define R_BBWRAP_ELMSR_BE4 0x11974
+#define B_BBWRAP_ELMSR_EN_BE4 GENMASK(29, 28)
#define R_COMP_CIM3K_BE4 0x11998
#define B_COMP_CIM3K_OW_BE4 BIT(1)
#define B_COMP_CIM3K_TH_BE4 BIT(2)
@@ -10452,6 +10457,12 @@
#define R_BANDEDGE_DBWY_BE4 0x11AD0
#define B_BANDEDGE_DBW160_BE4 BIT(0)
+#define R_SYS_DBCC_BE4 0x20000
+#define B_SYS_DBCC_BE4 BIT(0)
+#define B_SYS_DBCC_24G_BAND_SEL_BE4 BIT(1)
+#define R_EMLSR_SWITCH_BE4 0x20044
+#define B_EMLSR_SWITCH_BE4 GENMASK(27, 12)
+#define B_EMLSR_BB_CLK_BE4 GENMASK(31, 30)
#define R_CHINFO_SEG_BE4 0x200B4
#define B_CHINFO_SEG_LEN_BE4 GENMASK(12, 10)
#define R_STS_HDR2_PARSING_BE4 0x2070C
@@ -10467,11 +10478,25 @@
#define B_RXBW7_BE4 GENMASK(25, 23)
#define R_RXBW_BE4 0x20410
#define B_RXBW_BE4 GENMASK(29, 27)
+#define R_TXERRCT_EN_BE4 0x20518
+#define B_TXERRCT_EN_BE4 BIT(13)
+#define R_TXERRCT1_EN_BE4 0x2051C
+#define B_TXERRCT1_EN_BE4 BIT(31)
#define R_ENABLE_CCK0_BE4 0x20700
#define B_ENABLE_CCK0_BE4 BIT(5)
+#define R_RSTB_ASYNC_BE4 0x20704
+#define B_RSTB_ASYNC_BE4 BIT(1)
#define R_EDCCA_RPT_SEL_BE4 0x20780
#define R_EDCCA_RPT_SEL_BE4_C1 0x21780
#define B_EDCCA_RPT_SEL_BE4_MSK 0xE0000
+#define R_IMR_TX_ERROR_BE4 0x20920
+#define B_IMR_TX_ERROR_BE4 BIT(30)
+#define R_TXINFO_PATH_BE4 0x209A4
+#define B_TXINFO_PATH_EN_BE4 BIT(17)
+#define B_TXINFO_PATH_MA_BE4 BIT(18)
+#define B_TXINFO_PATH_MB_BE4 BIT(19)
+#define R_SHAPER_COEFF_BE4 0x20CBC
+#define B_SHAPER_COEFF_BE4 BIT(19)
#define R_IFS_T1_AVG_BE4 0x20EDC
#define B_IFS_T1_AVG_BE4 GENMASK(15, 0)
#define B_IFS_T2_AVG_BE4 GENMASK(31, 16)
@@ -10494,6 +10519,12 @@
#define B_IFS_T3_HIS_BE4 GENMASK(15, 0)
#define B_IFS_T4_HIS_BE4 GENMASK(31, 16)
+#define R_TX_ERROR_SEL_BE4 0x21254
+#define B_TX_ERROR_PSDU_BE4 BIT(11)
+#define B_TX_ERROR_NSYM_BE4 BIT(10)
+#define B_TX_ERROR_LSIG_BE4 BIT(9)
+#define B_TX_ERROR_TXINFO_BE4 BIT(8)
+
#define R_TXPWR_RSTB0_BE4 0x2250C
#define B_TXPWR_RSTB0_BE4 BIT(16)
#define R_TXPWR_RSTB1_BE4 0x2260C
@@ -10546,6 +10577,10 @@
#define B_PRISB_BE4 GENMASK(3, 0)
#define R_FC0_BE4 0x24EE8
#define B_FC0_BE4 GENMASK(12, 0)
+#define R_ANT_RX_1RCCA_BE4 0x24EEC
+#define B_ANT_RX_1RCCA_BE4 GENMASK(17, 14)
+#define R_ANT_RX_BE4 0x24EF0
+#define B_ANT_RX_BE4 GENMASK(3, 0)
#define R_FC0_INV_BE4 0x24EF4
#define B_FC0_INV_BE4 GENMASK(15, 0)
@@ -10569,6 +10604,32 @@
#define B_CHINFO_NX_BE4 GENMASK(16, 6)
#define R_CHINFO_ALG_BE4 0x267C8
#define B_CHINFO_ALG_BE4 GENMASK(31, 30)
+#define R_RX_AWGN02_BE4 0x2680C
+#define B_RX_AWGN11_BE4 GENMASK(23, 18)
+#define R_RX_AWGN00_BE4 0x26814
+#define B_RX_AWGN04_BE4 GENMASK(5, 0)
+#define B_RX_AWGN07_BE4 GENMASK(23, 18)
+#define R_RX_AWGN01_BE4 0x26818
+#define B_RX_AWGN09_BE4 GENMASK(5, 0)
+#define R_RXCH_BCC0_BE4 0x26824
+#define B_RXCH_MCS4_BE4 GENMASK(29, 24)
+#define R_RXCH_BCC1_BE4 0x26828
+#define B_RXCH_MCS5_BE4 GENMASK(5, 0)
+#define B_RXCH_MCS6_BE4 GENMASK(11, 6)
+#define B_RXCH_MCS7_BE4 GENMASK(17, 12)
+#define B_RXCH_MCS8_BE4 GENMASK(23, 18)
+#define B_RXCH_MCS9_BE4 GENMASK(29, 24)
+#define R_RX_LDPC02_BE4 0x26834
+#define B_RX_LDPC10_BE4 GENMASK(17, 12)
+#define B_RX_LDPC11_BE4 GENMASK(23, 18)
+#define R_RX_LDPC00_BE4 0x2683C
+#define B_RX_LDPC04_BE4 GENMASK(5, 0)
+#define B_RX_LDPC05_BE4 GENMASK(11, 6)
+#define B_RX_LDPC06_BE4 GENMASK(17, 12)
+#define B_RX_LDPC07_BE4 GENMASK(23, 18)
+#define B_RX_LDPC08_BE4 GENMASK(29, 24)
+#define R_RX_LDPC01_BE4 0x26840
+#define B_RX_LDPC09_BE4 GENMASK(5, 0)
#define R_SW_SI_DATA_BE4 0x2CF4C
#define B_SW_SI_READ_DATA_BE4 GENMASK(19, 0)
@@ -10576,6 +10637,9 @@
#define B_SW_SI_R_BUSY_BE4 BIT(25)
#define B_SW_SI_READ_DATA_DONE_BE4 BIT(26)
+#define R_RX_PATH0_TBL0_BE4 0x2E028
+#define R_RX_PATH1_TBL0_BE4 0x2E128
+
/* WiFi CPU local domain */
#define R_AX_WDT_CTRL 0x0040
#define B_AX_WDT_EN BIT(31)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index 1b5fc6c9ea85..51b025d898ff 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -2,6 +2,7 @@
/* Copyright(c) 2026 Realtek Corporation
*/
+#include "chan.h"
#include "debug.h"
#include "efuse.h"
#include "mac.h"
@@ -1690,6 +1691,94 @@ static void rtw8922d_spur_elimination(struct rtw89_dev *rtwdev,
rtw8922d_set_nbi_tone_idx(rtwdev, chan, RF_PATH_B, phy_idx);
}
+static const u32 bbrst_mask[2] = {B_BE_FEN_BBPLAT_RSTB, B_BE_FEN_BB1PLAT_RSTB};
+static const u32 glbrst_mask[2] = {B_BE_FEN_BB_IP_RSTN, B_BE_FEN_BB1_IP_RSTN};
+static const u32 chip_top_bitmask[2] = {0xffff, 0xffff0000};
+
+static void rtw8922d_bb_preinit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, glbrst_mask[phy_idx], 0x0);
+ rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, bbrst_mask[phy_idx], 0x0);
+ rtw89_write32_mask(rtwdev, R_BE_DMAC_SYS_CR32B, chip_top_bitmask[phy_idx], 0x74F9);
+ rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, glbrst_mask[phy_idx], 0x1);
+ rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC_BE4, B_RSTB_ASYNC_BE4, 0, phy_idx);
+ rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, bbrst_mask[phy_idx], 0x1);
+}
+
+static void rtw8922d_bb_postinit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ rtw89_phy_write32_idx_clr(rtwdev, R_SHAPER_COEFF_BE4, B_SHAPER_COEFF_BE4, phy_idx);
+ rtw89_phy_write32_idx_set(rtwdev, R_SHAPER_COEFF_BE4, B_SHAPER_COEFF_BE4, phy_idx);
+}
+
+static void rtw8922d_bb_reset_en(struct rtw89_dev *rtwdev, enum rtw89_band band,
+ bool en, enum rtw89_phy_idx phy_idx)
+{
+ if (en)
+ rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC_BE4, B_RSTB_ASYNC_BE4, 1, phy_idx);
+ else
+ rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC_BE4, B_RSTB_ASYNC_BE4, 0, phy_idx);
+}
+
+static int rtw8922d_ctrl_tx_path_tmac(struct rtw89_dev *rtwdev,
+ enum rtw89_rf_path tx_path,
+ enum rtw89_phy_idx phy_idx)
+{
+ struct rtw89_reg2_def path_com_cr[] = {
+ {0x11A00, 0x21C86900},
+ {0x11A04, 0x00E4E433},
+ {0x11A08, 0x39390CC9},
+ {0x11A10, 0x10CC0000},
+ {0x11A14, 0x00240393},
+ {0x11A18, 0x201C8600},
+ {0x11B38, 0x39393FDB},
+ {0x11B3C, 0x00E4E4FF},
+ };
+ int ret = 0;
+ u32 reg;
+ int i;
+
+ rtw89_phy_write32_idx(rtwdev, R_TXINFO_PATH_BE4, B_TXINFO_PATH_EN_BE4, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_TXINFO_PATH_BE4, B_TXINFO_PATH_MA_BE4, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_TXINFO_PATH_BE4, B_TXINFO_PATH_MB_BE4, 0x0, phy_idx);
+
+ if (phy_idx == RTW89_PHY_1 && !rtwdev->dbcc_en)
+ return 0;
+
+ if (tx_path == RF_PATH_A) {
+ path_com_cr[1].data = 0x40031;
+ path_com_cr[2].data = 0x1000C48;
+ path_com_cr[5].data = 0x200;
+ path_com_cr[6].data = 0x1000C48;
+ path_com_cr[7].data = 0x40031;
+ } else if (tx_path == RF_PATH_B) {
+ path_com_cr[1].data = 0x40032;
+ path_com_cr[2].data = 0x1000C88;
+ path_com_cr[5].data = 0x400;
+ path_com_cr[6].data = 0x1000C88;
+ path_com_cr[7].data = 0x40032;
+ } else if (tx_path == RF_PATH_AB) {
+ path_com_cr[1].data = 0x00E4E433;
+ path_com_cr[2].data = 0x39390CC9;
+ path_com_cr[5].data = 0x201C8600;
+ path_com_cr[6].data = 0x1010CC9;
+ path_com_cr[7].data = 0x40433;
+ } else {
+ ret = -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(path_com_cr); i++) {
+ reg = rtw89_mac_reg_by_idx(rtwdev, path_com_cr[i].addr, phy_idx);
+ rtw89_write32(rtwdev, reg, path_com_cr[i].data);
+ }
+
+ return ret;
+}
+
+static void rtw8922d_bb_reset(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+}
+
static void rtw8922d_tssi_reset(struct rtw89_dev *rtwdev,
enum rtw89_rf_path path,
enum rtw89_phy_idx phy_idx)
@@ -1714,6 +1803,235 @@ static void rtw8922d_tssi_reset(struct rtw89_dev *rtwdev,
}
}
+static int rtw8922d_ctrl_rx_path_tmac(struct rtw89_dev *rtwdev,
+ enum rtw89_rf_path rx_path,
+ enum rtw89_phy_idx phy_idx)
+{
+ enum rtw89_rf_path_bit path;
+
+ if (rx_path == RF_PATH_A)
+ path = RF_A;
+ else if (rx_path == RF_PATH_B)
+ path = RF_B;
+ else
+ path = RF_AB;
+
+ rtw89_phy_write32_idx(rtwdev, R_ANT_RX_BE4, B_ANT_RX_BE4, path, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_ANT_RX_1RCCA_BE4, B_ANT_RX_1RCCA_BE4,
+ path, phy_idx);
+
+ if (rx_path == RF_PATH_AB) {
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC0_BE4, B_RXCH_MCS4_BE4, 8, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS5_BE4, 4, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS6_BE4, 3, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS7_BE4, 7, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS8_BE4, 2, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS9_BE4, 2, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN00_BE4, B_RX_AWGN04_BE4, 4, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN00_BE4, B_RX_AWGN07_BE4, 2, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN01_BE4, B_RX_AWGN09_BE4, 0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN02_BE4, B_RX_AWGN11_BE4, 1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC04_BE4, 8, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC05_BE4, 5, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC06_BE4, 3, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC07_BE4, 5, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC08_BE4, 1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC01_BE4, B_RX_LDPC09_BE4, 2, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC02_BE4, B_RX_LDPC10_BE4, 4, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC02_BE4, B_RX_LDPC11_BE4, 2, phy_idx);
+ } else {
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC0_BE4, B_RXCH_MCS4_BE4, 13, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS5_BE4, 15, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS6_BE4, 6, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS7_BE4, 15, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS8_BE4, 4, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXCH_BCC1_BE4, B_RXCH_MCS9_BE4, 15, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN00_BE4, B_RX_AWGN04_BE4, 9, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN00_BE4, B_RX_AWGN07_BE4, 3, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN01_BE4, B_RX_AWGN09_BE4, 1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_AWGN02_BE4, B_RX_AWGN11_BE4, 0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC04_BE4, 9, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC05_BE4, 8, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC06_BE4, 6, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC07_BE4, 16, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC00_BE4, B_RX_LDPC08_BE4, 4, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC01_BE4, B_RX_LDPC09_BE4, 9, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC02_BE4, B_RX_LDPC10_BE4, 9, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RX_LDPC02_BE4, B_RX_LDPC11_BE4, 7, phy_idx);
+ }
+
+ return 0;
+}
+
+static void rtw8922d_set_digital_pwr_comp(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan, u8 nss,
+ enum rtw89_rf_path path,
+ enum rtw89_phy_idx phy_idx)
+{
+#define DIGITAL_PWR_COMP_REG_NUM 22
+ static const u32 pw_comp_cr[2] = {R_RX_PATH0_TBL0_BE4, R_RX_PATH1_TBL0_BE4};
+ const __le32 (*pwr_comp_val)[2][RTW89_TX_COMP_BAND_NR]
+ [BB_PATH_NUM_8922D][DIGITAL_PWR_COMP_REG_NUM];
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
+ const struct rtw89_fw_element_hdr *txcomp_elm = elm_info->tx_comp;
+ const __le32 *digital_pwr_comp;
+ u32 addr, val;
+ u32 i;
+
+ if (sizeof(*pwr_comp_val) != le32_to_cpu(txcomp_elm->size)) {
+ rtw89_debug(rtwdev, RTW89_DBG_UNEXP,
+ "incorrect power comp size %d\n",
+ le32_to_cpu(txcomp_elm->size));
+ return;
+ }
+
+ pwr_comp_val = (const void *)txcomp_elm->u.common.contents;
+ digital_pwr_comp = (*pwr_comp_val)[nss][chan->tx_comp_band][path];
+ addr = pw_comp_cr[path];
+
+ for (i = 0; i < DIGITAL_PWR_COMP_REG_NUM; i++, addr += 4) {
+ val = le32_to_cpu(digital_pwr_comp[i]);
+ rtw89_phy_write32_idx(rtwdev, addr, MASKDWORD, val, phy_idx);
+ }
+}
+
+static void rtw8922d_digital_pwr_comp(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
+{
+ const struct rtw89_chan *chan0 = rtw89_mgnt_chan_get(rtwdev, 0);
+ const struct rtw89_chan *chan1 = rtw89_mgnt_chan_get(rtwdev, 1);
+
+ if (rtwdev->mlo_dbcc_mode == MLO_1_PLUS_1_1RF) {
+ rtw8922d_set_digital_pwr_comp(rtwdev, chan0, 0, RF_PATH_A, RTW89_PHY_0);
+ rtw8922d_set_digital_pwr_comp(rtwdev, chan1, 0, RF_PATH_B, RTW89_PHY_1);
+ } else {
+ rtw8922d_set_digital_pwr_comp(rtwdev, chan0, 1, RF_PATH_A, phy_idx);
+ rtw8922d_set_digital_pwr_comp(rtwdev, chan0, 1, RF_PATH_B, phy_idx);
+ }
+}
+
+static int rtw8922d_ctrl_mlo(struct rtw89_dev *rtwdev, enum rtw89_mlo_dbcc_mode mode,
+ bool pwr_comp)
+{
+ const struct rtw89_chan *chan1;
+ u32 reg0, reg1;
+ u8 cck_phy_idx;
+
+ if (mode == MLO_2_PLUS_0_1RF) {
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xBBBB);
+ udelay(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x3);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xAFFF);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEBAD);
+ udelay(1);
+
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEAAD);
+ } else if (mode == MLO_0_PLUS_2_1RF) {
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xBBBB);
+ udelay(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x3);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xAFFF);
+ udelay(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEFFF);
+
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEEFF);
+ } else if ((mode == MLO_1_PLUS_1_1RF) || (mode == DBCC_LEGACY)) {
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xBBBB);
+ udelay(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x3);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xAFFF);
+ udelay(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0x3AAB);
+ } else {
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0x6180);
+ udelay(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x3);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0x180);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0x0);
+ }
+
+ if (pwr_comp)
+ rtw8922d_digital_pwr_comp(rtwdev, RTW89_PHY_0);
+
+ reg0 = R_BBWRAP_ELMSR_BE4;
+ reg1 = rtw89_mac_reg_by_idx(rtwdev, reg0, 1);
+
+ if (mode == MLO_2_PLUS_0_1RF) {
+ rtw89_phy_write32_mask(rtwdev, R_SYS_DBCC_BE4,
+ B_SYS_DBCC_24G_BAND_SEL_BE4, RTW89_PHY_0);
+ rtw89_write32_mask(rtwdev, reg0, B_BBWRAP_ELMSR_EN_BE4, 0);
+ rtw89_write32_mask(rtwdev, reg1, B_BBWRAP_ELMSR_EN_BE4, 0);
+ } else if (mode == MLO_0_PLUS_2_1RF) {
+ rtw89_phy_write32_mask(rtwdev, R_SYS_DBCC_BE4,
+ B_SYS_DBCC_24G_BAND_SEL_BE4, RTW89_PHY_0);
+ rtw89_write32_mask(rtwdev, reg0, B_BBWRAP_ELMSR_EN_BE4, 0);
+ rtw89_write32_mask(rtwdev, reg1, B_BBWRAP_ELMSR_EN_BE4, 0);
+ } else if ((mode == MLO_1_PLUS_1_1RF) || (mode == DBCC_LEGACY)) {
+ chan1 = rtw89_mgnt_chan_get(rtwdev, 1);
+ cck_phy_idx = chan1->band_type == RTW89_BAND_2G ?
+ RTW89_PHY_1 : RTW89_PHY_0;
+
+ rtw89_phy_write32_mask(rtwdev, R_SYS_DBCC_BE4,
+ B_SYS_DBCC_24G_BAND_SEL_BE4, cck_phy_idx);
+ rtw89_write32_mask(rtwdev, reg0, B_BBWRAP_ELMSR_EN_BE4, 0x3);
+ rtw89_write32_mask(rtwdev, reg1, B_BBWRAP_ELMSR_EN_BE4, 0x3);
+ } else {
+ rtw89_phy_write32_mask(rtwdev, R_SYS_DBCC_BE4,
+ B_SYS_DBCC_24G_BAND_SEL_BE4, RTW89_PHY_0);
+ rtw89_write32_mask(rtwdev, reg0, B_BBWRAP_ELMSR_EN_BE4, 0);
+ rtw89_write32_mask(rtwdev, reg1, B_BBWRAP_ELMSR_EN_BE4, 0);
+ }
+
+ udelay(1);
+
+ return 0;
+}
+
+static void rtw8922d_bb_sethw(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ enum rtw89_phy_idx phy_idx;
+ u32 reg;
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_BOOST, RTW89_PHY_0);
+ rtw89_write32_clr(rtwdev, reg, B_BE_PWR_CTRL_SEL);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_BOOST, RTW89_PHY_1);
+ rtw89_write32_clr(rtwdev, reg, B_BE_PWR_CTRL_SEL);
+
+ if (hal->cid == RTL8922D_CID7090) {
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_PWR_BOOST_BE4, RTW89_PHY_0);
+ rtw89_write32_set(rtwdev, reg, B_PWR_BOOST_BE4);
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_PWR_BOOST_BE4, RTW89_PHY_1);
+ rtw89_write32_set(rtwdev, reg, B_PWR_BOOST_BE4);
+ }
+
+ rtw89_phy_write32_mask(rtwdev, R_TX_ERROR_SEL_BE4, B_TX_ERROR_PSDU_BE4, 0);
+ rtw89_phy_write32_mask(rtwdev, R_TX_ERROR_SEL_BE4, B_TX_ERROR_NSYM_BE4, 1);
+ rtw89_phy_write32_mask(rtwdev, R_TX_ERROR_SEL_BE4, B_TX_ERROR_LSIG_BE4, 1);
+ rtw89_phy_write32_mask(rtwdev, R_TX_ERROR_SEL_BE4, B_TX_ERROR_TXINFO_BE4, 1);
+ rtw89_phy_write32_mask(rtwdev, R_TXERRCT_EN_BE4, B_TXERRCT_EN_BE4, 0);
+ rtw89_phy_write32_mask(rtwdev, R_TXERRCT1_EN_BE4, B_TXERRCT1_EN_BE4, 0);
+ rtw89_phy_write32_idx(rtwdev, R_IMR_TX_ERROR_BE4, B_IMR_TX_ERROR_BE4, 1, RTW89_PHY_0);
+ rtw89_phy_write32_idx(rtwdev, R_IMR_TX_ERROR_BE4, B_IMR_TX_ERROR_BE4, 1, RTW89_PHY_1);
+
+ rtw8922d_ctrl_mlo(rtwdev, rtwdev->mlo_dbcc_mode, false);
+
+ /* read these registers after loading BB parameters */
+ for (phy_idx = RTW89_PHY_0; phy_idx < RTW89_PHY_NUM; phy_idx++) {
+ gain->ref_gain_base[phy_idx] =
+ rtw89_phy_read32_idx(rtwdev, R_OFDM_OFST_P0_BE4,
+ B_OFDM_OFST_P0_BE4, phy_idx);
+ gain->cck_rpl_base[phy_idx] =
+ rtw89_phy_read32_idx(rtwdev, R_CCK_RPL_OFST_BE4,
+ B_CCK_RPL_OFST_BE4, phy_idx);
+ }
+}
+
static void rtw8922d_set_channel_bb(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
enum rtw89_phy_idx phy_idx)
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH rtw-next 2/9] wifi: rtw89: 8922d: add set channel with pre-/post- helpers
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 ` Ping-Ke Shih
2026-03-30 6:58 ` [PATCH rtw-next 3/9] wifi: rtw89: 8922d: add RF calibration ops Ping-Ke Shih
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ping-Ke Shih @ 2026-03-30 6:58 UTC (permalink / raw)
To: linux-wireless
The main set channel function calls MAC/BB/RF ones, and pre-/post- helpers
are called before/after the main function to backup/restore and
stop/restart circuits, including TX scheduler, PPDU status, DACK and TSSI.
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/reg.h | 14 ++
drivers/net/wireless/realtek/rtw89/rtw8922d.c | 102 ++++++++
.../net/wireless/realtek/rtw89/rtw8922d_rfk.c | 230 ++++++++++++++++++
.../net/wireless/realtek/rtw89/rtw8922d_rfk.h | 4 +
4 files changed, 350 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index e64bd74db83a..195d4806c4ef 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -8445,6 +8445,8 @@
#define RR_MOD_M_RXBB GENMASK(9, 5)
#define RR_MOD_LO_SEL BIT(1)
#define RR_MODOPT 0x01
+#define RR_MODOPT_V1 0x10001
+#define RR_SW_SEL BIT(19)
#define RR_TXG_SEL GENMASK(19, 17)
#define RR_MODOPT_M_TXPWR GENMASK(5, 0)
#define RR_WLSEL 0x02
@@ -10527,6 +10529,8 @@
#define R_TXPWR_RSTB0_BE4 0x2250C
#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_TXPWR_RSTB1_BE4 0x2260C
#define B_TXPWR_RSTB1_BE4 BIT(16)
@@ -10640,6 +10644,16 @@
#define R_RX_PATH0_TBL0_BE4 0x2E028
#define R_RX_PATH1_TBL0_BE4 0x2E128
+#define R_KTBL0A_BE4 0x38104
+#define R_KTBL0B_BE4 0x38204
+#define B_KTBL0_IDX0 GENMASK(1, 0)
+#define B_KTBL0_IDX1 GENMASK(9, 8)
+#define B_KTBL0_RST BIT(31)
+#define R_KTBL1A_BE4 0x38154
+#define R_KTBL1B_BE4 0x38254
+#define B_KTBL1_TBL0 BIT(3)
+#define B_KTBL1_TBL1 BIT(5)
+
/* WiFi CPU local domain */
#define R_AX_WDT_CTRL 0x0040
#define B_AX_WDT_EN BIT(31)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index 51b025d898ff..a2dd504c99ed 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -2066,6 +2066,108 @@ static void rtw8922d_set_channel_bb(struct rtw89_dev *rtwdev,
rtw8922d_tssi_reset(rtwdev, RF_PATH_AB, phy_idx);
}
+static void rtw8922d_pre_set_channel_bb(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
+{
+ if (!rtwdev->dbcc_en)
+ return;
+
+ rtw89_phy_write32_mask(rtwdev, R_SYS_DBCC_BE4, B_SYS_DBCC_BE4, 0x0);
+
+ if (phy_idx == RTW89_PHY_0) {
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xBBBB);
+ fsleep(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x3);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xAFFF);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEBAD);
+ fsleep(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEAAD);
+ } else {
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xBBBB);
+ fsleep(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x3);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xAFFF);
+ fsleep(1);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEFFF);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_BB_CLK_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_EMLSR_SWITCH_BE4, B_EMLSR_SWITCH_BE4, 0xEEFF);
+ }
+
+ fsleep(1);
+}
+
+static void rtw8922d_post_set_channel_bb(struct rtw89_dev *rtwdev,
+ enum rtw89_mlo_dbcc_mode mode,
+ enum rtw89_phy_idx phy_idx)
+{
+ if (!rtwdev->dbcc_en)
+ return;
+
+ rtw8922d_ctrl_mlo(rtwdev, mode, true);
+}
+
+static void rtw8922d_set_channel(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_mac_idx mac_idx,
+ enum rtw89_phy_idx phy_idx)
+{
+ rtw8922d_set_channel_mac(rtwdev, chan, mac_idx);
+ rtw8922d_set_channel_bb(rtwdev, chan, phy_idx);
+ rtw8922d_set_channel_rf(rtwdev, chan, phy_idx);
+}
+
+static void __rtw8922d_dack_reset(struct rtw89_dev *rtwdev, enum rtw89_rf_path path)
+{
+ rtw89_phy_write32_mask(rtwdev, 0x3c000 + (path << 8), BIT(17), 0x0);
+ rtw89_phy_write32_mask(rtwdev, 0x3c000 + (path << 8), BIT(17), 0x1);
+}
+
+static void rtw8922d_dack_reset(struct rtw89_dev *rtwdev)
+{
+ __rtw8922d_dack_reset(rtwdev, RF_PATH_A);
+ __rtw8922d_dack_reset(rtwdev, RF_PATH_B);
+}
+
+static
+void rtw8922d_hal_reset(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx, enum rtw89_mac_idx mac_idx,
+ enum rtw89_band band, u32 *tx_en, bool enter)
+{
+ if (enter) {
+ rtw89_chip_stop_sch_tx(rtwdev, mac_idx, tx_en, RTW89_SCH_TX_SEL_ALL);
+ rtw89_mac_cfg_ppdu_status(rtwdev, mac_idx, false);
+ rtw8922d_dack_reset(rtwdev);
+ rtw8922d_tssi_cont_en_phyidx(rtwdev, false, phy_idx);
+ fsleep(40);
+ rtw8922d_bb_reset_en(rtwdev, band, false, phy_idx);
+ } else {
+ rtw89_mac_cfg_ppdu_status(rtwdev, mac_idx, true);
+ rtw8922d_tssi_cont_en_phyidx(rtwdev, true, phy_idx);
+ rtw8922d_bb_reset_en(rtwdev, band, true, phy_idx);
+ rtw89_chip_resume_sch_tx(rtwdev, mac_idx, *tx_en);
+ }
+}
+
+static void rtw8922d_set_channel_help(struct rtw89_dev *rtwdev, bool enter,
+ struct rtw89_channel_help_params *p,
+ const struct rtw89_chan *chan,
+ enum rtw89_mac_idx mac_idx,
+ enum rtw89_phy_idx phy_idx)
+{
+ if (enter) {
+ rtw8922d_pre_set_channel_bb(rtwdev, phy_idx);
+ rtw8922d_pre_set_channel_rf(rtwdev, phy_idx);
+ }
+
+ rtw8922d_hal_reset(rtwdev, phy_idx, mac_idx, chan->band_type, &p->tx_en, enter);
+
+ if (!enter) {
+ rtw8922d_post_set_channel_bb(rtwdev, rtwdev->mlo_dbcc_mode, phy_idx);
+ rtw8922d_post_set_channel_rf(rtwdev, phy_idx);
+ }
+}
+
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 6b35d196cb81..d1eda19a39a9 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
@@ -2,11 +2,40 @@
/* Copyright(c) 2026 Realtek Corporation
*/
+#include "chan.h"
+#include "debug.h"
#include "phy.h"
#include "reg.h"
#include "rtw8922d.h"
#include "rtw8922d_rfk.h"
+static void rtw8922d_tssi_cont_en(struct rtw89_dev *rtwdev, bool en,
+ enum rtw89_rf_path path, u8 phy_idx)
+{
+ static const u32 tssi_trk_man[2] = {R_TSSI_EN_P0_BE4,
+ R_TSSI_EN_P0_BE4 + 0x100};
+
+ if (en)
+ rtw89_phy_write32_idx(rtwdev, tssi_trk_man[path],
+ B_TSSI_CONT_EN, 0, phy_idx);
+ else
+ rtw89_phy_write32_idx(rtwdev, tssi_trk_man[path],
+ B_TSSI_CONT_EN, 1, phy_idx);
+}
+
+void rtw8922d_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, u8 phy_idx)
+{
+ if (rtwdev->mlo_dbcc_mode == MLO_1_PLUS_1_1RF) {
+ if (phy_idx == RTW89_PHY_0)
+ rtw8922d_tssi_cont_en(rtwdev, en, RF_PATH_A, phy_idx);
+ else
+ rtw8922d_tssi_cont_en(rtwdev, en, RF_PATH_B, phy_idx);
+ } else {
+ rtw8922d_tssi_cont_en(rtwdev, en, RF_PATH_A, phy_idx);
+ rtw8922d_tssi_cont_en(rtwdev, en, RF_PATH_B, phy_idx);
+ }
+}
+
static
void rtw8922d_ctl_band_ch_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy,
const struct rtw89_chan *chan)
@@ -31,3 +60,204 @@ void rtw8922d_set_channel_rf(struct rtw89_dev *rtwdev,
{
rtw8922d_ctl_band_ch_bw(rtwdev, phy_idx, chan);
}
+
+enum _rf_syn_pow {
+ RF_SYN_ON_OFF,
+ RF_SYN_OFF_ON,
+ RF_SYN_ALLON,
+ RF_SYN_ALLOFF,
+};
+
+static void rtw8922d_set_syn01(struct rtw89_dev *rtwdev, enum _rf_syn_pow syn)
+{
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "SYN config=%d\n", syn);
+
+ if (syn == RF_SYN_ALLON) {
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, BIT(1), 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MOD, BIT(1), 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, MASKDWORD, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, MASKDWORD, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0xf);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0xf);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, MASKDWORD, 0x1);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, MASKDWORD, 0x1);
+ } else if (syn == RF_SYN_ON_OFF) {
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, BIT(1), 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, MASKDWORD, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0xf);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, MASKDWORD, 0x1);
+ } else if (syn == RF_SYN_OFF_ON) {
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MOD, BIT(1), 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, MASKDWORD, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0xf);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, MASKDWORD, 0x1);
+ } else if (syn == RF_SYN_ALLOFF) {
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN_V1, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_POW, RR_POW_SYN_V1, 0x0);
+ }
+}
+
+static void rtw8922d_chlk_ktbl_sel(struct rtw89_dev *rtwdev, u8 kpath, u8 idx)
+{
+ bool mlo_linking = false;
+
+ if (idx > 2) {
+ rtw89_warn(rtwdev, "[DBCC][ERROR]indx is out of limit!! index(%d)", idx);
+ return;
+ }
+
+ if (mlo_linking) {
+ if (kpath & RF_A) {
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MODOPT, RR_SW_SEL, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MODOPT_V1, RR_SW_SEL, 0x0);
+ }
+
+ if (kpath & RF_B) {
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MODOPT, RR_SW_SEL, 0x0);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MODOPT_V1, RR_SW_SEL, 0x0);
+ }
+
+ return;
+ }
+
+ if (kpath & RF_A) {
+ rtw89_phy_write32_mask(rtwdev, R_KTBL0A_BE4, B_KTBL0_RST, 0x1);
+ rtw89_phy_write32_mask(rtwdev, R_KTBL0A_BE4, B_KTBL0_IDX0, idx);
+ rtw89_phy_write32_mask(rtwdev, R_KTBL0A_BE4, B_KTBL0_IDX1, idx);
+
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MODOPT, RR_TXG_SEL, 0x4 | idx);
+ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MODOPT_V1, RR_TXG_SEL, 0x4 | idx);
+
+ rtw89_phy_write32_mask(rtwdev, R_KTBL1A_BE4, B_KTBL1_TBL0, idx & BIT(0));
+ rtw89_phy_write32_mask(rtwdev, R_KTBL1A_BE4, B_KTBL1_TBL1, (idx & BIT(1)) >> 1);
+ }
+
+ if (kpath & RF_B) {
+ rtw89_phy_write32_mask(rtwdev, R_KTBL0B_BE4, B_KTBL0_RST, 0x1);
+ rtw89_phy_write32_mask(rtwdev, R_KTBL0B_BE4, B_KTBL0_IDX0, idx);
+ rtw89_phy_write32_mask(rtwdev, R_KTBL0B_BE4, B_KTBL0_IDX1, idx);
+
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MODOPT, RR_TXG_SEL, 0x4 | idx);
+ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MODOPT_V1, RR_TXG_SEL, 0x4 | idx);
+
+ rtw89_phy_write32_mask(rtwdev, R_KTBL1B_BE4, B_KTBL1_TBL0, idx & BIT(0));
+ rtw89_phy_write32_mask(rtwdev, R_KTBL1B_BE4, B_KTBL1_TBL1, (idx & BIT(1)) >> 1);
+ }
+}
+
+static u8 rtw8922d_chlk_reload_sel_tbl(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan, u8 path)
+{
+ struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data;
+ struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V1] = {};
+ u8 tbl_sel;
+
+ for (tbl_sel = 0; tbl_sel < ARRAY_SIZE(desc); tbl_sel++) {
+ struct rtw89_rfk_chan_desc *p = &desc[tbl_sel];
+
+ p->ch = rfk_mcc->ch[tbl_sel];
+
+ p->has_band = true;
+ p->band = rfk_mcc->band[tbl_sel];
+
+ p->has_bw = true;
+ p->bw = rfk_mcc->bw[tbl_sel];
+ }
+
+ tbl_sel = rtw89_rfk_chan_lookup(rtwdev, desc, ARRAY_SIZE(desc), chan);
+
+ rfk_mcc->ch[tbl_sel] = chan->channel;
+ rfk_mcc->band[tbl_sel] = chan->band_type;
+ rfk_mcc->bw[tbl_sel] = chan->band_width;
+ rfk_mcc->rf18[tbl_sel] = rtw89_chip_chan_to_rf18_val(rtwdev, chan);
+
+ /* shared table array, but tbl_sel can be independent by path */
+ rfk_mcc[path].table_idx = tbl_sel;
+
+ return tbl_sel;
+}
+
+static void rtw8922d_chlk_reload(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chan *chan0, *chan1;
+ u8 s0_tbl, s1_tbl;
+
+ switch (rtwdev->mlo_dbcc_mode) {
+ default:
+ case MLO_2_PLUS_0_1RF:
+ chan0 = rtw89_mgnt_chan_get(rtwdev, 0);
+ chan1 = chan0;
+ break;
+ case MLO_0_PLUS_2_1RF:
+ chan1 = rtw89_mgnt_chan_get(rtwdev, 1);
+ chan0 = chan1;
+ break;
+ case MLO_1_PLUS_1_1RF:
+ chan0 = rtw89_mgnt_chan_get(rtwdev, 0);
+ chan1 = rtw89_mgnt_chan_get(rtwdev, 1);
+ break;
+ }
+
+ s0_tbl = rtw8922d_chlk_reload_sel_tbl(rtwdev, chan0, 0);
+ s1_tbl = rtw8922d_chlk_reload_sel_tbl(rtwdev, chan1, 1);
+
+ rtw8922d_chlk_ktbl_sel(rtwdev, RF_A, s0_tbl);
+ rtw8922d_chlk_ktbl_sel(rtwdev, RF_B, s1_tbl);
+}
+
+static enum _rf_syn_pow rtw8922d_get_syn_pow(struct rtw89_dev *rtwdev)
+{
+ switch (rtwdev->mlo_dbcc_mode) {
+ case MLO_0_PLUS_2_1RF:
+ return RF_SYN_OFF_ON;
+ case MLO_0_PLUS_2_2RF:
+ case MLO_1_PLUS_1_2RF:
+ case MLO_2_PLUS_0_1RF:
+ case MLO_2_PLUS_0_2RF:
+ case MLO_2_PLUS_2_2RF:
+ case MLO_DBCC_NOT_SUPPORT:
+ default:
+ return RF_SYN_ON_OFF;
+ case MLO_1_PLUS_1_1RF:
+ case DBCC_LEGACY:
+ return RF_SYN_ALLON;
+ }
+}
+
+void rtw8922d_rfk_mlo_ctrl(struct rtw89_dev *rtwdev)
+{
+ enum _rf_syn_pow syn_pow = rtw8922d_get_syn_pow(rtwdev);
+
+ if (!rtwdev->dbcc_en)
+ goto set_rfk_reload;
+
+ rtw8922d_set_syn01(rtwdev, syn_pow);
+
+set_rfk_reload:
+ rtw8922d_chlk_reload(rtwdev);
+}
+
+void rtw8922d_pre_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ bool mlo_1_1;
+
+ if (!rtwdev->dbcc_en)
+ return;
+
+ mlo_1_1 = rtw89_is_mlo_1_1(rtwdev);
+ if (mlo_1_1)
+ rtw8922d_set_syn01(rtwdev, RF_SYN_ALLON);
+ else if (phy_idx == RTW89_PHY_0)
+ rtw8922d_set_syn01(rtwdev, RF_SYN_ON_OFF);
+ else
+ rtw8922d_set_syn01(rtwdev, RF_SYN_OFF_ON);
+
+ fsleep(1000);
+}
+
+void rtw8922d_post_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ rtw8922d_rfk_mlo_ctrl(rtwdev);
+}
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
index 03af1f0497ac..4c505ae24261 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
@@ -7,8 +7,12 @@
#include "core.h"
+void rtw8922d_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, u8 phy_idx);
void rtw8922d_set_channel_rf(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
enum rtw89_phy_idx phy_idx);
+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);
#endif
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH rtw-next 3/9] wifi: rtw89: 8922d: add RF calibration ops
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
2026-03-30 6:58 ` [PATCH rtw-next 4/9] wifi: rtw89: 8922d: add set TX power callback Ping-Ke Shih
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ping-Ke Shih @ 2026-03-30 6:58 UTC (permalink / raw)
To: linux-wireless
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
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH rtw-next 4/9] wifi: rtw89: 8922d: add set TX power callback
2026-03-30 6:58 [PATCH rtw-next 0/9] wifi: rtw89: 8922d: add RTL8922DE part 2/2 Ping-Ke Shih
` (2 preceding siblings ...)
2026-03-30 6:58 ` [PATCH rtw-next 3/9] wifi: rtw89: 8922d: add RF calibration ops Ping-Ke Shih
@ 2026-03-30 6:58 ` 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
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ping-Ke Shih @ 2026-03-30 6:58 UTC (permalink / raw)
To: linux-wireless
Set TX power depends on operating channel. The Tx power factors are data
rate, channel, bandwidth and etc. Also, consider SAR as a factor of TX
power limit.
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/reg.h | 13 ++
drivers/net/wireless/realtek/rtw89/rtw8922d.c | 115 ++++++++++++++++++
2 files changed, 128 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index 1a5a5b30a28e..37de1c827814 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -10235,6 +10235,8 @@
#define B_TSSI_CONT_EN BIT(3)
#define R_P0_TXPWRB_BE 0xE61C
#define R_P1_TXPWRB_BE 0xE71C
+#define R_P0_TXPWRB_BE4 0x2251C
+#define R_P1_TXPWRB_BE4 0x2261C
#define B_TXPWRB_MAX_BE GENMASK(20, 12)
#define R_TSSI_MAP_OFST_P0 0xE620
#define R_TSSI_MAP_OFST_P1 0xE720
@@ -10531,13 +10533,24 @@
#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_TXAGC_REF_DBM_PATH0_TBL0_BE4 0x22528
+#define B_TXAGC_OFDM_REF_DBM_PATH0_TBL0_BE4 GENMASK(8, 0)
+#define B_TXAGC_CCK_REF_DBM_PATH0_TBL0_BE4 GENMASK(17, 9)
#define R_USED_TSSI_TRK_ON_P0_BE4 0x22534
#define B_USED_TSSI_TRK_ON_P0_BE4 BIT(22)
+#define R_TSSI_K_OFDM_PATH0_TBL0_BE4 0x225A0
+#define B_TSSI_K_OFDM_PATH0_TBL0_BE4 GENMASK(29, 20)
#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)
+#define R_TXAGC_REF_DBM_PATH0_TBL1_BE4 0x23528
+#define B_TXAGC_OFDM_REF_DBM_PATH0_TBL1_BE4 GENMASK(8, 0)
+#define B_TXAGC_CCK_REF_DBM_PATH0_TBL1_BE4 GENMASK(17, 9)
+#define R_TSSI_K_OFDM_PATH0_TBL1_BE4 0x235A0
+#define B_TSSI_K_OFDM_PATH0_TBL1_BE4 GENMASK(29, 20)
+
#define R_OFDM_OFST_P0_BE4 0x240C8
#define B_OFDM_OFST_P0_BE4 GENMASK(31, 24)
#define R_PATH0_RXIDX_INIT_BE4 0x24108
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index 2e6f4504caeb..9c62a5f12962 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -11,6 +11,7 @@
#include "reg.h"
#include "rtw8922d.h"
#include "rtw8922d_rfk.h"
+#include "sar.h"
#include "util.h"
#define RTW8922D_FW_FORMAT_MAX 0
@@ -2322,6 +2323,120 @@ static void rtw8922d_rfk_track(struct rtw89_dev *rtwdev)
rtw8922d_lck_track(rtwdev);
}
+static const struct rtw89_reg_def rtw8922d_txpwr_ref[][3] = {
+ {{ .addr = R_TXAGC_REF_DBM_PATH0_TBL0_BE4,
+ .mask = B_TXAGC_OFDM_REF_DBM_PATH0_TBL0_BE4 },
+ { .addr = R_TXAGC_REF_DBM_PATH0_TBL0_BE4,
+ .mask = B_TXAGC_CCK_REF_DBM_PATH0_TBL0_BE4 },
+ { .addr = R_TSSI_K_OFDM_PATH0_TBL0_BE4,
+ .mask = B_TSSI_K_OFDM_PATH0_TBL0_BE4 }
+ },
+ {{ .addr = R_TXAGC_REF_DBM_PATH0_TBL1_BE4,
+ .mask = B_TXAGC_OFDM_REF_DBM_PATH0_TBL1_BE4 },
+ { .addr = R_TXAGC_REF_DBM_PATH0_TBL1_BE4,
+ .mask = B_TXAGC_CCK_REF_DBM_PATH0_TBL1_BE4 },
+ { .addr = R_TSSI_K_OFDM_PATH0_TBL1_BE4,
+ .mask = B_TSSI_K_OFDM_PATH0_TBL1_BE4 }
+ },
+};
+
+static void rtw8922d_set_txpwr_diff(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
+{
+ s16 pwr_ofst = rtw89_phy_ant_gain_pwr_offset(rtwdev, chan);
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ static const u32 path_ofst[] = {0x0, 0x100};
+ const struct rtw89_reg_def *txpwr_ref;
+ s16 tssi_k_ofst = abs(pwr_ofst);
+ s16 ofst_dec[RF_PATH_NUM_8922D];
+ s16 tssi_k[RF_PATH_NUM_8922D];
+ s16 pwr_ref_ofst;
+ s16 pwr_ref = 16;
+ u8 i;
+
+ pwr_ref <<= chip->txpwr_factor_rf;
+ pwr_ref_ofst = pwr_ref - rtw89_phy_txpwr_bb_to_rf(rtwdev, abs(pwr_ofst));
+
+ ofst_dec[RF_PATH_A] = pwr_ofst > 0 ? pwr_ref : pwr_ref_ofst;
+ ofst_dec[RF_PATH_B] = pwr_ofst > 0 ? pwr_ref_ofst : pwr_ref;
+ tssi_k[RF_PATH_A] = pwr_ofst > 0 ? 0 : tssi_k_ofst;
+ tssi_k[RF_PATH_B] = pwr_ofst > 0 ? tssi_k_ofst : 0;
+
+ for (i = 0; i < RF_PATH_NUM_8922D; i++) {
+ txpwr_ref = rtw8922d_txpwr_ref[phy_idx];
+
+ rtw89_phy_write32_mask(rtwdev, txpwr_ref[0].addr + path_ofst[i],
+ txpwr_ref[0].mask, ofst_dec[i]);
+ rtw89_phy_write32_mask(rtwdev, txpwr_ref[1].addr + path_ofst[i],
+ txpwr_ref[1].mask, ofst_dec[i]);
+ rtw89_phy_write32_mask(rtwdev, txpwr_ref[2].addr + path_ofst[i],
+ txpwr_ref[2].mask, tssi_k[i]);
+ }
+}
+
+static void rtw8922d_set_txpwr_ref(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
+{
+ s16 ref_ofdm = 0;
+ s16 ref_cck = 0;
+
+ rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set txpwr reference\n");
+
+ rtw8922d_set_txpwr_diff(rtwdev, chan, phy_idx);
+
+ rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_BE_PWR_REF_CTRL,
+ B_BE_PWR_REF_CTRL_OFDM, ref_ofdm);
+ rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_BE_PWR_REF_CTRL,
+ B_BE_PWR_REF_CTRL_CCK, ref_cck);
+}
+
+static void rtw8922d_set_txpwr_sar_diff(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
+{
+ struct rtw89_sar_parm sar_parm = {
+ .center_freq = chan->freq,
+ .force_path = true,
+ };
+ s16 sar_rf;
+ s8 sar_mac;
+
+ if (phy_idx != RTW89_PHY_0)
+ return;
+
+ sar_parm.path = RF_PATH_A;
+ sar_mac = rtw89_query_sar(rtwdev, &sar_parm);
+ sar_rf = rtw89_phy_txpwr_mac_to_rf(rtwdev, sar_mac);
+ rtw89_phy_write32_mask(rtwdev, R_P0_TXPWRB_BE4, B_TXPWRB_MAX_BE, sar_rf);
+
+ sar_parm.path = RF_PATH_B;
+ sar_mac = rtw89_query_sar(rtwdev, &sar_parm);
+ sar_rf = rtw89_phy_txpwr_mac_to_rf(rtwdev, sar_mac);
+ rtw89_phy_write32_mask(rtwdev, R_P1_TXPWRB_BE4, B_TXPWRB_MAX_BE, sar_rf);
+}
+
+static void rtw8922d_set_txpwr(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_phy_idx phy_idx)
+{
+ rtw89_phy_set_txpwr_byrate(rtwdev, chan, phy_idx);
+ rtw89_phy_set_txpwr_offset(rtwdev, chan, phy_idx);
+ rtw89_phy_set_txpwr_limit(rtwdev, chan, phy_idx);
+ rtw89_phy_set_txpwr_limit_ru(rtwdev, chan, phy_idx);
+ rtw8922d_set_txpwr_ref(rtwdev, chan, phy_idx);
+ rtw8922d_set_txpwr_sar_diff(rtwdev, chan, phy_idx);
+}
+
+static void rtw8922d_set_txpwr_ctrl(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
+{
+ const struct rtw89_chan *chan = rtw89_mgnt_chan_get(rtwdev, phy_idx);
+
+ rtw8922d_set_txpwr_ref(rtwdev, chan, phy_idx);
+}
+
MODULE_FIRMWARE(RTW8922D_MODULE_FIRMWARE);
MODULE_FIRMWARE(RTW8922DS_MODULE_FIRMWARE);
MODULE_AUTHOR("Realtek Corporation");
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH rtw-next 5/9] wifi: rtw89: 8922d: configure TX/RX path assisting in BT coexistence
2026-03-30 6:58 [PATCH rtw-next 0/9] wifi: rtw89: 8922d: add RTL8922DE part 2/2 Ping-Ke Shih
` (3 preceding siblings ...)
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 ` 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
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ping-Ke Shih @ 2026-03-30 6:58 UTC (permalink / raw)
To: linux-wireless
The BT coexistence mechanism needs to control TX/RX path to co-work with
BT well, and these helpers are provided by BB to configure path.
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/reg.h | 9 +-
drivers/net/wireless/realtek/rtw89/rtw8922d.c | 125 ++++++++++++++++++
2 files changed, 132 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index 37de1c827814..78f2cf579fa6 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -10469,8 +10469,9 @@
#define B_EMLSR_BB_CLK_BE4 GENMASK(31, 30)
#define R_CHINFO_SEG_BE4 0x200B4
#define B_CHINFO_SEG_LEN_BE4 GENMASK(12, 10)
-#define R_STS_HDR2_PARSING_BE4 0x2070C
-#define B_STS_HDR2_PARSING_BE4 BIT(10)
+#define R_SEL_GNT_BT_RX_BE4 0x2010C
+#define B_SEL_GNT_BT_RX_PATH0_BE4 GENMASK(3, 0)
+#define B_SEL_GNT_BT_RX_PATH1_BE4 GENMASK(11, 8)
#define R_SW_SI_WDATA_BE4 0x20370
#define B_SW_SI_DATA_PATH_BE4 GENMASK(31, 28)
#define B_SW_SI_DATA_ADR_BE4 GENMASK(27, 20)
@@ -10490,9 +10491,13 @@
#define B_ENABLE_CCK0_BE4 BIT(5)
#define R_RSTB_ASYNC_BE4 0x20704
#define B_RSTB_ASYNC_BE4 BIT(1)
+#define R_STS_HDR2_PARSING_BE4 0x2070C
+#define B_STS_HDR2_PARSING_BE4 BIT(10)
#define R_EDCCA_RPT_SEL_BE4 0x20780
#define R_EDCCA_RPT_SEL_BE4_C1 0x21780
#define B_EDCCA_RPT_SEL_BE4_MSK 0xE0000
+#define R_SEL_GNT_BT_RXPHY_BE4 0x2079C
+#define B_SEL_GNT_BT_RXPHY_BE4 GENMASK(11, 8)
#define R_IMR_TX_ERROR_BE4 0x20920
#define B_IMR_TX_ERROR_BE4 BIT(30)
#define R_TXINFO_PATH_BE4 0x209A4
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index 9c62a5f12962..cfe9752abddc 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -238,6 +238,35 @@ static const struct rtw89_efuse_block_cfg rtw8922d_efuse_blocks[] = {
[RTW89_EFUSE_BLOCK_ADIE] = {.offset = 0x70000, .size = 0x10},
};
+static void rtw8922d_sel_bt_rx_path(struct rtw89_dev *rtwdev, u8 val,
+ enum rtw89_rf_path rx_path)
+{
+ if (rx_path == RF_PATH_A)
+ rtw89_phy_write32_mask(rtwdev, R_SEL_GNT_BT_RX_BE4,
+ B_SEL_GNT_BT_RX_PATH0_BE4, val);
+ else if (rx_path == RF_PATH_B)
+ rtw89_phy_write32_mask(rtwdev, R_SEL_GNT_BT_RX_BE4,
+ B_SEL_GNT_BT_RX_PATH1_BE4, val);
+ else
+ rtw89_warn(rtwdev, "[%s] Not support path = %d\n", __func__, rx_path);
+}
+
+static void rtw8922d_sel_bt_rx_phy(struct rtw89_dev *rtwdev, u8 val,
+ enum rtw89_phy_idx phy_idx)
+{
+ rtw89_phy_write32_idx(rtwdev, R_SEL_GNT_BT_RXPHY_BE4,
+ B_SEL_GNT_BT_RXPHY_BE4, val, phy_idx);
+}
+
+static void rtw8922d_set_gbt_bt_rx_sel(struct rtw89_dev *rtwdev, bool en,
+ enum rtw89_phy_idx phy_idx)
+{
+ rtw8922d_sel_bt_rx_path(rtwdev, 0x3, RF_PATH_A);
+ rtw8922d_sel_bt_rx_phy(rtwdev, 0x0, RTW89_PHY_0);
+ rtw8922d_sel_bt_rx_path(rtwdev, 0x3, RF_PATH_B);
+ rtw8922d_sel_bt_rx_phy(rtwdev, 0x0, RTW89_PHY_1);
+}
+
static int rtw8922d_pwr_on_func(struct rtw89_dev *rtwdev)
{
struct rtw89_hal *hal = &rtwdev->hal;
@@ -2437,6 +2466,102 @@ static void rtw8922d_set_txpwr_ctrl(struct rtw89_dev *rtwdev,
rtw8922d_set_txpwr_ref(rtwdev, chan, phy_idx);
}
+static void rtw8922d_ctrl_trx_path(struct rtw89_dev *rtwdev,
+ enum rtw89_rf_path tx_path, u8 tx_nss,
+ enum rtw89_rf_path rx_path, u8 rx_nss)
+{
+ enum rtw89_phy_idx phy_idx;
+
+ for (phy_idx = RTW89_PHY_0; phy_idx <= RTW89_PHY_1; phy_idx++) {
+ rtw8922d_ctrl_tx_path_tmac(rtwdev, tx_path, phy_idx);
+ rtw8922d_ctrl_rx_path_tmac(rtwdev, rx_path, phy_idx);
+
+ rtw8922d_tssi_reset(rtwdev, rx_path, phy_idx);
+ }
+}
+
+static void rtw8922d_ctrl_nbtg_bt_tx(struct rtw89_dev *rtwdev, bool en,
+ enum rtw89_phy_idx phy_idx)
+{
+ if (en) {
+ rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_A, B_FORCE_FIR_A, 0x3, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_A, B_RXBY_WBADC_A,
+ 0xf, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_A, B_BT_RXBY_WBADC_A,
+ 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_A, B_BT_TRK_OFF_A, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_OP1DB_A, B_OP1DB_A, 0x80, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_OP1DB1_A, B_TIA10_A, 0x8080, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BACKOFF_A, B_LNA_IBADC_A, 0x34, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BKOFF_A, B_BKOFF_IBADC_A, 0x34, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_B, B_FORCE_FIR_B, 0x3, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_B, B_RXBY_WBADC_B,
+ 0xf, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_B, B_BT_RXBY_WBADC_B,
+ 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_B, B_BT_TRK_OFF_B, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_LNA_TIA, B_TIA1_B, 0x80, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BACKOFF_B, B_LNA_IBADC_B, 0x34, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BKOFF_B, B_BKOFF_IBADC_B, 0x34, phy_idx);
+ } else {
+ rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_A, B_FORCE_FIR_A, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_A, B_RXBY_WBADC_A,
+ 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_A, B_BT_RXBY_WBADC_A,
+ 0x1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_A, B_BT_TRK_OFF_A, 0x1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_OP1DB_A, B_OP1DB_A, 0x1a, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_OP1DB1_A, B_TIA10_A, 0x2a2a, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BACKOFF_A, B_LNA_IBADC_A, 0x7a6, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BKOFF_A, B_BKOFF_IBADC_A, 0x26, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_B, B_FORCE_FIR_B, 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_B, B_RXBY_WBADC_B,
+ 0x0, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_B, B_BT_RXBY_WBADC_B,
+ 0x1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_B, B_BT_TRK_OFF_B, 0x1, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_LNA_TIA, B_TIA1_B, 0x2a, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BACKOFF_B, B_LNA_IBADC_B, 0x7a6, phy_idx);
+ rtw89_phy_write32_idx(rtwdev, R_BKOFF_B, B_BKOFF_IBADC_B, 0x26, phy_idx);
+ }
+}
+
+static void rtw8922d_bb_cfg_txrx_path(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_CHANCTX_0);
+ enum rtw89_band band = chan->band_type;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u8 ntx_path = RF_PATH_AB;
+ u8 nrx_path = RF_PATH_AB;
+ u32 tx_en0, tx_en1;
+ u8 rx_nss = 2;
+
+ if (hal->antenna_tx == RF_A)
+ ntx_path = RF_PATH_A;
+ else if (hal->antenna_tx == RF_B)
+ ntx_path = RF_PATH_B;
+
+ if (hal->antenna_rx == RF_A)
+ nrx_path = RF_PATH_A;
+ else if (hal->antenna_rx == RF_B)
+ nrx_path = RF_PATH_B;
+
+ if (nrx_path != RF_PATH_AB)
+ rx_nss = 1;
+
+ rtw8922d_hal_reset(rtwdev, RTW89_PHY_0, RTW89_MAC_0, band, &tx_en0, true);
+ if (rtwdev->dbcc_en)
+ rtw8922d_hal_reset(rtwdev, RTW89_PHY_1, RTW89_MAC_1, band,
+ &tx_en1, true);
+
+ rtw8922d_ctrl_trx_path(rtwdev, ntx_path, 2, nrx_path, rx_nss);
+
+ rtw8922d_hal_reset(rtwdev, RTW89_PHY_0, RTW89_MAC_0, band, &tx_en0, false);
+ if (rtwdev->dbcc_en)
+ rtw8922d_hal_reset(rtwdev, RTW89_PHY_1, RTW89_MAC_1, band,
+ &tx_en1, false);
+}
+
MODULE_FIRMWARE(RTW8922D_MODULE_FIRMWARE);
MODULE_FIRMWARE(RTW8922DS_MODULE_FIRMWARE);
MODULE_AUTHOR("Realtek Corporation");
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH rtw-next 6/9] wifi: rtw89: 8922d: add RF ops of init hardware and get thermal
2026-03-30 6:58 [PATCH rtw-next 0/9] wifi: rtw89: 8922d: add RTL8922DE part 2/2 Ping-Ke Shih
` (4 preceding siblings ...)
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 ` 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
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ping-Ke Shih @ 2026-03-30 6:58 UTC (permalink / raw)
To: linux-wireless
One is to initialize hardware for RF circuit, and the ops of get thermal
is used to monitor temperature to re-calibrate RF or reduce TX duty to
prevent overheating.
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/reg.h | 6 ++
drivers/net/wireless/realtek/rtw89/rtw8922d.c | 57 +++++++++++++++++++
.../net/wireless/realtek/rtw89/rtw8922d_rfk.c | 24 ++++++++
.../net/wireless/realtek/rtw89/rtw8922d_rfk.h | 3 +
4 files changed, 90 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index 78f2cf579fa6..e5e689f1bfa3 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -10676,6 +10676,12 @@
#define B_KTBL1_TBL0 BIT(3)
#define B_KTBL1_TBL1 BIT(5)
+#define R_TC_EN_BE4 0x3c200
+#define B_TC_EN_BE4 BIT(0)
+#define B_TC_TRIG_BE4 BIT(1)
+#define R_TC_VAL_BE4 0x3c208
+#define B_TC_VAL_BE4 GENMASK(7, 0)
+
/* WiFi CPU local domain */
#define R_AX_WDT_CTRL 0x0040
#define B_AX_WDT_EN BIT(31)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index cfe9752abddc..49b84d49ccac 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -2562,6 +2562,63 @@ static void rtw8922d_bb_cfg_txrx_path(struct rtw89_dev *rtwdev)
&tx_en1, false);
}
+static u8 rtw8922d_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path)
+{
+ u8 val;
+
+ rtw89_phy_write32_mask(rtwdev, R_TC_EN_BE4, B_TC_EN_BE4, 0x1);
+ rtw89_phy_write32_mask(rtwdev, R_TC_EN_BE4, B_TC_TRIG_BE4, 0x0);
+ rtw89_phy_write32_mask(rtwdev, R_TC_EN_BE4, B_TC_TRIG_BE4, 0x1);
+
+ fsleep(100);
+
+ val = rtw89_phy_read32_mask(rtwdev, R_TC_VAL_BE4, B_TC_VAL_BE4);
+
+ return val;
+}
+
+static u32 rtw8922d_chan_to_rf18_val(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan)
+{
+ u32 val = u32_encode_bits(chan->channel, RR_CFGCH_CH);
+
+ switch (chan->band_type) {
+ case RTW89_BAND_2G:
+ default:
+ break;
+ case RTW89_BAND_5G:
+ val |= u32_encode_bits(CFGCH_BAND1_5G, RR_CFGCH_BAND1) |
+ u32_encode_bits(CFGCH_BAND0_5G, RR_CFGCH_BAND0);
+ break;
+ case RTW89_BAND_6G:
+ val |= u32_encode_bits(CFGCH_BAND1_6G, RR_CFGCH_BAND1) |
+ u32_encode_bits(CFGCH_BAND0_6G, RR_CFGCH_BAND0);
+ break;
+ }
+
+ switch (chan->band_width) {
+ case RTW89_CHANNEL_WIDTH_5:
+ case RTW89_CHANNEL_WIDTH_10:
+ case RTW89_CHANNEL_WIDTH_20:
+ default:
+ break;
+ case RTW89_CHANNEL_WIDTH_40:
+ val |= u32_encode_bits(CFGCH_BW_V2_40M, RR_CFGCH_BW_V2);
+ break;
+ case RTW89_CHANNEL_WIDTH_80:
+ val |= u32_encode_bits(CFGCH_BW_V2_80M, RR_CFGCH_BW_V2);
+ break;
+ case RTW89_CHANNEL_WIDTH_160:
+ val |= u32_encode_bits(CFGCH_BW_V2_160M, RR_CFGCH_BW_V2);
+ break;
+ case RTW89_CHANNEL_WIDTH_320:
+ val |= u32_encode_bits(CFGCH_BW_V2_320M, RR_CFGCH_BW_V2);
+ break;
+ }
+
+ return val;
+}
+
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 147cf91d2cb0..4e6a8e88a71e 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
@@ -9,6 +9,12 @@
#include "rtw8922d.h"
#include "rtw8922d_rfk.h"
+static const struct rtw89_reg5_def rtw8922d_nctl_post_defs[] = {
+ RTW89_DECL_RFK_WM(0x20c7c, 0x00e00000, 0x1),
+};
+
+RTW89_DECLARE_RFK_TBL(rtw8922d_nctl_post_defs);
+
static void rtw8922d_tssi_cont_en(struct rtw89_dev *rtwdev, bool en,
enum rtw89_rf_path path, u8 phy_idx)
{
@@ -239,6 +245,24 @@ void rtw8922d_rfk_mlo_ctrl(struct rtw89_dev *rtwdev)
rtw8922d_chlk_reload(rtwdev);
}
+static void rtw8922d_x4k_setting(struct rtw89_dev *rtwdev)
+{
+ u32 val;
+
+ val = rtw89_read_rf(rtwdev, RF_PATH_A, 0xB9, 0xF000);
+ rtw89_write_rf(rtwdev, RF_PATH_A, 0xB9, 0xF000, val);
+ val = rtw89_read_rf(rtwdev, RF_PATH_B, 0xB9, 0xF000);
+ rtw89_write_rf(rtwdev, RF_PATH_B, 0xB9, 0xF000, val);
+
+ rtw89_write_rf(rtwdev, RF_PATH_A, 0xC2, BIT(19), 0x1);
+ rtw89_write_rf(rtwdev, RF_PATH_B, 0xC2, BIT(19), 0x1);
+}
+
+void rtw8922d_rfk_hw_init(struct rtw89_dev *rtwdev)
+{
+ rtw8922d_x4k_setting(rtwdev);
+}
+
void rtw8922d_pre_set_channel_rf(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
{
bool mlo_1_1;
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
index 8a5f4b56b8ce..c5bbe0eb972a 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
@@ -7,10 +7,13 @@
#include "core.h"
+extern const struct rtw89_rfk_tbl rtw8922d_nctl_post_defs_tbl;
+
void rtw8922d_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, u8 phy_idx);
void rtw8922d_set_channel_rf(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
enum rtw89_phy_idx phy_idx);
+void rtw8922d_rfk_hw_init(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);
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH rtw-next 7/9] wifi: rtw89: 8922d: add ops related to BT coexistence mechanism
2026-03-30 6:58 [PATCH rtw-next 0/9] wifi: rtw89: 8922d: add RTL8922DE part 2/2 Ping-Ke Shih
` (5 preceding siblings ...)
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 ` 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
8 siblings, 0 replies; 10+ messages in thread
From: Ping-Ke Shih @ 2026-03-30 6:58 UTC (permalink / raw)
To: linux-wireless
The ops is used by shared BT coexistence mechanism to set WiFi TX power,
get BT RSSI, and TX/RX parameters.
The RTL8922D uses TX/RX parameter v9, so define it and fill NULL for
other chips.
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/core.h | 21 +++
drivers/net/wireless/realtek/rtw89/rtw8851b.c | 4 +
drivers/net/wireless/realtek/rtw89/rtw8852a.c | 4 +
drivers/net/wireless/realtek/rtw89/rtw8852b.c | 4 +
.../net/wireless/realtek/rtw89/rtw8852bt.c | 4 +
drivers/net/wireless/realtek/rtw89/rtw8852c.c | 4 +
drivers/net/wireless/realtek/rtw89/rtw8922a.c | 4 +
drivers/net/wireless/realtek/rtw89/rtw8922d.c | 123 ++++++++++++++++++
8 files changed, 168 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 696a1d92d62b..5c5bd7d02a62 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -873,6 +873,14 @@ enum rtw89_phy_idx {
RTW89_PHY_NUM,
};
+enum rtw89_fbtc_bt_index {
+ BTC_BT_1ST = 0x0,
+ BTC_BT_2ND = 0x1,
+ BTC_BT_EXT = 0x2,
+ BTC_ALL_BT = 0x2,
+ BTC_ALL_BT_EZL = 0x3 /* BT0+BT1+Ext-ZB(or Thread, or LTE) */
+};
+
#define __RTW89_MLD_MAX_LINK_NUM 2
#define RTW89_MLD_NON_STA_LINK_NUM 1
@@ -2197,6 +2205,15 @@ struct rtw89_btc_bt_info {
u32 rsvd: 17;
};
+struct rtw89_btc_rf_trx_para_v9 {
+ u32 wl_tx_power[RTW89_PHY_NUM]; /* absolute Tx power (dBm), 1's complement -5->0x85 */
+ u32 wl_rx_gain[RTW89_PHY_NUM]; /* rx gain table index (TBD.) */
+ u32 bt_tx_power[BTC_ALL_BT]; /* decrease Tx power (dB) */
+ u32 bt_rx_gain[BTC_ALL_BT]; /* LNA constrain level */
+ u32 zb_tx_power[BTC_ALL_BT]; /* 15.4 devrease Tx power (dB) */
+ u32 zb_rx_gain[BTC_ALL_BT]; /* 15.4 constrain level */
+};
+
struct rtw89_btc_cx {
struct rtw89_btc_wl_info wl;
struct rtw89_btc_bt_info bt;
@@ -4609,6 +4626,10 @@ struct rtw89_chip_info {
const struct rtw89_btc_rf_trx_para *rf_para_ulink;
u8 rf_para_dlink_num;
const struct rtw89_btc_rf_trx_para *rf_para_dlink;
+ const struct rtw89_btc_rf_trx_para_v9 *rf_para_ulink_v9;
+ const struct rtw89_btc_rf_trx_para_v9 *rf_para_dlink_v9;
+ u8 rf_para_ulink_num_v9;
+ u8 rf_para_dlink_num_v9;
u8 ps_mode_supported;
u8 low_power_hci_modes;
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
index a3a5b6fbe46c..f9eda3f16d32 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
@@ -2681,6 +2681,10 @@ const struct rtw89_chip_info rtw8851b_chip_info = {
.rf_para_ulink = rtw89_btc_8851b_rf_ul,
.rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8851b_rf_dl),
.rf_para_dlink = rtw89_btc_8851b_rf_dl,
+ .rf_para_ulink_v9 = NULL,
+ .rf_para_dlink_v9 = NULL,
+ .rf_para_ulink_num_v9 = 0,
+ .rf_para_dlink_num_v9 = 0,
.ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
BIT(RTW89_PS_MODE_CLK_GATED),
.low_power_hci_modes = 0,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
index 898c534a5762..c894c31156e4 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
@@ -2418,6 +2418,10 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
.rf_para_ulink = rtw89_btc_8852a_rf_ul,
.rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8852a_rf_dl),
.rf_para_dlink = rtw89_btc_8852a_rf_dl,
+ .rf_para_ulink_v9 = NULL,
+ .rf_para_dlink_v9 = NULL,
+ .rf_para_ulink_num_v9 = 0,
+ .rf_para_dlink_num_v9 = 0,
.ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
BIT(RTW89_PS_MODE_CLK_GATED) |
BIT(RTW89_PS_MODE_PWR_GATED),
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
index 19a9f07e8714..f2e839122194 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
@@ -1014,6 +1014,10 @@ const struct rtw89_chip_info rtw8852b_chip_info = {
.rf_para_ulink = rtw89_btc_8852b_rf_ul,
.rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8852b_rf_dl),
.rf_para_dlink = rtw89_btc_8852b_rf_dl,
+ .rf_para_ulink_v9 = NULL,
+ .rf_para_dlink_v9 = NULL,
+ .rf_para_ulink_num_v9 = 0,
+ .rf_para_dlink_num_v9 = 0,
.ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
BIT(RTW89_PS_MODE_CLK_GATED) |
BIT(RTW89_PS_MODE_PWR_GATED),
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
index c86b995a7cb1..b1eb6fb1ece8 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c
@@ -853,6 +853,10 @@ const struct rtw89_chip_info rtw8852bt_chip_info = {
.rf_para_ulink = rtw89_btc_8852bt_rf_ul,
.rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8852bt_rf_dl),
.rf_para_dlink = rtw89_btc_8852bt_rf_dl,
+ .rf_para_ulink_v9 = NULL,
+ .rf_para_dlink_v9 = NULL,
+ .rf_para_ulink_num_v9 = 0,
+ .rf_para_dlink_num_v9 = 0,
.ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
BIT(RTW89_PS_MODE_CLK_GATED) |
BIT(RTW89_PS_MODE_PWR_GATED),
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 7ea0a8905282..0f2902af1c72 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -3211,6 +3211,10 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
.rf_para_ulink = rtw89_btc_8852c_rf_ul,
.rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8852c_rf_dl),
.rf_para_dlink = rtw89_btc_8852c_rf_dl,
+ .rf_para_ulink_v9 = NULL,
+ .rf_para_dlink_v9 = NULL,
+ .rf_para_ulink_num_v9 = 0,
+ .rf_para_dlink_num_v9 = 0,
.ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
BIT(RTW89_PS_MODE_CLK_GATED) |
BIT(RTW89_PS_MODE_PWR_GATED),
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
index a489aaf90f23..e8731d2f1703 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
@@ -3015,6 +3015,10 @@ const struct rtw89_chip_info rtw8922a_chip_info = {
.rf_para_ulink = rtw89_btc_8922a_rf_ul,
.rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8922a_rf_dl),
.rf_para_dlink = rtw89_btc_8922a_rf_dl,
+ .rf_para_ulink_v9 = NULL,
+ .rf_para_dlink_v9 = NULL,
+ .rf_para_ulink_num_v9 = 0,
+ .rf_para_dlink_num_v9 = 0,
.ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
BIT(RTW89_PS_MODE_CLK_GATED) |
BIT(RTW89_PS_MODE_PWR_GATED),
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index 49b84d49ccac..a9a7ffb5fb58 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -2619,6 +2619,129 @@ static u32 rtw8922d_chan_to_rf18_val(struct rtw89_dev *rtwdev,
return val;
}
+static void rtw8922d_btc_set_rfe(struct rtw89_dev *rtwdev)
+{
+}
+
+static void rtw8922d_btc_init_cfg(struct rtw89_dev *rtwdev)
+{
+ /* offload to firmware */
+}
+
+static void
+rtw8922d_btc_set_wl_txpwr_ctrl(struct rtw89_dev *rtwdev, u32 txpwr_val)
+{
+ u16 ctrl_all_time = u32_get_bits(txpwr_val, GENMASK(15, 0));
+ u16 ctrl_gnt_bt = u32_get_bits(txpwr_val, GENMASK(31, 16));
+
+ switch (ctrl_all_time) {
+ case 0xffff:
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_RATE_CTRL,
+ B_BE_FORCE_PWR_BY_RATE_EN, 0x0);
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_RATE_CTRL,
+ B_BE_FORCE_PWR_BY_RATE_VAL, 0x0);
+ break;
+ default:
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_RATE_CTRL,
+ B_BE_FORCE_PWR_BY_RATE_VAL, ctrl_all_time);
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_RATE_CTRL,
+ B_BE_FORCE_PWR_BY_RATE_EN, 0x1);
+ break;
+ }
+
+ switch (ctrl_gnt_bt) {
+ case 0xffff:
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_REG_CTRL,
+ B_BE_PWR_BT_EN, 0x0);
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_COEX_CTRL,
+ B_BE_PWR_BT_VAL, 0x0);
+ break;
+ default:
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_COEX_CTRL,
+ B_BE_PWR_BT_VAL, ctrl_gnt_bt);
+ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, R_BE_PWR_REG_CTRL,
+ B_BE_PWR_BT_EN, 0x1);
+ break;
+ }
+}
+
+static
+s8 rtw8922d_btc_get_bt_rssi(struct rtw89_dev *rtwdev, s8 val)
+{
+ return clamp_t(s8, val, -100, 0) + 100;
+}
+
+static const struct rtw89_btc_rf_trx_para_v9 rtw89_btc_8922d_rf_ul_v9[] = {
+ /*
+ * 0 -> original
+ * 1 -> for BT-connected ACI issue && BTG co-rx
+ * 2 ~ 4 ->reserved for shared-antenna
+ * 5 ~ 8 ->for non-shared-antenna free-run
+ */
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {2, 2}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{ 6, 6}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{13, 13}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{13, 13}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+};
+
+static const struct rtw89_btc_rf_trx_para_v9 rtw89_btc_8922d_rf_dl_v9[] = {
+ /*
+ * 0 -> original
+ * 1 -> for BT-connected ACI issue && BTG co-rx
+ * 2 ~ 4 ->reserved for shared-antenna
+ * 5 ~ 8 ->for non-shared-antenna free-run
+ */
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {2, 2}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {0, 0}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+ {{15, 15}, {1, 1}, {0, 0}, {7, 7}, {0, 0}, {0, 0}},
+};
+
+static const u8 rtw89_btc_8922d_wl_rssi_thres[BTC_WL_RSSI_THMAX] = {60, 50, 40, 30};
+static const u8 rtw89_btc_8922d_bt_rssi_thres[BTC_BT_RSSI_THMAX] = {50, 40, 30, 20};
+
+static const struct rtw89_btc_fbtc_mreg rtw89_btc_8922d_mon_reg[] = {
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe300),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe330),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe334),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe338),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe344),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe348),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe34c),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe350),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe354),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe35c),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe370),
+ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xe380),
+};
+
+static
+void rtw8922d_btc_update_bt_cnt(struct rtw89_dev *rtwdev)
+{
+ /* Feature move to firmware */
+}
+
+static
+void rtw8922d_btc_wl_s1_standby(struct rtw89_dev *rtwdev, bool state)
+{
+ /* Feature move to firmware */
+}
+
+static void rtw8922d_btc_set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level)
+{
+ /* Feature move to firmware */
+}
+
MODULE_FIRMWARE(RTW8922D_MODULE_FIRMWARE);
MODULE_FIRMWARE(RTW8922DS_MODULE_FIRMWARE);
MODULE_AUTHOR("Realtek Corporation");
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH rtw-next 8/9] wifi: rtw89: 8922d: add chip_info and chip_ops struct
2026-03-30 6:58 [PATCH rtw-next 0/9] wifi: rtw89: 8922d: add RTL8922DE part 2/2 Ping-Ke Shih
` (6 preceding siblings ...)
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 ` 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
8 siblings, 0 replies; 10+ messages in thread
From: Ping-Ke Shih @ 2026-03-30 6:58 UTC (permalink / raw)
To: linux-wireless
Add remaining functions including calculate RX gain for power saving,
channel frequency and RSSI from PPDU status, and WoWLAN declaration.
Then fill chip_info and chip_ops tables, which RTL8922D has two variants
RTL8922D and RTL8922DS supporting 4096 and 1024 QAM respectively. Other
features, such as support of 2/5/6 GHz and up to 160 MHz bandwidth, for
variants are the same,
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/fw.h | 23 +-
drivers/net/wireless/realtek/rtw89/reg.h | 17 +
drivers/net/wireless/realtek/rtw89/rtw8922d.c | 344 ++++++++++++++++++
drivers/net/wireless/realtek/rtw89/rtw8922d.h | 3 +
4 files changed, 380 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 4574a281d352..db252d45e498 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -4298,13 +4298,22 @@ enum rtw89_fw_element_id {
BIT(RTW89_FW_ELEMENT_ID_TXPWR_TRK) | \
BITS_OF_RTW89_TXPWR_FW_ELEMENTS_NO_6GHZ)
-#define RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS (BIT(RTW89_FW_ELEMENT_ID_BBMCU0) | \
- BIT(RTW89_FW_ELEMENT_ID_BB_REG) | \
- BIT(RTW89_FW_ELEMENT_ID_RADIO_A) | \
- BIT(RTW89_FW_ELEMENT_ID_RADIO_B) | \
- BIT(RTW89_FW_ELEMENT_ID_RF_NCTL) | \
- BIT(RTW89_FW_ELEMENT_ID_TXPWR_TRK) | \
- BITS_OF_RTW89_TXPWR_FW_ELEMENTS)
+#define RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS_BASE \
+ (BIT(RTW89_FW_ELEMENT_ID_BB_REG) | \
+ BIT(RTW89_FW_ELEMENT_ID_RADIO_A) | \
+ BIT(RTW89_FW_ELEMENT_ID_RADIO_B) | \
+ BIT(RTW89_FW_ELEMENT_ID_RF_NCTL) | \
+ BIT(RTW89_FW_ELEMENT_ID_TXPWR_TRK) | \
+ BITS_OF_RTW89_TXPWR_FW_ELEMENTS)
+
+#define RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS \
+ (RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS_BASE | \
+ BIT(RTW89_FW_ELEMENT_ID_BBMCU0))
+
+#define RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS_V1 \
+ (RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS_BASE | \
+ BIT(RTW89_FW_ELEMENT_ID_AFE_PWR_SEQ) | \
+ BIT(RTW89_FW_ELEMENT_ID_TX_COMP))
struct __rtw89_fw_txpwr_element {
u8 rsvd0;
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index e5e689f1bfa3..42ffe83931a3 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -4291,6 +4291,20 @@
#define B_BE_VERIFY_ENV_MASK GENMASK(9, 8)
#define B_BE_HW_ID_MASK GENMASK(7, 0)
+#define R_BE_SCOREBOARD_0 0x0110
+#define B_BE_SB0_TOGGLE BIT(31)
+#define B_BE_SB0_WL_DATA_LINE_MASK GENMASK(30, 0)
+
+#define R_BE_SCOREBOARD_0_BT_DATA 0x0114
+#define B_BE_SB0_BT_DATA_LINE_MASK GENMASK(30, 0)
+
+#define R_BE_SCOREBOARD_1 0x0118
+#define B_BE_SB1_TOGGLE BIT(31)
+#define B_BE_SB1_WL_DATA_LINE_MASK GENMASK(30, 0)
+
+#define R_BE_SCOREBOARD_1_BT_DATA 0x011C
+#define B_BE_SB1_BT_DATA_LINE_MASK GENMASK(30, 0)
+
#define R_BE_HALT_H2C_CTRL 0x0160
#define B_BE_HALT_H2C_TRIGGER BIT(0)
@@ -10656,6 +10670,9 @@
#define B_RX_LDPC08_BE4 GENMASK(29, 24)
#define R_RX_LDPC01_BE4 0x26840
#define B_RX_LDPC09_BE4 GENMASK(5, 0)
+#define R_BSS_CLR_MAP_BE4 0x26914
+#define R_BSS_CLR_VLD_BE4 0x26920
+#define B_BSS_CLR_VLD_BE4 BIT(2)
#define R_SW_SI_DATA_BE4 0x2CF4C
#define B_SW_SI_READ_DATA_BE4 GENMASK(19, 0)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.c b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
index a9a7ffb5fb58..e3b77cd23514 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.c
@@ -1447,6 +1447,20 @@ static void rtw8922d_set_rx_gain_normal(struct rtw89_dev *rtwdev,
rtw8922d_set_rx_gain_normal_ofdm(rtwdev, chan, path, phy_idx);
}
+static void rtw8922d_calc_rx_gain_normal(struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan,
+ enum rtw89_rf_path path,
+ enum rtw89_phy_idx phy_idx,
+ struct rtw89_phy_calc_efuse_gain *calc)
+{
+ rtw8922d_calc_rx_gain_normal_ofdm(rtwdev, chan, path, phy_idx, calc);
+
+ if (chan->band_type != RTW89_BAND_2G)
+ return;
+
+ rtw8922d_calc_rx_gain_normal_cck(rtwdev, chan, path, phy_idx, calc);
+}
+
static void rtw8922d_set_cck_parameters(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
enum rtw89_phy_idx phy_idx)
@@ -2742,6 +2756,336 @@ static void rtw8922d_btc_set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level)
/* Feature move to firmware */
}
+static void rtw8922d_fill_freq_with_ppdu(struct rtw89_dev *rtwdev,
+ struct rtw89_rx_phy_ppdu *phy_ppdu,
+ struct ieee80211_rx_status *status)
+{
+ u8 chan_idx = phy_ppdu->chan_idx;
+ enum nl80211_band band;
+ u8 ch;
+
+ if (chan_idx == 0)
+ return;
+
+ rtw89_decode_chan_idx(rtwdev, chan_idx, &ch, &band);
+ status->freq = ieee80211_channel_to_frequency(ch, band);
+ status->band = band;
+}
+
+static void rtw8922d_query_ppdu(struct rtw89_dev *rtwdev,
+ struct rtw89_rx_phy_ppdu *phy_ppdu,
+ struct ieee80211_rx_status *status)
+{
+ u8 path;
+ u8 *rx_power = phy_ppdu->rssi;
+
+ if (!status->signal)
+ status->signal = RTW89_RSSI_RAW_TO_DBM(max(rx_power[RF_PATH_A],
+ rx_power[RF_PATH_B]));
+
+ for (path = 0; path < rtwdev->chip->rf_path_num; path++) {
+ status->chains |= BIT(path);
+ status->chain_signal[path] = RTW89_RSSI_RAW_TO_DBM(rx_power[path]);
+ }
+ if (phy_ppdu->valid)
+ rtw8922d_fill_freq_with_ppdu(rtwdev, phy_ppdu, status);
+}
+
+static void rtw8922d_convert_rpl_to_rssi(struct rtw89_dev *rtwdev,
+ struct rtw89_rx_phy_ppdu *phy_ppdu)
+{
+ /* Mapping to BW: 5, 10, 20, 40, 80, 160, 80_80 */
+ static const u8 bw_compensate[] = {0, 0, 0, 6, 12, 18, 0};
+ u8 *rssi = phy_ppdu->rssi;
+ u8 compensate = 0;
+ u8 i;
+
+ if (phy_ppdu->bw_idx < ARRAY_SIZE(bw_compensate))
+ compensate = bw_compensate[phy_ppdu->bw_idx];
+
+ for (i = 0; i < RF_PATH_NUM_8922D; i++) {
+ if (!(phy_ppdu->rx_path_en & BIT(i))) {
+ rssi[i] = 0;
+ phy_ppdu->rpl_path[i] = 0;
+ phy_ppdu->rpl_fd[i] = 0;
+ }
+
+ if (phy_ppdu->ie != RTW89_CCK_PKT && rssi[i])
+ rssi[i] += compensate;
+
+ phy_ppdu->rpl_path[i] = rssi[i];
+ }
+}
+
+static void rtw8922d_phy_rpt_to_rssi(struct rtw89_dev *rtwdev,
+ struct rtw89_rx_desc_info *desc_info,
+ struct ieee80211_rx_status *rx_status)
+{
+ if (desc_info->rssi <= 0x1 || (desc_info->rssi >> 2) > MAX_RSSI)
+ return;
+
+ rx_status->signal = (desc_info->rssi >> 2) - MAX_RSSI;
+}
+
+static int rtw8922d_mac_enable_bb_rf(struct rtw89_dev *rtwdev)
+{
+ return 0;
+}
+
+static int rtw8922d_mac_disable_bb_rf(struct rtw89_dev *rtwdev)
+{
+ return 0;
+}
+
+static const struct rtw89_chanctx_listener rtw8922d_chanctx_listener = {
+ .callbacks[RTW89_CHANCTX_CALLBACK_TAS] = rtw89_tas_chanctx_cb,
+};
+
+#ifdef CONFIG_PM
+static const struct wiphy_wowlan_support rtw_wowlan_stub_8922d = {
+ .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT |
+ WIPHY_WOWLAN_NET_DETECT,
+ .n_patterns = RTW89_MAX_PATTERN_NUM,
+ .pattern_max_len = RTW89_MAX_PATTERN_SIZE,
+ .pattern_min_len = 1,
+ .max_nd_match_sets = RTW89_SCANOFLD_MAX_SSID,
+};
+#endif
+
+static const struct rtw89_chip_ops rtw8922d_chip_ops = {
+ .enable_bb_rf = rtw8922d_mac_enable_bb_rf,
+ .disable_bb_rf = rtw8922d_mac_disable_bb_rf,
+ .bb_preinit = rtw8922d_bb_preinit,
+ .bb_postinit = rtw8922d_bb_postinit,
+ .bb_reset = rtw8922d_bb_reset,
+ .bb_sethw = rtw8922d_bb_sethw,
+ .read_rf = rtw89_phy_read_rf_v3,
+ .write_rf = rtw89_phy_write_rf_v3,
+ .set_channel = rtw8922d_set_channel,
+ .set_channel_help = rtw8922d_set_channel_help,
+ .read_efuse = rtw8922d_read_efuse,
+ .read_phycap = rtw8922d_read_phycap,
+ .fem_setup = NULL,
+ .rfe_gpio = NULL,
+ .rfk_hw_init = rtw8922d_rfk_hw_init,
+ .rfk_init = rtw8922d_rfk_init,
+ .rfk_init_late = rtw8922d_rfk_init_late,
+ .rfk_channel = rtw8922d_rfk_channel,
+ .rfk_band_changed = rtw8922d_rfk_band_changed,
+ .rfk_scan = rtw8922d_rfk_scan,
+ .rfk_track = rtw8922d_rfk_track,
+ .power_trim = rtw8922d_power_trim,
+ .set_txpwr = rtw8922d_set_txpwr,
+ .set_txpwr_ctrl = rtw8922d_set_txpwr_ctrl,
+ .init_txpwr_unit = NULL,
+ .get_thermal = rtw8922d_get_thermal,
+ .chan_to_rf18_val = rtw8922d_chan_to_rf18_val,
+ .ctrl_btg_bt_rx = rtw8922d_set_gbt_bt_rx_sel,
+ .query_ppdu = rtw8922d_query_ppdu,
+ .convert_rpl_to_rssi = rtw8922d_convert_rpl_to_rssi,
+ .phy_rpt_to_rssi = rtw8922d_phy_rpt_to_rssi,
+ .ctrl_nbtg_bt_tx = rtw8922d_ctrl_nbtg_bt_tx,
+ .cfg_txrx_path = rtw8922d_bb_cfg_txrx_path,
+ .set_txpwr_ul_tb_offset = NULL,
+ .digital_pwr_comp = rtw8922d_digital_pwr_comp,
+ .calc_rx_gain_normal = rtw8922d_calc_rx_gain_normal,
+ .pwr_on_func = rtw8922d_pwr_on_func,
+ .pwr_off_func = rtw8922d_pwr_off_func,
+ .query_rxdesc = rtw89_core_query_rxdesc_v3,
+ .fill_txdesc = rtw89_core_fill_txdesc_v3,
+ .fill_txdesc_fwcmd = rtw89_core_fill_txdesc_fwcmd_v2,
+ .get_ch_dma = {rtw89_core_get_ch_dma_v1,
+ NULL,
+ NULL,},
+ .cfg_ctrl_path = rtw89_mac_cfg_ctrl_path_v2,
+ .mac_cfg_gnt = rtw89_mac_cfg_gnt_v3,
+ .stop_sch_tx = rtw89_mac_stop_sch_tx_v2,
+ .resume_sch_tx = rtw89_mac_resume_sch_tx_v2,
+ .h2c_dctl_sec_cam = rtw89_fw_h2c_dctl_sec_cam_v3,
+ .h2c_default_cmac_tbl = rtw89_fw_h2c_default_cmac_tbl_be,
+ .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl_be,
+ .h2c_ampdu_cmac_tbl = rtw89_fw_h2c_ampdu_cmac_tbl_be,
+ .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl_be,
+ .h2c_punctured_cmac_tbl = rtw89_fw_h2c_punctured_cmac_tbl_be,
+ .h2c_default_dmac_tbl = rtw89_fw_h2c_default_dmac_tbl_v3,
+ .h2c_update_beacon = rtw89_fw_h2c_update_beacon_be,
+ .h2c_ba_cam = rtw89_fw_h2c_ba_cam_v1,
+ .h2c_wow_cam_update = rtw89_fw_h2c_wow_cam_update_v1,
+
+ .btc_set_rfe = rtw8922d_btc_set_rfe,
+ .btc_init_cfg = rtw8922d_btc_init_cfg,
+ .btc_set_wl_pri = NULL,
+ .btc_set_wl_txpwr_ctrl = rtw8922d_btc_set_wl_txpwr_ctrl,
+ .btc_get_bt_rssi = rtw8922d_btc_get_bt_rssi,
+ .btc_update_bt_cnt = rtw8922d_btc_update_bt_cnt,
+ .btc_wl_s1_standby = rtw8922d_btc_wl_s1_standby,
+ .btc_set_wl_rx_gain = rtw8922d_btc_set_wl_rx_gain,
+ .btc_set_policy = rtw89_btc_set_policy_v1,
+};
+
+const struct rtw89_chip_info rtw8922d_chip_info = {
+ .chip_id = RTL8922D,
+ .chip_gen = RTW89_CHIP_BE,
+ .ops = &rtw8922d_chip_ops,
+ .mac_def = &rtw89_mac_gen_be,
+ .phy_def = &rtw89_phy_gen_be_v1,
+ .fw_def = {
+ .fw_basename = RTW8922D_FW_BASENAME,
+ .fw_format_max = RTW8922D_FW_FORMAT_MAX,
+ .fw_b_aid = RTL8922D_AID7102,
+ },
+ .try_ce_fw = false,
+ .bbmcu_nr = 0,
+ .needed_fw_elms = RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS_V1,
+ .fw_blacklist = &rtw89_fw_blacklist_default,
+ .fifo_size = 393216,
+ .small_fifo_size = false,
+ .dle_scc_rsvd_size = 0,
+ .max_amsdu_limit = 11000,
+ .max_vht_mpdu_cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991,
+ .max_eht_mpdu_cap = IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991,
+ .max_tx_agg_num = 128,
+ .max_rx_agg_num = 256,
+ .dis_2g_40m_ul_ofdma = false,
+ .rsvd_ple_ofst = 0x5f800,
+ .hfc_param_ini = {rtw8922d_hfc_param_ini_pcie, NULL, NULL},
+ .dle_mem = {rtw8922d_dle_mem_pcie, NULL, NULL, NULL},
+ .wde_qempty_acq_grpnum = 8,
+ .wde_qempty_mgq_grpsel = 8,
+ .rf_base_addr = {0x3e000, 0x3f000},
+ .thermal_th = {0xac, 0xad},
+ .pwr_on_seq = NULL,
+ .pwr_off_seq = NULL,
+ .bb_table = NULL,
+ .bb_gain_table = NULL,
+ .rf_table = {},
+ .nctl_table = NULL,
+ .nctl_post_table = &rtw8922d_nctl_post_defs_tbl,
+ .dflt_parms = NULL, /* load parm from fw */
+ .rfe_parms_conf = NULL, /* load parm from fw */
+ .chanctx_listener = &rtw8922d_chanctx_listener,
+ .txpwr_factor_bb = 3,
+ .txpwr_factor_rf = 2,
+ .txpwr_factor_mac = 1,
+ .dig_table = NULL,
+ .dig_regs = &rtw8922d_dig_regs,
+ .tssi_dbw_table = NULL,
+ .support_macid_num = 64,
+ .support_link_num = 2,
+ .support_chanctx_num = 2,
+ .support_rnr = true,
+ .support_bands = BIT(NL80211_BAND_2GHZ) |
+ BIT(NL80211_BAND_5GHZ) |
+ BIT(NL80211_BAND_6GHZ),
+ .support_bandwidths = BIT(NL80211_CHAN_WIDTH_20) |
+ BIT(NL80211_CHAN_WIDTH_40) |
+ BIT(NL80211_CHAN_WIDTH_80) |
+ BIT(NL80211_CHAN_WIDTH_160),
+ .support_unii4 = true,
+ .support_ant_gain = false,
+ .support_tas = false,
+ .support_sar_by_ant = true,
+ .support_noise = false,
+ .ul_tb_waveform_ctrl = false,
+ .ul_tb_pwr_diff = false,
+ .rx_freq_frome_ie = false,
+ .hw_sec_hdr = true,
+ .hw_mgmt_tx_encrypt = true,
+ .hw_tkip_crypto = true,
+ .hw_mlo_bmc_crypto = true,
+ .rf_path_num = 2,
+ .tx_nss = 2,
+ .rx_nss = 2,
+ .acam_num = 128,
+ .bcam_num = 16,
+ .scam_num = 32,
+ .bacam_num = 24,
+ .bacam_dynamic_num = 8,
+ .bacam_ver = RTW89_BACAM_V1,
+ .addrcam_ver = 1,
+ .ppdu_max_usr = 16,
+ .sec_ctrl_efuse_size = 4,
+ .physical_efuse_size = 0x1300,
+ .logical_efuse_size = 0x70000,
+ .limit_efuse_size = 0x40000,
+ .dav_phy_efuse_size = 0,
+ .dav_log_efuse_size = 0,
+ .efuse_blocks = rtw8922d_efuse_blocks,
+ .phycap_addr = 0x1700,
+ .phycap_size = 0x60,
+ .para_ver = 0x3ff,
+ .wlcx_desired = 0x09150000,
+ .scbd = 0x1,
+ .mailbox = 0x1,
+
+ .afh_guard_ch = 6,
+ .wl_rssi_thres = rtw89_btc_8922d_wl_rssi_thres,
+ .bt_rssi_thres = rtw89_btc_8922d_bt_rssi_thres,
+ .rssi_tol = 2,
+ .mon_reg_num = ARRAY_SIZE(rtw89_btc_8922d_mon_reg),
+ .mon_reg = rtw89_btc_8922d_mon_reg,
+ .rf_para_ulink_v9 = rtw89_btc_8922d_rf_ul_v9,
+ .rf_para_dlink_v9 = rtw89_btc_8922d_rf_dl_v9,
+ .rf_para_ulink_num_v9 = ARRAY_SIZE(rtw89_btc_8922d_rf_ul_v9),
+ .rf_para_dlink_num_v9 = ARRAY_SIZE(rtw89_btc_8922d_rf_dl_v9),
+ .ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
+ BIT(RTW89_PS_MODE_CLK_GATED) |
+ BIT(RTW89_PS_MODE_PWR_GATED),
+ .low_power_hci_modes = 0,
+ .h2c_cctl_func_id = H2C_FUNC_MAC_CCTLINFO_UD_G7,
+ .hci_func_en_addr = R_BE_HCI_FUNC_EN,
+ .h2c_desc_size = sizeof(struct rtw89_rxdesc_short_v3),
+ .txwd_body_size = sizeof(struct rtw89_txwd_body_v2),
+ .txwd_info_size = sizeof(struct rtw89_txwd_info_v2),
+ .h2c_ctrl_reg = R_BE_H2CREG_CTRL,
+ .h2c_counter_reg = {R_BE_UDM1 + 1, B_BE_UDM1_HALMAC_H2C_DEQ_CNT_MASK >> 8},
+ .h2c_regs = rtw8922d_h2c_regs,
+ .c2h_ctrl_reg = R_BE_C2HREG_CTRL,
+ .c2h_counter_reg = {R_BE_UDM1 + 1, B_BE_UDM1_HALMAC_C2H_ENQ_CNT_MASK >> 8},
+ .c2h_regs = rtw8922d_c2h_regs,
+ .page_regs = &rtw8922d_page_regs,
+ .wow_reason_reg = rtw8922d_wow_wakeup_regs,
+ .cfo_src_fd = true,
+ .cfo_hw_comp = true,
+ .dcfo_comp = NULL,
+ .dcfo_comp_sft = 0,
+ .nhm_report = NULL,
+ .nhm_th = NULL,
+ .imr_info = NULL,
+ .imr_dmac_table = &rtw8922d_imr_dmac_table,
+ .imr_cmac_table = &rtw8922d_imr_cmac_table,
+ .rrsr_cfgs = &rtw8922d_rrsr_cfgs,
+ .bss_clr_vld = {R_BSS_CLR_VLD_BE4, B_BSS_CLR_VLD_BE4},
+ .bss_clr_map_reg = R_BSS_CLR_MAP_BE4,
+ .rfkill_init = &rtw8922d_rfkill_regs,
+ .rfkill_get = {R_BE_GPIO_EXT_CTRL, B_BE_GPIO_IN_9},
+ .btc_sb = {{{R_BE_SCOREBOARD_0, R_BE_SCOREBOARD_0_BT_DATA},
+ {R_BE_SCOREBOARD_1, R_BE_SCOREBOARD_1_BT_DATA}}},
+ .dma_ch_mask = BIT(RTW89_DMA_ACH1) | BIT(RTW89_DMA_ACH3) |
+ BIT(RTW89_DMA_ACH5) | BIT(RTW89_DMA_ACH7) |
+ BIT(RTW89_DMA_B0HI) | BIT(RTW89_DMA_B1HI),
+ .edcca_regs = &rtw8922d_edcca_regs,
+#ifdef CONFIG_PM
+ .wowlan_stub = &rtw_wowlan_stub_8922d,
+#endif
+ .xtal_info = NULL,
+ .default_quirks = BIT(RTW89_QUIRK_THERMAL_PROT_120C),
+};
+EXPORT_SYMBOL(rtw8922d_chip_info);
+
+static const struct rtw89_fw_def rtw8922de_vs_fw_def = {
+ .fw_basename = RTW8922DS_FW_BASENAME,
+ .fw_format_max = RTW8922DS_FW_FORMAT_MAX,
+ .fw_b_aid = RTL8922D_AID7060,
+};
+
+const struct rtw89_chip_variant rtw8922de_vs_variant = {
+ .no_mcs_12_13 = true,
+ .fw_min_ver_code = RTW89_FW_VER_CODE(0, 0, 0, 0),
+ .fw_def_override = &rtw8922de_vs_fw_def,
+};
+EXPORT_SYMBOL(rtw8922de_vs_variant);
+
MODULE_FIRMWARE(RTW8922D_MODULE_FIRMWARE);
MODULE_FIRMWARE(RTW8922DS_MODULE_FIRMWARE);
MODULE_AUTHOR("Realtek Corporation");
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922d.h b/drivers/net/wireless/realtek/rtw89/rtw8922d.h
index a3b98ad6636c..22a7d1cc244f 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922d.h
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922d.h
@@ -77,4 +77,7 @@ struct rtw8922d_efuse {
struct rtw8922d_rx_gain_6g rx_gain_6g_b_2;
} __packed;
+extern const struct rtw89_chip_info rtw8922d_chip_info;
+extern const struct rtw89_chip_variant rtw8922de_vs_variant;
+
#endif
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH rtw-next 9/9] wifi: rtw89: 8922d: add PCI ID of RTL8922DE and RTL8922DE-VS
2026-03-30 6:58 [PATCH rtw-next 0/9] wifi: rtw89: 8922d: add RTL8922DE part 2/2 Ping-Ke Shih
` (7 preceding siblings ...)
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 ` Ping-Ke Shih
8 siblings, 0 replies; 10+ messages in thread
From: Ping-Ke Shih @ 2026-03-30 6:58 UTC (permalink / raw)
To: linux-wireless
Add PCI ID tables with RTL8922DE whose ID is 10EC:895D, and with
RTL8922DE-VS whose ID are 10EC:892D and 10EC:882D. Also, add pci_info
struct to describe the hardware capabilities and registers accordingly.
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/pci.h | 3 +
.../net/wireless/realtek/rtw89/rtw8922de.c | 119 ++++++++++++++++++
2 files changed, 122 insertions(+)
create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8922de.c
diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h
index c7cd34e99349..e7da37b9da7d 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.h
+++ b/drivers/net/wireless/realtek/rtw89/pci.h
@@ -1105,6 +1105,9 @@
B_BE_CH6_BUSY | B_BE_CH7_BUSY | B_BE_CH8_BUSY | \
B_BE_CH9_BUSY | B_BE_CH10_BUSY | B_BE_CH11_BUSY | \
B_BE_CH12_BUSY | B_BE_CH13_BUSY | B_BE_CH14_BUSY)
+#define DMA_BUSY1_CHECK_BE_V1 (B_BE_CH0_BUSY | B_BE_CH2_BUSY | B_BE_CH4_BUSY | \
+ B_BE_CH6_BUSY | B_BE_CH8_BUSY | B_BE_CH10_BUSY | \
+ B_BE_CH12_BUSY)
#define R_BE_HAXI_EXP_CTRL_V1 0xB020
#define B_BE_R_NO_SEC_ACCESS BIT(31)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922de.c b/drivers/net/wireless/realtek/rtw89/rtw8922de.c
new file mode 100644
index 000000000000..f144e7fc76de
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922de.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2026 Realtek Corporation
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "pci.h"
+#include "reg.h"
+#include "rtw8922d.h"
+
+static const struct rtw89_pci_info rtw8922d_pci_info = {
+ .gen_def = &rtw89_pci_gen_be,
+ .isr_def = &rtw89_pci_isr_be_v1,
+ .txbd_trunc_mode = MAC_AX_BD_TRUNC,
+ .rxbd_trunc_mode = MAC_AX_BD_TRUNC,
+ .rxbd_mode = MAC_AX_RXBD_PKT,
+ .tag_mode = MAC_AX_TAG_MULTI,
+ .tx_burst = MAC_AX_TX_BURST_V1_256B,
+ .rx_burst = MAC_AX_RX_BURST_V1_128B,
+ .wd_dma_idle_intvl = MAC_AX_WD_DMA_INTVL_256NS,
+ .wd_dma_act_intvl = MAC_AX_WD_DMA_INTVL_256NS,
+ .multi_tag_num = MAC_AX_TAG_NUM_8,
+ .lbc_en = MAC_AX_PCIE_ENABLE,
+ .lbc_tmr = MAC_AX_LBC_TMR_2MS,
+ .autok_en = MAC_AX_PCIE_DISABLE,
+ .io_rcy_en = MAC_AX_PCIE_ENABLE,
+ .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_DEF,
+ .rx_ring_eq_is_full = true,
+ .check_rx_tag = true,
+ .no_rxbd_fs = true,
+ .group_bd_addr = true,
+ .rpp_fmt_size = sizeof(struct rtw89_pci_rpp_fmt_v1),
+
+ .init_cfg_reg = R_BE_HAXI_INIT_CFG1,
+ .txhci_en_bit = B_BE_TXDMA_EN,
+ .rxhci_en_bit = B_BE_RXDMA_EN,
+ .rxbd_mode_bit = B_BE_RXQ_RXBD_MODE_MASK,
+ .exp_ctrl_reg = R_BE_HAXI_EXP_CTRL_V1,
+ .max_tag_num_mask = B_BE_MAX_TAG_NUM_MASK,
+ .rxbd_rwptr_clr_reg = R_BE_RXBD_RWPTR_CLR1_V1,
+ .txbd_rwptr_clr2_reg = R_BE_TXBD_RWPTR_CLR1,
+ .dma_io_stop = {R_BE_HAXI_INIT_CFG1, B_BE_STOP_AXI_MST},
+ .dma_stop1 = {R_BE_HAXI_DMA_STOP1, B_BE_TX_STOP1_MASK_V1},
+ .dma_stop2 = {0},
+ .dma_busy1 = {R_BE_HAXI_DMA_BUSY1, DMA_BUSY1_CHECK_BE_V1},
+ .dma_busy2_reg = 0,
+ .dma_busy3_reg = R_BE_HAXI_DMA_BUSY1,
+
+ .rpwm_addr = R_BE_PCIE_HRPWM,
+ .cpwm_addr = R_BE_PCIE_CRPWM,
+ .mit_addr = R_BE_PCIE_MIT_CH_EN,
+ .wp_sel_addr = R_BE_WP_ADDR_H_SEL0_3_V1,
+ .tx_dma_ch_mask = BIT(RTW89_TXCH_ACH1) | BIT(RTW89_TXCH_ACH3) |
+ BIT(RTW89_TXCH_ACH5) | BIT(RTW89_TXCH_ACH7) |
+ BIT(RTW89_TXCH_CH9) | BIT(RTW89_TXCH_CH11),
+ .bd_idx_addr_low_power = NULL,
+ .dma_addr_set = &rtw89_pci_ch_dma_addr_set_be_v1,
+ .bd_ram_table = NULL,
+
+ .ltr_set = rtw89_pci_ltr_set_v2,
+ .fill_txaddr_info = rtw89_pci_fill_txaddr_info_v1,
+ .parse_rpp = rtw89_pci_parse_rpp_v1,
+ .config_intr_mask = rtw89_pci_config_intr_mask_v3,
+ .enable_intr = rtw89_pci_enable_intr_v3,
+ .disable_intr = rtw89_pci_disable_intr_v3,
+ .recognize_intrs = rtw89_pci_recognize_intrs_v3,
+
+ .ssid_quirks = NULL,
+};
+
+static const struct rtw89_driver_info rtw89_8922de_vs_info = {
+ .chip = &rtw8922d_chip_info,
+ .variant = &rtw8922de_vs_variant,
+ .quirks = NULL,
+ .bus = {
+ .pci = &rtw8922d_pci_info,
+ },
+};
+
+static const struct rtw89_driver_info rtw89_8922de_info = {
+ .chip = &rtw8922d_chip_info,
+ .variant = NULL,
+ .quirks = NULL,
+ .bus = {
+ .pci = &rtw8922d_pci_info,
+ },
+};
+
+static const struct pci_device_id rtw89_8922de_id_table[] = {
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x892D),
+ .driver_data = (kernel_ulong_t)&rtw89_8922de_vs_info,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x882D),
+ .driver_data = (kernel_ulong_t)&rtw89_8922de_vs_info,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x895D),
+ .driver_data = (kernel_ulong_t)&rtw89_8922de_info,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(pci, rtw89_8922de_id_table);
+
+static struct pci_driver rtw89_8922de_driver = {
+ .name = "rtw89_8922de",
+ .id_table = rtw89_8922de_id_table,
+ .probe = rtw89_pci_probe,
+ .remove = rtw89_pci_remove,
+ .driver.pm = &rtw89_pm_ops_be,
+ .err_handler = &rtw89_pci_err_handler,
+};
+module_pci_driver(rtw89_8922de_driver);
+
+MODULE_AUTHOR("Realtek Corporation");
+MODULE_DESCRIPTION("Realtek 802.11be wireless 8922DE/8922DE-VS driver");
+MODULE_LICENSE("Dual BSD/GPL");
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread