OSDN Git Service

rtw88: coex: Add WLAN MIMO power saving for Bluetooth gaming controller
authorChing-Te Ku <ku920601@realtek.com>
Tue, 15 Feb 2022 00:48:53 +0000 (08:48 +0800)
committerKalle Valo <kvalo@kernel.org>
Mon, 21 Feb 2022 08:49:09 +0000 (10:49 +0200)
To keep high sensitivity reaction, Bluetooth gaming controller will send
packet very frequently, it will make WLAN performance very poor. To solve
this situation, MIMO PS mechanism makes WLAN/BT own an antenna itself, WLAN
quits 2SS performance but it can get a stable 1SS performance and Bluetooth
gaming controller can keep sensitivity reaction at the same time.

Signed-off-by: Ching-Te Ku <ku920601@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/20220215004855.4098-5-pkshih@realtek.com
drivers/net/wireless/realtek/rtw88/coex.c
drivers/net/wireless/realtek/rtw88/coex.h
drivers/net/wireless/realtek/rtw88/main.h
drivers/net/wireless/realtek/rtw88/rtw8723d.c
drivers/net/wireless/realtek/rtw88/rtw8821c.c
drivers/net/wireless/realtek/rtw88/rtw8822b.c
drivers/net/wireless/realtek/rtw88/rtw8822c.c

index 0aca8f0..632151f 100644 (file)
@@ -211,6 +211,10 @@ static void rtw_coex_wl_ccklock_detect(struct rtw_dev *rtwdev)
 
        bool is_cck_lock_rate = false;
 
