1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2014  Realtek Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * The full GNU General Public License is included in this distribution in the
15  * file called LICENSE.
16  *
17  * Contact Information:
18  * wlanfae <wlanfae@realtek.com>
19  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20  * Hsinchu 300, Taiwan.
21  *
22  * Larry Finger <Larry.Finger@lwfinger.net>
23  *
24  *****************************************************************************/
25 
26 #include "../wifi.h"
27 #include "../pci.h"
28 #include "../base.h"
29 #include "../core.h"
30 #include "reg.h"
31 #include "def.h"
32 #include "fw.h"
33 #include "../rtl8723com/fw_common.h"
34 
35 static bool _rtl8723be_check_fw_read_last_h2c(struct ieee80211_hw *hw,
36 					      u8 boxnum)
37 {
38 	struct rtl_priv *rtlpriv = rtl_priv(hw);
39 	u8 val_hmetfr;
40 	bool result = false;
41 
42 	val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
43 	if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
44 		result = true;
45 	return result;
46 }
47 
48 static void _rtl8723be_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id,
49 					u32 cmd_len, u8 *p_cmdbuffer)
50 {
51 	struct rtl_priv *rtlpriv = rtl_priv(hw);
52 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
53 	u8 boxnum;
54 	u16 box_reg = 0, box_extreg = 0;
55 	u8 u1b_tmp;
56 	bool isfw_read = false;
57 	u8 buf_index = 0;
58 	bool bwrite_sucess = false;
59 	u8 wait_h2c_limmit = 100;
60 	u8 wait_writeh2c_limmit = 100;
61 	u8 boxcontent[4], boxextcontent[4];
62 	u32 h2c_waitcounter = 0;
63 	unsigned long flag;
64 	u8 idx;
65 
66 	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
67 
68 	while (true) {
69 		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
70 		if (rtlhal->h2c_setinprogress) {
71 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
72 				 "H2C set in progress! Wait to set..element_id(%d).\n",
73 				 element_id);
74 
75 			while (rtlhal->h2c_setinprogress) {
76 				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
77 						       flag);
78 				h2c_waitcounter++;
79 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
80 					 "Wait 100 us (%d times)...\n",
81 					 h2c_waitcounter);
82 				udelay(100);
83 
84 				if (h2c_waitcounter > 1000)
85 					return;
86 				spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
87 						  flag);
88 			}
89 			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
90 		} else {
91 			rtlhal->h2c_setinprogress = true;
92 			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
93 			break;
94 		}
95 	}
96 
97 	while (!bwrite_sucess) {
98 		wait_writeh2c_limmit--;
99 		if (wait_writeh2c_limmit == 0) {
100 			pr_err("Write H2C fail because no trigger for FW INT!\n");
101 			break;
102 		}
103 
104 		boxnum = rtlhal->last_hmeboxnum;
105 		switch (boxnum) {
106 		case 0:
107 			box_reg = REG_HMEBOX_0;
108 			box_extreg = REG_HMEBOX_EXT_0;
109 			break;
110 		case 1:
111 			box_reg = REG_HMEBOX_1;
112 			box_extreg = REG_HMEBOX_EXT_1;
113 			break;
114 		case 2:
115 			box_reg = REG_HMEBOX_2;
116 			box_extreg = REG_HMEBOX_EXT_2;
117 			break;
118 		case 3:
119 			box_reg = REG_HMEBOX_3;
120 			box_extreg = REG_HMEBOX_EXT_3;
121 			break;
122 		default:
123 			pr_err("switch case %#x not processed\n",
124 			       boxnum);
125 			break;
126 		}
127 
128 		isfw_read = _rtl8723be_check_fw_read_last_h2c(hw, boxnum);
129 		while (!isfw_read) {
130 			wait_h2c_limmit--;
131 			if (wait_h2c_limmit == 0) {
132 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
133 					 "Waiting too long for FW read clear HMEBox(%d)!\n",
134 					 boxnum);
135 				break;
136 			}
137 
138 			udelay(10);
139 
140 			isfw_read = _rtl8723be_check_fw_read_last_h2c(hw,
141 								boxnum);
142 			u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
143 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
144 				 "Waiting for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
145 				 boxnum, u1b_tmp);
146 		}
147 
148 		if (!isfw_read) {
149 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
150 				 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
151 				 boxnum);
152 			break;
153 		}
154 
155 		memset(boxcontent, 0, sizeof(boxcontent));
156 		memset(boxextcontent, 0, sizeof(boxextcontent));
157 		boxcontent[0] = element_id;
158 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
159 			 "Write element_id box_reg(%4x) = %2x\n",
160 			  box_reg, element_id);
161 
162 		switch (cmd_len) {
163 		case 1:
164 		case 2:
165 		case 3:
166 			/*boxcontent[0] &= ~(BIT(7));*/
167 			memcpy((u8 *)(boxcontent) + 1,
168 			       p_cmdbuffer + buf_index, cmd_len);
169 
170 			for (idx = 0; idx < 4; idx++) {
171 				rtl_write_byte(rtlpriv, box_reg + idx,
172 					       boxcontent[idx]);
173 			}
174 			break;
175 		case 4:
176 		case 5:
177 		case 6:
178 		case 7:
179 			/*boxcontent[0] |= (BIT(7));*/
180 			memcpy((u8 *)(boxextcontent),
181 			       p_cmdbuffer + buf_index+3, cmd_len-3);
182 			memcpy((u8 *)(boxcontent) + 1,
183 			       p_cmdbuffer + buf_index, 3);
184 
185 			for (idx = 0; idx < 4; idx++) {
186 				rtl_write_byte(rtlpriv, box_extreg + idx,
187 					       boxextcontent[idx]);
188 			}
189 
190 			for (idx = 0; idx < 4; idx++) {
191 				rtl_write_byte(rtlpriv, box_reg + idx,
192 					       boxcontent[idx]);
193 			}
194 			break;
195 		default:
196 			pr_err("switch case %#x not processed\n",
197 			       cmd_len);
198 			break;
199 		}
200 
201 		bwrite_sucess = true;
202 
203 		rtlhal->last_hmeboxnum = boxnum + 1;
204 		if (rtlhal->last_hmeboxnum == 4)
205 			rtlhal->last_hmeboxnum = 0;
206 
207 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
208 			 "pHalData->last_hmeboxnum  = %d\n",
209 			  rtlhal->last_hmeboxnum);
210 	}
211 
212 	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
213 	rtlhal->h2c_setinprogress = false;
214 	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
215 
216 	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
217 }
218 
219 void rtl8723be_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
220 			    u32 cmd_len, u8 *p_cmdbuffer)
221 {
222 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
223 	u32 tmp_cmdbuf[2];
224 
225 	if (!rtlhal->fw_ready) {
226 		WARN_ONCE(true,
227 			  "rtl8723be: error H2C cmd because of Fw download fail!!!\n");
228 		return;
229 	}
230 
231 	memset(tmp_cmdbuf, 0, 8);
232 	memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
233 	_rtl8723be_fill_h2c_command(hw, element_id, cmd_len,
234 				    (u8 *)&tmp_cmdbuf);
235 	return;
236 }
237 
238 void rtl8723be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
239 {
240 	struct rtl_priv *rtlpriv = rtl_priv(hw);
241 	u8 u1_h2c_set_pwrmode[H2C_PWEMODE_LENGTH] = { 0 };
242 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
243 	u8 rlbm, power_state = 0, byte5 = 0;
244 	u8 awake_intvl;	/* DTIM = (awake_intvl - 1) */
245 	struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops;
246 	bool bt_ctrl_lps = (rtlpriv->cfg->ops->get_btc_status() ?
247 			    btc_ops->btc_is_bt_ctrl_lps(rtlpriv) : false);
248 	bool bt_lps_on = (rtlpriv->cfg->ops->get_btc_status() ?
249 			  btc_ops->btc_is_bt_lps_on(rtlpriv) : false);
250 
251 	if (bt_ctrl_lps)
252 		mode = (bt_lps_on ? FW_PS_MIN_MODE : FW_PS_ACTIVE_MODE);
253 
254 	RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, "FW LPS mode = %d (coex:%d)\n",
255 		 mode, bt_ctrl_lps);
256 
257 	switch (mode) {
258 	case FW_PS_MIN_MODE:
259 		rlbm = 0;
260 		awake_intvl = 2;
261 		break;
262 	case FW_PS_MAX_MODE:
263 		rlbm = 1;
264 		awake_intvl = 2;
265 		break;
266 	case FW_PS_DTIM_MODE:
267 		rlbm = 2;
268 		awake_intvl = ppsc->reg_max_lps_awakeintvl;
269 		/* hw->conf.ps_dtim_period or mac->vif->bss_conf.dtim_period
270 		 * is only used in swlps.
271 		 */
272 		break;
273 	default:
274 		rlbm = 2;
275 		awake_intvl = 4;
276 		break;
277 	}
278 
279 	if (rtlpriv->mac80211.p2p) {
280 		awake_intvl = 2;
281 		rlbm = 1;
282 	}
283 
284 	if (mode == FW_PS_ACTIVE_MODE) {
285 		byte5 = 0x40;
286 		power_state = FW_PWR_STATE_ACTIVE;
287 	} else {
288 		if (bt_ctrl_lps) {
289 			byte5 = btc_ops->btc_get_lps_val(rtlpriv);
290 			power_state = btc_ops->btc_get_rpwm_val(rtlpriv);
291 
292 			if ((rlbm == 2) && (byte5 & BIT(4))) {
293 				/* Keep awake interval to 1 to prevent from
294 				 * decreasing coex performance
295 				 */
296 				awake_intvl = 2;
297 				rlbm = 2;
298 			}
299 		} else {
300 			byte5 = 0x40;
301 			power_state = FW_PWR_STATE_RF_OFF;
302 		}
303 	}
304 
305 	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
306 	SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm);
307 	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
308 					 bt_ctrl_lps ? 0 : ppsc->smart_ps);
309 	SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
310 					       awake_intvl);
311 	SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
312 	SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
313 	SET_H2CCMD_PWRMODE_PARM_BYTE5(u1_h2c_set_pwrmode, byte5);
314 
315 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
316 		      "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
317 		      u1_h2c_set_pwrmode, H2C_PWEMODE_LENGTH);
318 	if (rtlpriv->cfg->ops->get_btc_status())
319 		btc_ops->btc_record_pwr_mode(rtlpriv, u1_h2c_set_pwrmode,
320 					     H2C_PWEMODE_LENGTH);
321 	rtl8723be_fill_h2c_cmd(hw, H2C_8723B_SETPWRMODE, H2C_PWEMODE_LENGTH,
322 			       u1_h2c_set_pwrmode);
323 }
324 
325 void rtl8723be_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw, u8 mstatus)
326 {
327 	u8 parm[3] = { 0, 0, 0 };
328 	/* parm[0]: bit0=0-->Disconnect, bit0=1-->Connect
329 	 *          bit1=0-->update Media Status to MACID
330 	 *          bit1=1-->update Media Status from MACID to MACID_End
331 	 * parm[1]: MACID, if this is INFRA_STA, MacID = 0
332 	 * parm[2]: MACID_End
333 	*/
334 	SET_H2CCMD_MSRRPT_PARM_OPMODE(parm, mstatus);
335 	SET_H2CCMD_MSRRPT_PARM_MACID_IND(parm, 0);
336 
337 	rtl8723be_fill_h2c_cmd(hw, H2C_8723B_MSRRPT, 3, parm);
338 }
339 
340 #define BEACON_PG		0 /* ->1 */
341 #define PSPOLL_PG		2
342 #define NULL_PG			3
343 #define PROBERSP_PG		4 /* ->5 */
344 #define QOS_NULL_PG		6
345 #define BT_QOS_NULL_PG	7
346 
347 #define TOTAL_RESERVED_PKT_LEN	1024	/* can be up to 1280 (tx_bndy=245) */
348 
349 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
350 	/* page 0 beacon */
351 	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
352 	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
353 	0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x20, 0x00,
354 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355 	0x64, 0x00, 0x10, 0x04, 0x00, 0x05, 0x54, 0x65,
356 	0x73, 0x74, 0x32, 0x01, 0x08, 0x82, 0x84, 0x0B,
357 	0x16, 0x24, 0x30, 0x48, 0x6C, 0x03, 0x01, 0x06,
358 	0x06, 0x02, 0x00, 0x00, 0x2A, 0x01, 0x02, 0x32,
359 	0x04, 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C,
360 	0x09, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
361 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
362 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
363 	0x00, 0x3D, 0x00, 0xDD, 0x07, 0x00, 0xE0, 0x4C,
364 	0x02, 0x02, 0x00, 0x00, 0xDD, 0x18, 0x00, 0x50,
365 	0xF2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04,
366 	0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, 0x01, 0x00,
367 
368 	/* page 1 beacon */
369 	0x00, 0x50, 0xF2, 0x02, 0x00, 0x00, 0x00, 0x00,
370 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
371 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
372 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
373 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
374 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
375 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
376 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
377 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
378 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
379 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
380 	0x10, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
381 	0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00,
382 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
383 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
384 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385 
386 	/* page 2  ps-poll */
387 	0xA4, 0x10, 0x01, 0xC0, 0xEC, 0x1A, 0x59, 0x0B,
388 	0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
389 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
390 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
391 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
392 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
393 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
394 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
395 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
396 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
397 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
398 	0x18, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
399 	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
400 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
401 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
402 	0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
403 
404 	/* page 3  null */
405 	0x48, 0x01, 0x00, 0x00, 0xEC, 0x1A, 0x59, 0x0B,
406 	0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
407 	0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x00, 0x00,
408 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
409 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
410 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
411 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
412 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
413 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
414 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
415 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
416 	0x72, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
417 	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
418 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
419 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
420 	0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
421 
422 	/* page 4  probe_resp */
423 	0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
424 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
425 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
426 	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
427 	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
428 	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
429 	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
430 	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
431 	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
432 	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
433 	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
434 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
435 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
436 	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
437 	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
438 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
439 
440 	/* page 5  probe_resp */
441 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
442 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
443 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
444 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
445 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
446 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
447 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
448 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
449 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
450 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
451 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
452 	0x1A, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
453 	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
454 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
455 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
456 	0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
457 
458 	/* page 6 qos null data */
459 	0xC8, 0x01, 0x00, 0x00, 0x84, 0xC9, 0xB2, 0xA7,
460 	0xB3, 0x6E, 0x00, 0xE0, 0x4C, 0x02, 0x51, 0x02,
461 	0x84, 0xC9, 0xB2, 0xA7, 0xB3, 0x6E, 0x00, 0x00,
462 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
463 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
464 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
465 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
466 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
467 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
468 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
469 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
470 	0x1A, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
471 	0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00,
472 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
473 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
474 	0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
475 
476 	/* page 7 BT-qos null data */
477 	0xC8, 0x01, 0x00, 0x00, 0x84, 0xC9, 0xB2, 0xA7,
478 	0xB3, 0x6E, 0x00, 0xE0, 0x4C, 0x02, 0x51, 0x02,
479 	0x84, 0xC9, 0xB2, 0xA7, 0xB3, 0x6E, 0x00, 0x00,
480 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
481 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
482 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
483 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
484 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
485 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
486 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
487 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
488 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
489 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
490 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
491 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
492 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
493 
494 };
495 
496 void rtl8723be_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
497 				  bool b_dl_finished)
498 {
499 	struct rtl_priv *rtlpriv = rtl_priv(hw);
500 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
501 	struct sk_buff *skb = NULL;
502 
503 	u32 totalpacketlen;
504 	bool rtstatus;
505 	u8 u1rsvdpageloc[5] = { 0 };
506 	bool b_dlok = false;
507 
508 	u8 *beacon;
509 	u8 *p_pspoll;
510 	u8 *nullfunc;
511 	u8 *p_probersp;
512 	u8 *qosnull;
513 	u8 *btqosnull;
514 	/*---------------------------------------------------------
515 	 *			(1) beacon
516 	 *---------------------------------------------------------
517 	 */
518 	beacon = &reserved_page_packet[BEACON_PG * 128];
519 	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
520 	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
521 
522 	/*-------------------------------------------------------
523 	 *			(2) ps-poll
524 	 *-------------------------------------------------------
525 	 */
526 	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
527 	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
528 	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
529 	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
530 
531 	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
532 
533 	/*--------------------------------------------------------
534 	 *			(3) null data
535 	 *--------------------------------------------------------
536 	 */
537 	nullfunc = &reserved_page_packet[NULL_PG * 128];
538 	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
539 	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
540 	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
541 
542 	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
543 
544 	/*---------------------------------------------------------
545 	 *			(4) probe response
546 	 *---------------------------------------------------------
547 	 */
548 	p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
549 	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
550 	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
551 	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
552 
553 	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
554 
555 	/*---------------------------------------------------------
556 	 *			(5) QoS Null
557 	 *---------------------------------------------------------
558 	 */
559 	qosnull = &reserved_page_packet[QOS_NULL_PG * 128];
560 	SET_80211_HDR_ADDRESS1(qosnull, mac->bssid);
561 	SET_80211_HDR_ADDRESS2(qosnull, mac->mac_addr);
562 	SET_80211_HDR_ADDRESS3(qosnull, mac->bssid);
563 
564 	SET_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(u1rsvdpageloc, QOS_NULL_PG);
565 
566 	/*---------------------------------------------------------
567 	 *			(5) QoS Null
568 	 *---------------------------------------------------------
569 	 */
570 	btqosnull = &reserved_page_packet[BT_QOS_NULL_PG * 128];
571 	SET_80211_HDR_ADDRESS1(btqosnull, mac->bssid);
572 	SET_80211_HDR_ADDRESS2(btqosnull, mac->mac_addr);
573 	SET_80211_HDR_ADDRESS3(btqosnull, mac->bssid);
574 
575 	SET_H2CCMD_RSVDPAGE_LOC_BT_QOS_NULL_DATA(u1rsvdpageloc, BT_QOS_NULL_PG);
576 
577 	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
578 
579 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
580 		      "rtl8723be_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
581 		      &reserved_page_packet[0], totalpacketlen);
582 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
583 		      "rtl8723be_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
584 		      u1rsvdpageloc, sizeof(u1rsvdpageloc));
585 
586 	skb = dev_alloc_skb(totalpacketlen);
587 	skb_put_data(skb, &reserved_page_packet, totalpacketlen);
588 
589 	rtstatus = rtl_cmd_send_packet(hw, skb);
590 
591 	if (rtstatus)
592 		b_dlok = true;
593 
594 	if (b_dlok) {
595 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
596 			 "Set RSVD page location to Fw.\n");
597 		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, "H2C_RSVDPAGE:\n",
598 			      u1rsvdpageloc, sizeof(u1rsvdpageloc));
599 		rtl8723be_fill_h2c_cmd(hw, H2C_8723B_RSVDPAGE,
600 				       sizeof(u1rsvdpageloc), u1rsvdpageloc);
601 	} else
602 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
603 			 "Set RSVD page location to Fw FAIL!!!!!!.\n");
604 }
605 
606 /*Should check FW support p2p or not.*/
607 static void rtl8723be_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw,
608 					     u8 ctwindow)
609 {
610 	u8 u1_ctwindow_period[1] = { ctwindow};
611 
612 	rtl8723be_fill_h2c_cmd(hw, H2C_8723B_P2P_PS_CTW_CMD, 1,
613 			       u1_ctwindow_period);
614 }
615 
616 void rtl8723be_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw,
617 				      u8 p2p_ps_state)
618 {
619 	struct rtl_priv *rtlpriv = rtl_priv(hw);
620 	struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
621 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
622 	struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
623 	struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
624 	u8 i;
625 	u16 ctwindow;
626 	u32 start_time, tsf_low;
627 
628 	switch (p2p_ps_state) {
629 	case P2P_PS_DISABLE:
630 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
631 		memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
632 		break;
633 	case P2P_PS_ENABLE:
634 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
635 		/* update CTWindow value. */
636 		if (p2pinfo->ctwindow > 0) {
637 			p2p_ps_offload->ctwindow_en = 1;
638 			ctwindow = p2pinfo->ctwindow;
639 			rtl8723be_set_p2p_ctw_period_cmd(hw, ctwindow);
640 		}
641 		/* hw only support 2 set of NoA */
642 		for (i = 0 ; i < p2pinfo->noa_num ; i++) {
643 			/* To control the register setting
644 			 * for which NOA
645 			 */
646 			rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
647 			if (i == 0)
648 				p2p_ps_offload->noa0_en = 1;
649 			else
650 				p2p_ps_offload->noa1_en = 1;
651 
652 			/* config P2P NoA Descriptor Register */
653 			rtl_write_dword(rtlpriv, 0x5E0,
654 					p2pinfo->noa_duration[i]);
655 			rtl_write_dword(rtlpriv, 0x5E4,
656 					p2pinfo->noa_interval[i]);
657 
658 			/*Get Current TSF value */
659 			tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
660 
661 			start_time = p2pinfo->noa_start_time[i];
662 			if (p2pinfo->noa_count_type[i] != 1) {
663 				while (start_time <= (tsf_low + (50 * 1024))) {
664 					start_time += p2pinfo->noa_interval[i];
665 					if (p2pinfo->noa_count_type[i] != 255)
666 						p2pinfo->noa_count_type[i]--;
667 				}
668 			}
669 			rtl_write_dword(rtlpriv, 0x5E8, start_time);
670 			rtl_write_dword(rtlpriv, 0x5EC,
671 					p2pinfo->noa_count_type[i]);
672 		}
673 
674 		if ((p2pinfo->opp_ps == 1) ||
675 		    (p2pinfo->noa_num > 0)) {
676 			/* rst p2p circuit */
677 			rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
678 
679 			p2p_ps_offload->offload_en = 1;
680 
681 			if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
682 				p2p_ps_offload->role = 1;
683 				p2p_ps_offload->allstasleep = 0;
684 			} else {
685 				p2p_ps_offload->role = 0;
686 			}
687 			p2p_ps_offload->discovery = 0;
688 		}
689 		break;
690 	case P2P_PS_SCAN:
691 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
692 		p2p_ps_offload->discovery = 1;
693 		break;
694 	case P2P_PS_SCAN_DONE:
695 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
696 		p2p_ps_offload->discovery = 0;
697 		p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
698 		break;
699 	default:
700 		break;
701 	}
702 
703 	rtl8723be_fill_h2c_cmd(hw, H2C_8723B_P2P_PS_OFFLOAD, 1,
704 			       (u8 *)p2p_ps_offload);
705 }
706