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 
228 	return 0;
229 }
230 
231 static bool _rtl88e_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
232 {
233 	struct rtl_priv *rtlpriv = rtl_priv(hw);
234 	u8 val_hmetfr;
235 
236 	val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
237 	if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
238 		return true;
239 	return false;
240 }
241 
242 static void _rtl88e_fill_h2c_command(struct ieee80211_hw *hw,
243 				     u8 element_id, u32 cmd_len,
244 				     u8 *cmd_b)
245 {
246 	struct rtl_priv *rtlpriv = rtl_priv(hw);
247 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
248 	u8 boxnum;
249 	u16 box_reg = 0, box_extreg = 0;
250 	u8 u1b_tmp;
251 	bool isfw_read = false;
252 	u8 buf_index = 0;
253 	bool write_sucess = false;
254 	u8 wait_h2c_limmit = 100;
255 	u8 wait_writeh2c_limit = 100;
256 	u8 boxcontent[4], boxextcontent[4];
257 	u32 h2c_waitcounter = 0;
258 	unsigned long flag;
259 	u8 idx;
260 
261 	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
262 
263 	while (true) {
264 		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
265 		if (rtlhal->h2c_setinprogress) {
266 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
267 				 "H2C set in progress! Wait to set..element_id(%d).\n",
268 				 element_id);
269 
270 			while (rtlhal->h2c_setinprogress) {
271 				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
272 						       flag);
273 				h2c_waitcounter++;
274 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
275 					 "Wait 100 us (%d times)...\n",
276 					 h2c_waitcounter);
277 				udelay(100);
278 
279 				if (h2c_waitcounter > 1000)
280 					return;
281 				spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
282 						  flag);
283 			}
284 			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
285 		} else {
286 			rtlhal->h2c_setinprogress = true;
287 			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
288 			break;
289 		}
290 	}
291 
292 	while (!write_sucess) {
293 		wait_writeh2c_limit--;
294 		if (wait_writeh2c_limit == 0) {
295 			pr_err("Write H2C fail because no trigger for FW INT!\n");
296 			break;
297 		}
298 
299 		boxnum = rtlhal->last_hmeboxnum;
300 		switch (boxnum) {
301 		case 0:
302 			box_reg = REG_HMEBOX_0;
303 			box_extreg = REG_HMEBOX_EXT_0;
304 			break;
305 		case 1:
306 			box_reg = REG_HMEBOX_1;
307 			box_extreg = REG_HMEBOX_EXT_1;
308 			break;
309 		case 2:
310 			box_reg = REG_HMEBOX_2;
311 			box_extreg = REG_HMEBOX_EXT_2;
312 			break;
313 		case 3:
314 			box_reg = REG_HMEBOX_3;
315 			box_extreg = REG_HMEBOX_EXT_3;
316 			break;
317 		default:
318 			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
319 				 "switch case %#x not processed\n", boxnum);
320 			break;
321 		}
322 		isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
323 		while (!isfw_read) {
324 			wait_h2c_limmit--;
325 			if (wait_h2c_limmit == 0) {
326 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
327 					 "Waiting too long for FW read clear HMEBox(%d)!\n",
328 					 boxnum);
329 				break;
330 			}
331 
332 			udelay(10);
333 
334 			isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
335 			u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
336 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
337 				 "Waiting for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
338 				 boxnum, u1b_tmp);
339 		}
340 
341 		if (!isfw_read) {
342 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
343 				 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
344 				 boxnum);
345 			break;
346 		}
347 
348 		memset(boxcontent, 0, sizeof(boxcontent));
349 		memset(boxextcontent, 0, sizeof(boxextcontent));
350 		boxcontent[0] = element_id;
351 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
352 			 "Write element_id box_reg(%4x) = %2x\n",
353 			 box_reg, element_id);
354 
355 		switch (cmd_len) {
356 		case 1:
357 		case 2:
358 		case 3:
359 			/*boxcontent[0] &= ~(BIT(7));*/
360 			memcpy((u8 *)(boxcontent) + 1,
361 			       cmd_b + buf_index, cmd_len);
362 
363 			for (idx = 0; idx < 4; idx++) {
364 				rtl_write_byte(rtlpriv, box_reg + idx,
365 					       boxcontent[idx]);
366 			}
367 			break;
368 		case 4:
369 		case 5:
370 		case 6:
371 		case 7:
372 			/*boxcontent[0] |= (BIT(7));*/
373 			memcpy((u8 *)(boxextcontent),
374 			       cmd_b + buf_index+3, cmd_len-3);
375 			memcpy((u8 *)(boxcontent) + 1,
376 			       cmd_b + buf_index, 3);
377 
378 			for (idx = 0; idx < 2; idx++) {
379 				rtl_write_byte(rtlpriv, box_extreg + idx,
380 					       boxextcontent[idx]);
381 			}
382 
383 			for (idx = 0; idx < 4; idx++) {
384 				rtl_write_byte(rtlpriv, box_reg + idx,
385 					       boxcontent[idx]);
386 			}
387 			break;
388 		default:
389 			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
390 				 "switch case %#x not processed\n", cmd_len);
391 			break;
392 		}
393 
394 		write_sucess = true;
395 
396 		rtlhal->last_hmeboxnum = boxnum + 1;
397 		if (rtlhal->last_hmeboxnum == 4)
398 			rtlhal->last_hmeboxnum = 0;
399 
400 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
401 			 "pHalData->last_hmeboxnum  = %d\n",
402 			  rtlhal->last_hmeboxnum);
403 	}
404 
405 	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
406 	rtlhal->h2c_setinprogress = false;
407 	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
408 
409 	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
410 }
411 
412 void rtl88e_fill_h2c_cmd(struct ieee80211_hw *hw,
413 			 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
414 {
415 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
416 	u32 tmp_cmdbuf[2];
417 
418 	if (!rtlhal->fw_ready) {
419 		WARN_ONCE(true,
420 			  "rtl8188ee: error H2C cmd because of Fw download fail!!!\n");
421 		return;
422 	}
423 
424 	memset(tmp_cmdbuf, 0, 8);
425 	memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
426 	_rtl88e_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
427 
428 	return;
429 }
430 
431 void rtl88e_firmware_selfreset(struct ieee80211_hw *hw)
432 {
433 	u8 u1b_tmp;
434 	struct rtl_priv *rtlpriv = rtl_priv(hw);
435 
436 	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1);
437 	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2))));
438 	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp | BIT(2)));
439 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
440 		 "8051Reset88E(): 8051 reset success\n");
441 
442 }
443 
444 void rtl88e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
445 {
446 	struct rtl_priv *rtlpriv = rtl_priv(hw);
447 	u8 u1_h2c_set_pwrmode[H2C_88E_PWEMODE_LENGTH] = { 0 };
448 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
449 	u8 rlbm, power_state = 0;
450 	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
451 
452 	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
453 	rlbm = 0;/*YJ, temp, 120316. FW now not support RLBM=2.*/
454 	SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm);
455 	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
456 		(rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1);
457 	SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
458 		ppsc->reg_max_lps_awakeintvl);
459 	SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
460 	if (mode == FW_PS_ACTIVE_MODE)
461 		power_state |= FW_PWR_STATE_ACTIVE;
462 	else
463 		power_state |= FW_PWR_STATE_RF_OFF;
464 
465 	SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
466 
467 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
468 		      "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
469 		      u1_h2c_set_pwrmode, H2C_88E_PWEMODE_LENGTH);
470 	rtl88e_fill_h2c_cmd(hw, H2C_88E_SETPWRMODE,
471 			    H2C_88E_PWEMODE_LENGTH, u1_h2c_set_pwrmode);
472 }
473 
474 void rtl88e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
475 {
476 	u8 u1_joinbssrpt_parm[1] = { 0 };
477 
478 	SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
479 
480 	rtl88e_fill_h2c_cmd(hw, H2C_88E_JOINBSSRPT, 1, u1_joinbssrpt_parm);
481 }
482 
483 void rtl88e_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,
484 				   u8 ap_offload_enable)
485 {
486 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
487 	u8 u1_apoffload_parm[H2C_88E_AP_OFFLOAD_LENGTH] = { 0 };
488 
489 	SET_H2CCMD_AP_OFFLOAD_ON(u1_apoffload_parm, ap_offload_enable);
490 	SET_H2CCMD_AP_OFFLOAD_HIDDEN(u1_apoffload_parm, mac->hiddenssid);
491 	SET_H2CCMD_AP_OFFLOAD_DENYANY(u1_apoffload_parm, 0);
492 
493 	rtl88e_fill_h2c_cmd(hw, H2C_88E_AP_OFFLOAD,
494 			    H2C_88E_AP_OFFLOAD_LENGTH, u1_apoffload_parm);
495 
496 }
497 
498 #define BEACON_PG		0 /* ->1 */
499 #define PSPOLL_PG		2
500 #define NULL_PG			3
501 #define PROBERSP_PG		4 /* ->5 */
502 
503 #define TOTAL_RESERVED_PKT_LEN	768
504 
505 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
506 	/* page 0 beacon */
507 	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
508 	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
509 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
510 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
511 	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
512 	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
513 	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
514 	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
515 	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
516 	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
517 	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
518 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
519 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
520 	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
521 	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
522 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
523 
524 	/* page 1 beacon */
525 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
526 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
527 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
528 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 	0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
538 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
539 	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
540 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
541 
542 	/* page 2  ps-poll */
543 	0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
544 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
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 	0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
556 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
557 	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
558 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
559 
560 	/* page 3  null */
561 	0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
562 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
563 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
564 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
565 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
566 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
567 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 	0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
574 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
575 	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
576 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
577 
578 	/* page 4  probe_resp */
579 	0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
580 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
581 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
582 	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
583 	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
584 	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
585 	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
586 	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
587 	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
588 	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
589 	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
590 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
591 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
592 	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
593 	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
594 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
595 
596 	/* page 5  probe_resp */
597 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
599 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
600 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 };
614 
615 void rtl88e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
616 {
617 	struct rtl_priv *rtlpriv = rtl_priv(hw);
618 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
619 	struct sk_buff *skb = NULL;
620 	u32 totalpacketlen;
621 	bool rtstatus;
622 	u8 u1rsvdpageloc[5] = { 0 };
623 	bool b_dlok = false;
624 	u8 *beacon;
625 	u8 *p_pspoll;
626 	u8 *nullfunc;
627 	u8 *p_probersp;
628 
629 	/*---------------------------------------------------------
630 	 *			(1) beacon
631 	 *---------------------------------------------------------
632 	 */
633 	beacon = &reserved_page_packet[BEACON_PG * 128];
634 	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
635 	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
636 
637 	/*-------------------------------------------------------
638 	 *			(2) ps-poll
639 	 *--------------------------------------------------------
640 	 */
641 	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
642 	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
643 	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
644 	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
645 
646 	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
647 
648 	/*--------------------------------------------------------
649 	 *			(3) null data
650 	 *---------------------------------------------------------
651 	 */
652 	nullfunc = &reserved_page_packet[NULL_PG * 128];
653 	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
654 	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
655 	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
656 
657 	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
658 
659 	/*---------------------------------------------------------
660 	 *			(4) probe response
661 	 *----------------------------------------------------------
662 	 */
663 	p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
664 	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
665 	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
666 	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
667 
668 	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
669 
670 	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
671 
672 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
673 		      "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
674 		      &reserved_page_packet[0], totalpacketlen);
675 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
676 		      "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
677 		      u1rsvdpageloc, 3);
678 
679 	skb = dev_alloc_skb(totalpacketlen);
680 	memcpy(skb_put(skb, totalpacketlen),
681 	       &reserved_page_packet, totalpacketlen);
682 
683 	rtstatus = rtl_cmd_send_packet(hw, skb);
684 
685 	if (rtstatus)
686 		b_dlok = true;
687 
688 	if (b_dlok) {
689 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
690 			 "Set RSVD page location to Fw.\n");
691 		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
692 			      "H2C_RSVDPAGE:\n", u1rsvdpageloc, 3);
693 		rtl88e_fill_h2c_cmd(hw, H2C_88E_RSVDPAGE,
694 				    sizeof(u1rsvdpageloc), u1rsvdpageloc);
695 	} else
696 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
697 			 "Set RSVD page location to Fw FAIL!!!!!!.\n");
698 }
699 
700 /*Should check FW support p2p or not.*/
701 static void rtl88e_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
702 {
703 	u8 u1_ctwindow_period[1] = { ctwindow};
704 
705 	rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
706 
707 }
708 
709 void rtl88e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
710 {
711 	struct rtl_priv *rtlpriv = rtl_priv(hw);
712 	struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
713 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
714 	struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
715 	struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
716 	u8	i;
717 	u16	ctwindow;
718 	u32	start_time, tsf_low;
719 
720 	switch (p2p_ps_state) {
721 	case P2P_PS_DISABLE:
722 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
723 		memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
724 		break;
725 	case P2P_PS_ENABLE:
726 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
727 		/* update CTWindow value. */
728 		if (p2pinfo->ctwindow > 0) {
729 			p2p_ps_offload->ctwindow_en = 1;
730 			ctwindow = p2pinfo->ctwindow;
731 			rtl88e_set_p2p_ctw_period_cmd(hw, ctwindow);
732 		}
733 
734 		/* hw only support 2 set of NoA */
735 		for (i = 0 ; i < p2pinfo->noa_num; i++) {
736 			/* To control the register setting for which NOA*/
737 			rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
738 			if (i == 0)
739 				p2p_ps_offload->noa0_en = 1;
740 			else
741 				p2p_ps_offload->noa1_en = 1;
742 
743 			/* config P2P NoA Descriptor Register */
744 			rtl_write_dword(rtlpriv, 0x5E0,
745 					p2pinfo->noa_duration[i]);
746 			rtl_write_dword(rtlpriv, 0x5E4,
747 					p2pinfo->noa_interval[i]);
748 
749 			/*Get Current TSF value */
750 			tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
751 
752 			start_time = p2pinfo->noa_start_time[i];
753 			if (p2pinfo->noa_count_type[i] != 1) {
754 				while (start_time <= (tsf_low+(50*1024))) {
755 					start_time += p2pinfo->noa_interval[i];
756 					if (p2pinfo->noa_count_type[i] != 255)
757 						p2pinfo->noa_count_type[i]--;
758 				}
759 			}
760 			rtl_write_dword(rtlpriv, 0x5E8, start_time);
761 			rtl_write_dword(rtlpriv, 0x5EC,
762 					p2pinfo->noa_count_type[i]);
763 		}
764 
765 		if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
766 			/* rst p2p circuit */
767 			rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
768 
769 			p2p_ps_offload->offload_en = 1;
770 
771 			if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
772 				p2p_ps_offload->role = 1;
773 				p2p_ps_offload->allstasleep = -1;
774 			} else {
775 				p2p_ps_offload->role = 0;
776 			}
777 
778 			p2p_ps_offload->discovery = 0;
779 		}
780 		break;
781 	case P2P_PS_SCAN:
782 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
783 		p2p_ps_offload->discovery = 1;
784 		break;
785 	case P2P_PS_SCAN_DONE:
786 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
787 		p2p_ps_offload->discovery = 0;
788 		p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
789 		break;
790 	default:
791 		break;
792 	}
793 
794 	rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_OFFLOAD, 1,
795 			    (u8 *)p2p_ps_offload);
796 
797 }
798