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