Branch data Line data Source code
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 : 0 : static int rtw_ips_pwr_up(struct rtw_dev *rtwdev)
14 : : {
15 : 0 : int ret;
16 : :
17 : 0 : ret = rtw_core_start(rtwdev);
18 [ # # ]: 0 : if (ret)
19 : 0 : rtw_err(rtwdev, "leave idle state failed\n");
20 : :
21 : 0 : rtw_set_channel(rtwdev);
22 : 0 : clear_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags);
23 : :
24 : 0 : return ret;
25 : : }
26 : :
27 : 0 : int rtw_enter_ips(struct rtw_dev *rtwdev)
28 : : {
29 : 0 : set_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags);
30 : :
31 : 0 : rtw_coex_ips_notify(rtwdev, COEX_IPS_ENTER);
32 : :
33 : 0 : rtw_core_stop(rtwdev);
34 : 0 : rtw_hci_link_ps(rtwdev, true);
35 : :
36 : 0 : return 0;
37 : : }
38 : :
39 : 0 : static void rtw_restore_port_cfg_iter(void *data, u8 *mac,
40 : : struct ieee80211_vif *vif)
41 : : {
42 : 0 : struct rtw_dev *rtwdev = data;
43 : 0 : struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
44 : 0 : u32 config = ~0;
45 : :
46 : 0 : rtw_vif_port_config(rtwdev, rtwvif, config);
47 : 0 : }
48 : :
49 : 0 : int rtw_leave_ips(struct rtw_dev *rtwdev)
50 : : {
51 : 0 : int ret;
52 : :
53 : 0 : rtw_hci_link_ps(rtwdev, false);
54 : :
55 : 0 : ret = rtw_ips_pwr_up(rtwdev);
56 [ # # ]: 0 : if (ret) {
57 : 0 : rtw_err(rtwdev, "failed to leave ips state\n");
58 : 0 : return ret;
59 : : }
60 : :
61 : 0 : rtw_iterate_vifs_atomic(rtwdev, rtw_restore_port_cfg_iter, rtwdev);
62 : :
63 : 0 : rtw_coex_ips_notify(rtwdev, COEX_IPS_LEAVE);
64 : :
65 : 0 : return 0;
66 : : }
67 : :
68 : 0 : void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter)
69 : : {
70 : 0 : u8 request, confirm, polling;
71 : 0 : u8 polling_cnt;
72 : 0 : u8 retry_cnt = 0;
73 : :
74 [ # # ]: 0 : for (retry_cnt = 0; retry_cnt < 3; retry_cnt++) {
75 : 0 : request = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr);
76 : 0 : confirm = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr);
77 : :
78 : : /* toggle to request power mode, others remain 0 */
79 : 0 : request ^= request | BIT_RPWM_TOGGLE;
80 [ # # ]: 0 : if (!enter) {
81 : 0 : request |= POWER_MODE_ACK;
82 : : } else {
83 : 0 : request |= POWER_MODE_LCLK;
84 [ # # ]: 0 : if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG)
85 : 0 : request |= POWER_MODE_PG;
86 : : }
87 : :
88 : 0 : rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, request);
89 : :
90 [ # # ]: 0 : if (enter)
91 : : return;
92 : :
93 : : /* check confirm power mode has left power save state */
94 [ # # ]: 0 : for (polling_cnt = 0; polling_cnt < 50; polling_cnt++) {
95 : 0 : polling = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr);
96 [ # # ]: 0 : if ((polling ^ confirm) & BIT_RPWM_TOGGLE)
97 : : return;
98 : 0 : udelay(100);
99 : : }
100 : :
101 : : /* in case of fw/hw missed the request, retry */
102 : 0 : 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 : 0 : WARN(1, "Hardware power state locked\n");
113 : : }
114 : : EXPORT_SYMBOL(rtw_power_mode_change);
115 : :
116 : 0 : static void __rtw_leave_lps_deep(struct rtw_dev *rtwdev)
117 : : {
118 : 0 : rtw_hci_deep_ps(rtwdev, false);
119 : 0 : }
120 : :
121 : 0 : static void rtw_fw_leave_lps_state_check(struct rtw_dev *rtwdev)
122 : : {
123 : 0 : 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 [ # # ]: 0 : for (i = 0 ; i < LEAVE_LPS_TRY_CNT; i++) {
138 [ # # ]: 0 : if (rtw_read32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN) == 0)
139 : : return;
140 : 0 : msleep(20);
141 : : }
142 : :
143 : 0 : rtw_write32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN, 0);
144 : 0 : rtw_warn(rtwdev, "firmware failed to restore hardware setting\n");
145 : : }
146 : :
147 : 0 : static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
148 : : {
149 : 0 : struct rtw_lps_conf *conf = &rtwdev->lps_conf;
150 : :
151 : 0 : conf->state = RTW_ALL_ON;
152 : 0 : conf->awake_interval = 1;
153 : 0 : conf->rlbm = 0;
154 : 0 : conf->smart_ps = 0;
155 : :
156 : 0 : rtw_hci_link_ps(rtwdev, false);
157 : 0 : rtw_fw_set_pwr_mode(rtwdev);
158 : 0 : rtw_fw_leave_lps_state_check(rtwdev);
159 : :
160 : 0 : clear_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
161 : :
162 : 0 : rtw_coex_lps_notify(rtwdev, COEX_LPS_DISABLE);
163 : 0 : }
164 : :
165 : 0 : static void __rtw_enter_lps_deep(struct rtw_dev *rtwdev)
166 : : {
167 [ # # ]: 0 : if (rtwdev->lps_conf.deep_mode == LPS_DEEP_MODE_NONE)
168 : : return;
169 : :
170 [ # # ]: 0 : if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) {
171 : 0 : rtw_dbg(rtwdev, RTW_DBG_PS,
172 : : "Should enter LPS before entering deep PS\n");
173 : 0 : return;
174 : : }
175 : :
176 [ # # ]: 0 : if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG)
177 : 0 : rtw_fw_set_pg_info(rtwdev);
178 : :
179 : 0 : rtw_hci_deep_ps(rtwdev, true);
180 : : }
181 : :
182 : 0 : static void rtw_enter_lps_core(struct rtw_dev *rtwdev)
183 : : {
184 : 0 : struct rtw_lps_conf *conf = &rtwdev->lps_conf;
185 : :
186 : 0 : conf->state = RTW_RF_OFF;
187 : 0 : conf->awake_interval = 1;
188 : 0 : conf->rlbm = 1;
189 : 0 : conf->smart_ps = 2;
190 : :
191 : 0 : rtw_coex_lps_notify(rtwdev, COEX_LPS_ENABLE);
192 : :
193 : 0 : rtw_fw_set_pwr_mode(rtwdev);
194 : 0 : rtw_hci_link_ps(rtwdev, true);
195 : :
196 : 0 : set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
197 : 0 : }
198 : :
199 : 0 : static void __rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id)
200 : : {
201 : 0 : struct rtw_lps_conf *conf = &rtwdev->lps_conf;
202 : :
203 [ # # ]: 0 : if (test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags))
204 : : return;
205 : :
206 : 0 : conf->mode = RTW_MODE_LPS;
207 : 0 : conf->port_id = port_id;
208 : :
209 : 0 : rtw_enter_lps_core(rtwdev);
210 : : }
211 : :
212 : 0 : static void __rtw_leave_lps(struct rtw_dev *rtwdev)
213 : : {
214 : 0 : struct rtw_lps_conf *conf = &rtwdev->lps_conf;
215 : :
216 [ # # ]: 0 : if (test_and_clear_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) {
217 : 0 : rtw_dbg(rtwdev, RTW_DBG_PS,
218 : : "Should leave deep PS before leaving LPS\n");
219 : 0 : __rtw_leave_lps_deep(rtwdev);
220 : : }
221 : :
222 [ # # ]: 0 : if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags))
223 : : return;
224 : :
225 : 0 : conf->mode = RTW_MODE_ACTIVE;
226 : :
227 : 0 : rtw_leave_lps_core(rtwdev);
228 : : }
229 : :
230 : 0 : void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id)
231 : : {
232 : 0 : lockdep_assert_held(&rtwdev->mutex);
233 : :
234 [ # # ]: 0 : if (rtwdev->coex.stat.wl_force_lps_ctrl)
235 : : return;
236 : :
237 : 0 : __rtw_enter_lps(rtwdev, port_id);
238 : 0 : __rtw_enter_lps_deep(rtwdev);
239 : : }
240 : :
241 : 0 : void rtw_leave_lps(struct rtw_dev *rtwdev)
242 : : {
243 : 0 : lockdep_assert_held(&rtwdev->mutex);
244 : :
245 : 0 : __rtw_leave_lps_deep(rtwdev);
246 : 0 : __rtw_leave_lps(rtwdev);
247 : 0 : }
248 : :
249 : 0 : void rtw_leave_lps_deep(struct rtw_dev *rtwdev)
250 : : {
251 : 0 : lockdep_assert_held(&rtwdev->mutex);
252 : :
253 : 0 : __rtw_leave_lps_deep(rtwdev);
254 : 0 : }
|