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