rtw88: Fix an error message
[linux-2.6-block.git] / drivers / net / wireless / realtek / rtw88 / ps.c
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 #include "reg.h"
13
14 static int rtw_ips_pwr_up(struct rtw_dev *rtwdev)
15 {
16         int ret;
17
18         ret = rtw_core_start(rtwdev);
19         if (ret)
20                 rtw_err(rtwdev, "leave idle state failed\n");
21
22         rtw_set_channel(rtwdev);
23         clear_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags);
24
25         return ret;
26 }
27
28 int rtw_enter_ips(struct rtw_dev *rtwdev)
29 {
30         set_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags);
31
32         rtw_coex_ips_notify(rtwdev, COEX_IPS_ENTER);
33
34         rtw_core_stop(rtwdev);
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         ret = rtw_ips_pwr_up(rtwdev);
54         if (ret) {
55                 rtw_err(rtwdev, "failed to leave ips state\n");
56                 return ret;
57         }
58
59         rtw_iterate_vifs_atomic(rtwdev, rtw_restore_port_cfg_iter, rtwdev);
60
61         rtw_coex_ips_notify(rtwdev, COEX_IPS_LEAVE);
62
63         return 0;
64 }
65
66 void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter)
67 {
68         u8 request, confirm, polling;
69         u8 polling_cnt;
70         u8 retry_cnt = 0;
71
72 retry:
73         request = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr);
74         confirm = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr);
75
76         /* toggle to request power mode, others remain 0 */
77         request ^= request | BIT_RPWM_TOGGLE;
78         if (!enter) {
79                 request |= POWER_MODE_ACK;
80         } else {
81                 request |= POWER_MODE_LCLK;
82                 if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG)
83                         request |= POWER_MODE_PG;
84         }
85
86         rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, request);
87
88         /* check confirm power mode has left power save state */
89         if (!enter) {
90                 for (polling_cnt = 0; polling_cnt < 3; polling_cnt++) {
91                         polling = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr);
92                         if ((polling ^ confirm) & BIT_RPWM_TOGGLE)
93                                 return;
94                         mdelay(20);
95                 }
96
97                 /* in case of fw/hw missed the request, retry 3 times */
98                 if (retry_cnt < 3) {
99                         rtw_warn(rtwdev, "failed to leave deep PS, retry=%d\n",
100                                  retry_cnt);
101                         retry_cnt++;
102                         goto retry;
103                 }
104
105                 /* Hit here means that driver failed to change hardware
106                  * power mode to active state after retry 3 times.
107                  * If the power state is locked at Deep sleep, most of
108                  * the hardware circuits is not working, even register
109                  * 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 }
115 EXPORT_SYMBOL(rtw_power_mode_change);
116
117 static void __rtw_leave_lps_deep(struct rtw_dev *rtwdev)
118 {
119         rtw_hci_deep_ps(rtwdev, false);
120 }
121
122 static void rtw_fw_leave_lps_state_check(struct rtw_dev *rtwdev)
123 {
124         int i;
125
126         /* Driver needs to wait for firmware to leave LPS state
127          * successfully. Firmware will send null packet to inform AP,
128          * and see if AP sends an ACK back, then firmware will restore
129          * the REG_TCR register.
130          *
131          * If driver does not wait for firmware, null packet with
132          * PS bit could be sent due to incorrect REG_TCR setting.
133          *
134          * In our test, 100ms should be enough for firmware to finish
135          * the flow. If REG_TCR Register is still incorrect after 100ms,
136          * just modify it directly, and throw a warn message.
137          */
138         for (i = 0 ; i < LEAVE_LPS_TRY_CNT; i++) {
139                 if (rtw_read32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN) == 0)
140                         return;
141                 msleep(20);
142         }
143
144         rtw_write32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN, 0);
145         rtw_warn(rtwdev, "firmware failed to restore hardware setting\n");
146 }
147
148 static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
149 {
150         struct rtw_lps_conf *conf = &rtwdev->lps_conf;
151
152         conf->state = RTW_ALL_ON;
153         conf->awake_interval = 1;
154         conf->rlbm = 0;
155         conf->smart_ps = 0;
156
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         set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
195 }
196
197 static void __rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id)
198 {
199         struct rtw_lps_conf *conf = &rtwdev->lps_conf;
200
201         if (test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags))
202                 return;
203
204         conf->mode = RTW_MODE_LPS;
205         conf->port_id = port_id;
206
207         rtw_enter_lps_core(rtwdev);
208 }
209
210 static void __rtw_leave_lps(struct rtw_dev *rtwdev)
211 {
212         struct rtw_lps_conf *conf = &rtwdev->lps_conf;
213
214         if (test_and_clear_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) {
215                 rtw_dbg(rtwdev, RTW_DBG_PS,
216                         "Should leave deep PS before leaving LPS\n");
217                 __rtw_leave_lps_deep(rtwdev);
218         }
219
220         if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags))
221                 return;
222
223         conf->mode = RTW_MODE_ACTIVE;
224
225         rtw_leave_lps_core(rtwdev);
226 }
227
228 void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id)
229 {
230         lockdep_assert_held(&rtwdev->mutex);
231
232         if (rtwdev->coex.stat.wl_force_lps_ctrl)
233                 return;
234
235         __rtw_enter_lps(rtwdev, port_id);
236         __rtw_enter_lps_deep(rtwdev);
237 }
238
239 void rtw_leave_lps(struct rtw_dev *rtwdev)
240 {
241         lockdep_assert_held(&rtwdev->mutex);
242
243         __rtw_leave_lps_deep(rtwdev);
244         __rtw_leave_lps(rtwdev);
245 }
246
247 void rtw_leave_lps_deep(struct rtw_dev *rtwdev)
248 {
249         lockdep_assert_held(&rtwdev->mutex);
250
251         __rtw_leave_lps_deep(rtwdev);
252 }