xref: /linux/drivers/net/wireless/realtek/rtw88/ps.c (revision 9a6b55ac)
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 < 3; polling_cnt++) {
95 			polling = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr);
96 			if ((polling ^ confirm) & BIT_RPWM_TOGGLE)
97 				return;
98 			mdelay(20);
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