+       if (coex_stat->wl_coex_mode != COEX_WLINK_2G1PORT &&
+           coex_stat->wl_coex_mode != COEX_WLINK_2GFREE)
+               return;
+
        if (coex_dm->bt_status == COEX_BTSTATUS_INQ_PAGE ||
            coex_stat->bt_setup_link) {
                coex_stat->wl_cck_lock = false;
@@ -803,7 +807,9 @@ static void rtw_coex_update_bt_link_info(struct rtw_dev *rtwdev)
 static void rtw_coex_update_wl_ch_info(struct rtw_dev *rtwdev, u8 type)
 {
        struct rtw_chip_info *chip = rtwdev->chip;
+       struct rtw_efuse *efuse = &rtwdev->efuse;
        struct rtw_coex_dm *coex_dm = &rtwdev->coex.dm;
+       struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
        u8 link = 0;
        u8 center_chan = 0;
        u8 bw;
@@ -814,7 +820,9 @@ static void rtw_coex_update_wl_ch_info(struct rtw_dev *rtwdev, u8 type)
        if (type != COEX_MEDIA_DISCONNECT)
                center_chan = rtwdev->hal.current_channel;
 
-       if (center_chan == 0) {
+       if (center_chan == 0 ||
+           (efuse->share_ant && center_chan <= 14 &&
+            coex_stat->wl_coex_mode != COEX_WLINK_2GFREE)) {
                link = 0;
                center_chan = 0;
                bw = 0;
@@ -953,6 +961,23 @@ static void rtw_coex_set_gnt_wl(struct rtw_dev *rtwdev, u8 state)
        rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x0300, state);
 }
 
+static void rtw_coex_mimo_ps(struct rtw_dev *rtwdev, bool force, bool state)
+{
+       struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
+
+       if (!force && state == coex_stat->wl_mimo_ps)
+               return;
+
+       coex_stat->wl_mimo_ps = state;
+
+       rtw_set_txrx_1ss(rtwdev, state);
+
+       rtw_coex_update_wl_ch_info(rtwdev, (u8)coex_stat->wl_connected);
+
+       rtw_dbg(rtwdev, RTW_DBG_COEX,
+               "[BTCoex], %s(): state = %d\n", __func__, state);
+}
+
 static void rtw_btc_wltoggle_table_a(struct rtw_dev *rtwdev, bool force,
                                     u8 table_case)
 {
@@ -1129,7 +1154,8 @@ static void rtw_coex_set_tdma(struct rtw_dev *rtwdev, u8 byte1, u8 byte2,
 
                ps_type = COEX_PS_WIFI_NATIVE;
                rtw_coex_power_save_state(rtwdev, ps_type, 0x0, 0x0);
-       } else if (byte1 & BIT(4) && !(byte1 & BIT(5))) {
+       } else if ((byte1 & BIT(4) && !(byte1 & BIT(5))) ||
+                  coex_stat->wl_coex_mode == COEX_WLINK_2GFREE) {
                rtw_dbg(rtwdev, RTW_DBG_COEX,
                        "[BTCoex], %s(): Force LPS (byte1 = 0x%x)\n", __func__,
                        byte1);
@@ -1825,6 +1851,54 @@ static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev)
        rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);
 }
 
+static void rtw_coex_action_bt_game_hid(struct rtw_dev *rtwdev)
+{
+       struct rtw_coex *coex = &rtwdev->coex;
+       struct rtw_coex_stat *coex_stat = &coex->stat;
+       struct rtw_efuse *efuse = &rtwdev->efuse;
+       struct rtw_coex_dm *coex_dm = &coex->dm;
+       struct rtw_chip_info *chip = rtwdev->chip;
+       u8 table_case, tdma_case;
+
+       rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
+       rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
+
+       if (efuse->share_ant) {
+               coex_stat->wl_coex_mode = COEX_WLINK_2GFREE;
+               if (coex_stat->bt_whck_test)
+                       table_case = 2;
+               else if (coex_stat->wl_linkscan_proc || coex_stat->bt_hid_exist)
+                       table_case = 33;
+               else if (coex_stat->bt_setup_link || coex_stat->bt_inq_page)
+                       table_case = 0;
+               else if (coex_stat->bt_a2dp_exist)
+                       table_case = 34;
+               else
+                       table_case = 33;
+
+               tdma_case = 0;
+       } else {
+               if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]))
+                       tdma_case = 112;
+               else
+                       tdma_case = 113;
+
+               table_case = 121;
+       }
+
+       if (coex_stat->wl_coex_mode == COEX_WLINK_2GFREE) {
+               if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX)
+                       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_tx[6]);
+               else
+                       rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[5]);
+       } else {
+               rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
+       }
+
+       rtw_coex_table(rtwdev, false, table_case);
+       rtw_coex_tdma(rtwdev, false, tdma_case);
+}
+
 static void rtw_coex_action_bt_hfp(struct rtw_dev *rtwdev)
 {
        struct rtw_coex *coex = &rtwdev->coex;
@@ -2242,8 +2316,10 @@ static void rtw_coex_action_bt_a2dp_pan_hid(struct rtw_dev *rtwdev)
 
 static void rtw_coex_action_wl_under5g(struct rtw_dev *rtwdev)
 {
+       struct rtw_coex *coex = &rtwdev->coex;
        struct rtw_efuse *efuse = &rtwdev->efuse;
        struct rtw_chip_info *chip = rtwdev->chip;
+       struct rtw_coex_stat *coex_stat = &coex->stat;
        u8 table_case, tdma_case;
 
        rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
@@ -2253,6 +2329,9 @@ static void rtw_coex_action_wl_under5g(struct rtw_dev *rtwdev)
 
        rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false);
 
+       if (coex_stat->bt_game_hid_exist && coex_stat->wl_linkscan_proc)
+               coex_stat->wl_coex_mode = COEX_WLINK_2GFREE;
+
        if (efuse->share_ant) {
                /* Shared-Ant */
                table_case = 0;
@@ -2440,6 +2519,7 @@ static void rtw_coex_action_wl_connected(struct rtw_dev *rtwdev)
 static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason)
 {
        struct rtw_coex *coex = &rtwdev->coex;
+       struct rtw_chip_info *chip = rtwdev->chip;
        struct rtw_coex_dm *coex_dm = &coex->dm;
        struct rtw_coex_stat *coex_stat = &coex->stat;
        bool rf4ce_en = false;
@@ -2512,6 +2592,11 @@ static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason)
                goto exit;
        }
 
+       if (coex_stat->bt_game_hid_exist && coex_stat->wl_connected) {
+               rtw_coex_action_bt_game_hid(rtwdev);
+               goto exit;
+       }
+
        if (coex_stat->bt_whck_test) {
                rtw_coex_action_bt_whql_test(rtwdev);
                goto exit;
@@ -2548,6 +2633,18 @@ static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason)
        }
 
 exit:
+
+       if (chip->wl_mimo_ps_support) {
+               if (coex_stat->wl_coex_mode == COEX_WLINK_2GFREE) {
+                       if (coex_dm->reason == COEX_RSN_2GMEDIA)
+                               rtw_coex_mimo_ps(rtwdev, true, true);
+                       else
+                               rtw_coex_mimo_ps(rtwdev, false, true);
+               } else {
+                       rtw_coex_mimo_ps(rtwdev, false, false);
+               }
+       }
+
        rtw_coex_gnt_workaround(rtwdev, false, coex_stat->wl_coex_mode);
        rtw_coex_limited_wl(rtwdev);
 }
