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