wifi: rtw88: 8821c: tweak CCK TX filter setting for SRRC regulation
authorZong-Zhe Yang <kevin_yang@realtek.com>
Wed, 4 Oct 2023 08:50:51 +0000 (16:50 +0800)
committerKalle Valo <kvalo@kernel.org>
Mon, 9 Oct 2023 06:55:03 +0000 (09:55 +0300)
Since new criterion released by SRRC (State Radio Regulatory Commission,
China) is stricter, we have adjusted TX power limit tables for it. But,
due to RTL8821C HW characteristic, we still need to use specific parameter
in CCK TX filter when set channel to avoid violations in some corner cases.

Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20231004085051.205683-6-pkshih@realtek.com
drivers/net/wireless/realtek/rtw88/regd.c
drivers/net/wireless/realtek/rtw88/regd.h
drivers/net/wireless/realtek/rtw88/rtw8821c.c
drivers/net/wireless/realtek/rtw88/rtw8821c.h

index 124fc7ae6a147630673571774a11a3686c424487..7f3b2ea3f2a560a150087a4d693a0c376c9bdabb 100644 (file)
@@ -502,6 +502,14 @@ u8 rtw_regd_get(struct rtw_dev *rtwdev)
 }
 EXPORT_SYMBOL(rtw_regd_get);
 
+bool rtw_regd_srrc(struct rtw_dev *rtwdev)
+{
+       struct rtw_regd *regd = &rtwdev->regd;
+
+       return rtw_reg_match(regd->regulatory, "CN");
+}
+EXPORT_SYMBOL(rtw_regd_srrc);
+
 struct rtw_regd_alternative_t {
        bool set;
        u8 alt;
index 34cb13d0cd9ebce8f3ada4141729f16157241055..3c5a6fd8e6ddd825c81c72bd1702c4b4dcf79185 100644 (file)
@@ -68,4 +68,6 @@ int rtw_regd_init(struct rtw_dev *rtwdev);
 int rtw_regd_hint(struct rtw_dev *rtwdev);
 u8 rtw_regd_get(struct rtw_dev *rtwdev);
 bool rtw_regd_has_alt(u8 regd, u8 *regd_alt);
+bool rtw_regd_srrc(struct rtw_dev *rtwdev);
+
 #endif
index adf224618a2a6f3cae2d8dffc8bce5c7a98b407d..429bb420b0563e5a6b5693c4f1655011d0967ef8 100644 (file)
@@ -381,6 +381,65 @@ static void rtw8821c_set_channel_rxdfir(struct rtw_dev *rtwdev, u8 bw)
        }
 }
 
+static void rtw8821c_cck_tx_filter_srrc(struct rtw_dev *rtwdev, u8 channel, u8 bw)
+{
+       struct rtw_hal *hal = &rtwdev->hal;
+
+       if (channel == 14) {
+               rtw_write32_mask(rtwdev, REG_CCA_FLTR, MASKHWORD, 0xe82c);
+               rtw_write32_mask(rtwdev, REG_TXSF2, MASKDWORD, 0x0000b81c);
+               rtw_write32_mask(rtwdev, REG_TXSF6, MASKLWORD, 0x0000);
+               rtw_write32_mask(rtwdev, REG_TXFILTER, MASKDWORD, 0x00003667);
+
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE2, RFREG_MASK, 0x00002);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWA, RFREG_MASK, 0x0001e);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWD0, RFREG_MASK, 0x00000);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWA, RFREG_MASK, 0x0001c);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWD0, RFREG_MASK, 0x00000);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWA, RFREG_MASK, 0x0000e);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWD0, RFREG_MASK, 0x00000);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWA, RFREG_MASK, 0x0000c);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWD0, RFREG_MASK, 0x00000);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE2, RFREG_MASK, 0x00000);
+       } else if (channel == 13 ||
+                  (channel == 11 && bw == RTW_CHANNEL_WIDTH_40)) {
+               rtw_write32_mask(rtwdev, REG_CCA_FLTR, MASKHWORD, 0xf8fe);
+               rtw_write32_mask(rtwdev, REG_TXSF2, MASKDWORD, 0x64b80c1c);
+               rtw_write32_mask(rtwdev, REG_TXSF6, MASKLWORD, 0x8810);
+               rtw_write32_mask(rtwdev, REG_TXFILTER, MASKDWORD, 0x01235667);
+
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE2, RFREG_MASK, 0x00002);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWA, RFREG_MASK, 0x0001e);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWD0, RFREG_MASK, 0x00027);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWA, RFREG_MASK, 0x0001c);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWD0, RFREG_MASK, 0x00027);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWA, RFREG_MASK, 0x0000e);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWD0, RFREG_MASK, 0x00029);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWA, RFREG_MASK, 0x0000c);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWD0, RFREG_MASK, 0x00026);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE2, RFREG_MASK, 0x00000);
+       } else {
+               rtw_write32_mask(rtwdev, REG_CCA_FLTR, MASKHWORD, 0xe82c);
+               rtw_write32_mask(rtwdev, REG_TXSF2, MASKDWORD,
+                                hal->ch_param[0]);
+               rtw_write32_mask(rtwdev, REG_TXSF6, MASKLWORD,
+                                hal->ch_param[1] & MASKLWORD);
+               rtw_write32_mask(rtwdev, REG_TXFILTER, MASKDWORD,
+                                hal->ch_param[2]);
+
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE2, RFREG_MASK, 0x00002);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWA, RFREG_MASK, 0x0001e);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWD0, RFREG_MASK, 0x00000);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWA, RFREG_MASK, 0x0001c);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWD0, RFREG_MASK, 0x00000);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWA, RFREG_MASK, 0x0000e);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWD0, RFREG_MASK, 0x00000);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWA, RFREG_MASK, 0x0000c);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWD0, RFREG_MASK, 0x00000);
+               rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE2, RFREG_MASK, 0x00000);
+       }
+}
+
 static void rtw8821c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
                                    u8 primary_ch_idx)
 {
@@ -395,6 +454,13 @@ static void rtw8821c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
 
                rtw_write32_mask(rtwdev, REG_TXSCALE_A, 0xf00, 0x0);
                rtw_write32_mask(rtwdev, REG_CLKTRK, 0x1ffe0000, 0x96a);
+
+               if (rtw_regd_srrc(rtwdev)) {
+                       rtw8821c_cck_tx_filter_srrc(rtwdev, channel, bw);
+                       goto set_bw;
+               }
+
+               /* CCK TX filter parameters for default case */
                if (channel == 14) {
                        rtw_write32_mask(rtwdev, REG_TXSF2, MASKDWORD, 0x0000b81c);
                        rtw_write32_mask(rtwdev, REG_TXSF6, MASKLWORD, 0x0000);
@@ -430,6 +496,7 @@ static void rtw8821c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
                        rtw_write32_mask(rtwdev, REG_CLKTRK, 0x1ffe0000, 0x412);
        }
 
+set_bw:
        switch (bw) {
        case RTW_CHANNEL_WIDTH_20:
        default:
index fcff31688c453a1da2930cd3b70f8554eeca5d84..91ed921407bbe7957589bde3af0c34d89916dda7 100644 (file)
@@ -238,6 +238,7 @@ extern const struct rtw_chip_info rtw8821c_hw_spec;
 #define REG_RXSB       0xa00
 #define REG_ADCINI     0xa04
 #define REG_PWRTH      0xa08
+#define REG_CCA_FLTR   0xa20
 #define REG_TXSF2      0xa24
 #define REG_TXSF6      0xa28
 #define REG_FA_CCK     0xa5c