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