1*4882a593Smuzhiyun /******************************************************************************
2*4882a593Smuzhiyun *
3*4882a593Smuzhiyun * Copyright(c) 2021 Realtek Corporation.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or modify it
6*4882a593Smuzhiyun * under the terms of version 2 of the GNU General Public License as
7*4882a593Smuzhiyun * published by the Free Software Foundation.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * This program is distributed in the hope that it will be useful, but WITHOUT
10*4882a593Smuzhiyun * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11*4882a593Smuzhiyun * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12*4882a593Smuzhiyun * more details.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun *****************************************************************************/
15*4882a593Smuzhiyun #define _PHL_PS_C_
16*4882a593Smuzhiyun #include "phl_headers.h"
17*4882a593Smuzhiyun #ifdef CONFIG_POWER_SAVE
phl_ps_op_mode_to_str(u8 op_mode)18*4882a593Smuzhiyun const char *phl_ps_op_mode_to_str(u8 op_mode)
19*4882a593Smuzhiyun {
20*4882a593Smuzhiyun switch (op_mode) {
21*4882a593Smuzhiyun case PS_OP_MODE_DISABLED:
22*4882a593Smuzhiyun return "Disabled";
23*4882a593Smuzhiyun case PS_OP_MODE_FORCE_ENABLED:
24*4882a593Smuzhiyun return "Force Enabled";
25*4882a593Smuzhiyun case PS_OP_MODE_AUTO:
26*4882a593Smuzhiyun return "Auto";
27*4882a593Smuzhiyun default:
28*4882a593Smuzhiyun return "-";
29*4882a593Smuzhiyun }
30*4882a593Smuzhiyun }
31*4882a593Smuzhiyun
phl_ps_ps_mode_to_str(u8 ps_mode)32*4882a593Smuzhiyun const char *phl_ps_ps_mode_to_str(u8 ps_mode)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun switch (ps_mode) {
35*4882a593Smuzhiyun case PS_MODE_IPS:
36*4882a593Smuzhiyun return "IPS";
37*4882a593Smuzhiyun case PS_MODE_LPS:
38*4882a593Smuzhiyun return "LPS";
39*4882a593Smuzhiyun default:
40*4882a593Smuzhiyun return "NONE";
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #define case_pwr_lvl(src) \
45*4882a593Smuzhiyun case PS_PWR_LVL_##src: return #src
phl_ps_pwr_lvl_to_str(u8 pwr_lvl)46*4882a593Smuzhiyun const char *phl_ps_pwr_lvl_to_str(u8 pwr_lvl)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun switch (pwr_lvl) {
49*4882a593Smuzhiyun case_pwr_lvl(PWROFF);
50*4882a593Smuzhiyun case_pwr_lvl(PWR_GATED);
51*4882a593Smuzhiyun case_pwr_lvl(CLK_GATED);
52*4882a593Smuzhiyun case_pwr_lvl(RF_OFF);
53*4882a593Smuzhiyun case_pwr_lvl(PWRON);
54*4882a593Smuzhiyun case_pwr_lvl(MAX);
55*4882a593Smuzhiyun default:
56*4882a593Smuzhiyun return "Undefined";
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
phl_ps_judge_pwr_lvl(u8 ps_cap,u8 ps_mode,u8 ps_en)60*4882a593Smuzhiyun u8 phl_ps_judge_pwr_lvl(u8 ps_cap, u8 ps_mode, u8 ps_en)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun if (!ps_en)
63*4882a593Smuzhiyun return PS_PWR_LVL_PWRON;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun if (ps_mode == PS_MODE_IPS) {
66*4882a593Smuzhiyun if (ps_cap & PS_CAP_PWR_OFF)
67*4882a593Smuzhiyun return PS_PWR_LVL_PWROFF;
68*4882a593Smuzhiyun else if (ps_cap & PS_CAP_PWR_GATED)
69*4882a593Smuzhiyun return PS_PWR_LVL_PWR_GATED;
70*4882a593Smuzhiyun else if (ps_cap & PS_CAP_CLK_GATED)
71*4882a593Smuzhiyun return PS_PWR_LVL_CLK_GATED;
72*4882a593Smuzhiyun else if (ps_cap & PS_CAP_RF_OFF)
73*4882a593Smuzhiyun return PS_PWR_LVL_RF_OFF;
74*4882a593Smuzhiyun else
75*4882a593Smuzhiyun return PS_PWR_LVL_PWROFF; /* ips default support power off */
76*4882a593Smuzhiyun } else if (ps_mode == PS_MODE_LPS) {
77*4882a593Smuzhiyun if (ps_cap & PS_CAP_PWR_GATED)
78*4882a593Smuzhiyun return PS_PWR_LVL_PWR_GATED;
79*4882a593Smuzhiyun else if (ps_cap & PS_CAP_CLK_GATED)
80*4882a593Smuzhiyun return PS_PWR_LVL_CLK_GATED;
81*4882a593Smuzhiyun else if (ps_cap & PS_CAP_RF_OFF)
82*4882a593Smuzhiyun return PS_PWR_LVL_RF_OFF;
83*4882a593Smuzhiyun else if (ps_cap & PS_CAP_PWRON)
84*4882a593Smuzhiyun return PS_PWR_LVL_PWRON;
85*4882a593Smuzhiyun else
86*4882a593Smuzhiyun return PS_PWR_LVL_PWRON; /* lps default support protocol */
87*4882a593Smuzhiyun } else {
88*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS], %s(): unknown ps mode!\n", __func__);
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun return PS_PWR_LVL_PWRON;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun
_ps_ntfy_before_pwr_cfg(struct phl_info_t * phl_info,u8 ps_mode,u8 cur_pwr_lvl,u8 req_pwr_lvl)94*4882a593Smuzhiyun static void _ps_ntfy_before_pwr_cfg(struct phl_info_t *phl_info, u8 ps_mode,
95*4882a593Smuzhiyun u8 cur_pwr_lvl, u8 req_pwr_lvl)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS], %s(): \n", __func__);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun if (cur_pwr_lvl == PS_PWR_LVL_PWRON) { /* enter ps */
100*4882a593Smuzhiyun if (req_pwr_lvl == PS_PWR_LVL_PWROFF) {
101*4882a593Smuzhiyun #ifdef CONFIG_BTCOEX
102*4882a593Smuzhiyun rtw_hal_btc_radio_state_ntfy(phl_info->hal, BTC_RFCTRL_WL_OFF);
103*4882a593Smuzhiyun #endif
104*4882a593Smuzhiyun #if defined(CONFIG_PCI_HCI) && defined(RTW_WKARD_DYNAMIC_LTR)
105*4882a593Smuzhiyun phl_ltr_sw_ctrl_ntfy(phl_info->phl_com, false);
106*4882a593Smuzhiyun #endif
107*4882a593Smuzhiyun } else if (req_pwr_lvl <= PS_PWR_LVL_RF_OFF) {
108*4882a593Smuzhiyun #ifdef CONFIG_BTCOEX
109*4882a593Smuzhiyun rtw_hal_btc_radio_state_ntfy(phl_info->hal, BTC_RFCTRL_FW_CTRL);
110*4882a593Smuzhiyun #endif
111*4882a593Smuzhiyun #if defined(CONFIG_PCI_HCI) && defined(RTW_WKARD_DYNAMIC_LTR)
112*4882a593Smuzhiyun if (req_pwr_lvl == PS_PWR_LVL_PWR_GATED)
113*4882a593Smuzhiyun phl_ltr_sw_ctrl_ntfy(phl_info->phl_com, false);
114*4882a593Smuzhiyun #endif
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
_ps_ntfy_after_pwr_cfg(struct phl_info_t * phl_info,u8 ps_mode,u8 cur_pwr_lvl,u8 req_pwr_lvl,u8 cfg_ok)119*4882a593Smuzhiyun static void _ps_ntfy_after_pwr_cfg(struct phl_info_t *phl_info, u8 ps_mode,
120*4882a593Smuzhiyun u8 cur_pwr_lvl, u8 req_pwr_lvl, u8 cfg_ok)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_DEBUG_, "[PS], %s(): \n", __func__);
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun if (cur_pwr_lvl > req_pwr_lvl) { /* enter ps */
125*4882a593Smuzhiyun if (!cfg_ok) { /* fail */
126*4882a593Smuzhiyun if (req_pwr_lvl == PS_PWR_LVL_PWROFF) { /* driver ips */
127*4882a593Smuzhiyun #ifdef CONFIG_BTCOEX
128*4882a593Smuzhiyun rtw_hal_btc_radio_state_ntfy(phl_info->hal, BTC_RFCTRL_WL_ON);
129*4882a593Smuzhiyun #endif
130*4882a593Smuzhiyun #if defined(CONFIG_PCI_HCI) && defined(RTW_WKARD_DYNAMIC_LTR)
131*4882a593Smuzhiyun phl_ltr_sw_ctrl_ntfy(phl_info->phl_com, true);
132*4882a593Smuzhiyun #endif
133*4882a593Smuzhiyun } else { /* fw control */
134*4882a593Smuzhiyun #ifdef CONFIG_BTCOEX
135*4882a593Smuzhiyun if (ps_mode == PS_MODE_LPS)
136*4882a593Smuzhiyun rtw_hal_btc_radio_state_ntfy(phl_info->hal, BTC_RFCTRL_LPS_WL_ON);
137*4882a593Smuzhiyun else
138*4882a593Smuzhiyun rtw_hal_btc_radio_state_ntfy(phl_info->hal, BTC_RFCTRL_WL_ON);
139*4882a593Smuzhiyun #endif
140*4882a593Smuzhiyun #if defined(CONFIG_PCI_HCI) && defined(RTW_WKARD_DYNAMIC_LTR)
141*4882a593Smuzhiyun phl_ltr_sw_ctrl_ntfy(phl_info->phl_com, true);
142*4882a593Smuzhiyun #endif
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun } else { /* leave ps */
146*4882a593Smuzhiyun if (cfg_ok) { /* ok */
147*4882a593Smuzhiyun if (cur_pwr_lvl == PS_PWR_LVL_PWROFF) { /* driver ips */
148*4882a593Smuzhiyun if (req_pwr_lvl == PS_PWR_LVL_PWRON) {
149*4882a593Smuzhiyun #ifdef CONFIG_BTCOEX
150*4882a593Smuzhiyun rtw_hal_btc_radio_state_ntfy(phl_info->hal, BTC_RFCTRL_WL_ON);
151*4882a593Smuzhiyun #endif
152*4882a593Smuzhiyun #if defined(CONFIG_PCI_HCI) && defined(RTW_WKARD_DYNAMIC_LTR)
153*4882a593Smuzhiyun phl_ltr_sw_ctrl_ntfy(phl_info->phl_com, true);
154*4882a593Smuzhiyun #endif
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun } else { /* fw control */
157*4882a593Smuzhiyun if (req_pwr_lvl == PS_PWR_LVL_PWRON) {
158*4882a593Smuzhiyun #ifdef CONFIG_BTCOEX
159*4882a593Smuzhiyun if (ps_mode == PS_MODE_LPS)
160*4882a593Smuzhiyun rtw_hal_btc_radio_state_ntfy(phl_info->hal, BTC_RFCTRL_LPS_WL_ON);
161*4882a593Smuzhiyun else
162*4882a593Smuzhiyun rtw_hal_btc_radio_state_ntfy(phl_info->hal, BTC_RFCTRL_WL_ON);
163*4882a593Smuzhiyun #endif
164*4882a593Smuzhiyun #if defined(CONFIG_PCI_HCI) && defined(RTW_WKARD_DYNAMIC_LTR)
165*4882a593Smuzhiyun phl_ltr_sw_ctrl_ntfy(phl_info->phl_com, true);
166*4882a593Smuzhiyun #endif
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun enum rtw_phl_status
phl_ps_cfg_pwr_lvl(struct phl_info_t * phl_info,u8 ps_mode,u8 cur_pwr_lvl,u8 req_pwr_lvl)174*4882a593Smuzhiyun phl_ps_cfg_pwr_lvl(struct phl_info_t *phl_info, u8 ps_mode, u8 cur_pwr_lvl, u8 req_pwr_lvl)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun enum rtw_hal_status hstatus = RTW_HAL_STATUS_SUCCESS;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS], %s(): from %s to %s.\n",
179*4882a593Smuzhiyun __func__, phl_ps_pwr_lvl_to_str(cur_pwr_lvl), phl_ps_pwr_lvl_to_str(req_pwr_lvl));
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun if (cur_pwr_lvl == req_pwr_lvl)
182*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS], %s(): pwr lvl is not change!\n", __func__);
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun _ps_ntfy_before_pwr_cfg(phl_info, ps_mode, cur_pwr_lvl, req_pwr_lvl);
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun hstatus = rtw_hal_ps_pwr_lvl_cfg(phl_info->phl_com, phl_info->hal,
187*4882a593Smuzhiyun req_pwr_lvl);
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun _ps_ntfy_after_pwr_cfg(phl_info, ps_mode, cur_pwr_lvl, req_pwr_lvl,
190*4882a593Smuzhiyun (hstatus == RTW_HAL_STATUS_SUCCESS ? true : false));
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun return (hstatus == RTW_HAL_STATUS_SUCCESS) ? RTW_PHL_STATUS_SUCCESS : RTW_PHL_STATUS_FAILURE;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun
_ps_ntfy_before_lps_proto_cfg(struct phl_info_t * phl_info,u8 lps_en)196*4882a593Smuzhiyun static void _ps_ntfy_before_lps_proto_cfg(struct phl_info_t *phl_info, u8 lps_en)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS], %s(): \n", __func__);
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun if (lps_en) { /* enter lps */
201*4882a593Smuzhiyun #ifdef CONFIG_BTCOEX
202*4882a593Smuzhiyun rtw_hal_btc_radio_state_ntfy(phl_info->hal, BTC_RFCTRL_LPS_WL_ON);
203*4882a593Smuzhiyun #endif
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun static void
_ps_ntfy_after_lps_proto_cfg(struct phl_info_t * phl_info,u8 lps_en,u8 cfg_ok)208*4882a593Smuzhiyun _ps_ntfy_after_lps_proto_cfg(struct phl_info_t *phl_info, u8 lps_en, u8 cfg_ok)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS], %s(): \n", __func__);
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun if (lps_en) { /* enter lps */
213*4882a593Smuzhiyun if (!cfg_ok) { /* fail */
214*4882a593Smuzhiyun #ifdef CONFIG_BTCOEX
215*4882a593Smuzhiyun rtw_hal_btc_radio_state_ntfy(phl_info->hal, BTC_RFCTRL_WL_ON);
216*4882a593Smuzhiyun #endif
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun } else { /* leave lps */
219*4882a593Smuzhiyun if (cfg_ok) { /* ok */
220*4882a593Smuzhiyun #ifdef CONFIG_BTCOEX
221*4882a593Smuzhiyun rtw_hal_btc_radio_state_ntfy(phl_info->hal, BTC_RFCTRL_WL_ON);
222*4882a593Smuzhiyun #endif
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
_phl_lps_role_config_tbtt_agg(struct phl_info_t * phl_info,struct rtw_wifi_role_t * cur_wrole,u32 tbtt_agg_val)227*4882a593Smuzhiyun static void _phl_lps_role_config_tbtt_agg(struct phl_info_t *phl_info,
228*4882a593Smuzhiyun struct rtw_wifi_role_t *cur_wrole, u32 tbtt_agg_val)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun u8 role_idx;
231*4882a593Smuzhiyun struct rtw_wifi_role_t * wrole;
232*4882a593Smuzhiyun u32 tbtt_agg = tbtt_agg_val;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun if (cur_wrole == NULL) {
235*4882a593Smuzhiyun PHL_ERR("%s cur role is NULL\n", __func__);
236*4882a593Smuzhiyun return;
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun for (role_idx = 0; role_idx < MAX_WIFI_ROLE_NUMBER; role_idx++) {
240*4882a593Smuzhiyun wrole = rtw_phl_get_wrole_by_ridx(phl_info->phl_com, role_idx);
241*4882a593Smuzhiyun if(wrole == NULL || !wrole->active)
242*4882a593Smuzhiyun continue;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun if (wrole == cur_wrole)
245*4882a593Smuzhiyun continue;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun PHL_INFO("%s role %d config tbtt agg = %d\n", __func__, role_idx, tbtt_agg_val);
248*4882a593Smuzhiyun rtw_hal_role_cfg_ex(phl_info->hal, wrole, PCFG_TBTT_AGG, &tbtt_agg);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
_phl_ips_role_config_tbtt_agg(struct phl_info_t * phl_info,u32 tbtt_agg_val)252*4882a593Smuzhiyun static void _phl_ips_role_config_tbtt_agg(struct phl_info_t *phl_info,
253*4882a593Smuzhiyun u32 tbtt_agg_val)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun u8 role_idx;
256*4882a593Smuzhiyun struct rtw_wifi_role_t *wrole;
257*4882a593Smuzhiyun u32 tbtt_agg = tbtt_agg_val;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun for (role_idx = 0; role_idx < MAX_WIFI_ROLE_NUMBER; role_idx++) {
260*4882a593Smuzhiyun wrole = rtw_phl_get_wrole_by_ridx(phl_info->phl_com, role_idx);
261*4882a593Smuzhiyun if (wrole == NULL || !wrole->active)
262*4882a593Smuzhiyun continue;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun PHL_INFO("%s role %d config tbtt agg = %d\n", __func__, role_idx,
265*4882a593Smuzhiyun tbtt_agg_val);
266*4882a593Smuzhiyun rtw_hal_role_cfg_ex(phl_info->hal, wrole, PCFG_TBTT_AGG, &tbtt_agg);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun enum rtw_phl_status
phl_ps_ips_cfg(struct phl_info_t * phl_info,struct ps_cfg * cfg,u8 en)271*4882a593Smuzhiyun phl_ps_ips_cfg(struct phl_info_t *phl_info, struct ps_cfg *cfg, u8 en)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun u32 tbtt_agg = en ? 0 : RTW_MAC_TBTT_AGG_DEF;
274*4882a593Smuzhiyun struct rtw_hal_ips_info ips_info = {0};
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun /* avoid waking up at each TBTT under disconnected standby */
277*4882a593Smuzhiyun _phl_ips_role_config_tbtt_agg(phl_info, tbtt_agg);
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun ips_info.en = en;
280*4882a593Smuzhiyun ips_info.macid = cfg->macid;
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun return rtw_hal_ps_ips_cfg(phl_info->hal, &ips_info);
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun enum rtw_phl_status
phl_ps_lps_cfg(struct phl_info_t * phl_info,struct ps_cfg * cfg,u8 en)286*4882a593Smuzhiyun phl_ps_lps_cfg(struct phl_info_t *phl_info, struct ps_cfg *cfg, u8 en)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun enum rtw_phl_status status = RTW_PHL_STATUS_SUCCESS;
289*4882a593Smuzhiyun struct rtw_hal_lps_info lps_info;
290*4882a593Smuzhiyun struct rtw_wifi_role_t *wrole = NULL;
291*4882a593Smuzhiyun struct rtw_phl_stainfo_t *sta = NULL;
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun sta = rtw_phl_get_stainfo_by_macid(phl_info, cfg->macid);
294*4882a593Smuzhiyun if (sta != NULL) {
295*4882a593Smuzhiyun wrole = sta->wrole;
296*4882a593Smuzhiyun } else {
297*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_WARNING_, "[PS], %s(): cannot get sta!\n", __func__);
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun if (RTW_PHL_STATUS_SUCCESS != phl_snd_cmd_ntfy_ps(phl_info, wrole, en)) {
301*4882a593Smuzhiyun status = RTW_PHL_STATUS_FAILURE;
302*4882a593Smuzhiyun return status;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun if (en) {
306*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS], %s(): enter lps, macid %d.\n", __func__, cfg->macid);
307*4882a593Smuzhiyun _phl_lps_role_config_tbtt_agg(phl_info, wrole, 0);
308*4882a593Smuzhiyun } else {
309*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS], %s(): leave lps, macid %d.\n", __func__, cfg->macid);
310*4882a593Smuzhiyun _phl_lps_role_config_tbtt_agg(phl_info, wrole, RTW_MAC_TBTT_AGG_DEF);
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun lps_info.en = en;
314*4882a593Smuzhiyun lps_info.macid = cfg->macid;
315*4882a593Smuzhiyun lps_info.listen_bcn_mode = cfg->listen_bcn_mode;
316*4882a593Smuzhiyun lps_info.awake_interval = cfg->awake_interval;
317*4882a593Smuzhiyun lps_info.smart_ps_mode = cfg->smart_ps_mode;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun _ps_ntfy_before_lps_proto_cfg(phl_info, en);
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun if (rtw_hal_ps_lps_cfg(phl_info->hal, &lps_info) != RTW_HAL_STATUS_SUCCESS) {
322*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS], %s(): config lps fail.\n", __func__);
323*4882a593Smuzhiyun rtw_hal_notification(phl_info->hal, MSG_EVT_DBG_TX_DUMP, HW_PHY_0);
324*4882a593Smuzhiyun status = RTW_PHL_STATUS_FAILURE;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun _ps_ntfy_after_lps_proto_cfg(phl_info, en, (status == RTW_PHL_STATUS_SUCCESS ? true : false));
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun return status;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun
_lps_enter_proto_cfg(struct phl_info_t * phl_info,struct ps_cfg * cfg)332*4882a593Smuzhiyun static enum rtw_phl_status _lps_enter_proto_cfg(struct phl_info_t *phl_info, struct ps_cfg *cfg)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
335*4882a593Smuzhiyun struct rtw_pkt_ofld_null_info null_info = {0};
336*4882a593Smuzhiyun struct rtw_phl_stainfo_t *phl_sta = NULL;
337*4882a593Smuzhiyun void *d = phl_to_drvpriv(phl_info);
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS], %s(): \n", __func__);
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun #ifdef CONFIG_PHL_PS_FW_DBG
342*4882a593Smuzhiyun rtw_hal_cfg_fw_ps_log(phl_info->hal, true);
343*4882a593Smuzhiyun #endif
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun phl_sta = rtw_phl_get_stainfo_by_macid(phl_info, cfg->macid);
346*4882a593Smuzhiyun if (phl_sta == NULL)
347*4882a593Smuzhiyun return RTW_PHL_STATUS_FAILURE;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun _os_mem_cpy(d, &(null_info.a1[0]), &(phl_sta->mac_addr[0]),
350*4882a593Smuzhiyun MAC_ADDRESS_LENGTH);
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun _os_mem_cpy(d,&(null_info.a2[0]), &(phl_sta->wrole->mac_addr[0]),
353*4882a593Smuzhiyun MAC_ADDRESS_LENGTH);
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun _os_mem_cpy(d, &(null_info.a3[0]), &(phl_sta->mac_addr[0]),
356*4882a593Smuzhiyun MAC_ADDRESS_LENGTH);
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun status = RTW_PHL_PKT_OFLD_REQ(phl_info, cfg->macid,
359*4882a593Smuzhiyun PKT_TYPE_NULL_DATA, cfg->token, &null_info);
360*4882a593Smuzhiyun if (status != RTW_PHL_STATUS_SUCCESS) {
361*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS], %s(): add null pkt ofld fail!\n", __func__);
362*4882a593Smuzhiyun return status;
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun status = phl_ps_lps_cfg(phl_info, cfg, true);
366*4882a593Smuzhiyun if (status != RTW_PHL_STATUS_SUCCESS) {
367*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS], %s(): config lps fail!\n", __func__);
368*4882a593Smuzhiyun return status;
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun return RTW_PHL_STATUS_SUCCESS;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun
_lps_leave_proto_cfg(struct phl_info_t * phl_info,struct ps_cfg * cfg)374*4882a593Smuzhiyun static enum rtw_phl_status _lps_leave_proto_cfg(struct phl_info_t *phl_info, struct ps_cfg *cfg)
375*4882a593Smuzhiyun {
376*4882a593Smuzhiyun enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS], %s(): \n", __func__);
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun status = phl_ps_lps_cfg(phl_info, cfg, false);
381*4882a593Smuzhiyun if (status != RTW_PHL_STATUS_SUCCESS) {
382*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS], %s(): config lps fail!\n", __func__);
383*4882a593Smuzhiyun return status;
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun status = phl_pkt_ofld_cancel(phl_info, cfg->macid,
387*4882a593Smuzhiyun PKT_TYPE_NULL_DATA, cfg->token);
388*4882a593Smuzhiyun if (status != RTW_PHL_STATUS_SUCCESS) {
389*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS], %s(): del null pkt ofld fail!\n", __func__);
390*4882a593Smuzhiyun return status;
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun return RTW_PHL_STATUS_SUCCESS;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun
phl_ps_lps_proto_cfg(struct phl_info_t * phl_info,struct ps_cfg * cfg,bool lps_en)396*4882a593Smuzhiyun enum rtw_phl_status phl_ps_lps_proto_cfg(struct phl_info_t *phl_info, struct ps_cfg *cfg, bool lps_en)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun if (lps_en)
399*4882a593Smuzhiyun return _lps_enter_proto_cfg(phl_info, cfg);
400*4882a593Smuzhiyun else
401*4882a593Smuzhiyun return _lps_leave_proto_cfg(phl_info, cfg);
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun
phl_ps_lps_enter(struct phl_info_t * phl_info,struct ps_cfg * cfg)404*4882a593Smuzhiyun enum rtw_phl_status phl_ps_lps_enter(struct phl_info_t *phl_info, struct ps_cfg *cfg)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun if (cfg->proto_cfg) {
409*4882a593Smuzhiyun status = phl_ps_lps_proto_cfg(phl_info, cfg, true);
410*4882a593Smuzhiyun if (status != RTW_PHL_STATUS_SUCCESS) {
411*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS], %s(): config lps protocol fail!\n", __func__);
412*4882a593Smuzhiyun return status;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun if (cfg->pwr_cfg) {
417*4882a593Smuzhiyun status = phl_ps_cfg_pwr_lvl(phl_info, cfg->ps_mode, cfg->cur_pwr_lvl, cfg->pwr_lvl);
418*4882a593Smuzhiyun if (status != RTW_PHL_STATUS_SUCCESS) {
419*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS], %s(): config lps pwr lvl fail!\n", __func__);
420*4882a593Smuzhiyun return status;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun return RTW_PHL_STATUS_SUCCESS;
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun
phl_ps_lps_leave(struct phl_info_t * phl_info,struct ps_cfg * cfg)427*4882a593Smuzhiyun enum rtw_phl_status phl_ps_lps_leave(struct phl_info_t *phl_info, struct ps_cfg *cfg)
428*4882a593Smuzhiyun {
429*4882a593Smuzhiyun enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun if (cfg->pwr_cfg) {
432*4882a593Smuzhiyun status = phl_ps_cfg_pwr_lvl(phl_info, cfg->ps_mode, cfg->cur_pwr_lvl, cfg->pwr_lvl);
433*4882a593Smuzhiyun if (status != RTW_PHL_STATUS_SUCCESS) {
434*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS], %s(): config lps pwr lvl fail!\n", __func__);
435*4882a593Smuzhiyun return status;
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun if (cfg->proto_cfg) {
440*4882a593Smuzhiyun status = phl_ps_lps_proto_cfg(phl_info, cfg, false);
441*4882a593Smuzhiyun if (status != RTW_PHL_STATUS_SUCCESS) {
442*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS], %s(): config lps protocol fail!\n", __func__);
443*4882a593Smuzhiyun return status;
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun return RTW_PHL_STATUS_SUCCESS;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
phl_ps_ips_proto_cfg(struct phl_info_t * phl_info,struct ps_cfg * cfg,bool ips_en)450*4882a593Smuzhiyun enum rtw_phl_status phl_ps_ips_proto_cfg(struct phl_info_t *phl_info, struct ps_cfg *cfg, bool ips_en)
451*4882a593Smuzhiyun {
452*4882a593Smuzhiyun if (cfg->pwr_lvl == PS_PWR_LVL_PWROFF)
453*4882a593Smuzhiyun return RTW_PHL_STATUS_SUCCESS;
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun /* ips protocol config */
456*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS], %s(): \n", __func__);
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun phl_ps_ips_cfg(phl_info, cfg, ips_en);
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun return RTW_PHL_STATUS_SUCCESS;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
phl_ps_ips_enter(struct phl_info_t * phl_info,struct ps_cfg * cfg)463*4882a593Smuzhiyun enum rtw_phl_status phl_ps_ips_enter(struct phl_info_t *phl_info, struct ps_cfg *cfg)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun status = phl_ps_ips_proto_cfg(phl_info, cfg, true);
468*4882a593Smuzhiyun if (status != RTW_PHL_STATUS_SUCCESS) {
469*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS], %s(): config ips protocol fail!\n", __func__);
470*4882a593Smuzhiyun return status;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun status = phl_ps_cfg_pwr_lvl(phl_info, cfg->ps_mode, cfg->cur_pwr_lvl, cfg->pwr_lvl);
474*4882a593Smuzhiyun if (status != RTW_PHL_STATUS_SUCCESS) {
475*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS], %s(): config ips pwr lvl fail!\n", __func__);
476*4882a593Smuzhiyun return status;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun return status;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
phl_ps_ips_leave(struct phl_info_t * phl_info,struct ps_cfg * cfg)482*4882a593Smuzhiyun enum rtw_phl_status phl_ps_ips_leave(struct phl_info_t *phl_info, struct ps_cfg *cfg)
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun status = phl_ps_cfg_pwr_lvl(phl_info, cfg->ps_mode, cfg->cur_pwr_lvl, cfg->pwr_lvl);
487*4882a593Smuzhiyun if (status != RTW_PHL_STATUS_SUCCESS) {
488*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS], %s(): config ips pwr lvl fail!\n", __func__);
489*4882a593Smuzhiyun return status;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun status = phl_ps_ips_proto_cfg(phl_info, cfg, false);
493*4882a593Smuzhiyun if (status != RTW_PHL_STATUS_SUCCESS) {
494*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_ERR_, "[PS], %s(): config ips protocol fail!\n", __func__);
495*4882a593Smuzhiyun return status;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun return status;
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun enum rtw_phl_status
phl_ps_enter_ps(struct phl_info_t * phl_info,struct ps_cfg * cfg)502*4882a593Smuzhiyun phl_ps_enter_ps(struct phl_info_t *phl_info, struct ps_cfg *cfg)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS], %s(): ps mode(%s), pwr lvl(%s), macid(%d), token(0x%x), proto_cfg(%d), pwr_cfg(%d)\n",
507*4882a593Smuzhiyun __func__, phl_ps_ps_mode_to_str(cfg->ps_mode), phl_ps_pwr_lvl_to_str(cfg->pwr_lvl),
508*4882a593Smuzhiyun cfg->macid, (cfg->token == NULL) ? 0xFF : *cfg->token, cfg->proto_cfg, cfg->pwr_cfg);
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun if (cfg->ps_mode == PS_MODE_LPS)
511*4882a593Smuzhiyun status = phl_ps_lps_enter(phl_info, cfg);
512*4882a593Smuzhiyun else if (cfg->ps_mode == PS_MODE_IPS)
513*4882a593Smuzhiyun status = phl_ps_ips_enter(phl_info, cfg);
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun return status;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun enum rtw_phl_status
phl_ps_leave_ps(struct phl_info_t * phl_info,struct ps_cfg * cfg)519*4882a593Smuzhiyun phl_ps_leave_ps(struct phl_info_t *phl_info, struct ps_cfg *cfg)
520*4882a593Smuzhiyun {
521*4882a593Smuzhiyun enum rtw_phl_status status = RTW_PHL_STATUS_FAILURE;
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun PHL_TRACE(COMP_PHL_PS, _PHL_INFO_, "[PS], %s(): current ps mode(%s), pwr lvl(%s), macid(%d), token(0x%x), proto_cfg(%d), pwr_cfg(%d)\n",
524*4882a593Smuzhiyun __func__, phl_ps_ps_mode_to_str(cfg->ps_mode), phl_ps_pwr_lvl_to_str(cfg->pwr_lvl),
525*4882a593Smuzhiyun cfg->macid, (cfg->token == NULL) ? 0xFF : *cfg->token, cfg->proto_cfg, cfg->pwr_cfg);
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun if (cfg->ps_mode == PS_MODE_LPS)
528*4882a593Smuzhiyun status = phl_ps_lps_leave(phl_info, cfg);
529*4882a593Smuzhiyun else if (cfg->ps_mode == PS_MODE_IPS)
530*4882a593Smuzhiyun status = phl_ps_ips_leave(phl_info, cfg);
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun return status;
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun #endif
535