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