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
rtw_ips_pwr_up(struct rtw_dev * rtwdev)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
rtw_enter_ips(struct rtw_dev * rtwdev)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
rtw_restore_port_cfg_iter(void * data,u8 * mac,struct ieee80211_vif * vif)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
rtw_leave_ips(struct rtw_dev * rtwdev)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
rtw_power_mode_change(struct rtw_dev * rtwdev,bool enter)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
__rtw_leave_lps_deep(struct rtw_dev * rtwdev)116 static void __rtw_leave_lps_deep(struct rtw_dev *rtwdev)
117 {
118 rtw_hci_deep_ps(rtwdev, false);
119 }
120
rtw_fw_leave_lps_state_check(struct rtw_dev * rtwdev)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
rtw_leave_lps_core(struct rtw_dev * rtwdev)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
__rtw_enter_lps_deep(struct rtw_dev * rtwdev)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
rtw_enter_lps_core(struct rtw_dev * rtwdev)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
__rtw_enter_lps(struct rtw_dev * rtwdev,u8 port_id)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
__rtw_leave_lps(struct rtw_dev * rtwdev)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
rtw_enter_lps(struct rtw_dev * rtwdev,u8 port_id)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
rtw_leave_lps(struct rtw_dev * rtwdev)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
rtw_leave_lps_deep(struct rtw_dev * rtwdev)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