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