1 /******************************************************************************
3 * Copyright(c) 2009-2013 Realtek Corporation.
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.
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
14 * The full GNU General Public License is included in this distribution in the
15 * file called LICENSE.
17 * Contact Information:
18 * wlanfae <wlanfae@realtek.com>
19 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20 * Hsinchu 300, Taiwan.
22 * Larry Finger <Larry.Finger@lwfinger.net>
24 *****************************************************************************/
34 static void _rtl88e_enable_fw_download(struct ieee80211_hw
*hw
, bool enable
)
36 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
40 tmp
= rtl_read_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1);
41 rtl_write_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1, tmp
| 0x04);
43 tmp
= rtl_read_byte(rtlpriv
, REG_MCUFWDL
);
44 rtl_write_byte(rtlpriv
, REG_MCUFWDL
, tmp
| 0x01);
46 tmp
= rtl_read_byte(rtlpriv
, REG_MCUFWDL
+ 2);
47 rtl_write_byte(rtlpriv
, REG_MCUFWDL
+ 2, tmp
& 0xf7);
49 tmp
= rtl_read_byte(rtlpriv
, REG_MCUFWDL
);
50 rtl_write_byte(rtlpriv
, REG_MCUFWDL
, tmp
& 0xfe);
52 rtl_write_byte(rtlpriv
, REG_MCUFWDL
+ 1, 0x00);
56 static void _rtl88e_fw_block_write(struct ieee80211_hw
*hw
,
57 const u8
*buffer
, u32 size
)
59 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
60 u32 blocksize
= sizeof(u32
);
61 u8
*bufferptr
= (u8
*)buffer
;
62 u32
*pu4BytePtr
= (u32
*)buffer
;
63 u32 i
, offset
, blockcount
, remainsize
;
65 blockcount
= size
/ blocksize
;
66 remainsize
= size
% blocksize
;
68 for (i
= 0; i
< blockcount
; i
++) {
69 offset
= i
* blocksize
;
70 rtl_write_dword(rtlpriv
, (FW_8192C_START_ADDRESS
+ offset
),
75 offset
= blockcount
* blocksize
;
77 for (i
= 0; i
< remainsize
; i
++) {
78 rtl_write_byte(rtlpriv
, (FW_8192C_START_ADDRESS
+
79 offset
+ i
), *(bufferptr
+ i
));
84 static void _rtl88e_fw_page_write(struct ieee80211_hw
*hw
,
85 u32 page
, const u8
*buffer
, u32 size
)
87 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
89 u8 u8page
= (u8
) (page
& 0x07);
91 value8
= (rtl_read_byte(rtlpriv
, REG_MCUFWDL
+ 2) & 0xF8) | u8page
;
93 rtl_write_byte(rtlpriv
, (REG_MCUFWDL
+ 2), value8
);
94 _rtl88e_fw_block_write(hw
, buffer
, size
);
97 static void _rtl88e_fill_dummy(u8
*pfwbuf
, u32
*pfwlen
)
100 u8 remain
= (u8
) (fwlen
% 4);
102 remain
= (remain
== 0) ? 0 : (4 - remain
);
113 static void _rtl88e_write_fw(struct ieee80211_hw
*hw
,
114 enum version_8188e version
, u8
*buffer
, u32 size
)
116 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
117 u8
*bufferptr
= (u8
*)buffer
;
118 u32 pagenums
, remainsize
;
121 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
, "FW size is %d bytes,\n", size
);
123 _rtl88e_fill_dummy(bufferptr
, &size
);
125 pagenums
= size
/ FW_8192C_PAGE_SIZE
;
126 remainsize
= size
% FW_8192C_PAGE_SIZE
;
129 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
130 "Page numbers should not greater then 8\n");
133 for (page
= 0; page
< pagenums
; page
++) {
134 offset
= page
* FW_8192C_PAGE_SIZE
;
135 _rtl88e_fw_page_write(hw
, page
, (bufferptr
+ offset
),
140 offset
= pagenums
* FW_8192C_PAGE_SIZE
;
142 _rtl88e_fw_page_write(hw
, page
, (bufferptr
+ offset
),
147 static int _rtl88e_fw_free_to_go(struct ieee80211_hw
*hw
)
149 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
155 value32
= rtl_read_dword(rtlpriv
, REG_MCUFWDL
);
156 } while ((counter
++ < FW_8192C_POLLING_TIMEOUT_COUNT
) &&
157 (!(value32
& FWDL_CHKSUM_RPT
)));
159 if (counter
>= FW_8192C_POLLING_TIMEOUT_COUNT
) {
160 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
161 "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
166 RT_TRACE(rtlpriv
, COMP_FW
, DBG_TRACE
,
167 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32
);
169 value32
= rtl_read_dword(rtlpriv
, REG_MCUFWDL
);
170 value32
|= MCUFWDL_RDY
;
171 value32
&= ~WINTINI_RDY
;
172 rtl_write_dword(rtlpriv
, REG_MCUFWDL
, value32
);
174 rtl88e_firmware_selfreset(hw
);
178 value32
= rtl_read_dword(rtlpriv
, REG_MCUFWDL
);
179 if (value32
& WINTINI_RDY
) {
180 RT_TRACE(rtlpriv
, COMP_FW
, DBG_TRACE
,
181 "Polling FW ready success!! REG_MCUFWDL:0x%08x.\n",
187 udelay(FW_8192C_POLLING_DELAY
);
189 } while (counter
++ < FW_8192C_POLLING_TIMEOUT_COUNT
);
191 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
192 "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32
);
198 int rtl88e_download_fw(struct ieee80211_hw
*hw
,
199 bool buse_wake_on_wlan_fw
)
201 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
202 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
203 struct rtl92c_firmware_header
*pfwheader
;
207 enum version_8188e version
= rtlhal
->version
;
209 if (!rtlhal
->pfirmware
)
212 pfwheader
= (struct rtl92c_firmware_header
*)rtlhal
->pfirmware
;
213 pfwdata
= rtlhal
->pfirmware
;
214 fwsize
= rtlhal
->fwsize
;
215 RT_TRACE(rtlpriv
, COMP_FW
, DBG_DMESG
,
216 "normal Firmware SIZE %d\n", fwsize
);
218 if (IS_FW_HEADER_EXIST(pfwheader
)) {
219 RT_TRACE(rtlpriv
, COMP_FW
, DBG_DMESG
,
220 "Firmware Version(%d), Signature(%#x), Size(%d)\n",
221 pfwheader
->version
, pfwheader
->signature
,
222 (int)sizeof(struct rtl92c_firmware_header
));
224 pfwdata
= pfwdata
+ sizeof(struct rtl92c_firmware_header
);
225 fwsize
= fwsize
- sizeof(struct rtl92c_firmware_header
);
228 if (rtl_read_byte(rtlpriv
, REG_MCUFWDL
) & BIT(7)) {
229 rtl_write_byte(rtlpriv
, REG_MCUFWDL
, 0);
230 rtl88e_firmware_selfreset(hw
);
232 _rtl88e_enable_fw_download(hw
, true);
233 _rtl88e_write_fw(hw
, version
, pfwdata
, fwsize
);
234 _rtl88e_enable_fw_download(hw
, false);
236 err
= _rtl88e_fw_free_to_go(hw
);
238 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
239 "Firmware is not ready to run!\n");
241 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
,
242 "Firmware is ready to run!\n");
248 static bool _rtl88e_check_fw_read_last_h2c(struct ieee80211_hw
*hw
, u8 boxnum
)
250 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
253 val_hmetfr
= rtl_read_byte(rtlpriv
, REG_HMETFR
);
254 if (((val_hmetfr
>> boxnum
) & BIT(0)) == 0)
259 static void _rtl88e_fill_h2c_command(struct ieee80211_hw
*hw
,
260 u8 element_id
, u32 cmd_len
,
263 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
264 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
266 u16 box_reg
= 0, box_extreg
= 0;
268 bool isfw_read
= false;
270 bool write_sucess
= false;
271 u8 wait_h2c_limmit
= 100;
272 u8 wait_writeh2c_limit
= 100;
273 u8 boxcontent
[4], boxextcontent
[4];
274 u32 h2c_waitcounter
= 0;
278 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
, "come in\n");
281 spin_lock_irqsave(&rtlpriv
->locks
.h2c_lock
, flag
);
282 if (rtlhal
->h2c_setinprogress
) {
283 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
,
284 "H2C set in progress! Wait to set..element_id(%d).\n",
287 while (rtlhal
->h2c_setinprogress
) {
288 spin_unlock_irqrestore(&rtlpriv
->locks
.h2c_lock
,
291 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
,
292 "Wait 100 us (%d times)...\n",
296 if (h2c_waitcounter
> 1000)
298 spin_lock_irqsave(&rtlpriv
->locks
.h2c_lock
,
301 spin_unlock_irqrestore(&rtlpriv
->locks
.h2c_lock
, flag
);
303 rtlhal
->h2c_setinprogress
= true;
304 spin_unlock_irqrestore(&rtlpriv
->locks
.h2c_lock
, flag
);
309 while (!write_sucess
) {
310 wait_writeh2c_limit
--;
311 if (wait_writeh2c_limit
== 0) {
312 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
313 "Write H2C fail because no trigger for FW INT!\n");
317 boxnum
= rtlhal
->last_hmeboxnum
;
320 box_reg
= REG_HMEBOX_0
;
321 box_extreg
= REG_HMEBOX_EXT_0
;
324 box_reg
= REG_HMEBOX_1
;
325 box_extreg
= REG_HMEBOX_EXT_1
;
328 box_reg
= REG_HMEBOX_2
;
329 box_extreg
= REG_HMEBOX_EXT_2
;
332 box_reg
= REG_HMEBOX_3
;
333 box_extreg
= REG_HMEBOX_EXT_3
;
336 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_LOUD
,
337 "switch case not process\n");
340 isfw_read
= _rtl88e_check_fw_read_last_h2c(hw
, boxnum
);
343 if (wait_h2c_limmit
== 0) {
344 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
,
345 "Waiting too long for FW read clear HMEBox(%d)!\n",
352 isfw_read
= _rtl88e_check_fw_read_last_h2c(hw
, boxnum
);
353 u1b_tmp
= rtl_read_byte(rtlpriv
, 0x130);
354 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
,
355 "Waiting for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
360 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
,
361 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
366 memset(boxcontent
, 0, sizeof(boxcontent
));
367 memset(boxextcontent
, 0, sizeof(boxextcontent
));
368 boxcontent
[0] = element_id
;
369 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
,
370 "Write element_id box_reg(%4x) = %2x\n",
371 box_reg
, element_id
);
377 /*boxcontent[0] &= ~(BIT(7));*/
378 memcpy((u8
*)(boxcontent
) + 1,
379 cmd_b
+ buf_index
, cmd_len
);
381 for (idx
= 0; idx
< 4; idx
++) {
382 rtl_write_byte(rtlpriv
, box_reg
+ idx
,
390 /*boxcontent[0] |= (BIT(7));*/
391 memcpy((u8
*)(boxextcontent
),
392 cmd_b
+ buf_index
+3, cmd_len
-3);
393 memcpy((u8
*)(boxcontent
) + 1,
394 cmd_b
+ buf_index
, 3);
396 for (idx
= 0; idx
< 2; idx
++) {
397 rtl_write_byte(rtlpriv
, box_extreg
+ idx
,
401 for (idx
= 0; idx
< 4; idx
++) {
402 rtl_write_byte(rtlpriv
, box_reg
+ idx
,
407 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_LOUD
,
408 "switch case not process\n");
414 rtlhal
->last_hmeboxnum
= boxnum
+ 1;
415 if (rtlhal
->last_hmeboxnum
== 4)
416 rtlhal
->last_hmeboxnum
= 0;
418 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
,
419 "pHalData->last_hmeboxnum = %d\n",
420 rtlhal
->last_hmeboxnum
);
423 spin_lock_irqsave(&rtlpriv
->locks
.h2c_lock
, flag
);
424 rtlhal
->h2c_setinprogress
= false;
425 spin_unlock_irqrestore(&rtlpriv
->locks
.h2c_lock
, flag
);
427 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
, "go out\n");
430 void rtl88e_fill_h2c_cmd(struct ieee80211_hw
*hw
,
431 u8 element_id
, u32 cmd_len
, u8
*cmdbuffer
)
433 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
436 if (!rtlhal
->fw_ready
) {
438 "return H2C cmd because of Fw download fail!!!\n");
442 memset(tmp_cmdbuf
, 0, 8);
443 memcpy(tmp_cmdbuf
, cmdbuffer
, cmd_len
);
444 _rtl88e_fill_h2c_command(hw
, element_id
, cmd_len
, (u8
*)&tmp_cmdbuf
);
449 void rtl88e_firmware_selfreset(struct ieee80211_hw
*hw
)
452 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
454 u1b_tmp
= rtl_read_byte(rtlpriv
, REG_SYS_FUNC_EN
+1);
455 rtl_write_byte(rtlpriv
, REG_SYS_FUNC_EN
+1, (u1b_tmp
& (~BIT(2))));
456 rtl_write_byte(rtlpriv
, REG_SYS_FUNC_EN
+1, (u1b_tmp
| BIT(2)));
457 RT_TRACE(rtlpriv
, COMP_INIT
, DBG_LOUD
,
458 "8051Reset88E(): 8051 reset success\n");
462 void rtl88e_set_fw_pwrmode_cmd(struct ieee80211_hw
*hw
, u8 mode
)
464 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
465 u8 u1_h2c_set_pwrmode
[H2C_88E_PWEMODE_LENGTH
] = { 0 };
466 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
467 u8 rlbm
, power_state
= 0;
468 RT_TRACE(rtlpriv
, COMP_POWER
, DBG_LOUD
, "FW LPS mode = %d\n", mode
);
470 SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode
, ((mode
) ? 1 : 0));
471 rlbm
= 0;/*YJ, temp, 120316. FW now not support RLBM=2.*/
472 SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode
, rlbm
);
473 SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode
,
474 (rtlpriv
->mac80211
.p2p
) ? ppsc
->smart_ps
: 1);
475 SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode
,
476 ppsc
->reg_max_lps_awakeintvl
);
477 SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode
, 0);
478 if (mode
== FW_PS_ACTIVE_MODE
)
479 power_state
|= FW_PWR_STATE_ACTIVE
;
481 power_state
|= FW_PWR_STATE_RF_OFF
;
483 SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode
, power_state
);
485 RT_PRINT_DATA(rtlpriv
, COMP_CMD
, DBG_DMESG
,
486 "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
487 u1_h2c_set_pwrmode
, H2C_88E_PWEMODE_LENGTH
);
488 rtl88e_fill_h2c_cmd(hw
, H2C_88E_SETPWRMODE
,
489 H2C_88E_PWEMODE_LENGTH
, u1_h2c_set_pwrmode
);
492 void rtl88e_set_fw_joinbss_report_cmd(struct ieee80211_hw
*hw
, u8 mstatus
)
494 u8 u1_joinbssrpt_parm
[1] = { 0 };
496 SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm
, mstatus
);
498 rtl88e_fill_h2c_cmd(hw
, H2C_88E_JOINBSSRPT
, 1, u1_joinbssrpt_parm
);
501 void rtl88e_set_fw_ap_off_load_cmd(struct ieee80211_hw
*hw
,
502 u8 ap_offload_enable
)
504 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
505 u8 u1_apoffload_parm
[H2C_88E_AP_OFFLOAD_LENGTH
] = { 0 };
507 SET_H2CCMD_AP_OFFLOAD_ON(u1_apoffload_parm
, ap_offload_enable
);
508 SET_H2CCMD_AP_OFFLOAD_HIDDEN(u1_apoffload_parm
, mac
->hiddenssid
);
509 SET_H2CCMD_AP_OFFLOAD_DENYANY(u1_apoffload_parm
, 0);
511 rtl88e_fill_h2c_cmd(hw
, H2C_88E_AP_OFFLOAD
,
512 H2C_88E_AP_OFFLOAD_LENGTH
, u1_apoffload_parm
);
516 #define BEACON_PG 0 /* ->1 */
519 #define PROBERSP_PG 4 /* ->5 */
521 #define TOTAL_RESERVED_PKT_LEN 768
523 static u8 reserved_page_packet
[TOTAL_RESERVED_PKT_LEN
] = {
525 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
526 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
527 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
528 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
529 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
530 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
531 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
532 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
533 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
534 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
535 0x03, 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 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
539 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
540 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
543 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
544 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
556 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
557 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
561 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
562 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
563 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
564 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
565 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
566 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
574 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
575 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
576 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
579 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
580 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
581 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
582 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
583 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
584 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
585 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
586 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
587 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
588 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
589 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
590 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
591 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
592 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
593 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
594 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
596 /* page 4 probe_resp */
597 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
598 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
599 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
600 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
601 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
602 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
603 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
604 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
605 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
606 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
607 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
608 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
609 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
610 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
611 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
612 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
614 /* page 5 probe_resp */
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
619 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
620 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
621 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
622 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
623 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
624 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
625 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
626 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
627 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
628 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
629 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
630 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
633 void rtl88e_set_fw_rsvdpagepkt(struct ieee80211_hw
*hw
, bool b_dl_finished
)
635 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
636 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
637 struct sk_buff
*skb
= NULL
;
640 u8 u1rsvdpageloc
[5] = { 0 };
647 /*---------------------------------------------------------
649 *---------------------------------------------------------
651 beacon
= &reserved_page_packet
[BEACON_PG
* 128];
652 SET_80211_HDR_ADDRESS2(beacon
, mac
->mac_addr
);
653 SET_80211_HDR_ADDRESS3(beacon
, mac
->bssid
);
655 /*-------------------------------------------------------
657 *--------------------------------------------------------
659 p_pspoll
= &reserved_page_packet
[PSPOLL_PG
* 128];
660 SET_80211_PS_POLL_AID(p_pspoll
, (mac
->assoc_id
| 0xc000));
661 SET_80211_PS_POLL_BSSID(p_pspoll
, mac
->bssid
);
662 SET_80211_PS_POLL_TA(p_pspoll
, mac
->mac_addr
);
664 SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc
, PSPOLL_PG
);
666 /*--------------------------------------------------------
668 *---------------------------------------------------------
670 nullfunc
= &reserved_page_packet
[NULL_PG
* 128];
671 SET_80211_HDR_ADDRESS1(nullfunc
, mac
->bssid
);
672 SET_80211_HDR_ADDRESS2(nullfunc
, mac
->mac_addr
);
673 SET_80211_HDR_ADDRESS3(nullfunc
, mac
->bssid
);
675 SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc
, NULL_PG
);
677 /*---------------------------------------------------------
679 *----------------------------------------------------------
681 p_probersp
= &reserved_page_packet
[PROBERSP_PG
* 128];
682 SET_80211_HDR_ADDRESS1(p_probersp
, mac
->bssid
);
683 SET_80211_HDR_ADDRESS2(p_probersp
, mac
->mac_addr
);
684 SET_80211_HDR_ADDRESS3(p_probersp
, mac
->bssid
);
686 SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc
, PROBERSP_PG
);
688 totalpacketlen
= TOTAL_RESERVED_PKT_LEN
;
690 RT_PRINT_DATA(rtlpriv
, COMP_CMD
, DBG_LOUD
,
691 "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
692 &reserved_page_packet
[0], totalpacketlen
);
693 RT_PRINT_DATA(rtlpriv
, COMP_CMD
, DBG_DMESG
,
694 "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
697 skb
= dev_alloc_skb(totalpacketlen
);
698 memcpy(skb_put(skb
, totalpacketlen
),
699 &reserved_page_packet
, totalpacketlen
);
701 rtstatus
= rtl_cmd_send_packet(hw
, skb
);
707 RT_TRACE(rtlpriv
, COMP_POWER
, DBG_LOUD
,
708 "Set RSVD page location to Fw.\n");
709 RT_PRINT_DATA(rtlpriv
, COMP_CMD
, DBG_DMESG
,
710 "H2C_RSVDPAGE:\n", u1rsvdpageloc
, 3);
711 rtl88e_fill_h2c_cmd(hw
, H2C_88E_RSVDPAGE
,
712 sizeof(u1rsvdpageloc
), u1rsvdpageloc
);
714 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_WARNING
,
715 "Set RSVD page location to Fw FAIL!!!!!!.\n");
718 /*Should check FW support p2p or not.*/
719 static void rtl88e_set_p2p_ctw_period_cmd(struct ieee80211_hw
*hw
, u8 ctwindow
)
721 u8 u1_ctwindow_period
[1] = { ctwindow
};
723 rtl88e_fill_h2c_cmd(hw
, H2C_88E_P2P_PS_CTW_CMD
, 1, u1_ctwindow_period
);
727 void rtl88e_set_p2p_ps_offload_cmd(struct ieee80211_hw
*hw
, u8 p2p_ps_state
)
729 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
730 struct rtl_ps_ctl
*rtlps
= rtl_psc(rtl_priv(hw
));
731 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
732 struct rtl_p2p_ps_info
*p2pinfo
= &(rtlps
->p2p_ps_info
);
733 struct p2p_ps_offload_t
*p2p_ps_offload
= &rtlhal
->p2p_ps_offload
;
736 u32 start_time
, tsf_low
;
738 switch (p2p_ps_state
) {
740 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
, "P2P_PS_DISABLE\n");
741 memset(p2p_ps_offload
, 0, sizeof(*p2p_ps_offload
));
744 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
, "P2P_PS_ENABLE\n");
745 /* update CTWindow value. */
746 if (p2pinfo
->ctwindow
> 0) {
747 p2p_ps_offload
->ctwindow_en
= 1;
748 ctwindow
= p2pinfo
->ctwindow
;
749 rtl88e_set_p2p_ctw_period_cmd(hw
, ctwindow
);
752 /* hw only support 2 set of NoA */
753 for (i
= 0 ; i
< p2pinfo
->noa_num
; i
++) {
754 /* To control the register setting for which NOA*/
755 rtl_write_byte(rtlpriv
, 0x5cf, (i
<< 4));
757 p2p_ps_offload
->noa0_en
= 1;
759 p2p_ps_offload
->noa1_en
= 1;
761 /* config P2P NoA Descriptor Register */
762 rtl_write_dword(rtlpriv
, 0x5E0,
763 p2pinfo
->noa_duration
[i
]);
764 rtl_write_dword(rtlpriv
, 0x5E4,
765 p2pinfo
->noa_interval
[i
]);
767 /*Get Current TSF value */
768 tsf_low
= rtl_read_dword(rtlpriv
, REG_TSFTR
);
770 start_time
= p2pinfo
->noa_start_time
[i
];
771 if (p2pinfo
->noa_count_type
[i
] != 1) {
772 while (start_time
<= (tsf_low
+(50*1024))) {
773 start_time
+= p2pinfo
->noa_interval
[i
];
774 if (p2pinfo
->noa_count_type
[i
] != 255)
775 p2pinfo
->noa_count_type
[i
]--;
778 rtl_write_dword(rtlpriv
, 0x5E8, start_time
);
779 rtl_write_dword(rtlpriv
, 0x5EC,
780 p2pinfo
->noa_count_type
[i
]);
783 if ((p2pinfo
->opp_ps
== 1) || (p2pinfo
->noa_num
> 0)) {
784 /* rst p2p circuit */
785 rtl_write_byte(rtlpriv
, REG_DUAL_TSF_RST
, BIT(4));
787 p2p_ps_offload
->offload_en
= 1;
789 if (P2P_ROLE_GO
== rtlpriv
->mac80211
.p2p
) {
790 p2p_ps_offload
->role
= 1;
791 p2p_ps_offload
->allstasleep
= -1;
793 p2p_ps_offload
->role
= 0;
796 p2p_ps_offload
->discovery
= 0;
800 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
, "P2P_PS_SCAN\n");
801 p2p_ps_offload
->discovery
= 1;
803 case P2P_PS_SCAN_DONE
:
804 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
, "P2P_PS_SCAN_DONE\n");
805 p2p_ps_offload
->discovery
= 0;
806 p2pinfo
->p2p_ps_state
= P2P_PS_ENABLE
;
812 rtl88e_fill_h2c_cmd(hw
, H2C_88E_P2P_PS_OFFLOAD
, 1,
813 (u8
*)p2p_ps_offload
);