1e7011369SLarry Finger // SPDX-License-Identifier: GPL-2.0
2e7011369SLarry Finger /* Copyright(c) 2009-2012  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 "../rtl8192ce/reg.h"
10f1d2b4d3SLarry Finger #include "../rtl8192ce/def.h"
11f1d2b4d3SLarry Finger #include "fw_common.h"
12f1d2b4d3SLarry Finger #include <linux/export.h>
13f1d2b4d3SLarry Finger 
_rtl92c_enable_fw_download(struct ieee80211_hw * hw,bool enable)14f1d2b4d3SLarry Finger static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable)
15f1d2b4d3SLarry Finger {
16f1d2b4d3SLarry Finger 	struct rtl_priv *rtlpriv = rtl_priv(hw);
17f1d2b4d3SLarry Finger 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
18f1d2b4d3SLarry Finger 
19f1d2b4d3SLarry Finger 	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU) {
20f1d2b4d3SLarry Finger 		u32 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
2152f88657SLarry Finger 
22f1d2b4d3SLarry Finger 		if (enable)
23f1d2b4d3SLarry Finger 			value32 |= MCUFWDL_EN;
24f1d2b4d3SLarry Finger 		else
25f1d2b4d3SLarry Finger 			value32 &= ~MCUFWDL_EN;
26f1d2b4d3SLarry Finger 		rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
27f1d2b4d3SLarry Finger 	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) {
28f1d2b4d3SLarry Finger 		u8 tmp;
29f1d2b4d3SLarry Finger 
3052f88657SLarry Finger 		if (enable) {
31f1d2b4d3SLarry Finger 			tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
32f1d2b4d3SLarry Finger 			rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
33f1d2b4d3SLarry Finger 				       tmp | 0x04);
34f1d2b4d3SLarry Finger 
35f1d2b4d3SLarry Finger 			tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
36f1d2b4d3SLarry Finger 			rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
37f1d2b4d3SLarry Finger 
38f1d2b4d3SLarry Finger 			tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
39f1d2b4d3SLarry Finger 			rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
40f1d2b4d3SLarry Finger 		} else {
41f1d2b4d3SLarry Finger 			tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
42f1d2b4d3SLarry Finger 			rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
43f1d2b4d3SLarry Finger 
44f1d2b4d3SLarry Finger 			rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
45f1d2b4d3SLarry Finger 		}
46f1d2b4d3SLarry Finger 	}
47f1d2b4d3SLarry Finger }
48f1d2b4d3SLarry Finger 
_rtl92c_write_fw(struct ieee80211_hw * hw,enum version_8192c version,u8 * buffer,u32 size)49f1d2b4d3SLarry Finger static void _rtl92c_write_fw(struct ieee80211_hw *hw,
50f1d2b4d3SLarry Finger 			     enum version_8192c version, u8 *buffer, u32 size)
51f1d2b4d3SLarry Finger {
52f1d2b4d3SLarry Finger 	struct rtl_priv *rtlpriv = rtl_priv(hw);
53f1d2b4d3SLarry Finger 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
54f1d2b4d3SLarry Finger 	bool is_version_b;
55f1d2b4d3SLarry Finger 	u8 *bufferptr = (u8 *)buffer;
56f1d2b4d3SLarry Finger 
575b4e998bSLarry Finger 	rtl_dbg(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
58f1d2b4d3SLarry Finger 	is_version_b = IS_NORMAL_CHIP(version);
59f1d2b4d3SLarry Finger 	if (is_version_b) {
60ff970453SLarry Finger 		u32 pagenums, remainsize;
61f1d2b4d3SLarry Finger 		u32 page, offset;
62f1d2b4d3SLarry Finger 
63f1d2b4d3SLarry Finger 		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE)
6489d32c90SLarry Finger 			rtl_fill_dummy(bufferptr, &size);
65f1d2b4d3SLarry Finger 
66ff970453SLarry Finger 		pagenums = size / FW_8192C_PAGE_SIZE;
67f1d2b4d3SLarry Finger 		remainsize = size % FW_8192C_PAGE_SIZE;
68f1d2b4d3SLarry Finger 
69ff970453SLarry Finger 		if (pagenums > 4)
700fc30e93SLarry Finger 			pr_err("Page numbers should not greater then 4\n");
71f1d2b4d3SLarry Finger 
72ff970453SLarry Finger 		for (page = 0; page < pagenums; page++) {
73f1d2b4d3SLarry Finger 			offset = page * FW_8192C_PAGE_SIZE;
7489d32c90SLarry Finger 			rtl_fw_page_write(hw, page, (bufferptr + offset),
75f1d2b4d3SLarry Finger 					  FW_8192C_PAGE_SIZE);
76f1d2b4d3SLarry Finger 		}
77f1d2b4d3SLarry Finger 
78f1d2b4d3SLarry Finger 		if (remainsize) {
79ff970453SLarry Finger 			offset = pagenums * FW_8192C_PAGE_SIZE;
80ff970453SLarry Finger 			page = pagenums;
8189d32c90SLarry Finger 			rtl_fw_page_write(hw, page, (bufferptr + offset),
82f1d2b4d3SLarry Finger 					  remainsize);
83f1d2b4d3SLarry Finger 		}
84f1d2b4d3SLarry Finger 	} else {
8589d32c90SLarry Finger 		rtl_fw_block_write(hw, buffer, size);
86f1d2b4d3SLarry Finger 	}
87f1d2b4d3SLarry Finger }
88f1d2b4d3SLarry Finger 
_rtl92c_fw_free_to_go(struct ieee80211_hw * hw)89f1d2b4d3SLarry Finger static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
90f1d2b4d3SLarry Finger {
91f1d2b4d3SLarry Finger 	struct rtl_priv *rtlpriv = rtl_priv(hw);
92f1d2b4d3SLarry Finger 	int err = -EIO;
93f1d2b4d3SLarry Finger 	u32 counter = 0;
94f1d2b4d3SLarry Finger 	u32 value32;
95f1d2b4d3SLarry Finger 
96f1d2b4d3SLarry Finger 	do {
97f1d2b4d3SLarry Finger 		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
98f1d2b4d3SLarry Finger 	} while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
99ff970453SLarry Finger 		 (!(value32 & FWDL_CHKSUM_RPT)));
100f1d2b4d3SLarry Finger 
101f1d2b4d3SLarry Finger 	if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
1020fc30e93SLarry Finger 		pr_err("chksum report fail! REG_MCUFWDL:0x%08x .\n",
103f1d2b4d3SLarry Finger 		       value32);
104f1d2b4d3SLarry Finger 		goto exit;
105f1d2b4d3SLarry Finger 	}
106f1d2b4d3SLarry Finger 	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
107f1d2b4d3SLarry Finger 	value32 |= MCUFWDL_RDY;
108f1d2b4d3SLarry Finger 	value32 &= ~WINTINI_RDY;
109f1d2b4d3SLarry Finger 	rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
110f1d2b4d3SLarry Finger 
111f1d2b4d3SLarry Finger 	counter = 0;
112f1d2b4d3SLarry Finger 
113f1d2b4d3SLarry Finger 	do {
114f1d2b4d3SLarry Finger 		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
1150fc30e93SLarry Finger 		if (value32 & WINTINI_RDY)
1160fc30e93SLarry Finger 			return 0;
117f1d2b4d3SLarry Finger 
118f1d2b4d3SLarry Finger 		mdelay(FW_8192C_POLLING_DELAY);
119f1d2b4d3SLarry Finger 
120f1d2b4d3SLarry Finger 	} while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
121f1d2b4d3SLarry Finger 
1220fc30e93SLarry Finger 	pr_err("Polling FW ready fail! REG_MCUFWDL:0x%08x.\n",
1230fc30e93SLarry Finger 	       value32);
124f1d2b4d3SLarry Finger 
125f1d2b4d3SLarry Finger exit:
126f1d2b4d3SLarry Finger 	return err;
127f1d2b4d3SLarry Finger }
128f1d2b4d3SLarry Finger 
rtl92c_download_fw(struct ieee80211_hw * hw)129f1d2b4d3SLarry Finger int rtl92c_download_fw(struct ieee80211_hw *hw)
130f1d2b4d3SLarry Finger {
131f1d2b4d3SLarry Finger 	struct rtl_priv *rtlpriv = rtl_priv(hw);
132f1d2b4d3SLarry Finger 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
133f1d2b4d3SLarry Finger 	struct rtlwifi_firmware_header *pfwheader;
134f1d2b4d3SLarry Finger 	u8 *pfwdata;
135f1d2b4d3SLarry Finger 	u32 fwsize;
136f1d2b4d3SLarry Finger 	int err;
137f1d2b4d3SLarry Finger 	enum version_8192c version = rtlhal->version;
138f1d2b4d3SLarry Finger 
139f1d2b4d3SLarry Finger 	if (!rtlhal->pfirmware)
140f1d2b4d3SLarry Finger 		return 1;
141f1d2b4d3SLarry Finger 
142f1d2b4d3SLarry Finger 	pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware;
143f1d2b4d3SLarry Finger 	pfwdata = (u8 *)rtlhal->pfirmware;
144f1d2b4d3SLarry Finger 	fwsize = rtlhal->fwsize;
145f1d2b4d3SLarry Finger 	if (IS_FW_HEADER_EXIST(pfwheader)) {
1465b4e998bSLarry Finger 		rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG,
147f1d2b4d3SLarry Finger 			"Firmware Version(%d), Signature(%#x),Size(%d)\n",
148f1d2b4d3SLarry Finger 			pfwheader->version, pfwheader->signature,
149f1d2b4d3SLarry Finger 			(int)sizeof(struct rtlwifi_firmware_header));
150f1d2b4d3SLarry Finger 
151f1d2b4d3SLarry Finger 		rtlhal->fw_version = le16_to_cpu(pfwheader->version);
152f1d2b4d3SLarry Finger 		rtlhal->fw_subversion = pfwheader->subversion;
153f1d2b4d3SLarry Finger 		pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header);
154f1d2b4d3SLarry Finger 		fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);
155f1d2b4d3SLarry Finger 	}
156f1d2b4d3SLarry Finger 
157f1d2b4d3SLarry Finger 	_rtl92c_enable_fw_download(hw, true);
158f1d2b4d3SLarry Finger 	_rtl92c_write_fw(hw, version, pfwdata, fwsize);
159f1d2b4d3SLarry Finger 	_rtl92c_enable_fw_download(hw, false);
160f1d2b4d3SLarry Finger 
161f1d2b4d3SLarry Finger 	err = _rtl92c_fw_free_to_go(hw);
162c93ac39dSLarry Finger 	if (err)
1630fc30e93SLarry Finger 		pr_err("Firmware is not ready to run!\n");
164f1d2b4d3SLarry Finger 
165f1d2b4d3SLarry Finger 	return 0;
166f1d2b4d3SLarry Finger }
167f1d2b4d3SLarry Finger EXPORT_SYMBOL(rtl92c_download_fw);
168f1d2b4d3SLarry Finger 
_rtl92c_check_fw_read_last_h2c(struct ieee80211_hw * hw,u8 boxnum)169f1d2b4d3SLarry Finger static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
170f1d2b4d3SLarry Finger {
171f1d2b4d3SLarry Finger 	struct rtl_priv *rtlpriv = rtl_priv(hw);
172f1d2b4d3SLarry Finger 	u8 val_hmetfr, val_mcutst_1;
173f1d2b4d3SLarry Finger 	bool result = false;
174f1d2b4d3SLarry Finger 
175f1d2b4d3SLarry Finger 	val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
176f1d2b4d3SLarry Finger 	val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
177f1d2b4d3SLarry Finger 
178f1d2b4d3SLarry Finger 	if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
179f1d2b4d3SLarry Finger 		result = true;
180f1d2b4d3SLarry Finger 	return result;
181f1d2b4d3SLarry Finger }
182f1d2b4d3SLarry Finger 
_rtl92c_fill_h2c_command(struct ieee80211_hw * hw,u8 element_id,u32 cmd_len,u8 * cmdbuffer)183f1d2b4d3SLarry Finger static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
184f1d2b4d3SLarry Finger 			      u8 element_id, u32 cmd_len, u8 *cmdbuffer)
185f1d2b4d3SLarry Finger {
186f1d2b4d3SLarry Finger 	struct rtl_priv *rtlpriv = rtl_priv(hw);
187f1d2b4d3SLarry Finger 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
188f1d2b4d3SLarry Finger 	u8 boxnum;
189f1d2b4d3SLarry Finger 	u16 box_reg = 0, box_extreg = 0;
190f1d2b4d3SLarry Finger 	u8 u1b_tmp;
191f1d2b4d3SLarry Finger 	bool isfw_read = false;
192f1d2b4d3SLarry Finger 	u8 buf_index = 0;
193f1d2b4d3SLarry Finger 	bool bwrite_sucess = false;
194f1d2b4d3SLarry Finger 	u8 wait_h2c_limmit = 100;
195f1d2b4d3SLarry Finger 	u8 wait_writeh2c_limmit = 100;
196f1d2b4d3SLarry Finger 	u8 boxcontent[4], boxextcontent[2];
197f1d2b4d3SLarry Finger 	u32 h2c_waitcounter = 0;
198f1d2b4d3SLarry Finger 	unsigned long flag;
199f1d2b4d3SLarry Finger 	u8 idx;
200f1d2b4d3SLarry Finger 
2015b4e998bSLarry Finger 	rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
202f1d2b4d3SLarry Finger 
203f1d2b4d3SLarry Finger 	while (true) {
204f1d2b4d3SLarry Finger 		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
205f1d2b4d3SLarry Finger 		if (rtlhal->h2c_setinprogress) {
2065b4e998bSLarry Finger 			rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
207f1d2b4d3SLarry Finger 				"H2C set in progress! Wait to set..element_id(%d).\n",
208f1d2b4d3SLarry Finger 				element_id);
209f1d2b4d3SLarry Finger 			while (rtlhal->h2c_setinprogress) {
210f1d2b4d3SLarry Finger 				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
211f1d2b4d3SLarry Finger 						       flag);
212f1d2b4d3SLarry Finger 				h2c_waitcounter++;
2135b4e998bSLarry Finger 				rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
214f1d2b4d3SLarry Finger 					"Wait 100 us (%d times)...\n",
215f1d2b4d3SLarry Finger 					 h2c_waitcounter);
216f1d2b4d3SLarry Finger 				udelay(100);
217f1d2b4d3SLarry Finger 
218f1d2b4d3SLarry Finger 				if (h2c_waitcounter > 1000)
219f1d2b4d3SLarry Finger 					return;
220f1d2b4d3SLarry Finger 				spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
221f1d2b4d3SLarry Finger 						  flag);
222f1d2b4d3SLarry Finger 			}
223f1d2b4d3SLarry Finger 			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
224f1d2b4d3SLarry Finger 		} else {
225f1d2b4d3SLarry Finger 			rtlhal->h2c_setinprogress = true;
226f1d2b4d3SLarry Finger 			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
227f1d2b4d3SLarry Finger 			break;
228f1d2b4d3SLarry Finger 		}
229f1d2b4d3SLarry Finger 	}
230f1d2b4d3SLarry Finger 
231f1d2b4d3SLarry Finger 	while (!bwrite_sucess) {
232f1d2b4d3SLarry Finger 		wait_writeh2c_limmit--;
233f1d2b4d3SLarry Finger 		if (wait_writeh2c_limmit == 0) {
2340fc30e93SLarry Finger 			pr_err("Write H2C fail because no trigger for FW INT!\n");
235f1d2b4d3SLarry Finger 			break;
236f1d2b4d3SLarry Finger 		}
237f1d2b4d3SLarry Finger 
238f1d2b4d3SLarry Finger 		boxnum = rtlhal->last_hmeboxnum;
239f1d2b4d3SLarry Finger 		switch (boxnum) {
240f1d2b4d3SLarry Finger 		case 0:
241f1d2b4d3SLarry Finger 			box_reg = REG_HMEBOX_0;
242f1d2b4d3SLarry Finger 			box_extreg = REG_HMEBOX_EXT_0;
243f1d2b4d3SLarry Finger 			break;
244f1d2b4d3SLarry Finger 		case 1:
245f1d2b4d3SLarry Finger 			box_reg = REG_HMEBOX_1;
246f1d2b4d3SLarry Finger 			box_extreg = REG_HMEBOX_EXT_1;
247f1d2b4d3SLarry Finger 			break;
248f1d2b4d3SLarry Finger 		case 2:
249f1d2b4d3SLarry Finger 			box_reg = REG_HMEBOX_2;
250f1d2b4d3SLarry Finger 			box_extreg = REG_HMEBOX_EXT_2;
251f1d2b4d3SLarry Finger 			break;
252f1d2b4d3SLarry Finger 		case 3:
253f1d2b4d3SLarry Finger 			box_reg = REG_HMEBOX_3;
254f1d2b4d3SLarry Finger 			box_extreg = REG_HMEBOX_EXT_3;
255f1d2b4d3SLarry Finger 			break;
256f1d2b4d3SLarry Finger 		default:
2575b4e998bSLarry Finger 			rtl_dbg(rtlpriv, COMP_ERR, DBG_LOUD,
258ad574889SJoe Perches 				"switch case %#x not processed\n", boxnum);
259f1d2b4d3SLarry Finger 			break;
260f1d2b4d3SLarry Finger 		}
261f1d2b4d3SLarry Finger 
262f1d2b4d3SLarry Finger 		isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
263f1d2b4d3SLarry Finger 		while (!isfw_read) {
264f1d2b4d3SLarry Finger 			wait_h2c_limmit--;
265f1d2b4d3SLarry Finger 			if (wait_h2c_limmit == 0) {
2665b4e998bSLarry Finger 				rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
267f1d2b4d3SLarry Finger 					"Waiting too long for FW read clear HMEBox(%d)!\n",
268f1d2b4d3SLarry Finger 					boxnum);
269f1d2b4d3SLarry Finger 				break;
270f1d2b4d3SLarry Finger 			}
271f1d2b4d3SLarry Finger 
272f1d2b4d3SLarry Finger 			udelay(10);
273f1d2b4d3SLarry Finger 
274f1d2b4d3SLarry Finger 			isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
275f1d2b4d3SLarry Finger 			u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
2765b4e998bSLarry Finger 			rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
277f1d2b4d3SLarry Finger 				"Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
278f1d2b4d3SLarry Finger 				boxnum, u1b_tmp);
279f1d2b4d3SLarry Finger 		}
280f1d2b4d3SLarry Finger 
281f1d2b4d3SLarry Finger 		if (!isfw_read) {
2825b4e998bSLarry Finger 			rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
283f1d2b4d3SLarry Finger 				"Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
284f1d2b4d3SLarry Finger 				boxnum);
285f1d2b4d3SLarry Finger 			break;
286f1d2b4d3SLarry Finger 		}
287f1d2b4d3SLarry Finger 
288f1d2b4d3SLarry Finger 		memset(boxcontent, 0, sizeof(boxcontent));
289f1d2b4d3SLarry Finger 		memset(boxextcontent, 0, sizeof(boxextcontent));
290f1d2b4d3SLarry Finger 		boxcontent[0] = element_id;
2915b4e998bSLarry Finger 		rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
292f1d2b4d3SLarry Finger 			"Write element_id box_reg(%4x) = %2x\n",
293f1d2b4d3SLarry Finger 			box_reg, element_id);
294f1d2b4d3SLarry Finger 
295f1d2b4d3SLarry Finger 		switch (cmd_len) {
296f1d2b4d3SLarry Finger 		case 1:
297f1d2b4d3SLarry Finger 			boxcontent[0] &= ~(BIT(7));
298f1d2b4d3SLarry Finger 			memcpy((u8 *)(boxcontent) + 1,
299f1d2b4d3SLarry Finger 			       cmdbuffer + buf_index, 1);
300f1d2b4d3SLarry Finger 
301f1d2b4d3SLarry Finger 			for (idx = 0; idx < 4; idx++) {
302f1d2b4d3SLarry Finger 				rtl_write_byte(rtlpriv, box_reg + idx,
303f1d2b4d3SLarry Finger 					       boxcontent[idx]);
304f1d2b4d3SLarry Finger 			}
305f1d2b4d3SLarry Finger 			break;
306f1d2b4d3SLarry Finger 		case 2:
307f1d2b4d3SLarry Finger 			boxcontent[0] &= ~(BIT(7));
308f1d2b4d3SLarry Finger 			memcpy((u8 *)(boxcontent) + 1,
309f1d2b4d3SLarry Finger 			       cmdbuffer + buf_index, 2);
310f1d2b4d3SLarry Finger 
311f1d2b4d3SLarry Finger 			for (idx = 0; idx < 4; idx++) {
312f1d2b4d3SLarry Finger 				rtl_write_byte(rtlpriv, box_reg + idx,
313f1d2b4d3SLarry Finger 					       boxcontent[idx]);
314f1d2b4d3SLarry Finger 			}
315f1d2b4d3SLarry Finger 			break;
316f1d2b4d3SLarry Finger 		case 3:
317f1d2b4d3SLarry Finger 			boxcontent[0] &= ~(BIT(7));
318f1d2b4d3SLarry Finger 			memcpy((u8 *)(boxcontent) + 1,
319f1d2b4d3SLarry Finger 			       cmdbuffer + buf_index, 3);
320f1d2b4d3SLarry Finger 
321f1d2b4d3SLarry Finger 			for (idx = 0; idx < 4; idx++) {
322f1d2b4d3SLarry Finger 				rtl_write_byte(rtlpriv, box_reg + idx,
323f1d2b4d3SLarry Finger 					       boxcontent[idx]);
324f1d2b4d3SLarry Finger 			}
325f1d2b4d3SLarry Finger 			break;
326f1d2b4d3SLarry Finger 		case 4:
327f1d2b4d3SLarry Finger 			boxcontent[0] |= (BIT(7));
328f1d2b4d3SLarry Finger 			memcpy((u8 *)(boxextcontent),
329f1d2b4d3SLarry Finger 			       cmdbuffer + buf_index, 2);
330f1d2b4d3SLarry Finger 			memcpy((u8 *)(boxcontent) + 1,
331f1d2b4d3SLarry Finger 			       cmdbuffer + buf_index + 2, 2);
332f1d2b4d3SLarry Finger 
333f1d2b4d3SLarry Finger 			for (idx = 0; idx < 2; idx++) {
334f1d2b4d3SLarry Finger 				rtl_write_byte(rtlpriv, box_extreg + idx,
335f1d2b4d3SLarry Finger 					       boxextcontent[idx]);
336f1d2b4d3SLarry Finger 			}
337f1d2b4d3SLarry Finger 
338f1d2b4d3SLarry Finger 			for (idx = 0; idx < 4; idx++) {
339f1d2b4d3SLarry Finger 				rtl_write_byte(rtlpriv, box_reg + idx,
340f1d2b4d3SLarry Finger 					       boxcontent[idx]);
341f1d2b4d3SLarry Finger 			}
342f1d2b4d3SLarry Finger 			break;
343f1d2b4d3SLarry Finger 		case 5:
344f1d2b4d3SLarry Finger 			boxcontent[0] |= (BIT(7));
345f1d2b4d3SLarry Finger 			memcpy((u8 *)(boxextcontent),
346f1d2b4d3SLarry Finger 			       cmdbuffer + buf_index, 2);
347f1d2b4d3SLarry Finger 			memcpy((u8 *)(boxcontent) + 1,
348f1d2b4d3SLarry Finger 			       cmdbuffer + buf_index + 2, 3);
349f1d2b4d3SLarry Finger 
350f1d2b4d3SLarry Finger 			for (idx = 0; idx < 2; idx++) {
351f1d2b4d3SLarry Finger 				rtl_write_byte(rtlpriv, box_extreg + idx,
352f1d2b4d3SLarry Finger 					       boxextcontent[idx]);
353f1d2b4d3SLarry Finger 			}
354f1d2b4d3SLarry Finger 
355f1d2b4d3SLarry Finger 			for (idx = 0; idx < 4; idx++) {
356f1d2b4d3SLarry Finger 				rtl_write_byte(rtlpriv, box_reg + idx,
357f1d2b4d3SLarry Finger 					       boxcontent[idx]);
358f1d2b4d3SLarry Finger 			}
359f1d2b4d3SLarry Finger 			break;
360f1d2b4d3SLarry Finger 		default:
3615b4e998bSLarry Finger 			rtl_dbg(rtlpriv, COMP_ERR, DBG_LOUD,
362ad574889SJoe Perches 				"switch case %#x not processed\n", cmd_len);
363f1d2b4d3SLarry Finger 			break;
364f1d2b4d3SLarry Finger 		}
365f1d2b4d3SLarry Finger 
366f1d2b4d3SLarry Finger 		bwrite_sucess = true;
367f1d2b4d3SLarry Finger 
368f1d2b4d3SLarry Finger 		rtlhal->last_hmeboxnum = boxnum + 1;
369f1d2b4d3SLarry Finger 		if (rtlhal->last_hmeboxnum == 4)
370f1d2b4d3SLarry Finger 			rtlhal->last_hmeboxnum = 0;
371f1d2b4d3SLarry Finger 
3725b4e998bSLarry Finger 		rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
373f1d2b4d3SLarry Finger 			"pHalData->last_hmeboxnum  = %d\n",
374f1d2b4d3SLarry Finger 			rtlhal->last_hmeboxnum);
375f1d2b4d3SLarry Finger 	}
376f1d2b4d3SLarry Finger 
377f1d2b4d3SLarry Finger 	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
378f1d2b4d3SLarry Finger 	rtlhal->h2c_setinprogress = false;
379f1d2b4d3SLarry Finger 	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
380f1d2b4d3SLarry Finger 
3815b4e998bSLarry Finger 	rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
382f1d2b4d3SLarry Finger }
383f1d2b4d3SLarry Finger 
rtl92c_fill_h2c_cmd(struct ieee80211_hw * hw,u8 element_id,u32 cmd_len,u8 * cmdbuffer)384f1d2b4d3SLarry Finger void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
385f1d2b4d3SLarry Finger 			 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
386f1d2b4d3SLarry Finger {
387f1d2b4d3SLarry Finger 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
388f1d2b4d3SLarry Finger 	u32 tmp_cmdbuf[2];
389f1d2b4d3SLarry Finger 
390f1d2b4d3SLarry Finger 	if (!rtlhal->fw_ready) {
391531940f9SLarry Finger 		WARN_ONCE(true,
392531940f9SLarry Finger 			  "rtl8192c-common: return H2C cmd because of Fw download fail!!!\n");
393f1d2b4d3SLarry Finger 		return;
394f1d2b4d3SLarry Finger 	}
395f1d2b4d3SLarry Finger 
396f1d2b4d3SLarry Finger 	memset(tmp_cmdbuf, 0, 8);
397f1d2b4d3SLarry Finger 	memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
398f1d2b4d3SLarry Finger 	_rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
399f1d2b4d3SLarry Finger 
400f1d2b4d3SLarry Finger 	return;
401f1d2b4d3SLarry Finger }
402f1d2b4d3SLarry Finger EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
403f1d2b4d3SLarry Finger 
rtl92c_firmware_selfreset(struct ieee80211_hw * hw)404f1d2b4d3SLarry Finger void rtl92c_firmware_selfreset(struct ieee80211_hw *hw)
405f1d2b4d3SLarry Finger {
406f1d2b4d3SLarry Finger 	u8 u1b_tmp;
407f1d2b4d3SLarry Finger 	u8 delay = 100;
408f1d2b4d3SLarry Finger 	struct rtl_priv *rtlpriv = rtl_priv(hw);
409f1d2b4d3SLarry Finger 
410f1d2b4d3SLarry Finger 	rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
411f1d2b4d3SLarry Finger 	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
412f1d2b4d3SLarry Finger 
413f1d2b4d3SLarry Finger 	while (u1b_tmp & BIT(2)) {
414f1d2b4d3SLarry Finger 		delay--;
415f1d2b4d3SLarry Finger 		if (delay == 0) {
416531940f9SLarry Finger 			WARN_ONCE(true, "rtl8192c-common: 8051 reset fail.\n");
417f1d2b4d3SLarry Finger 			break;
418f1d2b4d3SLarry Finger 		}
419f1d2b4d3SLarry Finger 		udelay(50);
420f1d2b4d3SLarry Finger 		u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
421f1d2b4d3SLarry Finger 	}
422f1d2b4d3SLarry Finger }
423f1d2b4d3SLarry Finger EXPORT_SYMBOL(rtl92c_firmware_selfreset);
424f1d2b4d3SLarry Finger 
rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw * hw,u8 mode)425f1d2b4d3SLarry Finger void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
426f1d2b4d3SLarry Finger {
427f1d2b4d3SLarry Finger 	struct rtl_priv *rtlpriv = rtl_priv(hw);
428f1d2b4d3SLarry Finger 	u8 u1_h2c_set_pwrmode[3] = { 0 };
429f1d2b4d3SLarry Finger 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
430f1d2b4d3SLarry Finger 
4315b4e998bSLarry Finger 	rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
432f1d2b4d3SLarry Finger 
433f1d2b4d3SLarry Finger 	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
434f1d2b4d3SLarry Finger 	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
435f1d2b4d3SLarry Finger 		(rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1);
436f1d2b4d3SLarry Finger 	SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
437f1d2b4d3SLarry Finger 					      ppsc->reg_max_lps_awakeintvl);
438f1d2b4d3SLarry Finger 
439f1d2b4d3SLarry Finger 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
440f1d2b4d3SLarry Finger 		      "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
441f1d2b4d3SLarry Finger 		      u1_h2c_set_pwrmode, 3);
442f1d2b4d3SLarry Finger 	rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
443f1d2b4d3SLarry Finger }
444f1d2b4d3SLarry Finger EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
445f1d2b4d3SLarry Finger 
446f1d2b4d3SLarry Finger #define BEACON_PG		0 /*->1*/
447f1d2b4d3SLarry Finger #define PSPOLL_PG		2
448f1d2b4d3SLarry Finger #define NULL_PG			3
449f1d2b4d3SLarry Finger #define PROBERSP_PG		4 /*->5*/
450f1d2b4d3SLarry Finger 
451f1d2b4d3SLarry Finger #define TOTAL_RESERVED_PKT_LEN	768
452f1d2b4d3SLarry Finger 
453f1d2b4d3SLarry Finger static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
454f1d2b4d3SLarry Finger 	/* page 0 beacon */
455f1d2b4d3SLarry Finger 	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
456f1d2b4d3SLarry Finger 	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
457f1d2b4d3SLarry Finger 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
458f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
459f1d2b4d3SLarry Finger 	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
460f1d2b4d3SLarry Finger 	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
461f1d2b4d3SLarry Finger 	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
462f1d2b4d3SLarry Finger 	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
463f1d2b4d3SLarry Finger 	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
464f1d2b4d3SLarry Finger 	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
465f1d2b4d3SLarry Finger 	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
466f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
467f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
468f1d2b4d3SLarry Finger 	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
469f1d2b4d3SLarry Finger 	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
470f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
471f1d2b4d3SLarry Finger 
472f1d2b4d3SLarry Finger 	/* page 1 beacon */
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 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
481f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
482f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
483f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
484f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
485f1d2b4d3SLarry Finger 	0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
486f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
487f1d2b4d3SLarry Finger 	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
488f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
489f1d2b4d3SLarry Finger 
490f1d2b4d3SLarry Finger 	/* page 2  ps-poll */
491f1d2b4d3SLarry Finger 	0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
492f1d2b4d3SLarry Finger 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
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 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
499f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
500f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
501f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
502f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
503f1d2b4d3SLarry Finger 	0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
504f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
505f1d2b4d3SLarry Finger 	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
506f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
507f1d2b4d3SLarry Finger 
508f1d2b4d3SLarry Finger 	/* page 3  null */
509f1d2b4d3SLarry Finger 	0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
510f1d2b4d3SLarry Finger 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
511f1d2b4d3SLarry Finger 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 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 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
517f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
518f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
519f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
520f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
521f1d2b4d3SLarry Finger 	0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
522f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
523f1d2b4d3SLarry Finger 	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
524f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
525f1d2b4d3SLarry Finger 
526f1d2b4d3SLarry Finger 	/* page 4  probe_resp */
527f1d2b4d3SLarry Finger 	0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
528f1d2b4d3SLarry Finger 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
529f1d2b4d3SLarry Finger 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
530f1d2b4d3SLarry Finger 	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
531f1d2b4d3SLarry Finger 	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
532f1d2b4d3SLarry Finger 	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
533f1d2b4d3SLarry Finger 	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
534f1d2b4d3SLarry Finger 	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
535f1d2b4d3SLarry Finger 	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
536f1d2b4d3SLarry Finger 	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
537f1d2b4d3SLarry Finger 	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
538f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
539f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
540f1d2b4d3SLarry Finger 	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
541f1d2b4d3SLarry Finger 	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
542f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
543f1d2b4d3SLarry Finger 
544f1d2b4d3SLarry Finger 	/* page 5  probe_resp */
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 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
557f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
558f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
559f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
560f1d2b4d3SLarry Finger 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
561f1d2b4d3SLarry Finger };
562f1d2b4d3SLarry Finger 
rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw * hw,bool (* cmd_send_packet)(struct ieee80211_hw *,struct sk_buff *))563f1d2b4d3SLarry Finger void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
564f1d2b4d3SLarry Finger 	 bool (*cmd_send_packet)(struct ieee80211_hw *, struct sk_buff *))
565f1d2b4d3SLarry Finger {
566f1d2b4d3SLarry Finger 	struct rtl_priv *rtlpriv = rtl_priv(hw);
567f1d2b4d3SLarry Finger 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
568f1d2b4d3SLarry Finger 	struct sk_buff *skb = NULL;
569f1d2b4d3SLarry Finger 
570f1d2b4d3SLarry Finger 	u32 totalpacketlen;
571f1d2b4d3SLarry Finger 	bool rtstatus;
572f1d2b4d3SLarry Finger 	u8 u1rsvdpageloc[3] = { 0 };
573f1d2b4d3SLarry Finger 	bool b_dlok = false;
574f1d2b4d3SLarry Finger 
575f1d2b4d3SLarry Finger 	u8 *beacon;
576f1d2b4d3SLarry Finger 	u8 *p_pspoll;
577f1d2b4d3SLarry Finger 	u8 *nullfunc;
578f1d2b4d3SLarry Finger 	u8 *p_probersp;
579f1d2b4d3SLarry Finger 	/*---------------------------------------------------------
580f1d2b4d3SLarry Finger 				(1) beacon
581f1d2b4d3SLarry Finger 	---------------------------------------------------------*/
582f1d2b4d3SLarry Finger 	beacon = &reserved_page_packet[BEACON_PG * 128];
583f1d2b4d3SLarry Finger 	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
584f1d2b4d3SLarry Finger 	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
585f1d2b4d3SLarry Finger 
586f1d2b4d3SLarry Finger 	/*-------------------------------------------------------
587f1d2b4d3SLarry Finger 				(2) ps-poll
588f1d2b4d3SLarry Finger 	--------------------------------------------------------*/
589f1d2b4d3SLarry Finger 	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
590f1d2b4d3SLarry Finger 	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
591f1d2b4d3SLarry Finger 	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
592f1d2b4d3SLarry Finger 	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
593f1d2b4d3SLarry Finger 
594f1d2b4d3SLarry Finger 	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
595f1d2b4d3SLarry Finger 
596f1d2b4d3SLarry Finger 	/*--------------------------------------------------------
597f1d2b4d3SLarry Finger 				(3) null data
598f1d2b4d3SLarry Finger 	---------------------------------------------------------*/
599f1d2b4d3SLarry Finger 	nullfunc = &reserved_page_packet[NULL_PG * 128];
600f1d2b4d3SLarry Finger 	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
601f1d2b4d3SLarry Finger 	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
602f1d2b4d3SLarry Finger 	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
603f1d2b4d3SLarry Finger 
604f1d2b4d3SLarry Finger 	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
605f1d2b4d3SLarry Finger 
606f1d2b4d3SLarry Finger 	/*---------------------------------------------------------
607f1d2b4d3SLarry Finger 				(4) probe response
608f1d2b4d3SLarry Finger 	----------------------------------------------------------*/
609f1d2b4d3SLarry Finger 	p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
610f1d2b4d3SLarry Finger 	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
611f1d2b4d3SLarry Finger 	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
612f1d2b4d3SLarry Finger 	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
613f1d2b4d3SLarry Finger 
614f1d2b4d3SLarry Finger 	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
615f1d2b4d3SLarry Finger 
616f1d2b4d3SLarry Finger 	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
617f1d2b4d3SLarry Finger 
618f1d2b4d3SLarry Finger 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
619f1d2b4d3SLarry Finger 		      "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
620f1d2b4d3SLarry Finger 		      &reserved_page_packet[0], totalpacketlen);
621f1d2b4d3SLarry Finger 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
622f1d2b4d3SLarry Finger 		      "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
623f1d2b4d3SLarry Finger 		      u1rsvdpageloc, 3);
624f1d2b4d3SLarry Finger 
625f1d2b4d3SLarry Finger 	skb = dev_alloc_skb(totalpacketlen);
62660209d48SPing-Ke Shih 	if (!skb)
62760209d48SPing-Ke Shih 		return;
628ad941e69Syuan linyu 	skb_put_data(skb, &reserved_page_packet, totalpacketlen);
629f1d2b4d3SLarry Finger 
630f1d2b4d3SLarry Finger 	if (cmd_send_packet)
631f1d2b4d3SLarry Finger 		rtstatus = cmd_send_packet(hw, skb);
632f1d2b4d3SLarry Finger 	else
633f1d2b4d3SLarry Finger 		rtstatus = rtl_cmd_send_packet(hw, skb);
634f1d2b4d3SLarry Finger 
635f1d2b4d3SLarry Finger 	if (rtstatus)
636f1d2b4d3SLarry Finger 		b_dlok = true;
637f1d2b4d3SLarry Finger 
638f1d2b4d3SLarry Finger 	if (b_dlok) {
6395b4e998bSLarry Finger 		rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
640f1d2b4d3SLarry Finger 			"Set RSVD page location to Fw.\n");
641f1d2b4d3SLarry Finger 		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
642f1d2b4d3SLarry Finger 				"H2C_RSVDPAGE:\n",
643f1d2b4d3SLarry Finger 				u1rsvdpageloc, 3);
644f1d2b4d3SLarry Finger 		rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
645f1d2b4d3SLarry Finger 				    sizeof(u1rsvdpageloc), u1rsvdpageloc);
646f1d2b4d3SLarry Finger 	} else
6475b4e998bSLarry Finger 		rtl_dbg(rtlpriv, COMP_ERR, DBG_WARNING,
648f1d2b4d3SLarry Finger 			"Set RSVD page location to Fw FAIL!!!!!!.\n");
649f1d2b4d3SLarry Finger }
650f1d2b4d3SLarry Finger EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
651f1d2b4d3SLarry Finger 
rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw * hw,u8 mstatus)652f1d2b4d3SLarry Finger void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
653f1d2b4d3SLarry Finger {
654f1d2b4d3SLarry Finger 	u8 u1_joinbssrpt_parm[1] = { 0 };
655f1d2b4d3SLarry Finger 
656f1d2b4d3SLarry Finger 	SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
657f1d2b4d3SLarry Finger 
658f1d2b4d3SLarry Finger 	rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
659f1d2b4d3SLarry Finger }
660f1d2b4d3SLarry Finger EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);
661f1d2b4d3SLarry Finger 
rtl92c_set_p2p_ctw_period_cmd(struct ieee80211_hw * hw,u8 ctwindow)662f1d2b4d3SLarry Finger static void rtl92c_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
663f1d2b4d3SLarry Finger {
664f1d2b4d3SLarry Finger 	u8 u1_ctwindow_period[1] = { ctwindow};
665f1d2b4d3SLarry Finger 
666f1d2b4d3SLarry Finger 	rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
667f1d2b4d3SLarry Finger }
668f1d2b4d3SLarry Finger 
669f1d2b4d3SLarry Finger /* refactored routine */
set_noa_data(struct rtl_priv * rtlpriv,struct rtl_p2p_ps_info * p2pinfo,struct p2p_ps_offload_t * p2p_ps_offload)670f1d2b4d3SLarry Finger static void set_noa_data(struct rtl_priv *rtlpriv,
671f1d2b4d3SLarry Finger 			 struct rtl_p2p_ps_info *p2pinfo,
672f1d2b4d3SLarry Finger 			 struct p2p_ps_offload_t *p2p_ps_offload)
673f1d2b4d3SLarry Finger {
674f1d2b4d3SLarry Finger 	int i;
675f1d2b4d3SLarry Finger 	u32	start_time, tsf_low;
676f1d2b4d3SLarry Finger 
677f1d2b4d3SLarry Finger 	/* hw only support 2 set of NoA */
678f1d2b4d3SLarry Finger 	for (i = 0 ; i < p2pinfo->noa_num ; i++) {
679f1d2b4d3SLarry Finger 		/* To control the reg setting for which NOA*/
680f1d2b4d3SLarry Finger 		rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
681f1d2b4d3SLarry Finger 		if (i == 0)
682f1d2b4d3SLarry Finger 			p2p_ps_offload->noa0_en = 1;
683f1d2b4d3SLarry Finger 		else
684f1d2b4d3SLarry Finger 			p2p_ps_offload->noa1_en = 1;
685f1d2b4d3SLarry Finger 
686f1d2b4d3SLarry Finger 		/* config P2P NoA Descriptor Register */
687f1d2b4d3SLarry Finger 		rtl_write_dword(rtlpriv, 0x5E0,
688f1d2b4d3SLarry Finger 				p2pinfo->noa_duration[i]);
689f1d2b4d3SLarry Finger 		rtl_write_dword(rtlpriv, 0x5E4,
690f1d2b4d3SLarry Finger 				p2pinfo->noa_interval[i]);
691f1d2b4d3SLarry Finger 
692f1d2b4d3SLarry Finger 		/*Get Current TSF value */
693f1d2b4d3SLarry Finger 		tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
694f1d2b4d3SLarry Finger 
695f1d2b4d3SLarry Finger 		start_time = p2pinfo->noa_start_time[i];
696f1d2b4d3SLarry Finger 		if (p2pinfo->noa_count_type[i] != 1) {
697f1d2b4d3SLarry Finger 			while (start_time <= (tsf_low+(50*1024))) {
698f1d2b4d3SLarry Finger 				start_time += p2pinfo->noa_interval[i];
699f1d2b4d3SLarry Finger 				if (p2pinfo->noa_count_type[i] != 255)
700f1d2b4d3SLarry Finger 					p2pinfo->noa_count_type[i]--;
701f1d2b4d3SLarry Finger 			}
702f1d2b4d3SLarry Finger 		}
703f1d2b4d3SLarry Finger 		rtl_write_dword(rtlpriv, 0x5E8, start_time);
704f1d2b4d3SLarry Finger 		rtl_write_dword(rtlpriv, 0x5EC,
705f1d2b4d3SLarry Finger 				p2pinfo->noa_count_type[i]);
706f1d2b4d3SLarry Finger 	}
707f1d2b4d3SLarry Finger }
708f1d2b4d3SLarry Finger 
rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw * hw,u8 p2p_ps_state)709f1d2b4d3SLarry Finger void rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
710f1d2b4d3SLarry Finger {
711f1d2b4d3SLarry Finger 	struct rtl_priv *rtlpriv = rtl_priv(hw);
712f1d2b4d3SLarry Finger 	struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
713f1d2b4d3SLarry Finger 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
714f1d2b4d3SLarry Finger 	struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
715f1d2b4d3SLarry Finger 	struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
716f1d2b4d3SLarry Finger 	u16	ctwindow;
717f1d2b4d3SLarry Finger 
718f1d2b4d3SLarry Finger 	switch (p2p_ps_state) {
719f1d2b4d3SLarry Finger 	case P2P_PS_DISABLE:
7205b4e998bSLarry Finger 			rtl_dbg(rtlpriv, COMP_FW, DBG_LOUD,
721f1d2b4d3SLarry Finger 				"P2P_PS_DISABLE\n");
722f1d2b4d3SLarry Finger 			memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
723f1d2b4d3SLarry Finger 			break;
724f1d2b4d3SLarry Finger 	case P2P_PS_ENABLE:
7255b4e998bSLarry Finger 			rtl_dbg(rtlpriv, COMP_FW, DBG_LOUD,
726f1d2b4d3SLarry Finger 				"P2P_PS_ENABLE\n");
727f1d2b4d3SLarry Finger 			/* update CTWindow value. */
728f1d2b4d3SLarry Finger 			if (p2pinfo->ctwindow > 0) {
729f1d2b4d3SLarry Finger 				p2p_ps_offload->ctwindow_en = 1;
730f1d2b4d3SLarry Finger 				ctwindow = p2pinfo->ctwindow;
731f1d2b4d3SLarry Finger 				rtl92c_set_p2p_ctw_period_cmd(hw, ctwindow);
732f1d2b4d3SLarry Finger 			}
733f1d2b4d3SLarry Finger 			/* call refactored routine */
734f1d2b4d3SLarry Finger 			set_noa_data(rtlpriv, p2pinfo, p2p_ps_offload);
735f1d2b4d3SLarry Finger 
736f1d2b4d3SLarry Finger 			if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
737f1d2b4d3SLarry Finger 				/* rst p2p circuit */
738f1d2b4d3SLarry Finger 				rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST,
739f1d2b4d3SLarry Finger 					       BIT(4));
740f1d2b4d3SLarry Finger 
741f1d2b4d3SLarry Finger 				p2p_ps_offload->offload_en = 1;
742f1d2b4d3SLarry Finger 
743f1d2b4d3SLarry Finger 				if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
744f1d2b4d3SLarry Finger 					p2p_ps_offload->role = 1;
745f1d2b4d3SLarry Finger 					p2p_ps_offload->allstasleep = 0;
746f1d2b4d3SLarry Finger 				} else {
747f1d2b4d3SLarry Finger 					p2p_ps_offload->role = 0;
748f1d2b4d3SLarry Finger 				}
749f1d2b4d3SLarry Finger 
750f1d2b4d3SLarry Finger 				p2p_ps_offload->discovery = 0;
751f1d2b4d3SLarry Finger 			}
752f1d2b4d3SLarry Finger 			break;
753f1d2b4d3SLarry Finger 	case P2P_PS_SCAN:
7545b4e998bSLarry Finger 			rtl_dbg(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
755f1d2b4d3SLarry Finger 			p2p_ps_offload->discovery = 1;
756f1d2b4d3SLarry Finger 			break;
757f1d2b4d3SLarry Finger 	case P2P_PS_SCAN_DONE:
7585b4e998bSLarry Finger 			rtl_dbg(rtlpriv, COMP_FW, DBG_LOUD,
759f1d2b4d3SLarry Finger 				"P2P_PS_SCAN_DONE\n");
760f1d2b4d3SLarry Finger 			p2p_ps_offload->discovery = 0;
761f1d2b4d3SLarry Finger 			p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
762f1d2b4d3SLarry Finger 			break;
763f1d2b4d3SLarry Finger 	default:
764f1d2b4d3SLarry Finger 			break;
765f1d2b4d3SLarry Finger 	}
766f1d2b4d3SLarry Finger 
767f1d2b4d3SLarry Finger 	rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
768f1d2b4d3SLarry Finger 
769f1d2b4d3SLarry Finger }
770f1d2b4d3SLarry Finger EXPORT_SYMBOL_GPL(rtl92c_set_p2p_ps_offload_cmd);
771