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