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