powerpc/eeh: Fix PE#0 check in eeh_add_to_parent_pe()
[linux/fpc-iii.git] / drivers / net / wireless / rtlwifi / rtl8188ee / fw.c
blobc8058aa73ecfc1aa8f282cc80aa27b789f657906
1 /******************************************************************************
3 * Copyright(c) 2009-2013 Realtek Corporation.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
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 *****************************************************************************/
26 #include "../wifi.h"
27 #include "../pci.h"
28 #include "../base.h"
29 #include "../core.h"
30 #include "reg.h"
31 #include "def.h"
32 #include "fw.h"
34 static void _rtl88e_enable_fw_download(struct ieee80211_hw *hw, bool enable)
36 struct rtl_priv *rtlpriv = rtl_priv(hw);
37 u8 tmp;
39 if (enable) {
40 tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
41 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
43 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
44 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
46 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
47 rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
48 } else {
49 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
50 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
52 rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
56 static void _rtl88e_fw_block_write(struct ieee80211_hw *hw,
57 const u8 *buffer, u32 size)
59 struct rtl_priv *rtlpriv = rtl_priv(hw);
60 u32 blocksize = sizeof(u32);
61 u8 *bufferptr = (u8 *)buffer;
62 u32 *pu4BytePtr = (u32 *)buffer;
63 u32 i, offset, blockcount, remainsize;
65 blockcount = size / blocksize;
66 remainsize = size % blocksize;
68 for (i = 0; i < blockcount; i++) {
69 offset = i * blocksize;
70 rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
71 *(pu4BytePtr + i));
74 if (remainsize) {
75 offset = blockcount * blocksize;
76 bufferptr += offset;
77 for (i = 0; i < remainsize; i++) {
78 rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS +
79 offset + i), *(bufferptr + i));
84 static void _rtl88e_fw_page_write(struct ieee80211_hw *hw,
85 u32 page, const u8 *buffer, u32 size)
87 struct rtl_priv *rtlpriv = rtl_priv(hw);
88 u8 value8;
89 u8 u8page = (u8) (page & 0x07);
91 value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
93 rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
94 _rtl88e_fw_block_write(hw, buffer, size);
97 static void _rtl88e_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
99 u32 fwlen = *pfwlen;
100 u8 remain = (u8) (fwlen % 4);
102 remain = (remain == 0) ? 0 : (4 - remain);
104 while (remain > 0) {
105 pfwbuf[fwlen] = 0;
106 fwlen++;
107 remain--;
110 *pfwlen = fwlen;
113 static void _rtl88e_write_fw(struct ieee80211_hw *hw,
114 enum version_8188e version, u8 *buffer, u32 size)
116 struct rtl_priv *rtlpriv = rtl_priv(hw);
117 u8 *bufferptr = (u8 *)buffer;
118 u32 pagenums, remainsize;
119 u32 page, offset;
121 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "FW size is %d bytes,\n", size);
123 _rtl88e_fill_dummy(bufferptr, &size);
125 pagenums = size / FW_8192C_PAGE_SIZE;
126 remainsize = size % FW_8192C_PAGE_SIZE;
128 if (pagenums > 8) {
129 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
130 "Page numbers should not greater then 8\n");
133 for (page = 0; page < pagenums; page++) {
134 offset = page * FW_8192C_PAGE_SIZE;
135 _rtl88e_fw_page_write(hw, page, (bufferptr + offset),
136 FW_8192C_PAGE_SIZE);
139 if (remainsize) {
140 offset = pagenums * FW_8192C_PAGE_SIZE;
141 page = pagenums;
142 _rtl88e_fw_page_write(hw, page, (bufferptr + offset),
143 remainsize);
147 static int _rtl88e_fw_free_to_go(struct ieee80211_hw *hw)
149 struct rtl_priv *rtlpriv = rtl_priv(hw);
150 int err = -EIO;
151 u32 counter = 0;
152 u32 value32;
154 do {
155 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
156 } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
157 (!(value32 & FWDL_CHKSUM_RPT)));
159 if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
160 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
161 "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
162 value32);
163 goto exit;
166 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
167 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
169 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
170 value32 |= MCUFWDL_RDY;
171 value32 &= ~WINTINI_RDY;
172 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
174 rtl88e_firmware_selfreset(hw);
175 counter = 0;
177 do {
178 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
179 if (value32 & WINTINI_RDY) {
180 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
181 "Polling FW ready success!! REG_MCUFWDL:0x%08x.\n",
182 value32);
183 err = 0;
184 goto exit;
187 udelay(FW_8192C_POLLING_DELAY);
189 } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
191 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
192 "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32);
194 exit:
195 return err;
198 int rtl88e_download_fw(struct ieee80211_hw *hw,
199 bool buse_wake_on_wlan_fw)
201 struct rtl_priv *rtlpriv = rtl_priv(hw);
202 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
203 struct rtl92c_firmware_header *pfwheader;
204 u8 *pfwdata;
205 u32 fwsize;
206 int err;
207 enum version_8188e version = rtlhal->version;
209 if (!rtlhal->pfirmware)
210 return 1;
212 pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
213 pfwdata = rtlhal->pfirmware;
214 fwsize = rtlhal->fwsize;
215 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
216 "normal Firmware SIZE %d\n", fwsize);
218 if (IS_FW_HEADER_EXIST(pfwheader)) {
219 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
220 "Firmware Version(%d), Signature(%#x), Size(%d)\n",
221 pfwheader->version, pfwheader->signature,
222 (int)sizeof(struct rtl92c_firmware_header));
224 pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
225 fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
228 if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
229 rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
230 rtl88e_firmware_selfreset(hw);
232 _rtl88e_enable_fw_download(hw, true);
233 _rtl88e_write_fw(hw, version, pfwdata, fwsize);
234 _rtl88e_enable_fw_download(hw, false);
236 err = _rtl88e_fw_free_to_go(hw);
237 if (err) {
238 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
239 "Firmware is not ready to run!\n");
240 } else {
241 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
242 "Firmware is ready to run!\n");
245 return 0;
248 static bool _rtl88e_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
250 struct rtl_priv *rtlpriv = rtl_priv(hw);
251 u8 val_hmetfr;
253 val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
254 if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
255 return true;
256 return false;
259 static void _rtl88e_fill_h2c_command(struct ieee80211_hw *hw,
260 u8 element_id, u32 cmd_len,
261 u8 *cmd_b)
263 struct rtl_priv *rtlpriv = rtl_priv(hw);
264 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
265 u8 boxnum;
266 u16 box_reg = 0, box_extreg = 0;
267 u8 u1b_tmp;
268 bool isfw_read = false;
269 u8 buf_index = 0;
270 bool write_sucess = false;
271 u8 wait_h2c_limmit = 100;
272 u8 wait_writeh2c_limit = 100;
273 u8 boxcontent[4], boxextcontent[4];
274 u32 h2c_waitcounter = 0;
275 unsigned long flag;
276 u8 idx;
278 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
280 while (true) {
281 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
282 if (rtlhal->h2c_setinprogress) {
283 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
284 "H2C set in progress! Wait to set..element_id(%d).\n",
285 element_id);
287 while (rtlhal->h2c_setinprogress) {
288 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
289 flag);
290 h2c_waitcounter++;
291 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
292 "Wait 100 us (%d times)...\n",
293 h2c_waitcounter);
294 udelay(100);
296 if (h2c_waitcounter > 1000)
297 return;
298 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
299 flag);
301 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
302 } else {
303 rtlhal->h2c_setinprogress = true;
304 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
305 break;
309 while (!write_sucess) {
310 wait_writeh2c_limit--;
311 if (wait_writeh2c_limit == 0) {
312 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
313 "Write H2C fail because no trigger for FW INT!\n");
314 break;
317 boxnum = rtlhal->last_hmeboxnum;
318 switch (boxnum) {
319 case 0:
320 box_reg = REG_HMEBOX_0;
321 box_extreg = REG_HMEBOX_EXT_0;
322 break;
323 case 1:
324 box_reg = REG_HMEBOX_1;
325 box_extreg = REG_HMEBOX_EXT_1;
326 break;
327 case 2:
328 box_reg = REG_HMEBOX_2;
329 box_extreg = REG_HMEBOX_EXT_2;
330 break;
331 case 3:
332 box_reg = REG_HMEBOX_3;
333 box_extreg = REG_HMEBOX_EXT_3;
334 break;
335 default:
336 RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
337 "switch case not process\n");
338 break;
340 isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
341 while (!isfw_read) {
342 wait_h2c_limmit--;
343 if (wait_h2c_limmit == 0) {
344 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
345 "Waiting too long for FW read clear HMEBox(%d)!\n",
346 boxnum);
347 break;
350 udelay(10);
352 isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
353 u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
354 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
355 "Waiting for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
356 boxnum, u1b_tmp);
359 if (!isfw_read) {
360 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
361 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
362 boxnum);
363 break;
366 memset(boxcontent, 0, sizeof(boxcontent));
367 memset(boxextcontent, 0, sizeof(boxextcontent));
368 boxcontent[0] = element_id;
369 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
370 "Write element_id box_reg(%4x) = %2x\n",
371 box_reg, element_id);
373 switch (cmd_len) {
374 case 1:
375 case 2:
376 case 3:
377 /*boxcontent[0] &= ~(BIT(7));*/
378 memcpy((u8 *)(boxcontent) + 1,
379 cmd_b + buf_index, cmd_len);
381 for (idx = 0; idx < 4; idx++) {
382 rtl_write_byte(rtlpriv, box_reg + idx,
383 boxcontent[idx]);
385 break;
386 case 4:
387 case 5:
388 case 6:
389 case 7:
390 /*boxcontent[0] |= (BIT(7));*/
391 memcpy((u8 *)(boxextcontent),
392 cmd_b + buf_index+3, cmd_len-3);
393 memcpy((u8 *)(boxcontent) + 1,
394 cmd_b + buf_index, 3);
396 for (idx = 0; idx < 2; idx++) {
397 rtl_write_byte(rtlpriv, box_extreg + idx,
398 boxextcontent[idx]);
401 for (idx = 0; idx < 4; idx++) {
402 rtl_write_byte(rtlpriv, box_reg + idx,
403 boxcontent[idx]);
405 break;
406 default:
407 RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
408 "switch case not process\n");
409 break;
412 write_sucess = true;
414 rtlhal->last_hmeboxnum = boxnum + 1;
415 if (rtlhal->last_hmeboxnum == 4)
416 rtlhal->last_hmeboxnum = 0;
418 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
419 "pHalData->last_hmeboxnum = %d\n",
420 rtlhal->last_hmeboxnum);
423 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
424 rtlhal->h2c_setinprogress = false;
425 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
427 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
430 void rtl88e_fill_h2c_cmd(struct ieee80211_hw *hw,
431 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
433 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
434 u32 tmp_cmdbuf[2];
436 if (!rtlhal->fw_ready) {
437 RT_ASSERT(false,
438 "return H2C cmd because of Fw download fail!!!\n");
439 return;
442 memset(tmp_cmdbuf, 0, 8);
443 memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
444 _rtl88e_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
446 return;
449 void rtl88e_firmware_selfreset(struct ieee80211_hw *hw)
451 u8 u1b_tmp;
452 struct rtl_priv *rtlpriv = rtl_priv(hw);
454 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1);
455 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2))));
456 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp | BIT(2)));
457 RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
458 "8051Reset88E(): 8051 reset success\n");
462 void rtl88e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
464 struct rtl_priv *rtlpriv = rtl_priv(hw);
465 u8 u1_h2c_set_pwrmode[H2C_88E_PWEMODE_LENGTH] = { 0 };
466 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
467 u8 rlbm, power_state = 0;
468 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
470 SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
471 rlbm = 0;/*YJ, temp, 120316. FW now not support RLBM=2.*/
472 SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm);
473 SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
474 (rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1);
475 SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
476 ppsc->reg_max_lps_awakeintvl);
477 SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
478 if (mode == FW_PS_ACTIVE_MODE)
479 power_state |= FW_PWR_STATE_ACTIVE;
480 else
481 power_state |= FW_PWR_STATE_RF_OFF;
483 SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
485 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
486 "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
487 u1_h2c_set_pwrmode, H2C_88E_PWEMODE_LENGTH);
488 rtl88e_fill_h2c_cmd(hw, H2C_88E_SETPWRMODE,
489 H2C_88E_PWEMODE_LENGTH, u1_h2c_set_pwrmode);
492 void rtl88e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
494 u8 u1_joinbssrpt_parm[1] = { 0 };
496 SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
498 rtl88e_fill_h2c_cmd(hw, H2C_88E_JOINBSSRPT, 1, u1_joinbssrpt_parm);
501 void rtl88e_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,
502 u8 ap_offload_enable)
504 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
505 u8 u1_apoffload_parm[H2C_88E_AP_OFFLOAD_LENGTH] = { 0 };
507 SET_H2CCMD_AP_OFFLOAD_ON(u1_apoffload_parm, ap_offload_enable);
508 SET_H2CCMD_AP_OFFLOAD_HIDDEN(u1_apoffload_parm, mac->hiddenssid);
509 SET_H2CCMD_AP_OFFLOAD_DENYANY(u1_apoffload_parm, 0);
511 rtl88e_fill_h2c_cmd(hw, H2C_88E_AP_OFFLOAD,
512 H2C_88E_AP_OFFLOAD_LENGTH, u1_apoffload_parm);
516 #define BEACON_PG 0 /* ->1 */
517 #define PSPOLL_PG 2
518 #define NULL_PG 3
519 #define PROBERSP_PG 4 /* ->5 */
521 #define TOTAL_RESERVED_PKT_LEN 768
523 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
524 /* page 0 beacon */
525 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
526 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
527 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
528 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
529 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
530 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
531 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
532 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
533 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
534 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
535 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
536 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
537 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
538 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
539 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
540 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
542 /* page 1 beacon */
543 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
544 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
545 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
546 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
547 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
548 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
549 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
550 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
551 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
552 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
553 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
554 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
555 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
556 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
557 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
560 /* page 2 ps-poll */
561 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
562 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
563 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
564 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
565 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
566 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
567 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
568 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
569 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
570 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
571 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
572 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
573 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
574 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
575 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
576 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
578 /* page 3 null */
579 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
580 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
581 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
582 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
583 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
584 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
585 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
586 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
587 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
588 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
589 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
590 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
591 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
592 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
593 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
594 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
596 /* page 4 probe_resp */
597 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
598 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
599 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
600 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
601 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
602 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
603 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
604 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
605 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
606 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
607 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
608 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
609 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
610 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
611 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
612 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
614 /* page 5 probe_resp */
615 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
616 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
617 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
618 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
619 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
620 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
621 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
622 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
623 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
624 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
625 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
626 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
627 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
628 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
629 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
630 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
633 void rtl88e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
635 struct rtl_priv *rtlpriv = rtl_priv(hw);
636 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
637 struct sk_buff *skb = NULL;
638 u32 totalpacketlen;
639 bool rtstatus;
640 u8 u1rsvdpageloc[5] = { 0 };
641 bool b_dlok = false;
642 u8 *beacon;
643 u8 *p_pspoll;
644 u8 *nullfunc;
645 u8 *p_probersp;
647 /*---------------------------------------------------------
648 * (1) beacon
649 *---------------------------------------------------------
651 beacon = &reserved_page_packet[BEACON_PG * 128];
652 SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
653 SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
655 /*-------------------------------------------------------
656 * (2) ps-poll
657 *--------------------------------------------------------
659 p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
660 SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
661 SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
662 SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
664 SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
666 /*--------------------------------------------------------
667 * (3) null data
668 *---------------------------------------------------------
670 nullfunc = &reserved_page_packet[NULL_PG * 128];
671 SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
672 SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
673 SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
675 SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
677 /*---------------------------------------------------------
678 * (4) probe response
679 *----------------------------------------------------------
681 p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
682 SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
683 SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
684 SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
686 SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
688 totalpacketlen = TOTAL_RESERVED_PKT_LEN;
690 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
691 "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
692 &reserved_page_packet[0], totalpacketlen);
693 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
694 "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
695 u1rsvdpageloc, 3);
697 skb = dev_alloc_skb(totalpacketlen);
698 memcpy(skb_put(skb, totalpacketlen),
699 &reserved_page_packet, totalpacketlen);
701 rtstatus = rtl_cmd_send_packet(hw, skb);
703 if (rtstatus)
704 b_dlok = true;
706 if (b_dlok) {
707 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
708 "Set RSVD page location to Fw.\n");
709 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
710 "H2C_RSVDPAGE:\n", u1rsvdpageloc, 3);
711 rtl88e_fill_h2c_cmd(hw, H2C_88E_RSVDPAGE,
712 sizeof(u1rsvdpageloc), u1rsvdpageloc);
713 } else
714 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
715 "Set RSVD page location to Fw FAIL!!!!!!.\n");
718 /*Should check FW support p2p or not.*/
719 static void rtl88e_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
721 u8 u1_ctwindow_period[1] = { ctwindow};
723 rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
727 void rtl88e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
729 struct rtl_priv *rtlpriv = rtl_priv(hw);
730 struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
731 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
732 struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
733 struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
734 u8 i;
735 u16 ctwindow;
736 u32 start_time, tsf_low;
738 switch (p2p_ps_state) {
739 case P2P_PS_DISABLE:
740 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
741 memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
742 break;
743 case P2P_PS_ENABLE:
744 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
745 /* update CTWindow value. */
746 if (p2pinfo->ctwindow > 0) {
747 p2p_ps_offload->ctwindow_en = 1;
748 ctwindow = p2pinfo->ctwindow;
749 rtl88e_set_p2p_ctw_period_cmd(hw, ctwindow);
752 /* hw only support 2 set of NoA */
753 for (i = 0 ; i < p2pinfo->noa_num; i++) {
754 /* To control the register setting for which NOA*/
755 rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
756 if (i == 0)
757 p2p_ps_offload->noa0_en = 1;
758 else
759 p2p_ps_offload->noa1_en = 1;
761 /* config P2P NoA Descriptor Register */
762 rtl_write_dword(rtlpriv, 0x5E0,
763 p2pinfo->noa_duration[i]);
764 rtl_write_dword(rtlpriv, 0x5E4,
765 p2pinfo->noa_interval[i]);
767 /*Get Current TSF value */
768 tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
770 start_time = p2pinfo->noa_start_time[i];
771 if (p2pinfo->noa_count_type[i] != 1) {
772 while (start_time <= (tsf_low+(50*1024))) {
773 start_time += p2pinfo->noa_interval[i];
774 if (p2pinfo->noa_count_type[i] != 255)
775 p2pinfo->noa_count_type[i]--;
778 rtl_write_dword(rtlpriv, 0x5E8, start_time);
779 rtl_write_dword(rtlpriv, 0x5EC,
780 p2pinfo->noa_count_type[i]);
783 if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
784 /* rst p2p circuit */
785 rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
787 p2p_ps_offload->offload_en = 1;
789 if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
790 p2p_ps_offload->role = 1;
791 p2p_ps_offload->allstasleep = -1;
792 } else {
793 p2p_ps_offload->role = 0;
796 p2p_ps_offload->discovery = 0;
798 break;
799 case P2P_PS_SCAN:
800 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
801 p2p_ps_offload->discovery = 1;
802 break;
803 case P2P_PS_SCAN_DONE:
804 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
805 p2p_ps_offload->discovery = 0;
806 p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
807 break;
808 default:
809 break;
812 rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_OFFLOAD, 1,
813 (u8 *)p2p_ps_offload);