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