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