1661cc2e5fe38bca801962ad5bcb8f410219dad4
[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
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
35         return 0;
36 }
37
38 static void rtw_restore_port_cfg_iter(void *data, u8 *mac,
39                                       struct ieee80211_vif *vif)
40 {
41         struct rtw_dev *rtwdev = data;
42         struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
43         u32 config = ~0;
44
45         rtw_vif_port_config(rtwdev, rtwvif, config);
46 }
47
48 int rtw_leave_ips(struct rtw_dev *rtwdev)
49 {
50         int ret;
51
52         ret = rtw_ips_pwr_up(rtwdev);
53         if (ret) {
54                 rtw_err(rtwdev, "failed to leave ips state\n");
55                 return ret;
56         }
57
58         rtw_iterate_vifs_atomic(rtwdev, rtw_restore_port_cfg_iter, rtwdev);
59
60         rtw_coex_ips_notify(rtwdev, COEX_IPS_LEAVE);
61
62         return 0;
63 }
64
65 void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter)
66 {
67         u8 request, confirm, polling;
68         u8 polling_cnt;
69         u8 retry_cnt = 0;
70
71 retry:
72         request = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr);
73         confirm = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr);
74
75         /* toggle to request power mode, others remain 0 */
76         request ^= request | BIT_RPWM_TOGGLE;
77         if (!enter)
78                 request |= POWER_MODE_ACK;
79         else
80                 request |= POWER_MODE_LCLK;
81
82         rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, request);
83
84         /* check confirm power mode has left power save state */
85         if (!enter) {
86                 for (polling_cnt = 0; polling_cnt < 3; polling_cnt++) {
87                         polling = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr);
88                         if ((polling ^ confirm) & BIT_RPWM_TOGGLE)
89                                 return;
90                         mdelay(20);
91                 }
92
93                 /* in case of fw/hw missed the request, retry 3 times */
94                 if (retry_cnt < 3) {
95                         rtw_warn(rtwdev, "failed to leave deep PS, retry=%d\n",
96                                  retry_cnt);
97                         retry_cnt++;
98                         goto retry;
99                 }
100
101                 /* Hit here means that driver failed to change hardware
102                  * power mode to active state after retry 3 times.
103                  * If the power state is locked at Deep sleep, most of
104                  * the hardware circuits is not working, even register
105                  * read/write. It should be treated as fatal error and
106                  * requires an entire analysis about the firmware/hardware
107                  */
108                 WARN_ON("Hardware power state locked\n");
109         }
110 }
111 EXPORT_SYMBOL(rtw_power_mode_change);
112
113 static void __rtw_leave_lps_deep(struct rtw_dev *rtwdev)
114 {
115         rtw_hci_deep_ps(rtwdev, false);
116 }
117
118 static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
119 {
120         struct rtw_lps_conf *conf = &rtwdev->lps_conf;
121
122         conf->state = RTW_ALL_ON;
123         conf->awake_interval = 1;
124         conf->rlbm = 0;
125         conf->smart_ps = 0;
126
127         rtw_fw_set_pwr_mode(rtwdev);
128         clear_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
129
130         rtw_coex_lps_notify(rtwdev, COEX_LPS_DISABLE);
131 }
132
133 static void __rtw_enter_lps_deep(struct rtw_dev *rtwdev)
134 {
135         if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) {
136                 rtw_dbg(rtwdev, RTW_DBG_PS,
137                         "Should enter LPS before entering deep PS\n");
138                 return;
139         }
140
141         rtw_hci_deep_ps(rtwdev, true);
142 }
143
144 static void rtw_enter_lps_core(struct rtw_dev *rtwdev)
145 {
146         struct rtw_lps_conf *conf = &rtwdev->lps_conf;
147
148         conf->state = RTW_RF_OFF;
149         conf->awake_interval = 1;
150         conf->rlbm = 1;
151         conf->smart_ps = 2;
152
153         rtw_coex_lps_notify(rtwdev, COEX_LPS_ENABLE);
154
155         rtw_fw_set_pwr_mode(rtwdev);
156         set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
157 }
158
159 static void __rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id)
160 {
161         struct rtw_lps_conf *conf = &rtwdev->lps_conf;
162
163         if (test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags))
164                 return;
165
166         conf->mode = RTW_MODE_LPS;
167         conf->port_id = port_id;
168
169         rtw_enter_lps_core(rtwdev);
170 }
171
172 static void __rtw_leave_lps(struct rtw_dev *rtwdev)
173 {
174         struct rtw_lps_conf *conf = &rtwdev->lps_conf;
175
176         if (test_and_clear_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) {
177                 rtw_dbg(rtwdev, RTW_DBG_PS,
178                         "Should leave deep PS before leaving LPS\n");
179                 __rtw_leave_lps_deep(rtwdev);
180         }
181
182         if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags))
183                 return;
184
185         conf->mode = RTW_MODE_ACTIVE;
186
187         rtw_leave_lps_core(rtwdev);
188 }
189
190 void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id)
191 {
192         lockdep_assert_held(&rtwdev->mutex);
193
194         if (rtwdev->coex.stat.wl_force_lps_ctrl)
195                 return;
196
197         __rtw_enter_lps(rtwdev, port_id);
198         __rtw_enter_lps_deep(rtwdev);
199 }
200
201 void rtw_leave_lps(struct rtw_dev *rtwdev)
202 {
203         lockdep_assert_held(&rtwdev->mutex);
204
205         __rtw_leave_lps_deep(rtwdev);
206         __rtw_leave_lps(rtwdev);
207 }
208
209 void rtw_leave_lps_deep(struct rtw_dev *rtwdev)
210 {
211         lockdep_assert_held(&rtwdev->mutex);
212
213         __rtw_leave_lps_deep(rtwdev);
214 }