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 *****************************************************************************/
31 #include "../rtl8192ce/reg.h"
32 #include "../rtl8192ce/def.h"
33 #include "fw_common.h"
34 #include <linux/export.h>
35 #include <linux/kmemleak.h>
37 static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable)
39 struct rtl_priv *rtlpriv = rtl_priv(hw);
40 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
42 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU) {
43 u32 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
45 value32 |= MCUFWDL_EN;
47 value32 &= ~MCUFWDL_EN;
48 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
49 } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) {
53 tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
54 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
57 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
58 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
60 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
61 rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
64 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
65 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
67 rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
72 static void _rtl92c_write_fw(struct ieee80211_hw *hw,
73 enum version_8192c version, u8 *buffer, u32 size)
75 struct rtl_priv *rtlpriv = rtl_priv(hw);
76 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
78 u8 *bufferptr = (u8 *)buffer;
80 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
81 is_version_b = IS_NORMAL_CHIP(version);
83 u32 pageNums, remainsize;
86 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE)
87 rtl_fill_dummy(bufferptr, &size);
89 pageNums = size / FW_8192C_PAGE_SIZE;
90 remainsize = size % FW_8192C_PAGE_SIZE;
93 pr_err("Page numbers should not greater then 4\n");
95 for (page = 0; page < pageNums; page++) {
96 offset = page * FW_8192C_PAGE_SIZE;
97 rtl_fw_page_write(hw, page, (bufferptr + offset),
102 offset = pageNums * FW_8192C_PAGE_SIZE;
104 rtl_fw_page_write(hw, page, (bufferptr + offset),
108 rtl_fw_block_write(hw, buffer, size);
112 static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
114 struct rtl_priv *rtlpriv = rtl_priv(hw);
120 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
121 } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
122 (!(value32 & FWDL_ChkSum_rpt)));
124 if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
125 pr_err("chksum report fail! REG_MCUFWDL:0x%08x .\n",
129 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
130 value32 |= MCUFWDL_RDY;
131 value32 &= ~WINTINI_RDY;
132 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
137 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
138 if (value32 & WINTINI_RDY)
141 mdelay(FW_8192C_POLLING_DELAY);
143 } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
145 pr_err("Polling FW ready fail! REG_MCUFWDL:0x%08x.\n",
152 int rtl92c_download_fw(struct ieee80211_hw *hw)
154 struct rtl_priv *rtlpriv = rtl_priv(hw);
155 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
156 struct rtlwifi_firmware_header *pfwheader;
160 enum version_8192c version = rtlhal->version;
162 if (!rtlhal->pfirmware)
165 pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware;
166 pfwdata = (u8 *)rtlhal->pfirmware;
167 fwsize = rtlhal->fwsize;
168 if (IS_FW_HEADER_EXIST(pfwheader)) {
169 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
170 "Firmware Version(%d), Signature(%#x),Size(%d)\n",
171 pfwheader->version, pfwheader->signature,
172 (int)sizeof(struct rtlwifi_firmware_header));
174 rtlhal->fw_version = le16_to_cpu(pfwheader->version);
175 rtlhal->fw_subversion = pfwheader->subversion;
176 pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header);
177 fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);
180 _rtl92c_enable_fw_download(hw, true);
181 _rtl92c_write_fw(hw, version, pfwdata, fwsize);
182 _rtl92c_enable_fw_download(hw, false);
184 err = _rtl92c_fw_free_to_go(hw);
186 pr_err("Firmware is not ready to run!\n");
190 EXPORT_SYMBOL(rtl92c_download_fw);
192 static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
194 struct rtl_priv *rtlpriv = rtl_priv(hw);
195 u8 val_hmetfr, val_mcutst_1;
198 val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
199 val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
201 if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
206 static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
207 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
209 struct rtl_priv *rtlpriv = rtl_priv(hw);
210 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
212 u16 box_reg = 0, box_extreg = 0;
214 bool isfw_read = false;
216 bool bwrite_sucess = false;
217 u8 wait_h2c_limmit = 100;
218 u8 wait_writeh2c_limmit = 100;
219 u8 boxcontent[4], boxextcontent[2];
220 u32 h2c_waitcounter = 0;
224 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
227 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
228 if (rtlhal->h2c_setinprogress) {
229 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
230 "H2C set in progress! Wait to set..element_id(%d).\n",
232 while (rtlhal->h2c_setinprogress) {
233 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
236 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
237 "Wait 100 us (%d times)...\n",
241 if (h2c_waitcounter > 1000)
243 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
246 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
248 rtlhal->h2c_setinprogress = true;
249 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
254 while (!bwrite_sucess) {
255 wait_writeh2c_limmit--;
256 if (wait_writeh2c_limmit == 0) {
257 pr_err("Write H2C fail because no trigger for FW INT!\n");
261 boxnum = rtlhal->last_hmeboxnum;
264 box_reg = REG_HMEBOX_0;
265 box_extreg = REG_HMEBOX_EXT_0;
268 box_reg = REG_HMEBOX_1;
269 box_extreg = REG_HMEBOX_EXT_1;
272 box_reg = REG_HMEBOX_2;
273 box_extreg = REG_HMEBOX_EXT_2;
276 box_reg = REG_HMEBOX_3;
277 box_extreg = REG_HMEBOX_EXT_3;
280 RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
281 "switch case %#x not processed\n", boxnum);
285 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
288 if (wait_h2c_limmit == 0) {
289 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
290 "Waiting too long for FW read clear HMEBox(%d)!\n",
297 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
298 u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
299 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
300 "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
305 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
306 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
311 memset(boxcontent, 0, sizeof(boxcontent));
312 memset(boxextcontent, 0, sizeof(boxextcontent));
313 boxcontent[0] = element_id;
314 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
315 "Write element_id box_reg(%4x) = %2x\n",
316 box_reg, element_id);
320 boxcontent[0] &= ~(BIT(7));
321 memcpy((u8 *)(boxcontent) + 1,
322 cmdbuffer + buf_index, 1);
324 for (idx = 0; idx < 4; idx++) {
325 rtl_write_byte(rtlpriv, box_reg + idx,
330 boxcontent[0] &= ~(BIT(7));
331 memcpy((u8 *)(boxcontent) + 1,
332 cmdbuffer + buf_index, 2);
334 for (idx = 0; idx < 4; idx++) {
335 rtl_write_byte(rtlpriv, box_reg + idx,
340 boxcontent[0] &= ~(BIT(7));
341 memcpy((u8 *)(boxcontent) + 1,
342 cmdbuffer + buf_index, 3);
344 for (idx = 0; idx < 4; idx++) {
345 rtl_write_byte(rtlpriv, box_reg + idx,
350 boxcontent[0] |= (BIT(7));
351 memcpy((u8 *)(boxextcontent),
352 cmdbuffer + buf_index, 2);
353 memcpy((u8 *)(boxcontent) + 1,
354 cmdbuffer + buf_index + 2, 2);
356 for (idx = 0; idx < 2; idx++) {
357 rtl_write_byte(rtlpriv, box_extreg + idx,
361 for (idx = 0; idx < 4; idx++) {
362 rtl_write_byte(rtlpriv, box_reg + idx,
367 boxcontent[0] |= (BIT(7));
368 memcpy((u8 *)(boxextcontent),
369 cmdbuffer + buf_index, 2);
370 memcpy((u8 *)(boxcontent) + 1,
371 cmdbuffer + buf_index + 2, 3);
373 for (idx = 0; idx < 2; idx++) {
374 rtl_write_byte(rtlpriv, box_extreg + idx,
378 for (idx = 0; idx < 4; idx++) {
379 rtl_write_byte(rtlpriv, box_reg + idx,
384 RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
385 "switch case %#x not processed\n", cmd_len);
389 bwrite_sucess = true;
391 rtlhal->last_hmeboxnum = boxnum + 1;
392 if (rtlhal->last_hmeboxnum == 4)
393 rtlhal->last_hmeboxnum = 0;
395 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
396 "pHalData->last_hmeboxnum = %d\n",
397 rtlhal->last_hmeboxnum);
400 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
401 rtlhal->h2c_setinprogress = false;
402 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
404 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
407 void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
408 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
410 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
413 if (!rtlhal->fw_ready) {
415 "rtl8192c-common: return H2C cmd because of Fw download fail!!!\n");
419 memset(tmp_cmdbuf, 0, 8);
420 memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
421 _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
425 EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
427 void rtl92c_firmware_selfreset(struct ieee80211_hw *hw)
431 struct rtl_priv *rtlpriv = rtl_priv(hw);
433 rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
434 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
436 while (u1b_tmp & BIT(2)) {
439 WARN_ONCE(true, "rtl8192c-common: 8051 reset fail.\n");
443 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
446 EXPORT_SYMBOL(rtl92c_firmware_selfreset);
448 void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
450 struct rtl_priv *rtlpriv = rtl_priv(hw);
451 u8 u1_h2c_set_pwrmode[3] = { 0 };
452 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
454 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
456 SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
457 SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
458 (rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1);
459 SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
460 ppsc->reg_max_lps_awakeintvl);
462 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
463 "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
464 u1_h2c_set_pwrmode, 3);
465 rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
467 EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
469 #define BEACON_PG 0 /*->1*/
472 #define PROBERSP_PG 4 /*->5*/
474 #define TOTAL_RESERVED_PKT_LEN 768
476 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
478 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
479 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
480 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
481 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
482 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
483 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
484 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
485 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
486 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
487 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
488 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
489 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
490 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
491 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
492 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
493 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
496 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
497 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
498 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
499 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
500 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
501 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
502 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
503 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
504 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
505 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
506 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
507 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
508 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
509 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
510 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
511 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
514 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
515 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
516 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
517 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
518 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
519 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
520 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
521 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
522 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
523 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
524 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
525 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
526 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
527 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
528 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
529 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
532 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
533 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
534 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
535 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
536 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
537 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
538 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
539 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
540 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
541 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
542 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
543 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
544 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
545 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
546 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
547 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
549 /* page 4 probe_resp */
550 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
551 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
552 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
553 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
554 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
555 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
556 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
557 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
558 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
559 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
560 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
561 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
562 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
563 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
564 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
565 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
567 /* page 5 probe_resp */
568 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
569 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
570 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
571 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
572 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
573 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
574 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
575 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
576 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
577 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
578 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
579 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
580 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
581 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
582 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
583 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
586 void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
587 bool (*cmd_send_packet)(struct ieee80211_hw *, struct sk_buff *))
589 struct rtl_priv *rtlpriv = rtl_priv(hw);
590 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
591 struct sk_buff *skb = NULL;
595 u8 u1rsvdpageloc[3] = { 0 };
602 /*---------------------------------------------------------
604 ---------------------------------------------------------*/
605 beacon = &reserved_page_packet[BEACON_PG * 128];
606 SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
607 SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
609 /*-------------------------------------------------------
611 --------------------------------------------------------*/
612 p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
613 SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
614 SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
615 SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
617 SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
619 /*--------------------------------------------------------
621 ---------------------------------------------------------*/
622 nullfunc = &reserved_page_packet[NULL_PG * 128];
623 SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
624 SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
625 SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
627 SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
629 /*---------------------------------------------------------
631 ----------------------------------------------------------*/
632 p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
633 SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
634 SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
635 SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
637 SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
639 totalpacketlen = TOTAL_RESERVED_PKT_LEN;
641 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
642 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
643 &reserved_page_packet[0], totalpacketlen);
644 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
645 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
649 skb = dev_alloc_skb(totalpacketlen);
652 skb_put_data(skb, &reserved_page_packet, totalpacketlen);
655 rtstatus = cmd_send_packet(hw, skb);
657 rtstatus = rtl_cmd_send_packet(hw, skb);
663 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
664 "Set RSVD page location to Fw.\n");
665 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
668 rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
669 sizeof(u1rsvdpageloc), u1rsvdpageloc);
671 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
672 "Set RSVD page location to Fw FAIL!!!!!!.\n");
674 EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
676 void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
678 u8 u1_joinbssrpt_parm[1] = { 0 };
680 SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
682 rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
684 EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);
686 static void rtl92c_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
688 u8 u1_ctwindow_period[1] = { ctwindow};
690 rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
693 /* refactored routine */
694 static void set_noa_data(struct rtl_priv *rtlpriv,
695 struct rtl_p2p_ps_info *p2pinfo,
696 struct p2p_ps_offload_t *p2p_ps_offload)
699 u32 start_time, tsf_low;
701 /* hw only support 2 set of NoA */
702 for (i = 0 ; i < p2pinfo->noa_num ; i++) {
703 /* To control the reg setting for which NOA*/
704 rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
706 p2p_ps_offload->noa0_en = 1;
708 p2p_ps_offload->noa1_en = 1;
710 /* config P2P NoA Descriptor Register */
711 rtl_write_dword(rtlpriv, 0x5E0,
712 p2pinfo->noa_duration[i]);
713 rtl_write_dword(rtlpriv, 0x5E4,
714 p2pinfo->noa_interval[i]);
716 /*Get Current TSF value */
717 tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
719 start_time = p2pinfo->noa_start_time[i];
720 if (p2pinfo->noa_count_type[i] != 1) {
721 while (start_time <= (tsf_low+(50*1024))) {
722 start_time += p2pinfo->noa_interval[i];
723 if (p2pinfo->noa_count_type[i] != 255)
724 p2pinfo->noa_count_type[i]--;
727 rtl_write_dword(rtlpriv, 0x5E8, start_time);
728 rtl_write_dword(rtlpriv, 0x5EC,
729 p2pinfo->noa_count_type[i]);
733 void rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
735 struct rtl_priv *rtlpriv = rtl_priv(hw);
736 struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
737 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
738 struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
739 struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
742 switch (p2p_ps_state) {
744 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
746 memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
749 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
751 /* update CTWindow value. */
752 if (p2pinfo->ctwindow > 0) {
753 p2p_ps_offload->ctwindow_en = 1;
754 ctwindow = p2pinfo->ctwindow;
755 rtl92c_set_p2p_ctw_period_cmd(hw, ctwindow);
757 /* call refactored routine */
758 set_noa_data(rtlpriv, p2pinfo, p2p_ps_offload);
760 if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
761 /* rst p2p circuit */
762 rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST,
765 p2p_ps_offload->offload_en = 1;
767 if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
768 p2p_ps_offload->role = 1;
769 p2p_ps_offload->allstasleep = 0;
771 p2p_ps_offload->role = 0;
774 p2p_ps_offload->discovery = 0;
778 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
779 p2p_ps_offload->discovery = 1;
781 case P2P_PS_SCAN_DONE:
782 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
783 "P2P_PS_SCAN_DONE\n");
784 p2p_ps_offload->discovery = 0;
785 p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
791 rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
794 EXPORT_SYMBOL_GPL(rtl92c_set_p2p_ps_offload_cmd);