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>
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_write_fw(struct ieee80211_hw *hw,
72 enum version_8192c version, u8 *buffer, u32 size)
74 struct rtl_priv *rtlpriv = rtl_priv(hw);
75 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
77 u8 *bufferptr = (u8 *)buffer;
79 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
80 is_version_b = IS_NORMAL_CHIP(version);
82 u32 pageNums, remainsize;
85 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE)
86 rtl_fill_dummy(bufferptr, &size);
88 pageNums = size / FW_8192C_PAGE_SIZE;
89 remainsize = size % FW_8192C_PAGE_SIZE;
92 pr_err("Page numbers should not greater then 4\n");
94 for (page = 0; page < pageNums; page++) {
95 offset = page * FW_8192C_PAGE_SIZE;
96 rtl_fw_page_write(hw, page, (bufferptr + offset),
101 offset = pageNums * FW_8192C_PAGE_SIZE;
103 rtl_fw_page_write(hw, page, (bufferptr + offset),
107 rtl_fw_block_write(hw, buffer, size);
111 static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
113 struct rtl_priv *rtlpriv = rtl_priv(hw);
119 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
120 } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
121 (!(value32 & FWDL_ChkSum_rpt)));
123 if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
124 pr_err("chksum report fail! REG_MCUFWDL:0x%08x .\n",
128 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
129 value32 |= MCUFWDL_RDY;
130 value32 &= ~WINTINI_RDY;
131 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
136 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
137 if (value32 & WINTINI_RDY)
140 mdelay(FW_8192C_POLLING_DELAY);
142 } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
144 pr_err("Polling FW ready fail! REG_MCUFWDL:0x%08x.\n",
151 int rtl92c_download_fw(struct ieee80211_hw *hw)
153 struct rtl_priv *rtlpriv = rtl_priv(hw);
154 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
155 struct rtlwifi_firmware_header *pfwheader;
159 enum version_8192c version = rtlhal->version;
161 if (!rtlhal->pfirmware)
164 pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware;
165 pfwdata = (u8 *)rtlhal->pfirmware;
166 fwsize = rtlhal->fwsize;
167 if (IS_FW_HEADER_EXIST(pfwheader)) {
168 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
169 "Firmware Version(%d), Signature(%#x),Size(%d)\n",
170 pfwheader->version, pfwheader->signature,
171 (int)sizeof(struct rtlwifi_firmware_header));
173 rtlhal->fw_version = le16_to_cpu(pfwheader->version);
174 rtlhal->fw_subversion = pfwheader->subversion;
175 pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header);
176 fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);
179 _rtl92c_enable_fw_download(hw, true);
180 _rtl92c_write_fw(hw, version, pfwdata, fwsize);
181 _rtl92c_enable_fw_download(hw, false);
183 err = _rtl92c_fw_free_to_go(hw);
185 pr_err("Firmware is not ready to run!\n");
189 EXPORT_SYMBOL(rtl92c_download_fw);
191 static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
193 struct rtl_priv *rtlpriv = rtl_priv(hw);
194 u8 val_hmetfr, val_mcutst_1;
197 val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
198 val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
200 if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
205 static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
206 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
208 struct rtl_priv *rtlpriv = rtl_priv(hw);
209 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
211 u16 box_reg = 0, box_extreg = 0;
213 bool isfw_read = false;
215 bool bwrite_sucess = false;
216 u8 wait_h2c_limmit = 100;
217 u8 wait_writeh2c_limmit = 100;
218 u8 boxcontent[4], boxextcontent[2];
219 u32 h2c_waitcounter = 0;
223 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
226 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
227 if (rtlhal->h2c_setinprogress) {
228 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
229 "H2C set in progress! Wait to set..element_id(%d).\n",
231 while (rtlhal->h2c_setinprogress) {
232 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
235 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
236 "Wait 100 us (%d times)...\n",
240 if (h2c_waitcounter > 1000)
242 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
245 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
247 rtlhal->h2c_setinprogress = true;
248 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
253 while (!bwrite_sucess) {
254 wait_writeh2c_limmit--;
255 if (wait_writeh2c_limmit == 0) {
256 pr_err("Write H2C fail because no trigger for FW INT!\n");
260 boxnum = rtlhal->last_hmeboxnum;
263 box_reg = REG_HMEBOX_0;
264 box_extreg = REG_HMEBOX_EXT_0;
267 box_reg = REG_HMEBOX_1;
268 box_extreg = REG_HMEBOX_EXT_1;
271 box_reg = REG_HMEBOX_2;
272 box_extreg = REG_HMEBOX_EXT_2;
275 box_reg = REG_HMEBOX_3;
276 box_extreg = REG_HMEBOX_EXT_3;
279 RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
280 "switch case %#x not processed\n", boxnum);
284 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
287 if (wait_h2c_limmit == 0) {
288 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
289 "Waiting too long for FW read clear HMEBox(%d)!\n",
296 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
297 u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
298 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
299 "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
304 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
305 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
310 memset(boxcontent, 0, sizeof(boxcontent));
311 memset(boxextcontent, 0, sizeof(boxextcontent));
312 boxcontent[0] = element_id;
313 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
314 "Write element_id box_reg(%4x) = %2x\n",
315 box_reg, element_id);
319 boxcontent[0] &= ~(BIT(7));
320 memcpy((u8 *)(boxcontent) + 1,
321 cmdbuffer + buf_index, 1);
323 for (idx = 0; idx < 4; idx++) {
324 rtl_write_byte(rtlpriv, box_reg + idx,
329 boxcontent[0] &= ~(BIT(7));
330 memcpy((u8 *)(boxcontent) + 1,
331 cmdbuffer + buf_index, 2);
333 for (idx = 0; idx < 4; idx++) {
334 rtl_write_byte(rtlpriv, box_reg + idx,
339 boxcontent[0] &= ~(BIT(7));
340 memcpy((u8 *)(boxcontent) + 1,
341 cmdbuffer + buf_index, 3);
343 for (idx = 0; idx < 4; idx++) {
344 rtl_write_byte(rtlpriv, box_reg + idx,
349 boxcontent[0] |= (BIT(7));
350 memcpy((u8 *)(boxextcontent),
351 cmdbuffer + buf_index, 2);
352 memcpy((u8 *)(boxcontent) + 1,
353 cmdbuffer + buf_index + 2, 2);
355 for (idx = 0; idx < 2; idx++) {
356 rtl_write_byte(rtlpriv, box_extreg + idx,
360 for (idx = 0; idx < 4; idx++) {
361 rtl_write_byte(rtlpriv, box_reg + idx,
366 boxcontent[0] |= (BIT(7));
367 memcpy((u8 *)(boxextcontent),
368 cmdbuffer + buf_index, 2);
369 memcpy((u8 *)(boxcontent) + 1,
370 cmdbuffer + buf_index + 2, 3);
372 for (idx = 0; idx < 2; idx++) {
373 rtl_write_byte(rtlpriv, box_extreg + idx,
377 for (idx = 0; idx < 4; idx++) {
378 rtl_write_byte(rtlpriv, box_reg + idx,
383 RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
384 "switch case %#x not processed\n", cmd_len);
388 bwrite_sucess = true;
390 rtlhal->last_hmeboxnum = boxnum + 1;
391 if (rtlhal->last_hmeboxnum == 4)
392 rtlhal->last_hmeboxnum = 0;
394 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
395 "pHalData->last_hmeboxnum = %d\n",
396 rtlhal->last_hmeboxnum);
399 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
400 rtlhal->h2c_setinprogress = false;
401 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
403 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
406 void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
407 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
409 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
412 if (!rtlhal->fw_ready) {
414 "rtl8192c-common: return H2C cmd because of Fw download fail!!!\n");
418 memset(tmp_cmdbuf, 0, 8);
419 memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
420 _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
424 EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
426 void rtl92c_firmware_selfreset(struct ieee80211_hw *hw)
430 struct rtl_priv *rtlpriv = rtl_priv(hw);
432 rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
433 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
435 while (u1b_tmp & BIT(2)) {
438 WARN_ONCE(true, "rtl8192c-common: 8051 reset fail.\n");
442 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
445 EXPORT_SYMBOL(rtl92c_firmware_selfreset);
447 void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
449 struct rtl_priv *rtlpriv = rtl_priv(hw);
450 u8 u1_h2c_set_pwrmode[3] = { 0 };
451 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
453 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
455 SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
456 SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
457 (rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1);
458 SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
459 ppsc->reg_max_lps_awakeintvl);
461 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
462 "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
463 u1_h2c_set_pwrmode, 3);
464 rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
466 EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
468 #define BEACON_PG 0 /*->1*/
471 #define PROBERSP_PG 4 /*->5*/
473 #define TOTAL_RESERVED_PKT_LEN 768
475 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
477 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
478 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
479 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
480 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
481 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
482 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
483 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
484 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
485 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
486 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
487 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
488 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
489 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
490 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
491 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
492 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
495 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 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
508 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
509 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
510 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
513 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
514 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
515 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
526 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
527 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
528 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
531 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
532 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
533 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
534 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
544 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
545 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
546 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
548 /* page 4 probe_resp */
549 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
550 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
551 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
552 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
553 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
554 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
555 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
556 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
557 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
558 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
559 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
560 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
561 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
562 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
563 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
564 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
566 /* page 5 probe_resp */
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 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,
585 void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
586 bool (*cmd_send_packet)(struct ieee80211_hw *, struct sk_buff *))
588 struct rtl_priv *rtlpriv = rtl_priv(hw);
589 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
590 struct sk_buff *skb = NULL;
594 u8 u1rsvdpageloc[3] = { 0 };
601 /*---------------------------------------------------------
603 ---------------------------------------------------------*/
604 beacon = &reserved_page_packet[BEACON_PG * 128];
605 SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
606 SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
608 /*-------------------------------------------------------
610 --------------------------------------------------------*/
611 p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
612 SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
613 SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
614 SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
616 SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
618 /*--------------------------------------------------------
620 ---------------------------------------------------------*/
621 nullfunc = &reserved_page_packet[NULL_PG * 128];
622 SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
623 SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
624 SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
626 SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
628 /*---------------------------------------------------------
630 ----------------------------------------------------------*/
631 p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
632 SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
633 SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
634 SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
636 SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
638 totalpacketlen = TOTAL_RESERVED_PKT_LEN;
640 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
641 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
642 &reserved_page_packet[0], totalpacketlen);
643 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
644 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
648 skb = dev_alloc_skb(totalpacketlen);
651 skb_put_data(skb, &reserved_page_packet, totalpacketlen);
654 rtstatus = cmd_send_packet(hw, skb);
656 rtstatus = rtl_cmd_send_packet(hw, skb);
662 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
663 "Set RSVD page location to Fw.\n");
664 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
667 rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
668 sizeof(u1rsvdpageloc), u1rsvdpageloc);
670 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
671 "Set RSVD page location to Fw FAIL!!!!!!.\n");
673 EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
675 void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
677 u8 u1_joinbssrpt_parm[1] = { 0 };
679 SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
681 rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
683 EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);
685 static void rtl92c_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
687 u8 u1_ctwindow_period[1] = { ctwindow};
689 rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
692 /* refactored routine */
693 static void set_noa_data(struct rtl_priv *rtlpriv,
694 struct rtl_p2p_ps_info *p2pinfo,
695 struct p2p_ps_offload_t *p2p_ps_offload)
698 u32 start_time, tsf_low;
700 /* hw only support 2 set of NoA */
701 for (i = 0 ; i < p2pinfo->noa_num ; i++) {
702 /* To control the reg setting for which NOA*/
703 rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
705 p2p_ps_offload->noa0_en = 1;
707 p2p_ps_offload->noa1_en = 1;
709 /* config P2P NoA Descriptor Register */
710 rtl_write_dword(rtlpriv, 0x5E0,
711 p2pinfo->noa_duration[i]);
712 rtl_write_dword(rtlpriv, 0x5E4,
713 p2pinfo->noa_interval[i]);
715 /*Get Current TSF value */
716 tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
718 start_time = p2pinfo->noa_start_time[i];
719 if (p2pinfo->noa_count_type[i] != 1) {
720 while (start_time <= (tsf_low+(50*1024))) {
721 start_time += p2pinfo->noa_interval[i];
722 if (p2pinfo->noa_count_type[i] != 255)
723 p2pinfo->noa_count_type[i]--;
726 rtl_write_dword(rtlpriv, 0x5E8, start_time);
727 rtl_write_dword(rtlpriv, 0x5EC,
728 p2pinfo->noa_count_type[i]);
732 void rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
734 struct rtl_priv *rtlpriv = rtl_priv(hw);
735 struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
736 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
737 struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
738 struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
741 switch (p2p_ps_state) {
743 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
745 memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
748 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
750 /* update CTWindow value. */
751 if (p2pinfo->ctwindow > 0) {
752 p2p_ps_offload->ctwindow_en = 1;
753 ctwindow = p2pinfo->ctwindow;
754 rtl92c_set_p2p_ctw_period_cmd(hw, ctwindow);
756 /* call refactored routine */
757 set_noa_data(rtlpriv, p2pinfo, p2p_ps_offload);
759 if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
760 /* rst p2p circuit */
761 rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST,
764 p2p_ps_offload->offload_en = 1;
766 if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
767 p2p_ps_offload->role = 1;
768 p2p_ps_offload->allstasleep = 0;
770 p2p_ps_offload->role = 0;
773 p2p_ps_offload->discovery = 0;
777 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
778 p2p_ps_offload->discovery = 1;
780 case P2P_PS_SCAN_DONE:
781 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
782 "P2P_PS_SCAN_DONE\n");
783 p2p_ps_offload->discovery = 0;
784 p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
790 rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
793 EXPORT_SYMBOL_GPL(rtl92c_set_p2p_ps_offload_cmd);