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