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 *****************************************************************************/
29 #include "../rtl8192ce/reg.h"
30 #include "../rtl8192ce/def.h"
31 #include "fw_common.h"
32 #include <linux/export.h>
33 #include <linux/kmemleak.h>
35 static void _rtl92c_enable_fw_download(struct ieee80211_hw
*hw
, bool enable
)
37 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
38 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
40 if (rtlhal
->hw_type
== HARDWARE_TYPE_RTL8192CU
) {
41 u32 value32
= rtl_read_dword(rtlpriv
, REG_MCUFWDL
);
43 value32
|= MCUFWDL_EN
;
45 value32
&= ~MCUFWDL_EN
;
46 rtl_write_dword(rtlpriv
, REG_MCUFWDL
, value32
);
47 } else if (rtlhal
->hw_type
== HARDWARE_TYPE_RTL8192CE
) {
51 tmp
= rtl_read_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1);
52 rtl_write_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1,
55 tmp
= rtl_read_byte(rtlpriv
, REG_MCUFWDL
);
56 rtl_write_byte(rtlpriv
, REG_MCUFWDL
, tmp
| 0x01);
58 tmp
= rtl_read_byte(rtlpriv
, REG_MCUFWDL
+ 2);
59 rtl_write_byte(rtlpriv
, REG_MCUFWDL
+ 2, tmp
& 0xf7);
62 tmp
= rtl_read_byte(rtlpriv
, REG_MCUFWDL
);
63 rtl_write_byte(rtlpriv
, REG_MCUFWDL
, tmp
& 0xfe);
65 rtl_write_byte(rtlpriv
, REG_MCUFWDL
+ 1, 0x00);
70 static void _rtl92c_fw_block_write(struct ieee80211_hw
*hw
,
71 const u8
*buffer
, u32 size
)
73 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
74 u32 blocksize
= sizeof(u32
);
75 u8
*bufferptr
= (u8
*)buffer
;
76 u32
*pu4byteptr
= (u32
*)buffer
;
77 u32 i
, offset
, blockcount
, remainsize
;
79 blockcount
= size
/ blocksize
;
80 remainsize
= size
% blocksize
;
82 for (i
= 0; i
< blockcount
; i
++) {
83 offset
= i
* blocksize
;
84 rtl_write_dword(rtlpriv
, (FW_8192C_START_ADDRESS
+ offset
),
89 offset
= blockcount
* blocksize
;
91 for (i
= 0; i
< remainsize
; i
++) {
92 rtl_write_byte(rtlpriv
, (FW_8192C_START_ADDRESS
+
93 offset
+ i
), *(bufferptr
+ i
));
98 static void _rtl92c_fw_page_write(struct ieee80211_hw
*hw
,
99 u32 page
, const u8
*buffer
, u32 size
)
101 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
103 u8 u8page
= (u8
) (page
& 0x07);
105 value8
= (rtl_read_byte(rtlpriv
, REG_MCUFWDL
+ 2) & 0xF8) | u8page
;
107 rtl_write_byte(rtlpriv
, (REG_MCUFWDL
+ 2), value8
);
108 _rtl92c_fw_block_write(hw
, buffer
, size
);
111 static void _rtl92c_fill_dummy(u8
*pfwbuf
, u32
*pfwlen
)
114 u8 remain
= (u8
) (fwlen
% 4);
116 remain
= (remain
== 0) ? 0 : (4 - remain
);
127 static void _rtl92c_write_fw(struct ieee80211_hw
*hw
,
128 enum version_8192c version
, u8
*buffer
, u32 size
)
130 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
131 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
133 u8
*bufferptr
= (u8
*)buffer
;
135 RT_TRACE(rtlpriv
, COMP_FW
, DBG_TRACE
, "FW size is %d bytes,\n", size
);
136 is_version_b
= IS_NORMAL_CHIP(version
);
138 u32 pageNums
, remainsize
;
141 if (rtlhal
->hw_type
== HARDWARE_TYPE_RTL8192CE
)
142 _rtl92c_fill_dummy(bufferptr
, &size
);
144 pageNums
= size
/ FW_8192C_PAGE_SIZE
;
145 remainsize
= size
% FW_8192C_PAGE_SIZE
;
148 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
149 "Page numbers should not greater then 4\n");
152 for (page
= 0; page
< pageNums
; page
++) {
153 offset
= page
* FW_8192C_PAGE_SIZE
;
154 _rtl92c_fw_page_write(hw
, page
, (bufferptr
+ offset
),
159 offset
= pageNums
* FW_8192C_PAGE_SIZE
;
161 _rtl92c_fw_page_write(hw
, page
, (bufferptr
+ offset
),
165 _rtl92c_fw_block_write(hw
, buffer
, size
);
169 static int _rtl92c_fw_free_to_go(struct ieee80211_hw
*hw
)
171 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
177 value32
= rtl_read_dword(rtlpriv
, REG_MCUFWDL
);
178 } while ((counter
++ < FW_8192C_POLLING_TIMEOUT_COUNT
) &&
179 (!(value32
& FWDL_ChkSum_rpt
)));
181 if (counter
>= FW_8192C_POLLING_TIMEOUT_COUNT
) {
182 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
183 "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
188 RT_TRACE(rtlpriv
, COMP_FW
, DBG_TRACE
,
189 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32
);
191 value32
= rtl_read_dword(rtlpriv
, REG_MCUFWDL
);
192 value32
|= MCUFWDL_RDY
;
193 value32
&= ~WINTINI_RDY
;
194 rtl_write_dword(rtlpriv
, REG_MCUFWDL
, value32
);
199 value32
= rtl_read_dword(rtlpriv
, REG_MCUFWDL
);
200 if (value32
& WINTINI_RDY
) {
201 RT_TRACE(rtlpriv
, COMP_FW
, DBG_TRACE
,
202 "Polling FW ready success!! REG_MCUFWDL:0x%08x .\n",
208 mdelay(FW_8192C_POLLING_DELAY
);
210 } while (counter
++ < FW_8192C_POLLING_TIMEOUT_COUNT
);
212 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
213 "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32
);
219 int rtl92c_download_fw(struct ieee80211_hw
*hw
)
221 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
222 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
223 struct rtl92c_firmware_header
*pfwheader
;
227 enum version_8192c version
= rtlhal
->version
;
229 if (!rtlhal
->pfirmware
)
232 pfwheader
= (struct rtl92c_firmware_header
*)rtlhal
->pfirmware
;
233 pfwdata
= (u8
*)rtlhal
->pfirmware
;
234 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 rtl92c_firmware_header
));
242 pfwdata
= pfwdata
+ sizeof(struct rtl92c_firmware_header
);
243 fwsize
= fwsize
- sizeof(struct rtl92c_firmware_header
);
246 _rtl92c_enable_fw_download(hw
, true);
247 _rtl92c_write_fw(hw
, version
, pfwdata
, fwsize
);
248 _rtl92c_enable_fw_download(hw
, false);
250 err
= _rtl92c_fw_free_to_go(hw
);
252 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
253 "Firmware is not ready to run!\n");
255 RT_TRACE(rtlpriv
, COMP_FW
, DBG_TRACE
,
256 "Firmware is ready to run!\n");
261 EXPORT_SYMBOL(rtl92c_download_fw
);
263 static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw
*hw
, u8 boxnum
)
265 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
266 u8 val_hmetfr
, val_mcutst_1
;
269 val_hmetfr
= rtl_read_byte(rtlpriv
, REG_HMETFR
);
270 val_mcutst_1
= rtl_read_byte(rtlpriv
, (REG_MCUTST_1
+ boxnum
));
272 if (((val_hmetfr
>> boxnum
) & BIT(0)) == 0 && val_mcutst_1
== 0)
277 static void _rtl92c_fill_h2c_command(struct ieee80211_hw
*hw
,
278 u8 element_id
, u32 cmd_len
, u8
*cmdbuffer
)
280 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
281 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
283 u16 box_reg
= 0, box_extreg
= 0;
285 bool isfw_read
= false;
287 bool bwrite_sucess
= false;
288 u8 wait_h2c_limmit
= 100;
289 u8 wait_writeh2c_limmit
= 100;
290 u8 boxcontent
[4], boxextcontent
[2];
291 u32 h2c_waitcounter
= 0;
295 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
, "come in\n");
298 spin_lock_irqsave(&rtlpriv
->locks
.h2c_lock
, flag
);
299 if (rtlhal
->h2c_setinprogress
) {
300 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
,
301 "H2C set in progress! Wait to set..element_id(%d).\n",
303 while (rtlhal
->h2c_setinprogress
) {
304 spin_unlock_irqrestore(&rtlpriv
->locks
.h2c_lock
,
307 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
,
308 "Wait 100 us (%d times)...\n",
312 if (h2c_waitcounter
> 1000)
314 spin_lock_irqsave(&rtlpriv
->locks
.h2c_lock
,
317 spin_unlock_irqrestore(&rtlpriv
->locks
.h2c_lock
, flag
);
319 rtlhal
->h2c_setinprogress
= true;
320 spin_unlock_irqrestore(&rtlpriv
->locks
.h2c_lock
, flag
);
325 while (!bwrite_sucess
) {
326 wait_writeh2c_limmit
--;
327 if (wait_writeh2c_limmit
== 0) {
328 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_EMERG
,
329 "Write H2C fail because no trigger for FW INT!\n");
333 boxnum
= rtlhal
->last_hmeboxnum
;
336 box_reg
= REG_HMEBOX_0
;
337 box_extreg
= REG_HMEBOX_EXT_0
;
340 box_reg
= REG_HMEBOX_1
;
341 box_extreg
= REG_HMEBOX_EXT_1
;
344 box_reg
= REG_HMEBOX_2
;
345 box_extreg
= REG_HMEBOX_EXT_2
;
348 box_reg
= REG_HMEBOX_3
;
349 box_extreg
= REG_HMEBOX_EXT_3
;
352 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_LOUD
,
353 "switch case not process\n");
357 isfw_read
= _rtl92c_check_fw_read_last_h2c(hw
, boxnum
);
360 if (wait_h2c_limmit
== 0) {
361 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
,
362 "Waiting too long for FW read clear HMEBox(%d)!\n",
369 isfw_read
= _rtl92c_check_fw_read_last_h2c(hw
, boxnum
);
370 u1b_tmp
= rtl_read_byte(rtlpriv
, 0x1BF);
371 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
,
372 "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
377 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
,
378 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
383 memset(boxcontent
, 0, sizeof(boxcontent
));
384 memset(boxextcontent
, 0, sizeof(boxextcontent
));
385 boxcontent
[0] = element_id
;
386 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
,
387 "Write element_id box_reg(%4x) = %2x\n",
388 box_reg
, element_id
);
392 boxcontent
[0] &= ~(BIT(7));
393 memcpy((u8
*)(boxcontent
) + 1,
394 cmdbuffer
+ buf_index
, 1);
396 for (idx
= 0; idx
< 4; idx
++) {
397 rtl_write_byte(rtlpriv
, box_reg
+ idx
,
402 boxcontent
[0] &= ~(BIT(7));
403 memcpy((u8
*)(boxcontent
) + 1,
404 cmdbuffer
+ buf_index
, 2);
406 for (idx
= 0; idx
< 4; idx
++) {
407 rtl_write_byte(rtlpriv
, box_reg
+ idx
,
412 boxcontent
[0] &= ~(BIT(7));
413 memcpy((u8
*)(boxcontent
) + 1,
414 cmdbuffer
+ buf_index
, 3);
416 for (idx
= 0; idx
< 4; idx
++) {
417 rtl_write_byte(rtlpriv
, box_reg
+ idx
,
422 boxcontent
[0] |= (BIT(7));
423 memcpy((u8
*)(boxextcontent
),
424 cmdbuffer
+ buf_index
, 2);
425 memcpy((u8
*)(boxcontent
) + 1,
426 cmdbuffer
+ buf_index
+ 2, 2);
428 for (idx
= 0; idx
< 2; idx
++) {
429 rtl_write_byte(rtlpriv
, box_extreg
+ idx
,
433 for (idx
= 0; idx
< 4; idx
++) {
434 rtl_write_byte(rtlpriv
, box_reg
+ idx
,
439 boxcontent
[0] |= (BIT(7));
440 memcpy((u8
*)(boxextcontent
),
441 cmdbuffer
+ buf_index
, 2);
442 memcpy((u8
*)(boxcontent
) + 1,
443 cmdbuffer
+ buf_index
+ 2, 3);
445 for (idx
= 0; idx
< 2; idx
++) {
446 rtl_write_byte(rtlpriv
, box_extreg
+ idx
,
450 for (idx
= 0; idx
< 4; idx
++) {
451 rtl_write_byte(rtlpriv
, box_reg
+ idx
,
456 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_LOUD
,
457 "switch case not process\n");
461 bwrite_sucess
= true;
463 rtlhal
->last_hmeboxnum
= boxnum
+ 1;
464 if (rtlhal
->last_hmeboxnum
== 4)
465 rtlhal
->last_hmeboxnum
= 0;
467 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
,
468 "pHalData->last_hmeboxnum = %d\n",
469 rtlhal
->last_hmeboxnum
);
472 spin_lock_irqsave(&rtlpriv
->locks
.h2c_lock
, flag
);
473 rtlhal
->h2c_setinprogress
= false;
474 spin_unlock_irqrestore(&rtlpriv
->locks
.h2c_lock
, flag
);
476 RT_TRACE(rtlpriv
, COMP_CMD
, DBG_LOUD
, "go out\n");
479 void rtl92c_fill_h2c_cmd(struct ieee80211_hw
*hw
,
480 u8 element_id
, u32 cmd_len
, u8
*cmdbuffer
)
482 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
485 if (!rtlhal
->fw_ready
) {
487 "return H2C cmd because of Fw download fail!!!\n");
491 memset(tmp_cmdbuf
, 0, 8);
492 memcpy(tmp_cmdbuf
, cmdbuffer
, cmd_len
);
493 _rtl92c_fill_h2c_command(hw
, element_id
, cmd_len
, (u8
*)&tmp_cmdbuf
);
497 EXPORT_SYMBOL(rtl92c_fill_h2c_cmd
);
499 void rtl92c_firmware_selfreset(struct ieee80211_hw
*hw
)
503 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
505 rtl_write_byte(rtlpriv
, REG_HMETFR
+ 3, 0x20);
506 u1b_tmp
= rtl_read_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1);
508 while (u1b_tmp
& BIT(2)) {
511 RT_ASSERT(false, "8051 reset fail.\n");
515 u1b_tmp
= rtl_read_byte(rtlpriv
, REG_SYS_FUNC_EN
+ 1);
518 EXPORT_SYMBOL(rtl92c_firmware_selfreset
);
520 void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw
*hw
, u8 mode
)
522 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
523 u8 u1_h2c_set_pwrmode
[3] = { 0 };
524 struct rtl_ps_ctl
*ppsc
= rtl_psc(rtl_priv(hw
));
526 RT_TRACE(rtlpriv
, COMP_POWER
, DBG_LOUD
, "FW LPS mode = %d\n", mode
);
528 SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode
, mode
);
529 SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode
,
530 (rtlpriv
->mac80211
.p2p
) ? ppsc
->smart_ps
: 1);
531 SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode
,
532 ppsc
->reg_max_lps_awakeintvl
);
534 RT_PRINT_DATA(rtlpriv
, COMP_CMD
, DBG_DMESG
,
535 "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
536 u1_h2c_set_pwrmode
, 3);
537 rtl92c_fill_h2c_cmd(hw
, H2C_SETPWRMODE
, 3, u1_h2c_set_pwrmode
);
539 EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd
);
541 static bool _rtl92c_cmd_send_packet(struct ieee80211_hw
*hw
,
544 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
545 struct rtl_pci
*rtlpci
= rtl_pcidev(rtl_pcipriv(hw
));
546 struct rtl8192_tx_ring
*ring
;
547 struct rtl_tx_desc
*pdesc
;
550 struct sk_buff
*pskb
= NULL
;
552 ring
= &rtlpci
->tx_ring
[BEACON_QUEUE
];
554 pskb
= __skb_dequeue(&ring
->queue
);
558 spin_lock_irqsave(&rtlpriv
->locks
.irq_th_lock
, flags
);
560 pdesc
= &ring
->desc
[0];
561 own
= (u8
)rtlpriv
->cfg
->ops
->get_desc((u8
*)pdesc
, true, HW_DESC_OWN
);
563 rtlpriv
->cfg
->ops
->fill_tx_cmddesc(hw
, (u8
*)pdesc
, 1, 1, skb
);
565 __skb_queue_tail(&ring
->queue
, skb
);
567 spin_unlock_irqrestore(&rtlpriv
->locks
.irq_th_lock
, flags
);
569 rtlpriv
->cfg
->ops
->tx_polling(hw
, BEACON_QUEUE
);
574 #define BEACON_PG 0 /*->1*/
577 #define PROBERSP_PG 4 /*->5*/
579 #define TOTAL_RESERVED_PKT_LEN 768
581 static u8 reserved_page_packet
[TOTAL_RESERVED_PKT_LEN
] = {
583 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
584 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
585 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
586 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
587 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
588 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
589 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
590 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
591 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
592 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
593 0x03, 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 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
597 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
601 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
602 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
603 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
604 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
605 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
606 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
607 0x00, 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 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 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
614 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
615 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
616 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
619 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
620 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
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,
631 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
632 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
633 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
634 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
637 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
638 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
639 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
640 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
641 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
650 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
651 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
652 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
654 /* page 4 probe_resp */
655 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
656 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
657 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
658 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
659 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
660 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
661 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
662 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
663 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
664 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
665 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
666 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
667 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
668 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
669 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
672 /* page 5 probe_resp */
673 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
674 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
675 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
676 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
677 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
678 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
680 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
682 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
683 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
684 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
685 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
686 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
687 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
688 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
691 void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw
*hw
, bool b_dl_finished
)
693 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
694 struct rtl_mac
*mac
= rtl_mac(rtl_priv(hw
));
695 struct sk_buff
*skb
= NULL
;
699 u8 u1rsvdpageloc
[3] = { 0 };
706 /*---------------------------------------------------------
708 ---------------------------------------------------------*/
709 beacon
= &reserved_page_packet
[BEACON_PG
* 128];
710 SET_80211_HDR_ADDRESS2(beacon
, mac
->mac_addr
);
711 SET_80211_HDR_ADDRESS3(beacon
, mac
->bssid
);
713 /*-------------------------------------------------------
715 --------------------------------------------------------*/
716 p_pspoll
= &reserved_page_packet
[PSPOLL_PG
* 128];
717 SET_80211_PS_POLL_AID(p_pspoll
, (mac
->assoc_id
| 0xc000));
718 SET_80211_PS_POLL_BSSID(p_pspoll
, mac
->bssid
);
719 SET_80211_PS_POLL_TA(p_pspoll
, mac
->mac_addr
);
721 SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc
, PSPOLL_PG
);
723 /*--------------------------------------------------------
725 ---------------------------------------------------------*/
726 nullfunc
= &reserved_page_packet
[NULL_PG
* 128];
727 SET_80211_HDR_ADDRESS1(nullfunc
, mac
->bssid
);
728 SET_80211_HDR_ADDRESS2(nullfunc
, mac
->mac_addr
);
729 SET_80211_HDR_ADDRESS3(nullfunc
, mac
->bssid
);
731 SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc
, NULL_PG
);
733 /*---------------------------------------------------------
735 ----------------------------------------------------------*/
736 p_probersp
= &reserved_page_packet
[PROBERSP_PG
* 128];
737 SET_80211_HDR_ADDRESS1(p_probersp
, mac
->bssid
);
738 SET_80211_HDR_ADDRESS2(p_probersp
, mac
->mac_addr
);
739 SET_80211_HDR_ADDRESS3(p_probersp
, mac
->bssid
);
741 SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc
, PROBERSP_PG
);
743 totalpacketlen
= TOTAL_RESERVED_PKT_LEN
;
745 RT_PRINT_DATA(rtlpriv
, COMP_CMD
, DBG_LOUD
,
746 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
747 &reserved_page_packet
[0], totalpacketlen
);
748 RT_PRINT_DATA(rtlpriv
, COMP_CMD
, DBG_DMESG
,
749 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
753 skb
= dev_alloc_skb(totalpacketlen
);
754 memcpy((u8
*)skb_put(skb
, totalpacketlen
),
755 &reserved_page_packet
, totalpacketlen
);
757 rtstatus
= _rtl92c_cmd_send_packet(hw
, skb
);
763 RT_TRACE(rtlpriv
, COMP_POWER
, DBG_LOUD
,
764 "Set RSVD page location to Fw.\n");
765 RT_PRINT_DATA(rtlpriv
, COMP_CMD
, DBG_DMESG
,
768 rtl92c_fill_h2c_cmd(hw
, H2C_RSVDPAGE
,
769 sizeof(u1rsvdpageloc
), u1rsvdpageloc
);
771 RT_TRACE(rtlpriv
, COMP_ERR
, DBG_WARNING
,
772 "Set RSVD page location to Fw FAIL!!!!!!.\n");
774 EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt
);
776 void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw
*hw
, u8 mstatus
)
778 u8 u1_joinbssrpt_parm
[1] = { 0 };
780 SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm
, mstatus
);
782 rtl92c_fill_h2c_cmd(hw
, H2C_JOINBSSRPT
, 1, u1_joinbssrpt_parm
);
784 EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd
);
786 static void rtl92c_set_p2p_ctw_period_cmd(struct ieee80211_hw
*hw
, u8 ctwindow
)
788 u8 u1_ctwindow_period
[1] = { ctwindow
};
790 rtl92c_fill_h2c_cmd(hw
, H2C_P2P_PS_CTW_CMD
, 1, u1_ctwindow_period
);
793 /* refactored routine */
794 static void set_noa_data(struct rtl_priv
*rtlpriv
,
795 struct rtl_p2p_ps_info
*p2pinfo
,
796 struct p2p_ps_offload_t
*p2p_ps_offload
)
799 u32 start_time
, tsf_low
;
801 /* hw only support 2 set of NoA */
802 for (i
= 0 ; i
< p2pinfo
->noa_num
; i
++) {
803 /* To control the reg setting for which NOA*/
804 rtl_write_byte(rtlpriv
, 0x5cf, (i
<< 4));
806 p2p_ps_offload
->noa0_en
= 1;
808 p2p_ps_offload
->noa1_en
= 1;
810 /* config P2P NoA Descriptor Register */
811 rtl_write_dword(rtlpriv
, 0x5E0,
812 p2pinfo
->noa_duration
[i
]);
813 rtl_write_dword(rtlpriv
, 0x5E4,
814 p2pinfo
->noa_interval
[i
]);
816 /*Get Current TSF value */
817 tsf_low
= rtl_read_dword(rtlpriv
, REG_TSFTR
);
819 start_time
= p2pinfo
->noa_start_time
[i
];
820 if (p2pinfo
->noa_count_type
[i
] != 1) {
821 while (start_time
<= (tsf_low
+(50*1024))) {
822 start_time
+= p2pinfo
->noa_interval
[i
];
823 if (p2pinfo
->noa_count_type
[i
] != 255)
824 p2pinfo
->noa_count_type
[i
]--;
827 rtl_write_dword(rtlpriv
, 0x5E8, start_time
);
828 rtl_write_dword(rtlpriv
, 0x5EC,
829 p2pinfo
->noa_count_type
[i
]);
833 void rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw
*hw
, u8 p2p_ps_state
)
835 struct rtl_priv
*rtlpriv
= rtl_priv(hw
);
836 struct rtl_ps_ctl
*rtlps
= rtl_psc(rtl_priv(hw
));
837 struct rtl_hal
*rtlhal
= rtl_hal(rtl_priv(hw
));
838 struct rtl_p2p_ps_info
*p2pinfo
= &(rtlps
->p2p_ps_info
);
839 struct p2p_ps_offload_t
*p2p_ps_offload
= &rtlhal
->p2p_ps_offload
;
842 switch (p2p_ps_state
) {
844 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
,
846 memset(p2p_ps_offload
, 0, sizeof(*p2p_ps_offload
));
849 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
,
851 /* update CTWindow value. */
852 if (p2pinfo
->ctwindow
> 0) {
853 p2p_ps_offload
->ctwindow_en
= 1;
854 ctwindow
= p2pinfo
->ctwindow
;
855 rtl92c_set_p2p_ctw_period_cmd(hw
, ctwindow
);
857 /* call refactored routine */
858 set_noa_data(rtlpriv
, p2pinfo
, p2p_ps_offload
);
860 if ((p2pinfo
->opp_ps
== 1) || (p2pinfo
->noa_num
> 0)) {
861 /* rst p2p circuit */
862 rtl_write_byte(rtlpriv
, REG_DUAL_TSF_RST
,
865 p2p_ps_offload
->offload_en
= 1;
867 if (P2P_ROLE_GO
== rtlpriv
->mac80211
.p2p
) {
868 p2p_ps_offload
->role
= 1;
869 p2p_ps_offload
->allstasleep
= 0;
871 p2p_ps_offload
->role
= 0;
874 p2p_ps_offload
->discovery
= 0;
878 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
, "P2P_PS_SCAN\n");
879 p2p_ps_offload
->discovery
= 1;
881 case P2P_PS_SCAN_DONE
:
882 RT_TRACE(rtlpriv
, COMP_FW
, DBG_LOUD
,
883 "P2P_PS_SCAN_DONE\n");
884 p2p_ps_offload
->discovery
= 0;
885 p2pinfo
->p2p_ps_state
= P2P_PS_ENABLE
;
891 rtl92c_fill_h2c_cmd(hw
, H2C_P2P_PS_OFFLOAD
, 1, (u8
*)p2p_ps_offload
);
894 EXPORT_SYMBOL_GPL(rtl92c_set_p2p_ps_offload_cmd
);