@@ -3152,6 +3249,17 @@ void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
                coex_stat->bt_a2dp_bitpool = 0;
 
        coex_stat->bt_a2dp_sink = ((coex_stat->bt_info_hb3 & BIT(7)) == BIT(7));
+       if (chip->wl_mimo_ps_support && !coex_stat->bt_inq_page) {
+               if ((coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION) &&
+                   (coex_stat->hi_pri_tx + coex_stat->hi_pri_rx >
+                    COEX_BT_GAMEHID_CNT) && !coex_stat->bt_slave) {
+                       coex_stat->bt_game_hid_exist = true;
+                       rtw_dbg(rtwdev, RTW_DBG_COEX,
+                               "[BTCoex], BT game controller exisit!!\n");
+               } else {
+                       coex_stat->bt_game_hid_exist = false;
+               }
+       }
 
        rtw_coex_update_bt_link_info(rtwdev);
        rtw_coex_run_coex(rtwdev, COEX_RSN_BTINFO);
@@ -3666,6 +3774,7 @@ static const char *rtw_coex_get_wl_coex_mode(u8 coex_wl_link_mode)
        switch (coex_wl_link_mode) {
        case_WLINK(2G1PORT);
        case_WLINK(5G);
+       case_WLINK(2GFREE);
        default:
                return "Unknown";
        }
index 60a701c..498b643 100644 (file)
@@ -11,6 +11,7 @@
 
 #define COEX_MIN_DELAY         10 /* delay unit in ms */
 #define COEX_RFK_TIMEOUT       600 /* RFK timeout in ms */
+#define COEX_BT_GAMEHID_CNT    800
 
 #define COEX_RF_OFF    0x0
 #define COEX_RF_ON     0x1
