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