1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* Copyright(c) 2018-2019 Realtek Corporation 3 */ 4 5 #include "main.h" 6 #include "reg.h" 7 #include "fw.h" 8 #include "ps.h" 9 #include "mac.h" 10 #include "coex.h" 11 #include "debug.h" 12 13 static int rtw_ips_pwr_up(struct rtw_dev *rtwdev) 14 { 15 int ret; 16 17 ret = rtw_core_start(rtwdev); 18 if (ret) 19 rtw_err(rtwdev, "leave idle state failed\n"); 20 21 rtw_set_channel(rtwdev); 22 clear_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags); 23 24 return ret; 25 } 26 27 int rtw_enter_ips(struct rtw_dev *rtwdev) 28 { 29 set_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags); 30 31 rtw_coex_ips_notify(rtwdev, COEX_IPS_ENTER); 32 33 rtw_core_stop(rtwdev); 34 rtw_hci_link_ps(rtwdev, true); 35 36 return 0; 37 } 38 39 static void rtw_restore_port_cfg_iter(void *data, u8 *mac, 40 struct ieee80211_vif *vif) 41 { 42 struct rtw_dev *rtwdev = data; 43 struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 44 u32 config = ~0; 45 46 rtw_vif_port_config(rtwdev, rtwvif, config); 47 } 48 49 int rtw_leave_ips(struct rtw_dev *rtwdev) 50 { 51 int ret; 52 53 rtw_hci_link_ps(rtwdev, false); 54 55 ret = rtw_ips_pwr_up(rtwdev); 56 if (ret) { 57 rtw_err(rtwdev, "failed to leave ips state\n"); 58 return ret; 59 } 60 61 rtw_iterate_vifs_atomic(rtwdev, rtw_restore_port_cfg_iter, rtwdev); 62 63 rtw_coex_ips_notify(rtwdev, COEX_IPS_LEAVE); 64 65 return 0; 66 } 67 68 void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter) 69 { 70 u8 request, confirm, polling; 71 u8 polling_cnt; 72 u8 retry_cnt = 0; 73 74 for (retry_cnt = 0; retry_cnt < 3; retry_cnt++) { 75 request = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr); 76 confirm = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr); 77 78 /* toggle to request power mode, others remain 0 */ 79 request ^= request | BIT_RPWM_TOGGLE; 80 if (!enter) { 81 request |= POWER_MODE_ACK; 82 } else { 83 request |= POWER_MODE_LCLK; 84 if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG) 85 request |= POWER_MODE_PG; 86 } 87 88 rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, request); 89 90 if (enter) 91 return; 92 93 /* check confirm power mode has left power save state */ 94 for (polling_cnt = 0; polling_cnt < 50; polling_cnt++) { 95 polling = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr); 96 if ((polling ^ confirm) & BIT_RPWM_TOGGLE) 97 return; 98 udelay(100); 99 } 100 101 /* in case of fw/hw missed the request, retry */ 102 rtw_warn(rtwdev, "failed to leave deep PS, retry=%d\n", 103 retry_cnt); 104 } 105 106 /* Hit here means that driver failed to change hardware power mode to 107 * active state after retry 3 times. If the power state is locked at 108 * Deep sleep, most of the hardware circuits is not working, even 109 * register read/write. It should be treated as fatal error and 110 * requires an entire analysis about the firmware/hardware 111 */ 112 WARN(1, "Hardware power state locked\n"); 113 } 114 EXPORT_SYMBOL(rtw_power_mode_change); 115 116 static void __rtw_leave_lps_deep(struct rtw_dev *rtwdev) 117 { 118 rtw_hci_deep_ps(rtwdev, false); 119 } 120 121 static void rtw_fw_leave_lps_state_check(struct rtw_dev *rtwdev) 122 { 123 int i; 124 125 /* Driver needs to wait for firmware to leave LPS state 126 * successfully. Firmware will send null packet to inform AP, 127 * and see if AP sends an ACK back, then firmware will restore 128 * the REG_TCR register. 129 * 130 * If driver does not wait for firmware, null packet with 131 * PS bit could be sent due to incorrect REG_TCR setting. 132 * 133 * In our test, 100ms should be enough for firmware to finish 134 * the flow. If REG_TCR Register is still incorrect after 100ms, 135 * just modify it directly, and throw a warn message. 136 */ 137 for (i = 0 ; i < LEAVE_LPS_TRY_CNT; i++) { 138 if (rtw_read32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN) == 0) 139 return; 140 msleep(20); 141 } 142 143 rtw_write32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN, 0); 144 rtw_warn(rtwdev, "firmware failed to restore hardware setting\n"); 145 } 146 147 static void rtw_leave_lps_core(struct rtw_dev *rtwdev) 148 { 149 struct rtw_lps_conf *conf = &rtwdev->lps_conf; 150 151 conf->state = RTW_ALL_ON; 152 conf->awake_interval = 1; 153 conf->rlbm = 0; 154 conf->smart_ps = 0; 155 156 rtw_hci_link_ps(rtwdev, false); 157 rtw_fw_set_pwr_mode(rtwdev); 158 rtw_fw_leave_lps_state_check(rtwdev); 159 160 clear_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags); 161 162 rtw_coex_lps_notify(rtwdev, COEX_LPS_DISABLE); 163 } 164 165 static void __rtw_enter_lps_deep(struct rtw_dev *rtwdev) 166 { 167 if (rtwdev->lps_conf.deep_mode == LPS_DEEP_MODE_NONE) 168 return; 169 170 if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) { 171 rtw_dbg(rtwdev, RTW_DBG_PS, 172 "Should enter LPS before entering deep PS\n"); 173 return; 174 } 175 176 if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG) 177 rtw_fw_set_pg_info(rtwdev); 178 179 rtw_hci_deep_ps(rtwdev, true); 180 } 181 182 static void rtw_enter_lps_core(struct rtw_dev *rtwdev) 183 { 184 struct rtw_lps_conf *conf = &rtwdev->lps_conf; 185 186 conf->state = RTW_RF_OFF; 187 conf->awake_interval = 1; 188 conf->rlbm = 1; 189 conf->smart_ps = 2; 190 191 rtw_coex_lps_notify(rtwdev, COEX_LPS_ENABLE); 192 193 rtw_fw_set_pwr_mode(rtwdev); 194 rtw_hci_link_ps(rtwdev, true); 195 196 set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags); 197 } 198 199 static void __rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id) 200 { 201 struct rtw_lps_conf *conf = &rtwdev->lps_conf; 202 203 if (test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) 204 return; 205 206 conf->mode = RTW_MODE_LPS; 207 conf->port_id = port_id; 208 209 rtw_enter_lps_core(rtwdev); 210 } 211 212 static void __rtw_leave_lps(struct rtw_dev *rtwdev) 213 { 214 struct rtw_lps_conf *conf = &rtwdev->lps_conf; 215 216 if (test_and_clear_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) { 217 rtw_dbg(rtwdev, RTW_DBG_PS, 218 "Should leave deep PS before leaving LPS\n"); 219 __rtw_leave_lps_deep(rtwdev); 220 } 221 222 if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) 223 return; 224 225 conf->mode = RTW_MODE_ACTIVE; 226 227 rtw_leave_lps_core(rtwdev); 228 } 229 230 void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id) 231 { 232 lockdep_assert_held(&rtwdev->mutex); 233 234 if (rtwdev->coex.stat.wl_force_lps_ctrl) 235 return; 236 237 __rtw_enter_lps(rtwdev, port_id); 238 __rtw_enter_lps_deep(rtwdev); 239 } 240 241 void rtw_leave_lps(struct rtw_dev *rtwdev) 242 { 243 lockdep_assert_held(&rtwdev->mutex); 244 245 __rtw_leave_lps_deep(rtwdev); 246 __rtw_leave_lps(rtwdev); 247 } 248 249 void rtw_leave_lps_deep(struct rtw_dev *rtwdev) 250 { 251 lockdep_assert_held(&rtwdev->mutex); 252 253 __rtw_leave_lps_deep(rtwdev); 254 } 255