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