@@ -172,6 +173,7 @@ enum coex_bt_profile {
 enum coex_wl_link_mode {
        COEX_WLINK_2G1PORT      = 0x0,
        COEX_WLINK_5G           = 0x3,
+       COEX_WLINK_2GFREE       = 0x7,
        COEX_WLINK_MAX
 };
 
index 970d29d..e62b085 100644 (file)
@@ -1242,6 +1242,7 @@ struct rtw_chip_info {
        bool scbd_support;
        bool new_scbd10_def; /* true: fix 2M(8822c) */
        bool ble_hid_profile_support;
+       bool wl_mimo_ps_support;
        u8 pstdma_type; /* 0: LPSoff, 1:LPSon */
        u8 bt_rssi_type;
        u8 ant_isolation;
@@ -1384,6 +1385,7 @@ struct rtw_coex_stat {
        bool bt_slave;
        bool bt_418_hid_exist;
        bool bt_ble_hid_exist;
+       bool bt_game_hid_exist;
        bool bt_mailbox_reply;
 
        bool wl_under_lps;
@@ -1404,6 +1406,7 @@ struct rtw_coex_stat {
        bool wl_connecting;
        bool wl_slot_toggle;
        bool wl_slot_toggle_change; /* if toggle to no-toggle */
+       bool wl_mimo_ps;
 
        u32 bt_supported_version;
        u32 bt_supported_feature;
index 3fdbaf7..ad2b323 100644 (file)
@@ -2753,6 +2753,7 @@ struct rtw_chip_info rtw8723d_hw_spec = {
        .scbd_support = true,
        .new_scbd10_def = true,
        .ble_hid_profile_support = false,
+       .wl_mimo_ps_support = false,
        .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF,
        .bt_rssi_type = COEX_BTRSSI_RATIO,
        .ant_isolation = 15,
index b1f4afb..a1ae1e7 100644 (file)
@@ -1925,6 +1925,7 @@ struct rtw_chip_info rtw8821c_hw_spec = {
        .scbd_support = true,
        .new_scbd10_def = false,
        .ble_hid_profile_support = false,
+       .wl_mimo_ps_support = false,
        .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF,
        .bt_rssi_type = COEX_BTRSSI_RATIO,
        .ant_isolation = 15,
index dd4fbb8..c9cedc3 100644 (file)
@@ -2554,6 +2554,7 @@ struct rtw_chip_info rtw8822b_hw_spec = {
        .scbd_support = true,
        .new_scbd10_def = false,
        .ble_hid_profile_support = false,
+       .wl_mimo_ps_support = false,
        .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF,
        .bt_rssi_type = COEX_BTRSSI_RATIO,
        .ant_isolation = 15,
index 01bb356..39daca4 100644 (file)
@@ -2996,19 +2996,34 @@ static void rtw8822c_coex_cfg_gnt_fix(struct rtw_dev *rtwdev)
         * enable "DAC off if GNT_WL = 0" for non-shared-antenna
         * disable 0x1c30[22] = 0,
         * enable: 0x1c30[22] = 1, 0x1c38[12] = 0, 0x1c38[28] = 1
-        *
-        * disable WL-S1 BB chage RF mode if GNT_BT
+        */
+       if (coex_stat->wl_coex_mode == COEX_WLINK_2GFREE) {
+               rtw_write8_mask(rtwdev, REG_ANAPAR + 2,
+                               BIT_ANAPAR_BTPS >> 16, 0);
+       } else {
+               rtw_write8_mask(rtwdev, REG_ANAPAR + 2,
+                               BIT_ANAPAR_BTPS >> 16, 1);
+               rtw_write8_mask(rtwdev, REG_RSTB_SEL + 1,
+                               BIT_DAC_OFF_ENABLE, 0);
+               rtw_write8_mask(rtwdev, REG_RSTB_SEL + 3,
+                               BIT_DAC_OFF_ENABLE, 1);
+       }
+
+       /* disable WL-S1 BB chage RF mode if GNT_BT
         * since RF TRx mask can do it
         */
-       rtw_write8_mask(rtwdev, REG_ANAPAR + 2, BIT_ANAPAR_BTPS >> 16, 1);
-       rtw_write8_mask(rtwdev, REG_RSTB_SEL + 1, BIT_DAC_OFF_ENABLE, 0);
-       rtw_write8_mask(rtwdev, REG_RSTB_SEL + 3, BIT_DAC_OFF_ENABLE, 1);
-       rtw_write8_mask(rtwdev, REG_IGN_GNTBT4, BIT_PI_IGNORE_GNT_BT, 1);
+       rtw_write8_mask(rtwdev, REG_IGN_GNTBT4,
+                       BIT_PI_IGNORE_GNT_BT, 1);
 
        /* disable WL-S0 BB chage RF mode if wifi is at 5G,
         * or antenna path is separated
         */
-       if (coex_stat->wl_coex_mode == COEX_WLINK_5G ||
+       if (coex_stat->wl_coex_mode == COEX_WLINK_2GFREE) {
+               rtw_write8_mask(rtwdev, REG_IGN_GNT_BT1,
+                               BIT_PI_IGNORE_GNT_BT, 1);
+               rtw_write8_mask(rtwdev, REG_NOMASK_TXBT,
+                               BIT_NOMASK_TXBT_ENABLE, 1);
+       } else if (coex_stat->wl_coex_mode == COEX_WLINK_5G ||
            coex->under_5g || !efuse->share_ant) {
                if (coex_stat->kt_ver >= 3) {
                        rtw_write8_mask(rtwdev, REG_IGN_GNT_BT1,
@@ -5008,6 +5023,8 @@ static const struct coex_table_para table_sant_8822c[] = {
        {0x66556aaa, 0x6a5a6aaa}, /*case-30*/
        {0xffffffff, 0x5aaa5aaa},
        {0x56555555, 0x5a5a5aaa},
+       {0xdaffdaff, 0xdaffdaff},
+       {0xddffddff, 0xddffddff},
 };
 
 /* Non-Shared-Antenna Coex Table */
@@ -5108,7 +5125,8 @@ static const struct coex_rf_para rf_para_tx_8822c[] = {
        {8, 17, true, 4},
        {7, 18, true, 4},
        {6, 19, true, 4},
-       {5, 20, true, 4}
+       {5, 20, true, 4},
+       {0, 21, true, 4}   /* for gamg hid */
 };
 
 static const struct coex_rf_para rf_para_rx_8822c[] = {
@@ -5117,7 +5135,8 @@ static const struct coex_rf_para rf_para_rx_8822c[] = {
        {3, 24, true, 5},
        {2, 26, true, 5},
        {1, 27, true, 5},
-       {0, 28, true, 5}
+       {0, 28, true, 5},
+       {0, 28, true, 5}   /* for gamg hid */
 };
 
 static_assert(ARRAY_SIZE(rf_para_tx_8822c) == ARRAY_SIZE(rf_para_rx_8822c));
@@ -5360,6 +5379,7 @@ struct rtw_chip_info rtw8822c_hw_spec = {
        .scbd_support = true,
        .new_scbd10_def = true,
        .ble_hid_profile_support = true,
+       .wl_mimo_ps_support = true,
        .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF,
        .bt_rssi_type = COEX_BTRSSI_DBM,
        .ant_isolation = 15,