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