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