1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* Copyright(c) 2019-2020 Realtek Corporation 3 */ 4 5 #include "coex.h" 6 #include "core.h" 7 #include "debug.h" 8 #include "fw.h" 9 #include "mac.h" 10 #include "ps.h" 11 #include "reg.h" 12 #include "util.h" 13 14 static int rtw89_fw_leave_lps_check(struct rtw89_dev *rtwdev, u8 macid) 15 { 16 u32 pwr_en_bit = 0xE; 17 u32 chk_msk = pwr_en_bit << (4 * macid); 18 u32 polling; 19 int ret; 20 21 ret = read_poll_timeout_atomic(rtw89_read32_mask, polling, !polling, 22 1000, 50000, false, rtwdev, 23 R_AX_PPWRBIT_SETTING, chk_msk); 24 if (ret) { 25 rtw89_info(rtwdev, "rtw89: failed to leave lps state\n"); 26 return -EBUSY; 27 } 28 29 return 0; 30 } 31 32 static void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev) 33 { 34 if (!rtwdev->ps_mode) 35 return; 36 37 if (test_and_set_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags)) 38 return; 39 40 rtw89_mac_power_mode_change(rtwdev, true); 41 } 42 43 void __rtw89_leave_ps_mode(struct rtw89_dev *rtwdev) 44 { 45 if (!rtwdev->ps_mode) 46 return; 47 48 if (test_and_clear_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags)) 49 rtw89_mac_power_mode_change(rtwdev, false); 50 } 51 52 static void __rtw89_enter_lps(struct rtw89_dev *rtwdev, u8 mac_id) 53 { 54 struct rtw89_lps_parm lps_param = { 55 .macid = mac_id, 56 .psmode = RTW89_MAC_AX_PS_MODE_LEGACY, 57 .lastrpwm = RTW89_LAST_RPWM_PS, 58 }; 59 60 rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_FW_CTRL); 61 rtw89_fw_h2c_lps_parm(rtwdev, &lps_param); 62 } 63 64 static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, u8 mac_id) 65 { 66 struct rtw89_lps_parm lps_param = { 67 .macid = mac_id, 68 .psmode = RTW89_MAC_AX_PS_MODE_ACTIVE, 69 .lastrpwm = RTW89_LAST_RPWM_ACTIVE, 70 }; 71 72 rtw89_fw_h2c_lps_parm(rtwdev, &lps_param); 73 rtw89_fw_leave_lps_check(rtwdev, 0); 74 rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON); 75 } 76 77 void rtw89_leave_ps_mode(struct rtw89_dev *rtwdev) 78 { 79 lockdep_assert_held(&rtwdev->mutex); 80 81 __rtw89_leave_ps_mode(rtwdev); 82 } 83 84 void rtw89_enter_lps(struct rtw89_dev *rtwdev, u8 mac_id) 85 { 86 lockdep_assert_held(&rtwdev->mutex); 87 88 if (test_and_set_bit(RTW89_FLAG_LEISURE_PS, rtwdev->flags)) 89 return; 90 91 __rtw89_enter_lps(rtwdev, mac_id); 92 __rtw89_enter_ps_mode(rtwdev); 93 } 94 95 static void rtw89_leave_lps_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) 96 { 97 if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION) 98 return; 99 100 __rtw89_leave_ps_mode(rtwdev); 101 __rtw89_leave_lps(rtwdev, rtwvif->mac_id); 102 } 103 104 void rtw89_leave_lps(struct rtw89_dev *rtwdev) 105 { 106 struct rtw89_vif *rtwvif; 107 108 lockdep_assert_held(&rtwdev->mutex); 109 110 if (!test_and_clear_bit(RTW89_FLAG_LEISURE_PS, rtwdev->flags)) 111 return; 112 113 rtw89_for_each_rtwvif(rtwdev, rtwvif) 114 rtw89_leave_lps_vif(rtwdev, rtwvif); 115 } 116 117 void rtw89_enter_ips(struct rtw89_dev *rtwdev) 118 { 119 struct rtw89_vif *rtwvif; 120 121 set_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags); 122 123 rtw89_for_each_rtwvif(rtwdev, rtwvif) 124 rtw89_mac_vif_deinit(rtwdev, rtwvif); 125 126 rtw89_core_stop(rtwdev); 127 } 128 129 void rtw89_leave_ips(struct rtw89_dev *rtwdev) 130 { 131 struct rtw89_vif *rtwvif; 132 int ret; 133 134 ret = rtw89_core_start(rtwdev); 135 if (ret) 136 rtw89_err(rtwdev, "failed to leave idle state\n"); 137 138 rtw89_set_channel(rtwdev); 139 140 rtw89_for_each_rtwvif(rtwdev, rtwvif) 141 rtw89_mac_vif_init(rtwdev, rtwvif); 142 143 clear_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags); 144 } 145 146 void rtw89_set_coex_ctrl_lps(struct rtw89_dev *rtwdev, bool btc_ctrl) 147 { 148 if (btc_ctrl) 149 rtw89_leave_lps(rtwdev); 150 } 151