1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2013  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 "../efuse.h"
31 #include "reg.h"
32 #include "def.h"
33 #include "fw.h"
34 
35 static void _rtl88e_enable_fw_download(struct ieee80211_hw *hw, bool enable)
36 {
37 	struct rtl_priv *rtlpriv = rtl_priv(hw);
38 	u8 tmp;
39 
40 	if (enable) {
41 		tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
42 		rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
43 
44 		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
45 		rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
46 
47 		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
48 		rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
49 	} else {
50 		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
51 		rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
52 
53 		rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
54 	}
55 }
56 
57 static void _rtl88e_write_fw(struct ieee80211_hw *hw,
58 			     enum version_8188e version, u8 *buffer, u32 size)
59 {
60 	struct rtl_priv *rtlpriv = rtl_priv(hw);
61 	u8 *bufferptr = (u8 *)buffer;
62 	u32 pagenums, remainsize;
63 	u32 page, offset;
64 
65 	RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "FW size is %d bytes,\n", size);
66 
67 	rtl_fill_dummy(bufferptr, &size);
68 
69 	pagenums = size / FW_8192C_PAGE_SIZE;
70 	remainsize = size % FW_8192C_PAGE_SIZE;
71 
72 	if (pagenums > 8)
73 		pr_err("Page numbers should not greater then 8\n");
74 
75 	for (page = 0; page < pagenums; page++) {
76 		offset = page * FW_8192C_PAGE_SIZE;
77 		rtl_fw_page_write(hw, page, (bufferptr + offset),
78 				  FW_8192C_PAGE_SIZE);
79 	}
80 
81 	if (remainsize) {
82 		offset = pagenums * FW_8192C_PAGE_SIZE;
83 		page = pagenums;
84 		rtl_fw_page_write(hw, page, (bufferptr + offset), remainsize);
85 	}
86 }
87 
88 static int _rtl88e_fw_free_to_go(struct ieee80211_hw *hw)
89 {
90 	struct rtl_priv *rtlpriv = rtl_priv(hw);
91 	int err = -EIO;
92 	u32 counter = 0;
93 	u32 value32;
94 
95 	do {
96 		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
97 	} while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
98 		 (!(value32 & FWDL_CHKSUM_RPT)));
99 
100 	if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
101 		pr_err("chksum report fail! REG_MCUFWDL:0x%08x .\n",
102 		       value32);
103 		goto exit;
104 	}
105 	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
106 	value32 |= MCUFWDL_RDY;
107 	value32 &= ~WINTINI_RDY;
108 	rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
109 
110 	rtl88e_firmware_selfreset(hw);
111 	counter = 0;
112 
113 	do {
114 		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
115 		if (value32 & WINTINI_RDY)
116 			return 0;
117 
118 		udelay(FW_8192C_POLLING_DELAY);
119 
120 	} while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
121 
122 	pr_err("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n",
123 	       value32);
124 
125 exit:
126 	return err;
127 }
128 
129 int rtl88e_download_fw(struct ieee80211_hw *hw,
130 		       bool buse_wake_on_wlan_fw)
131 {
132 	struct rtl_priv *rtlpriv = rtl_priv(hw);
133 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
134 	struct rtlwifi_firmware_header *pfwheader;
135 	u8 *pfwdata;
136 	u32 fwsize;
137 	int err;
138 	enum version_8188e version = rtlhal->version;
139 
140 	if (!rtlhal->pfirmware)
141 		return 1;
142 
143 	pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware;
144 	rtlhal->fw_version = le16_to_cpu(pfwheader->version);
145 	rtlhal->fw_subversion = pfwheader->subversion;
146 	pfwdata = rtlhal->pfirmware;
147 	fwsize = rtlhal->fwsize;
148 	RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
149 		 "normal Firmware SIZE %d\n", fwsize);
150 
151 	if (IS_FW_HEADER_EXIST(pfwheader)) {
152 		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
153 			 "Firmware Version(%d), Signature(%#x), Size(%d)\n",
154 			  pfwheader->version, pfwheader->signature,
155 			  (int)sizeof(struct rtlwifi_firmware_header));
156 
157 		pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header);
158 		fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);
159 	}
160 
161 	if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
162 		rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
163 		rtl88e_firmware_selfreset(hw);
164 	}
165 	_rtl88e_enable_fw_download(hw, true);
166 	_rtl88e_write_fw(hw, version, pfwdata, fwsize);
167 	_rtl88e_enable_fw_download(hw, false);
168 
169 	err = _rtl88e_fw_free_to_go(hw);
170 	if (err)
171 		pr_err("Firmware is not ready to run!\n");
172 
173 	return 0;
174 }
175 
176 static bool _rtl88e_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
177 {
178 	struct rtl_priv *rtlpriv = rtl_priv(hw);
179 	u8 val_hmetfr;
180 
181 	val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
182 	if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
183 		return true;
184 	return false;
185 }
186 
187 static void _rtl88e_fill_h2c_command(struct ieee80211_hw *hw,
188 				     u8 element_id, u32 cmd_len,
189 				     u8 *cmd_b)
190 {
191 	struct rtl_priv *rtlpriv = rtl_priv(hw);
192 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
193 	u8 boxnum;
194 	u16 box_reg = 0, box_extreg = 0;
195 	u8 u1b_tmp;
196 	bool isfw_read = false;
197 	u8 buf_index = 0;
198 	bool write_sucess = false;
199 	u8 wait_h2c_limmit = 100;
200 	u8 wait_writeh2c_limit = 100;
201 	u8 boxcontent[4], boxextcontent[4];
202 	u32 h2c_waitcounter = 0;
203 	unsigned long flag;
204 	u8 idx;
205 
206 	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
207 
208 	while (true) {
209 		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
210 		if (rtlhal->h2c_setinprogress) {
211 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
212 				 "H2C set in progress! Wait to set..element_id(%d).\n",
213 				 element_id);
214 
215 			while (rtlhal->h2c_setinprogress) {
216 				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
217 						       flag);
218 				h2c_waitcounter++;
219 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
220 					 "Wait 100 us (%d times)...\n",
221 					 h2c_waitcounter);
222 				udelay(100);
223 
224 				if (h2c_waitcounter > 1000)
225 					return;
226 				spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
227 						  flag);
228 			}
229 			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
230 		} else {
231 			rtlhal->h2c_setinprogress = true;
232 			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
233 			break;
234 		}
235 	}
236 
237 	while (!write_sucess) {
238 		wait_writeh2c_limit--;
239 		if (wait_writeh2c_limit == 0) {
240 			pr_err("Write H2C fail because no trigger for FW INT!\n");
241 			break;
242 		}
243 
244 		boxnum = rtlhal->last_hmeboxnum;
245 		switch (boxnum) {
246 		case 0:
247 			box_reg = REG_HMEBOX_0;
248 			box_extreg = REG_HMEBOX_EXT_0;
249 			break;
250 		case 1:
251 			box_reg = REG_HMEBOX_1;
252 			box_extreg = REG_HMEBOX_EXT_1;
253 			break;
254 		case 2:
255 			box_reg = REG_HMEBOX_2;
256 			box_extreg = REG_HMEBOX_EXT_2;
257 			break;
258 		case 3:
259 			box_reg = REG_HMEBOX_3;
260 			box_extreg = REG_HMEBOX_EXT_3;
261 			break;
262 		default:
263 			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
264 				 "switch case %#x not processed\n", boxnum);
265 			break;
266 		}
267 		isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
268 		while (!isfw_read) {
269 			wait_h2c_limmit--;
270 			if (wait_h2c_limmit == 0) {
271 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
272 					 "Waiting too long for FW read clear HMEBox(%d)!\n",
273 					 boxnum);
274 				break;
275 			}
276 
277 			udelay(10);
278 
279 			isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
280 			u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
281 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
282 				 "Waiting for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
283 				 boxnum, u1b_tmp);
284 		}
285 
286 		if (!isfw_read) {
287 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
288 				 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
289 				 boxnum);
290 			break;
291 		}
292 
293 		memset(boxcontent, 0, sizeof(boxcontent));
294 		memset(boxextcontent, 0, sizeof(boxextcontent));
295 		boxcontent[0] = element_id;
296 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
297 			 "Write element_id box_reg(%4x) = %2x\n",
298 			 box_reg, element_id);
299 
300 		switch (cmd_len) {
301 		case 1:
302 		case 2:
303 		case 3:
304 			/*boxcontent[0] &= ~(BIT(7));*/
305 			memcpy((u8 *)(boxcontent) + 1,
306 			       cmd_b + buf_index, cmd_len);
307 
308 			for (idx = 0; idx < 4; idx++) {
309 				rtl_write_byte(rtlpriv, box_reg + idx,
310 					       boxcontent[idx]);
311 			}
312 			break;
313 		case 4:
314 		case 5:
315 		case 6:
316 		case 7:
317 			/*boxcontent[0] |= (BIT(7));*/
318 			memcpy((u8 *)(boxextcontent),
319 			       cmd_b + buf_index+3, cmd_len-3);
320 			memcpy((u8 *)(boxcontent) + 1,
321 			       cmd_b + buf_index, 3);
322 
323 			for (idx = 0; idx < 2; idx++) {
324 				rtl_write_byte(rtlpriv, box_extreg + idx,
325 					       boxextcontent[idx]);
326 			}
327 
328 			for (idx = 0; idx < 4; idx++) {
329 				rtl_write_byte(rtlpriv, box_reg + idx,
330 					       boxcontent[idx]);
331 			}
332 			break;
333 		default:
334 			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
335 				 "switch case %#x not processed\n", cmd_len);
336 			break;
337 		}
338 
339 		write_sucess = true;
340 
341 		rtlhal->last_hmeboxnum = boxnum + 1;
342 		if (rtlhal->last_hmeboxnum == 4)
343 			rtlhal->last_hmeboxnum = 0;
344 
345 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
346 			 "pHalData->last_hmeboxnum  = %d\n",
347 			  rtlhal->last_hmeboxnum);
348 	}
349 
350 	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
351 	rtlhal->h2c_setinprogress = false;
352 	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
353 
354 	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
355 }
356 
357 void rtl88e_fill_h2c_cmd(struct ieee80211_hw *hw,
358 			 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
359 {
360 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
361 	u32 tmp_cmdbuf[2];
362 
363 	if (!rtlhal->fw_ready) {
364 		WARN_ONCE(true,
365 			  "rtl8188ee: error H2C cmd because of Fw download fail!!!\n");
366 		return;
367 	}
368 
369 	memset(tmp_cmdbuf, 0, 8);
370 	memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
371 	_rtl88e_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
372 
373 	return;
374 }
375 
376 void rtl88e_firmware_selfreset(struct ieee80211_hw *hw)
377 {
378 	u8 u1b_tmp;
379 	struct rtl_priv *rtlpriv = rtl_priv(hw);
380 
381 	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1);
382 	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2))));
383 	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp | BIT(2)));
384 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
385 		 "8051Reset88E(): 8051 reset success\n");
386 
387 }
388 
389 void rtl88e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
390 {
391 	struct rtl_priv *rtlpriv = rtl_priv(hw);
392 	u8 u1_h2c_set_pwrmode[H2C_88E_PWEMODE_LENGTH] = { 0 };
393 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
394 	u8 rlbm, power_state = 0;
395 	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
396 
397 	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
398 	rlbm = 0;/*YJ, temp, 120316. FW now not support RLBM=2.*/
399 	SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm);
400 	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
401 		(rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1);
402 	SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
403 		ppsc->reg_max_lps_awakeintvl);
404 	SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
405 	if (mode == FW_PS_ACTIVE_MODE)
406 		power_state |= FW_PWR_STATE_ACTIVE;
407 	else
408 		power_state |= FW_PWR_STATE_RF_OFF;
409 
410 	SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
411 
412 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
413 		      "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
414 		      u1_h2c_set_pwrmode, H2C_88E_PWEMODE_LENGTH);
415 	rtl88e_fill_h2c_cmd(hw, H2C_88E_SETPWRMODE,
416 			    H2C_88E_PWEMODE_LENGTH, u1_h2c_set_pwrmode);
417 }
418 
419 void rtl88e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
420 {
421 	u8 u1_joinbssrpt_parm[1] = { 0 };
422 
423 	SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
424 
425 	rtl88e_fill_h2c_cmd(hw, H2C_88E_JOINBSSRPT, 1, u1_joinbssrpt_parm);
426 }
427 
428 void rtl88e_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,
429 				   u8 ap_offload_enable)
430 {
431 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
432 	u8 u1_apoffload_parm[H2C_88E_AP_OFFLOAD_LENGTH] = { 0 };
433 
434 	SET_H2CCMD_AP_OFFLOAD_ON(u1_apoffload_parm, ap_offload_enable);
435 	SET_H2CCMD_AP_OFFLOAD_HIDDEN(u1_apoffload_parm, mac->hiddenssid);
436 	SET_H2CCMD_AP_OFFLOAD_DENYANY(u1_apoffload_parm, 0);
437 
438 	rtl88e_fill_h2c_cmd(hw, H2C_88E_AP_OFFLOAD,
439 			    H2C_88E_AP_OFFLOAD_LENGTH, u1_apoffload_parm);
440 
441 }
442 
443 #define BEACON_PG		0 /* ->1 */
444 #define PSPOLL_PG		2
445 #define NULL_PG			3
446 #define PROBERSP_PG		4 /* ->5 */
447 
448 #define TOTAL_RESERVED_PKT_LEN	768
449 
450 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
451 	/* page 0 beacon */
452 	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
453 	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
454 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
455 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
456 	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
457 	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
458 	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
459 	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
460 	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
461 	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
462 	0x03, 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 	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
466 	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
467 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
468 
469 	/* page 1 beacon */
470 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
471 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
472 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
473 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
474 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
475 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
476 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
477 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
478 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
479 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
480 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
481 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
482 	0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
483 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
484 	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
485 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
486 
487 	/* page 2  ps-poll */
488 	0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
489 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
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 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
494 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
495 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
496 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
497 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
498 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
499 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
500 	0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
501 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
502 	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
503 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
504 
505 	/* page 3  null */
506 	0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
507 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
508 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
509 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
510 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
511 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
512 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
513 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
514 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
515 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
516 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
517 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
518 	0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
519 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
520 	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
521 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
522 
523 	/* page 4  probe_resp */
524 	0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
525 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
526 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
527 	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
528 	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
529 	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
530 	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
531 	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
532 	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
533 	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
534 	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
535 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
536 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
537 	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
538 	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
539 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
540 
541 	/* page 5  probe_resp */
542 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
543 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
544 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
545 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
546 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
547 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
548 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
549 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
550 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
551 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
552 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
553 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
554 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
555 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
556 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
557 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
558 };
559 
560 void rtl88e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
561 {
562 	struct rtl_priv *rtlpriv = rtl_priv(hw);
563 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
564 	struct sk_buff *skb = NULL;
565 	u32 totalpacketlen;
566 	bool rtstatus;
567 	u8 u1rsvdpageloc[5] = { 0 };
568 	bool b_dlok = false;
569 	u8 *beacon;
570 	u8 *p_pspoll;
571 	u8 *nullfunc;
572 	u8 *p_probersp;
573 
574 	/*---------------------------------------------------------
575 	 *			(1) beacon
576 	 *---------------------------------------------------------
577 	 */
578 	beacon = &reserved_page_packet[BEACON_PG * 128];
579 	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
580 	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
581 
582 	/*-------------------------------------------------------
583 	 *			(2) ps-poll
584 	 *--------------------------------------------------------
585 	 */
586 	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
587 	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
588 	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
589 	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
590 
591 	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
592 
593 	/*--------------------------------------------------------
594 	 *			(3) null data
595 	 *---------------------------------------------------------
596 	 */
597 	nullfunc = &reserved_page_packet[NULL_PG * 128];
598 	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
599 	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
600 	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
601 
602 	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
603 
604 	/*---------------------------------------------------------
605 	 *			(4) probe response
606 	 *----------------------------------------------------------
607 	 */
608 	p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
609 	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
610 	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
611 	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
612 
613 	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
614 
615 	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
616 
617 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
618 		      "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
619 		      &reserved_page_packet[0], totalpacketlen);
620 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
621 		      "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
622 		      u1rsvdpageloc, 3);
623 
624 	skb = dev_alloc_skb(totalpacketlen);
625 	skb_put_data(skb, &reserved_page_packet, totalpacketlen);
626 
627 	rtstatus = rtl_cmd_send_packet(hw, skb);
628 
629 	if (rtstatus)
630 		b_dlok = true;
631 
632 	if (b_dlok) {
633 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
634 			 "Set RSVD page location to Fw.\n");
635 		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
636 			      "H2C_RSVDPAGE:\n", u1rsvdpageloc, 3);
637 		rtl88e_fill_h2c_cmd(hw, H2C_88E_RSVDPAGE,
638 				    sizeof(u1rsvdpageloc), u1rsvdpageloc);
639 	} else
640 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
641 			 "Set RSVD page location to Fw FAIL!!!!!!.\n");
642 }
643 
644 /*Should check FW support p2p or not.*/
645 static void rtl88e_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
646 {
647 	u8 u1_ctwindow_period[1] = { ctwindow};
648 
649 	rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
650 
651 }
652 
653 void rtl88e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
654 {
655 	struct rtl_priv *rtlpriv = rtl_priv(hw);
656 	struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
657 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
658 	struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
659 	struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
660 	u8	i;
661 	u16	ctwindow;
662 	u32	start_time, tsf_low;
663 
664 	switch (p2p_ps_state) {
665 	case P2P_PS_DISABLE:
666 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
667 		memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
668 		break;
669 	case P2P_PS_ENABLE:
670 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
671 		/* update CTWindow value. */
672 		if (p2pinfo->ctwindow > 0) {
673 			p2p_ps_offload->ctwindow_en = 1;
674 			ctwindow = p2pinfo->ctwindow;
675 			rtl88e_set_p2p_ctw_period_cmd(hw, ctwindow);
676 		}
677 
678 		/* hw only support 2 set of NoA */
679 		for (i = 0 ; i < p2pinfo->noa_num; i++) {
680 			/* To control the register setting for which NOA*/
681 			rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
682 			if (i == 0)
683 				p2p_ps_offload->noa0_en = 1;
684 			else
685 				p2p_ps_offload->noa1_en = 1;
686 
687 			/* config P2P NoA Descriptor Register */
688 			rtl_write_dword(rtlpriv, 0x5E0,
689 					p2pinfo->noa_duration[i]);
690 			rtl_write_dword(rtlpriv, 0x5E4,
691 					p2pinfo->noa_interval[i]);
692 
693 			/*Get Current TSF value */
694 			tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
695 
696 			start_time = p2pinfo->noa_start_time[i];
697 			if (p2pinfo->noa_count_type[i] != 1) {
698 				while (start_time <= (tsf_low+(50*1024))) {
699 					start_time += p2pinfo->noa_interval[i];
700 					if (p2pinfo->noa_count_type[i] != 255)
701 						p2pinfo->noa_count_type[i]--;
702 				}
703 			}
704 			rtl_write_dword(rtlpriv, 0x5E8, start_time);
705 			rtl_write_dword(rtlpriv, 0x5EC,
706 					p2pinfo->noa_count_type[i]);
707 		}
708 
709 		if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
710 			/* rst p2p circuit */
711 			rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
712 
713 			p2p_ps_offload->offload_en = 1;
714 
715 			if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
716 				p2p_ps_offload->role = 1;
717 				p2p_ps_offload->allstasleep = -1;
718 			} else {
719 				p2p_ps_offload->role = 0;
720 			}
721 
722 			p2p_ps_offload->discovery = 0;
723 		}
724 		break;
725 	case P2P_PS_SCAN:
726 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
727 		p2p_ps_offload->discovery = 1;
728 		break;
729 	case P2P_PS_SCAN_DONE:
730 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
731 		p2p_ps_offload->discovery = 0;
732 		p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
733 		break;
734 	default:
735 		break;
736 	}
737 
738 	rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_OFFLOAD, 1,
739 			    (u8 *)p2p_ps_offload);
740 
741 }
742