1 /******************************************************************************
3 * Copyright(c) 2009-2012 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 *****************************************************************************/
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>
36 static void _rtl92c_enable_fw_download(struct ieee80211_hw
*hw
, bool enable
)
38 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
39 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
41 if (rtlhal
->hw_type
== HARDWARE_TYPE_RTL8192CU
) {
42 u32 value32
= rtl_read_dword(rtlpriv
, REG_MCUFWDL
);
44 value32
|= MCUFWDL_EN
;
46 value32
&= ~MCUFWDL_EN
;
47 rtl_write_dword(rtlpriv
, REG_MCUFWDL
, value32
);
48 } else if (rtlhal
->hw_type
== HARDWARE_TYPE_RTL8192CE
) {
52 tmp
= rtl_read_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1);
53 rtl_write_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1,
56 tmp
= rtl_read_byte(rtlpriv
, REG_MCUFWDL
);
57 rtl_write_byte(rtlpriv
, REG_MCUFWDL
, tmp
| 0x01);
59 tmp
= rtl_read_byte(rtlpriv
, REG_MCUFWDL
+ 2);
60 rtl_write_byte(rtlpriv
, REG_MCUFWDL
+ 2, tmp
& 0xf7);
63 tmp
= rtl_read_byte(rtlpriv
, REG_MCUFWDL
);
64 rtl_write_byte(rtlpriv
, REG_MCUFWDL
, tmp
& 0xfe);
66 rtl_write_byte(rtlpriv
, REG_MCUFWDL
+ 1, 0x00);
71 static void _rtl92c_fw_block_write(struct ieee80211_hw
*hw
,
72 const u8
*buffer
, u32 size
)
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
;
80 blockcount
= size
/ blocksize
;
81 remainsize
= size
% blocksize
;
83 for (i
= 0; i
< blockcount
; i
++) {
84 offset
= i
* blocksize
;
85 rtl_write_dword(rtlpriv
, (FW_8192C_START_ADDRESS
+ offset
),
90 offset
= blockcount
* blocksize
;
92 for (i
= 0; i
< remainsize
; i
++) {
93 rtl_write_byte(rtlpriv
, (FW_8192C_START_ADDRESS
+
94 offset
+ i
), *(bufferptr
+ i
));
99 static void _rtl92c_fw_page_write(struct ieee80211_hw
*hw
,
100 u32 page
, const u8
*buffer
, u32 size
)
102 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
104 u8 u8page
= (u8
) (page
& 0x07);
106 value8
= (rtl_read_byte(rtlpriv
, REG_MCUFWDL
+ 2) & 0xF8) | u8page
;
108 rtl_write_byte(rtlpriv
, (REG_MCUFWDL
+ 2), value8
);
109 _rtl92c_fw_block_write(hw
, buffer
, size
);
112 static void _rtl92c_fill_dummy(u8
*pfwbuf
, u32
*pfwlen
)
115 u8 remain
= (u8
) (fwlen
% 4);
117 remain
= (remain
== 0) ? 0 : (4 - remain
);
128 static void _rtl92c_write_fw(struct ieee80211_hw
*hw
,
129 enum version_8192c version
, u8
*buffer
, u32 size
)
131 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
132 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
134 u8
*bufferptr
= (u8
*)buffer
;
136 RT_TRACE(rtlpriv
, COMP_FW
, DBG_TRACE
, "FW size is %d bytes,\n", size
);
137 is_version_b
= IS_NORMAL_CHIP(version
);
139 u32 pageNums
, remainsize
;
142 if (rtlhal
->hw_type
== HARDWARE_TYPE_RTL8192CE
)
143 _rtl92c_fill_dummy(bufferptr
, &size
);
145 pageNums
= size
/ FW_8192C_PAGE_SIZE
;
146 remainsize
= size
% FW_8192C_PAGE_SIZE
;
149 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
150 "Page numbers should not greater then 4\n");
153 for (page
= 0; page
< pageNums
; page
++) {
154 offset
= page
* FW_8192C_PAGE_SIZE
;
155 _rtl92c_fw_page_write(hw
, page
, (bufferptr
+ offset
),
160 offset
= pageNums
* FW_8192C_PAGE_SIZE
;
162 _rtl92c_fw_page_write(hw
, page
, (bufferptr
+ offset
),
166 _rtl92c_fw_block_write(hw
, buffer
, size
);
170 static int _rtl92c_fw_free_to_go(struct ieee80211_hw
*hw
)
172 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
178 value32
= rtl_read_dword(rtlpriv
, REG_MCUFWDL
);
179 } while ((counter
++ < FW_8192C_POLLING_TIMEOUT_COUNT
) &&
180 (!(value32
& FWDL_ChkSum_rpt
)));
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",
189 RT_TRACE(rtlpriv
, COMP_FW
, DBG_TRACE
,
190 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32
);
192 value32
= rtl_read_dword(rtlpriv
, REG_MCUFWDL
);
193 value32
|= MCUFWDL_RDY
;
194 value32
&= ~WINTINI_RDY
;
195 rtl_write_dword(rtlpriv
, REG_MCUFWDL
, value32
);
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",
209 mdelay(FW_8192C_POLLING_DELAY
);
211 } while (counter
++ < FW_8192C_POLLING_TIMEOUT_COUNT
);
213 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
214 "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32
);
220 int rtl92c_download_fw(struct ieee80211_hw
*hw
)
222 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
223 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
224 struct rtlwifi_firmware_header
*pfwheader
;
228 enum version_8192c version
= rtlhal
->version
;
230 if (!rtlhal
->pfirmware
)
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
));
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
);
248 _rtl92c_enable_fw_download(hw
, true);
249 _rtl92c_write_fw(hw
, version
, pfwdata
, fwsize
);
250 _rtl92c_enable_fw_download(hw
, false);
252 err
= _rtl92c_fw_free_to_go(hw
);
254 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
255 "Firmware is not ready to run!\n");
257 RT_TRACE(rtlpriv
, COMP_FW
, DBG_TRACE
,
258 "Firmware is ready to run!\n");
263 EXPORT_SYMBOL(rtl92c_download_fw
);
265 static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw
*hw
, u8 boxnum
)
267 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
268 u8 val_hmetfr
, val_mcutst_1
;
271 val_hmetfr
= rtl_read_byte(rtlpriv
, REG_HMETFR
);
272 val_mcutst_1
= rtl_read_byte(rtlpriv
, (REG_MCUTST_1
+ boxnum
));
274 if (((val_hmetfr
>> boxnum
) & BIT(0)) == 0 && val_mcutst_1
== 0)
279 static void _rtl92c_fill_h2c_command(struct ieee80211_hw
*hw
,
280 u8 element_id
, u32 cmd_len
, u8
*cmdbuffer
)
282 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
283 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
285 u16 box_reg
= 0, box_extreg
= 0;
287 bool isfw_read
= false;
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;
297 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
, "come in\n");
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",
305 while (rtlhal
->h2c_setinprogress
) {
306 spin_unlock_irqrestore(&rtlpriv
->locks
.h2c_lock
,
309 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
,
310 "Wait 100 us (%d times)...\n",
314 if (h2c_waitcounter
> 1000)
316 spin_lock_irqsave(&rtlpriv
->locks
.h2c_lock
,
319 spin_unlock_irqrestore(&rtlpriv
->locks
.h2c_lock
, flag
);
321 rtlhal
->h2c_setinprogress
= true;
322 spin_unlock_irqrestore(&rtlpriv
->locks
.h2c_lock
, flag
);
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");
335 boxnum
= rtlhal
->last_hmeboxnum
;
338 box_reg
= REG_HMEBOX_0
;
339 box_extreg
= REG_HMEBOX_EXT_0
;
342 box_reg
= REG_HMEBOX_1
;
343 box_extreg
= REG_HMEBOX_EXT_1
;
346 box_reg
= REG_HMEBOX_2
;
347 box_extreg
= REG_HMEBOX_EXT_2
;
350 box_reg
= REG_HMEBOX_3
;
351 box_extreg
= REG_HMEBOX_EXT_3
;
354 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_LOUD
,
355 "switch case not process\n");
359 isfw_read
= _rtl92c_check_fw_read_last_h2c(hw
, boxnum
);
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",
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",
379 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
,
380 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
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
);
394 boxcontent
[0] &= ~(BIT(7));
395 memcpy((u8
*)(boxcontent
) + 1,
396 cmdbuffer
+ buf_index
, 1);
398 for (idx
= 0; idx
< 4; idx
++) {
399 rtl_write_byte(rtlpriv
, box_reg
+ idx
,
404 boxcontent
[0] &= ~(BIT(7));
405 memcpy((u8
*)(boxcontent
) + 1,
406 cmdbuffer
+ buf_index
, 2);
408 for (idx
= 0; idx
< 4; idx
++) {
409 rtl_write_byte(rtlpriv
, box_reg
+ idx
,
414 boxcontent
[0] &= ~(BIT(7));
415 memcpy((u8
*)(boxcontent
) + 1,
416 cmdbuffer
+ buf_index
, 3);
418 for (idx
= 0; idx
< 4; idx
++) {
419 rtl_write_byte(rtlpriv
, box_reg
+ idx
,
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);
430 for (idx
= 0; idx
< 2; idx
++) {
431 rtl_write_byte(rtlpriv
, box_extreg
+ idx
,
435 for (idx
= 0; idx
< 4; idx
++) {
436 rtl_write_byte(rtlpriv
, box_reg
+ idx
,
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);
447 for (idx
= 0; idx
< 2; idx
++) {
448 rtl_write_byte(rtlpriv
, box_extreg
+ idx
,
452 for (idx
= 0; idx
< 4; idx
++) {
453 rtl_write_byte(rtlpriv
, box_reg
+ idx
,
458 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_LOUD
,
459 "switch case not process\n");
463 bwrite_sucess
= true;
465 rtlhal
->last_hmeboxnum
= boxnum
+ 1;
466 if (rtlhal
->last_hmeboxnum
== 4)
467 rtlhal
->last_hmeboxnum
= 0;
469 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
,
470 "pHalData->last_hmeboxnum = %d\n",
471 rtlhal
->last_hmeboxnum
);
474 spin_lock_irqsave(&rtlpriv
->locks
.h2c_lock
, flag
);
475 rtlhal
->h2c_setinprogress
= false;
476 spin_unlock_irqrestore(&rtlpriv
->locks
.h2c_lock
, flag
);
478 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
, "go out\n");
481 void rtl92c_fill_h2c_cmd(struct ieee80211_hw
*hw
,
482 u8 element_id
, u32 cmd_len
, u8
*cmdbuffer
)
484 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
487 if (!rtlhal
->fw_ready
) {
489 "return H2C cmd because of Fw download fail!!!\n");
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
);
499 EXPORT_SYMBOL(rtl92c_fill_h2c_cmd
);
501 void rtl92c_firmware_selfreset(struct ieee80211_hw
*hw
)
505 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
507 rtl_write_byte(rtlpriv
, REG_HMETFR
+ 3, 0x20);
508 u1b_tmp
= rtl_read_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1);
510 while (u1b_tmp
& BIT(2)) {
513 RT_ASSERT(false, "8051 reset fail.\n");
517 u1b_tmp
= rtl_read_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1);
520 EXPORT_SYMBOL(rtl92c_firmware_selfreset
);
522 void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw
*hw
, u8 mode
)
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
));
528 RT_TRACE(rtlpriv
, COMP_POWER
, DBG_LOUD
, "FW LPS mode = %d\n", mode
);
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
);
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
);
541 EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd
);
543 #define BEACON_PG 0 /*->1*/
546 #define PROBERSP_PG 4 /*->5*/
548 #define TOTAL_RESERVED_PKT_LEN 768
550 static u8 reserved_page_packet
[TOTAL_RESERVED_PKT_LEN
] = {
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,
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,
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,
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,
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,
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,
660 void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw
*hw
,
661 bool (*cmd_send_packet
)(struct ieee80211_hw
*, struct sk_buff
*))
663 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
664 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
665 struct sk_buff
*skb
= NULL
;
669 u8 u1rsvdpageloc
[3] = { 0 };
676 /*---------------------------------------------------------
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
);
683 /*-------------------------------------------------------
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
);
691 SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc
, PSPOLL_PG
);
693 /*--------------------------------------------------------
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
);
701 SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc
, NULL_PG
);
703 /*---------------------------------------------------------
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
);
711 SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc
, PROBERSP_PG
);
713 totalpacketlen
= TOTAL_RESERVED_PKT_LEN
;
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",
723 skb
= dev_alloc_skb(totalpacketlen
);
724 memcpy((u8
*)skb_put(skb
, totalpacketlen
),
725 &reserved_page_packet
, totalpacketlen
);
728 rtstatus
= cmd_send_packet(hw
, skb
);
730 rtstatus
= rtl_cmd_send_packet(hw
, skb
);
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
,
741 rtl92c_fill_h2c_cmd(hw
, H2C_RSVDPAGE
,
742 sizeof(u1rsvdpageloc
), u1rsvdpageloc
);
744 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_WARNING
,
745 "Set RSVD page location to Fw FAIL!!!!!!.\n");
747 EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt
);
749 void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw
*hw
, u8 mstatus
)
751 u8 u1_joinbssrpt_parm
[1] = { 0 };
753 SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm
, mstatus
);
755 rtl92c_fill_h2c_cmd(hw
, H2C_JOINBSSRPT
, 1, u1_joinbssrpt_parm
);
757 EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd
);
759 static void rtl92c_set_p2p_ctw_period_cmd(struct ieee80211_hw
*hw
, u8 ctwindow
)
761 u8 u1_ctwindow_period
[1] = { ctwindow
};
763 rtl92c_fill_h2c_cmd(hw
, H2C_P2P_PS_CTW_CMD
, 1, u1_ctwindow_period
);
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
)
772 u32 start_time
, tsf_low
;
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));
779 p2p_ps_offload
->noa0_en
= 1;
781 p2p_ps_offload
->noa1_en
= 1;
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
]);
789 /*Get Current TSF value */
790 tsf_low
= rtl_read_dword(rtlpriv
, REG_TSFTR
);
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
]--;
800 rtl_write_dword(rtlpriv
, 0x5E8, start_time
);
801 rtl_write_dword(rtlpriv
, 0x5EC,
802 p2pinfo
->noa_count_type
[i
]);
806 void rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw
*hw
, u8 p2p_ps_state
)
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
;
815 switch (p2p_ps_state
) {
817 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
,
819 memset(p2p_ps_offload
, 0, sizeof(*p2p_ps_offload
));
822 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
,
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
);
830 /* call refactored routine */
831 set_noa_data(rtlpriv
, p2pinfo
, p2p_ps_offload
);
833 if ((p2pinfo
->opp_ps
== 1) || (p2pinfo
->noa_num
> 0)) {
834 /* rst p2p circuit */
835 rtl_write_byte(rtlpriv
, REG_DUAL_TSF_RST
,
838 p2p_ps_offload
->offload_en
= 1;
840 if (P2P_ROLE_GO
== rtlpriv
->mac80211
.p2p
) {
841 p2p_ps_offload
->role
= 1;
842 p2p_ps_offload
->allstasleep
= 0;
844 p2p_ps_offload
->role
= 0;
847 p2p_ps_offload
->discovery
= 0;
851 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
, "P2P_PS_SCAN\n");
852 p2p_ps_offload
->discovery
= 1;
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
;
864 rtl92c_fill_h2c_cmd(hw
, H2C_P2P_PS_OFFLOAD
, 1, (u8
*)p2p_ps_offload
);
867 EXPORT_SYMBOL_GPL(rtl92c_set_p2p_ps_offload_cmd
);