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;
244 	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
245 
246 	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
247 	rlbm = 0;/*YJ,temp,120316. FW now not support RLBM=2.*/
248 	SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm);
249 	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
250 					 (rtlpriv->mac80211.p2p) ?
251 					  ppsc->smart_ps : 1);
252 	SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
253 					       ppsc->reg_max_lps_awakeintvl);
254 	SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
255 	if (mode == FW_PS_ACTIVE_MODE)
256 		power_state |= FW_PWR_STATE_ACTIVE;
257 	else
258 		power_state |= FW_PWR_STATE_RF_OFF;
259 	SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
260 
261 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
262 		      "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
263 		      u1_h2c_set_pwrmode, H2C_PWEMODE_LENGTH);
264 	rtl8723be_fill_h2c_cmd(hw, H2C_8723B_SETPWRMODE, H2C_PWEMODE_LENGTH,
265 			       u1_h2c_set_pwrmode);
266 }
267 
268 void rtl8723be_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw, u8 mstatus)
269 {
270 	u8 parm[3] = { 0, 0, 0 };
271 	/* parm[0]: bit0=0-->Disconnect, bit0=1-->Connect
272 	 *          bit1=0-->update Media Status to MACID
273 	 *          bit1=1-->update Media Status from MACID to MACID_End
274 	 * parm[1]: MACID, if this is INFRA_STA, MacID = 0
275 	 * parm[2]: MACID_End
276 	*/
277 	SET_H2CCMD_MSRRPT_PARM_OPMODE(parm, mstatus);
278 	SET_H2CCMD_MSRRPT_PARM_MACID_IND(parm, 0);
279 
280 	rtl8723be_fill_h2c_cmd(hw, H2C_8723B_MSRRPT, 3, parm);
281 }
282 
283 #define BEACON_PG		0 /* ->1 */
284 #define PSPOLL_PG		2
285 #define NULL_PG			3
286 #define PROBERSP_PG		4 /* ->5 */
287 #define QOS_NULL_PG		6
288 #define BT_QOS_NULL_PG	7
289 
290 #define TOTAL_RESERVED_PKT_LEN	1024	/* can be up to 1280 (tx_bndy=245) */
291 
292 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
293 	/* page 0 beacon */
294 	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
295 	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
296 	0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x20, 0x00,
297 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298 	0x64, 0x00, 0x10, 0x04, 0x00, 0x05, 0x54, 0x65,
299 	0x73, 0x74, 0x32, 0x01, 0x08, 0x82, 0x84, 0x0B,
300 	0x16, 0x24, 0x30, 0x48, 0x6C, 0x03, 0x01, 0x06,
301 	0x06, 0x02, 0x00, 0x00, 0x2A, 0x01, 0x02, 0x32,
302 	0x04, 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C,
303 	0x09, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
304 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
305 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
306 	0x00, 0x3D, 0x00, 0xDD, 0x07, 0x00, 0xE0, 0x4C,
307 	0x02, 0x02, 0x00, 0x00, 0xDD, 0x18, 0x00, 0x50,
308 	0xF2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04,
309 	0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, 0x01, 0x00,
310 
311 	/* page 1 beacon */
312 	0x00, 0x50, 0xF2, 0x02, 0x00, 0x00, 0x00, 0x00,
313 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
314 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
317 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
318 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323 	0x10, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
324 	0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00,
325 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328 
329 	/* page 2  ps-poll */
330 	0xA4, 0x10, 0x01, 0xC0, 0xEC, 0x1A, 0x59, 0x0B,
331 	0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
332 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
334 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
335 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
336 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
337 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
338 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
339 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
341 	0x18, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
342 	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
343 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
344 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
345 	0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
346 
347 	/* page 3  null */
348 	0x48, 0x01, 0x00, 0x00, 0xEC, 0x1A, 0x59, 0x0B,
349 	0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
350 	0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x00, 0x00,
351 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
352 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
353 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
354 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
356 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
357 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
358 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
359 	0x72, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
360 	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
361 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
362 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
363 	0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
364 
365 	/* page 4  probe_resp */
366 	0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
367 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
368 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
369 	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
370 	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
371 	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
372 	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
373 	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
374 	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
375 	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
376 	0x03, 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 	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
380 	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
381 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
382 
383 	/* page 5  probe_resp */
384 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
386 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
387 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
388 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 	0x1A, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
396 	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
397 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
398 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
399 	0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
400 
401 	/* page 6 qos null data */
402 	0xC8, 0x01, 0x00, 0x00, 0x84, 0xC9, 0xB2, 0xA7,
403 	0xB3, 0x6E, 0x00, 0xE0, 0x4C, 0x02, 0x51, 0x02,
404 	0x84, 0xC9, 0xB2, 0xA7, 0xB3, 0x6E, 0x00, 0x00,
405 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
406 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
407 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 	0x1A, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
414 	0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00,
415 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
416 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
417 	0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
418 
419 	/* page 7 BT-qos null data */
420 	0xC8, 0x01, 0x00, 0x00, 0x84, 0xC9, 0xB2, 0xA7,
421 	0xB3, 0x6E, 0x00, 0xE0, 0x4C, 0x02, 0x51, 0x02,
422 	0x84, 0xC9, 0xB2, 0xA7, 0xB3, 0x6E, 0x00, 0x00,
423 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
424 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
425 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
426 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
427 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
428 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
429 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
431 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
432 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
433 	0x00, 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 
437 };
438 
439 void rtl8723be_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
440 				  bool b_dl_finished)
441 {
442 	struct rtl_priv *rtlpriv = rtl_priv(hw);
443 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
444 	struct sk_buff *skb = NULL;
445 
446 	u32 totalpacketlen;
447 	bool rtstatus;
448 	u8 u1rsvdpageloc[5] = { 0 };
449 	bool b_dlok = false;
450 
451 	u8 *beacon;
452 	u8 *p_pspoll;
453 	u8 *nullfunc;
454 	u8 *p_probersp;
455 	u8 *qosnull;
456 	u8 *btqosnull;
457 	/*---------------------------------------------------------
458 	 *			(1) beacon
459 	 *---------------------------------------------------------
460 	 */
461 	beacon = &reserved_page_packet[BEACON_PG * 128];
462 	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
463 	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
464 
465 	/*-------------------------------------------------------
466 	 *			(2) ps-poll
467 	 *-------------------------------------------------------
468 	 */
469 	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
470 	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
471 	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
472 	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
473 
474 	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
475 
476 	/*--------------------------------------------------------
477 	 *			(3) null data
478 	 *--------------------------------------------------------
479 	 */
480 	nullfunc = &reserved_page_packet[NULL_PG * 128];
481 	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
482 	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
483 	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
484 
485 	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
486 
487 	/*---------------------------------------------------------
488 	 *			(4) probe response
489 	 *---------------------------------------------------------
490 	 */
491 	p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
492 	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
493 	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
494 	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
495 
496 	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
497 
498 	/*---------------------------------------------------------
499 	 *			(5) QoS Null
500 	 *---------------------------------------------------------
501 	 */
502 	qosnull = &reserved_page_packet[QOS_NULL_PG * 128];
503 	SET_80211_HDR_ADDRESS1(qosnull, mac->bssid);
504 	SET_80211_HDR_ADDRESS2(qosnull, mac->mac_addr);
505 	SET_80211_HDR_ADDRESS3(qosnull, mac->bssid);
506 
507 	SET_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(u1rsvdpageloc, QOS_NULL_PG);
508 
509 	/*---------------------------------------------------------
510 	 *			(5) QoS Null
511 	 *---------------------------------------------------------
512 	 */
513 	btqosnull = &reserved_page_packet[BT_QOS_NULL_PG * 128];
514 	SET_80211_HDR_ADDRESS1(btqosnull, mac->bssid);
515 	SET_80211_HDR_ADDRESS2(btqosnull, mac->mac_addr);
516 	SET_80211_HDR_ADDRESS3(btqosnull, mac->bssid);
517 
518 	SET_H2CCMD_RSVDPAGE_LOC_BT_QOS_NULL_DATA(u1rsvdpageloc, BT_QOS_NULL_PG);
519 
520 	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
521 
522 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
523 		      "rtl8723be_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
524 		      &reserved_page_packet[0], totalpacketlen);
525 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
526 		      "rtl8723be_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
527 		      u1rsvdpageloc, sizeof(u1rsvdpageloc));
528 
529 	skb = dev_alloc_skb(totalpacketlen);
530 	memcpy((u8 *)skb_put(skb, totalpacketlen),
531 	       &reserved_page_packet, totalpacketlen);
532 
533 	rtstatus = rtl_cmd_send_packet(hw, skb);
534 
535 	if (rtstatus)
536 		b_dlok = true;
537 
538 	if (b_dlok) {
539 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
540 			 "Set RSVD page location to Fw.\n");
541 		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, "H2C_RSVDPAGE:\n",
542 			      u1rsvdpageloc, sizeof(u1rsvdpageloc));
543 		rtl8723be_fill_h2c_cmd(hw, H2C_8723B_RSVDPAGE,
544 				       sizeof(u1rsvdpageloc), u1rsvdpageloc);
545 	} else
546 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
547 			 "Set RSVD page location to Fw FAIL!!!!!!.\n");
548 }
549 
550 /*Should check FW support p2p or not.*/
551 static void rtl8723be_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw,
552 					     u8 ctwindow)
553 {
554 	u8 u1_ctwindow_period[1] = { ctwindow};
555 
556 	rtl8723be_fill_h2c_cmd(hw, H2C_8723B_P2P_PS_CTW_CMD, 1,
557 			       u1_ctwindow_period);
558 }
559 
560 void rtl8723be_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw,
561 				      u8 p2p_ps_state)
562 {
563 	struct rtl_priv *rtlpriv = rtl_priv(hw);
564 	struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
565 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
566 	struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
567 	struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
568 	u8 i;
569 	u16 ctwindow;
570 	u32 start_time, tsf_low;
571 
572 	switch (p2p_ps_state) {
573 	case P2P_PS_DISABLE:
574 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
575 		memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
576 		break;
577 	case P2P_PS_ENABLE:
578 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
579 		/* update CTWindow value. */
580 		if (p2pinfo->ctwindow > 0) {
581 			p2p_ps_offload->ctwindow_en = 1;
582 			ctwindow = p2pinfo->ctwindow;
583 			rtl8723be_set_p2p_ctw_period_cmd(hw, ctwindow);
584 		}
585 		/* hw only support 2 set of NoA */
586 		for (i = 0 ; i < p2pinfo->noa_num ; i++) {
587 			/* To control the register setting
588 			 * for which NOA
589 			 */
590 			rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
591 			if (i == 0)
592 				p2p_ps_offload->noa0_en = 1;
593 			else
594 				p2p_ps_offload->noa1_en = 1;
595 
596 			/* config P2P NoA Descriptor Register */
597 			rtl_write_dword(rtlpriv, 0x5E0,
598 					p2pinfo->noa_duration[i]);
599 			rtl_write_dword(rtlpriv, 0x5E4,
600 					p2pinfo->noa_interval[i]);
601 
602 			/*Get Current TSF value */
603 			tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
604 
605 			start_time = p2pinfo->noa_start_time[i];
606 			if (p2pinfo->noa_count_type[i] != 1) {
607 				while (start_time <= (tsf_low + (50 * 1024))) {
608 					start_time += p2pinfo->noa_interval[i];
609 					if (p2pinfo->noa_count_type[i] != 255)
610 						p2pinfo->noa_count_type[i]--;
611 				}
612 			}
613 			rtl_write_dword(rtlpriv, 0x5E8, start_time);
614 			rtl_write_dword(rtlpriv, 0x5EC,
615 					p2pinfo->noa_count_type[i]);
616 		}
617 
618 		if ((p2pinfo->opp_ps == 1) ||
619 		    (p2pinfo->noa_num > 0)) {
620 			/* rst p2p circuit */
621 			rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
622 
623 			p2p_ps_offload->offload_en = 1;
624 
625 			if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
626 				p2p_ps_offload->role = 1;
627 				p2p_ps_offload->allstasleep = 0;
628 			} else {
629 				p2p_ps_offload->role = 0;
630 			}
631 			p2p_ps_offload->discovery = 0;
632 		}
633 		break;
634 	case P2P_PS_SCAN:
635 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
636 		p2p_ps_offload->discovery = 1;
637 		break;
638 	case P2P_PS_SCAN_DONE:
639 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
640 		p2p_ps_offload->discovery = 0;
641 		p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
642 		break;
643 	default:
644 		break;
645 	}
646 
647 	rtl8723be_fill_h2c_cmd(hw, H2C_8723B_P2P_PS_OFFLOAD, 1,
648 			       (u8 *)p2p_ps_offload);
649 }
650 
651 void rtl8723be_c2h_content_parsing(struct ieee80211_hw *hw,
652 				   u8 c2h_cmd_id,
653 				   u8 c2h_cmd_len, u8 *tmp_buf)
654 {
655 	struct rtl_priv *rtlpriv = rtl_priv(hw);
656 
657 	switch (c2h_cmd_id) {
658 	case C2H_8723B_DBG:
659 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
660 			 "[C2H], C2H_8723BE_DBG!!\n");
661 		break;
662 	case C2H_8723B_TX_REPORT:
663 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
664 			 "[C2H], C2H_8723BE_TX_REPORT!\n");
665 		break;
666 	case C2H_8723B_BT_INFO:
667 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
668 			 "[C2H], C2H_8723BE_BT_INFO!!\n");
669 		rtlpriv->btcoexist.btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf,
670 							      c2h_cmd_len);
671 		break;
672 	case C2H_8723B_BT_MP:
673 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
674 			 "[C2H], C2H_8723BE_BT_MP!!\n");
675 		break;
676 	default:
677 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
678 			 "[C2H], Unknown packet!! CmdId(%#X)!\n", c2h_cmd_id);
679 		break;
680 	}
681 }
682 
683 void rtl8723be_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len)
684 {
685 	struct rtl_priv *rtlpriv = rtl_priv(hw);
686 	u8 c2h_cmd_id = 0, c2h_cmd_seq = 0, c2h_cmd_len = 0;
687 	u8 *tmp_buf = NULL;
688 
689 	c2h_cmd_id = buffer[0];
690 	c2h_cmd_seq = buffer[1];
691 	c2h_cmd_len = len - 2;
692 	tmp_buf = buffer + 2;
693 
694 	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
695 		 "[C2H packet], c2hCmdId=0x%x, c2hCmdSeq=0x%x, c2hCmdLen=%d\n",
696 		 c2h_cmd_id, c2h_cmd_seq, c2h_cmd_len);
697 
698 	RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_TRACE,
699 		      "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len);
700 
701 	switch (c2h_cmd_id) {
702 	case C2H_8723B_BT_INFO:
703 	case C2H_8723B_BT_MP:
704 		rtl_c2hcmd_enqueue(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf);
705 		break;
706 
707 	default:
708 		rtl8723be_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len,
709 					      tmp_buf);
710 		break;
711 	}
712 }
713