xref: /linux/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/fw.c (revision e58e871becec2d3b04ed91c0c16fe8deac9c9dfa)
1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2012  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 _rtl8723e_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, val_mcutst_1;
40 	bool result = false;
41 
42 	val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
43 	val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
44 
45 	if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
46 		result = true;
47 	return result;
48 }
49 
50 static void _rtl8723e_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id,
51 				       u32 cmd_len, u8 *cmdbuffer)
52 {
53 	struct rtl_priv *rtlpriv = rtl_priv(hw);
54 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
55 	u8 boxnum;
56 	u16 box_reg = 0, box_extreg = 0;
57 	u8 u1b_tmp;
58 	bool isfw_read = false;
59 	u8 buf_index = 0;
60 	bool bwrite_sucess = false;
61 	u8 wait_h2c_limmit = 100;
62 	u8 wait_writeh2c_limmit = 100;
63 	u8 boxcontent[4], boxextcontent[2];
64 	u32 h2c_waitcounter = 0;
65 	unsigned long flag;
66 	u8 idx;
67 
68 	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
69 
70 	while (true) {
71 		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
72 		if (rtlhal->h2c_setinprogress) {
73 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
74 				 "H2C set in progress! Wait to set..element_id(%d).\n",
75 				 element_id);
76 
77 			while (rtlhal->h2c_setinprogress) {
78 				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
79 						       flag);
80 				h2c_waitcounter++;
81 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
82 					 "Wait 100 us (%d times)...\n",
83 					  h2c_waitcounter);
84 				udelay(100);
85 
86 				if (h2c_waitcounter > 1000)
87 					return;
88 				spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
89 						  flag);
90 			}
91 			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
92 		} else {
93 			rtlhal->h2c_setinprogress = true;
94 			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
95 			break;
96 		}
97 	}
98 
99 	while (!bwrite_sucess) {
100 		wait_writeh2c_limmit--;
101 		if (wait_writeh2c_limmit == 0) {
102 			pr_err("Write H2C fail because no trigger for FW INT!\n");
103 			break;
104 		}
105 
106 		boxnum = rtlhal->last_hmeboxnum;
107 		switch (boxnum) {
108 		case 0:
109 			box_reg = REG_HMEBOX_0;
110 			box_extreg = REG_HMEBOX_EXT_0;
111 			break;
112 		case 1:
113 			box_reg = REG_HMEBOX_1;
114 			box_extreg = REG_HMEBOX_EXT_1;
115 			break;
116 		case 2:
117 			box_reg = REG_HMEBOX_2;
118 			box_extreg = REG_HMEBOX_EXT_2;
119 			break;
120 		case 3:
121 			box_reg = REG_HMEBOX_3;
122 			box_extreg = REG_HMEBOX_EXT_3;
123 			break;
124 		default:
125 			pr_err("switch case %#x not processed\n",
126 			       boxnum);
127 			break;
128 		}
129 
130 		isfw_read = _rtl8723e_check_fw_read_last_h2c(hw, boxnum);
131 		while (!isfw_read) {
132 
133 			wait_h2c_limmit--;
134 			if (wait_h2c_limmit == 0) {
135 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
136 					 "Waiting too long for FW read clear HMEBox(%d)!\n",
137 					 boxnum);
138 				break;
139 			}
140 
141 			udelay(10);
142 
143 			isfw_read = _rtl8723e_check_fw_read_last_h2c(hw,
144 								boxnum);
145 			u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
146 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
147 				 "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
148 				 boxnum, u1b_tmp);
149 		}
150 
151 		if (!isfw_read) {
152 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
153 				 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
154 				 boxnum);
155 			break;
156 		}
157 
158 		memset(boxcontent, 0, sizeof(boxcontent));
159 		memset(boxextcontent, 0, sizeof(boxextcontent));
160 		boxcontent[0] = element_id;
161 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
162 			 "Write element_id box_reg(%4x) = %2x\n",
163 			  box_reg, element_id);
164 
165 		switch (cmd_len) {
166 		case 1:
167 			boxcontent[0] &= ~(BIT(7));
168 			memcpy((u8 *)(boxcontent) + 1,
169 			       cmdbuffer + buf_index, 1);
170 
171 			for (idx = 0; idx < 4; idx++) {
172 				rtl_write_byte(rtlpriv, box_reg + idx,
173 					       boxcontent[idx]);
174 			}
175 			break;
176 		case 2:
177 			boxcontent[0] &= ~(BIT(7));
178 			memcpy((u8 *)(boxcontent) + 1,
179 			       cmdbuffer + buf_index, 2);
180 
181 			for (idx = 0; idx < 4; idx++) {
182 				rtl_write_byte(rtlpriv, box_reg + idx,
183 					       boxcontent[idx]);
184 			}
185 			break;
186 		case 3:
187 			boxcontent[0] &= ~(BIT(7));
188 			memcpy((u8 *)(boxcontent) + 1,
189 			       cmdbuffer + buf_index, 3);
190 
191 			for (idx = 0; idx < 4; idx++) {
192 				rtl_write_byte(rtlpriv, box_reg + idx,
193 					       boxcontent[idx]);
194 			}
195 			break;
196 		case 4:
197 			boxcontent[0] |= (BIT(7));
198 			memcpy((u8 *)(boxextcontent),
199 			       cmdbuffer + buf_index, 2);
200 			memcpy((u8 *)(boxcontent) + 1,
201 			       cmdbuffer + buf_index + 2, 2);
202 
203 			for (idx = 0; idx < 2; idx++) {
204 				rtl_write_byte(rtlpriv, box_extreg + idx,
205 					       boxextcontent[idx]);
206 			}
207 
208 			for (idx = 0; idx < 4; idx++) {
209 				rtl_write_byte(rtlpriv, box_reg + idx,
210 					       boxcontent[idx]);
211 			}
212 			break;
213 		case 5:
214 			boxcontent[0] |= (BIT(7));
215 			memcpy((u8 *)(boxextcontent),
216 			       cmdbuffer + buf_index, 2);
217 			memcpy((u8 *)(boxcontent) + 1,
218 			       cmdbuffer + buf_index + 2, 3);
219 
220 			for (idx = 0; idx < 2; idx++) {
221 				rtl_write_byte(rtlpriv, box_extreg + idx,
222 					       boxextcontent[idx]);
223 			}
224 
225 			for (idx = 0; idx < 4; idx++) {
226 				rtl_write_byte(rtlpriv, box_reg + idx,
227 					       boxcontent[idx]);
228 			}
229 			break;
230 		default:
231 			pr_err("switch case %#x not processed\n",
232 			       cmd_len);
233 			break;
234 		}
235 
236 		bwrite_sucess = true;
237 
238 		rtlhal->last_hmeboxnum = boxnum + 1;
239 		if (rtlhal->last_hmeboxnum == 4)
240 			rtlhal->last_hmeboxnum = 0;
241 
242 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
243 			 "pHalData->last_hmeboxnum  = %d\n",
244 			  rtlhal->last_hmeboxnum);
245 	}
246 
247 	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
248 	rtlhal->h2c_setinprogress = false;
249 	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
250 
251 	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
252 }
253 
254 void rtl8723e_fill_h2c_cmd(struct ieee80211_hw *hw,
255 			   u8 element_id, u32 cmd_len, u8 *cmdbuffer)
256 {
257 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
258 	u32 tmp_cmdbuf[2];
259 
260 	if (!rtlhal->fw_ready) {
261 		WARN_ONCE(true,
262 			  "rtl8723ae: error H2C cmd because of Fw download fail!!!\n");
263 		return;
264 	}
265 	memset(tmp_cmdbuf, 0, 8);
266 	memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
267 	_rtl8723e_fill_h2c_command(hw, element_id, cmd_len,
268 				   (u8 *)&tmp_cmdbuf);
269 }
270 
271 void rtl8723e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
272 {
273 	struct rtl_priv *rtlpriv = rtl_priv(hw);
274 	u8 u1_h2c_set_pwrmode[3] = { 0 };
275 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
276 
277 	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
278 
279 	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
280 	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
281 		(rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1);
282 	SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
283 					      ppsc->reg_max_lps_awakeintvl);
284 
285 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
286 		      "rtl8723e_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
287 		      u1_h2c_set_pwrmode, 3);
288 	rtl8723e_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
289 }
290 
291 #define BEACON_PG		0 /* ->1 */
292 #define PSPOLL_PG		2
293 #define NULL_PG			3
294 #define PROBERSP_PG		4 /* ->5 */
295 
296 #define TOTAL_RESERVED_PKT_LEN	768
297 
298 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
299 	/* page 0 beacon */
300 	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
301 	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
302 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
303 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
305 	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
306 	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
307 	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
308 	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
309 	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
310 	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313 	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
314 	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 
317 	/* page 1 beacon */
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 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
329 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
330 	0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
331 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
332 	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
334 
335 	/* page 2  ps-poll */
336 	0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
337 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
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 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
344 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
345 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
346 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
348 	0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
349 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
350 	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
352 
353 	/* page 3  null */
354 	0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
355 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
356 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
357 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
358 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
359 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
360 	0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
364 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
365 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
366 	0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
367 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
368 	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
369 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
370 
371 	/* page 4  probe_resp */
372 	0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
373 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
374 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
375 	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
376 	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
377 	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
378 	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
379 	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
380 	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
381 	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
382 	0x03, 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 	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
386 	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
387 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
388 
389 	/* page 5  probe_resp */
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 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
399 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
400 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
401 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
402 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
403 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
404 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
405 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
406 };
407 
408 void rtl8723e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
409 {
410 	struct rtl_priv *rtlpriv = rtl_priv(hw);
411 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
412 	struct sk_buff *skb = NULL;
413 	u32 totalpacketlen;
414 	bool rtstatus;
415 	u8 u1rsvdpageloc[3] = { 0 };
416 	bool b_dlok = false;
417 	u8 *beacon;
418 	u8 *p_pspoll;
419 	u8 *nullfunc;
420 	u8 *p_probersp;
421 
422 	/*---------------------------------------------------------
423 	 *			(1) beacon
424 	 *---------------------------------------------------------
425 	 */
426 	beacon = &reserved_page_packet[BEACON_PG * 128];
427 	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
428 	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
429 
430 	/*-------------------------------------------------------
431 	 *			(2) ps-poll
432 	 *--------------------------------------------------------
433 	 */
434 	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
435 	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
436 	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
437 	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
438 
439 	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
440 
441 	/*--------------------------------------------------------
442 	 *			(3) null data
443 	 *---------------------------------------------------------
444 	 */
445 	nullfunc = &reserved_page_packet[NULL_PG * 128];
446 	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
447 	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
448 	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
449 
450 	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
451 
452 	/*---------------------------------------------------------
453 	 *			(4) probe response
454 	 *----------------------------------------------------------
455 	 */
456 	p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
457 	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
458 	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
459 	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
460 
461 	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
462 
463 	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
464 
465 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
466 		      "rtl8723e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
467 		      &reserved_page_packet[0], totalpacketlen);
468 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
469 		      "rtl8723e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
470 		      u1rsvdpageloc, 3);
471 
472 	skb = dev_alloc_skb(totalpacketlen);
473 	memcpy((u8 *)skb_put(skb, totalpacketlen),
474 	       &reserved_page_packet, totalpacketlen);
475 
476 	rtstatus = rtl_cmd_send_packet(hw, skb);
477 
478 	if (rtstatus)
479 		b_dlok = true;
480 
481 	if (b_dlok) {
482 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
483 			 "Set RSVD page location to Fw.\n");
484 		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
485 			      "H2C_RSVDPAGE:\n",
486 			      u1rsvdpageloc, 3);
487 		rtl8723e_fill_h2c_cmd(hw, H2C_RSVDPAGE,
488 				      sizeof(u1rsvdpageloc), u1rsvdpageloc);
489 	} else
490 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
491 			 "Set RSVD page location to Fw FAIL!!!!!!.\n");
492 }
493 
494 void rtl8723e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
495 {
496 	u8 u1_joinbssrpt_parm[1] = { 0 };
497 
498 	SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
499 
500 	rtl8723e_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
501 }
502 
503 static void rtl8723e_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw,
504 					    u8 ctwindow)
505 {
506 	u8 u1_ctwindow_period[1] = { ctwindow};
507 
508 	rtl8723e_fill_h2c_cmd(hw, H2C_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
509 
510 }
511 
512 void rtl8723e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
513 {
514 	struct rtl_priv *rtlpriv = rtl_priv(hw);
515 	struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
516 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
517 	struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
518 	struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
519 	u8	i;
520 	u16	ctwindow;
521 	u32	start_time, tsf_low;
522 
523 	switch (p2p_ps_state) {
524 	case P2P_PS_DISABLE:
525 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
526 		memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
527 		break;
528 	case P2P_PS_ENABLE:
529 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
530 		/* update CTWindow value. */
531 		if (p2pinfo->ctwindow > 0) {
532 			p2p_ps_offload->ctwindow_en = 1;
533 			ctwindow = p2pinfo->ctwindow;
534 			rtl8723e_set_p2p_ctw_period_cmd(hw, ctwindow);
535 		}
536 
537 		/* hw only support 2 set of NoA */
538 		for (i = 0 ; i < p2pinfo->noa_num ; i++) {
539 			/* To control the register setting for which NOA*/
540 			rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
541 			if (i == 0)
542 				p2p_ps_offload->noa0_en = 1;
543 			else
544 				p2p_ps_offload->noa1_en = 1;
545 
546 			/* config P2P NoA Descriptor Register */
547 			rtl_write_dword(rtlpriv, 0x5E0,
548 					p2pinfo->noa_duration[i]);
549 			rtl_write_dword(rtlpriv, 0x5E4,
550 					p2pinfo->noa_interval[i]);
551 
552 			/*Get Current TSF value */
553 			tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
554 
555 			start_time = p2pinfo->noa_start_time[i];
556 			if (p2pinfo->noa_count_type[i] != 1) {
557 				while (start_time <=
558 					(tsf_low+(50*1024))) {
559 					start_time +=
560 						p2pinfo->noa_interval[i];
561 					if (p2pinfo->noa_count_type[i] != 255)
562 						p2pinfo->noa_count_type[i]--;
563 				}
564 			}
565 			rtl_write_dword(rtlpriv, 0x5E8, start_time);
566 			rtl_write_dword(rtlpriv, 0x5EC,
567 				p2pinfo->noa_count_type[i]);
568 
569 		}
570 
571 		if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
572 			/* rst p2p circuit */
573 			rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
574 
575 			p2p_ps_offload->offload_en = 1;
576 
577 			if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
578 				p2p_ps_offload->role = 1;
579 				p2p_ps_offload->allstasleep = 0;
580 			} else {
581 				p2p_ps_offload->role = 0;
582 			}
583 
584 			p2p_ps_offload->discovery = 0;
585 		}
586 		break;
587 	case P2P_PS_SCAN:
588 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
589 		p2p_ps_offload->discovery = 1;
590 		break;
591 	case P2P_PS_SCAN_DONE:
592 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
593 		p2p_ps_offload->discovery = 0;
594 		p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
595 		break;
596 	default:
597 		break;
598 	}
599 
600 	rtl8723e_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
601 
602 }
603