]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/net/wireless/rtlwifi/rtl8188ee/fw.c
ide: pdc202xx_new: Replace timeval with ktime_t
[karo-tx-linux.git] / drivers / net / wireless / rtlwifi / rtl8188ee / fw.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2013  Realtek Corporation.
4  *
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.
8  *
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.
13  *
14  * The full GNU General Public License is included in this distribution in the
15  * file called LICENSE.
16  *
17  * Contact Information:
18  * wlanfae <wlanfae@realtek.com>
19  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20  * Hsinchu 300, Taiwan.
21  *
22  * Larry Finger <Larry.Finger@lwfinger.net>
23  *
24  *****************************************************************************/
25
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"
33
34 static void _rtl88e_enable_fw_download(struct ieee80211_hw *hw, bool enable)
35 {
36         struct rtl_priv *rtlpriv = rtl_priv(hw);
37         u8 tmp;
38
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);
42
43                 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
44                 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
45
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);
51
52                 rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
53         }
54 }
55
56 static void _rtl88e_fw_block_write(struct ieee80211_hw *hw,
57                                    const u8 *buffer, u32 size)
58 {
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;
64
65         blockcount = size / blocksize;
66         remainsize = size % blocksize;
67
68         for (i = 0; i < blockcount; i++) {
69                 offset = i * blocksize;
70                 rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
71                                 *(pu4BytePtr + i));
72         }
73
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));
80                 }
81         }
82 }
83
84 static void _rtl88e_fw_page_write(struct ieee80211_hw *hw,
85                                   u32 page, const u8 *buffer, u32 size)
86 {
87         struct rtl_priv *rtlpriv = rtl_priv(hw);
88         u8 value8;
89         u8 u8page = (u8) (page & 0x07);
90
91         value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
92
93         rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
94         _rtl88e_fw_block_write(hw, buffer, size);
95 }
96
97 static void _rtl88e_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
98 {
99         u32 fwlen = *pfwlen;
100         u8 remain = (u8) (fwlen % 4);
101
102         remain = (remain == 0) ? 0 : (4 - remain);
103
104         while (remain > 0) {
105                 pfwbuf[fwlen] = 0;
106                 fwlen++;
107                 remain--;
108         }
109
110         *pfwlen = fwlen;
111 }
112
113 static void _rtl88e_write_fw(struct ieee80211_hw *hw,
114                              enum version_8188e version, u8 *buffer, u32 size)
115 {
116         struct rtl_priv *rtlpriv = rtl_priv(hw);
117         u8 *bufferptr = (u8 *)buffer;
118         u32 pagenums, remainsize;
119         u32 page, offset;
120
121         RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "FW size is %d bytes,\n", size);
122
123         _rtl88e_fill_dummy(bufferptr, &size);
124
125         pagenums = size / FW_8192C_PAGE_SIZE;
126         remainsize = size % FW_8192C_PAGE_SIZE;
127
128         if (pagenums > 8) {
129                 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
130                          "Page numbers should not greater then 8\n");
131         }
132
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);
137         }
138
139         if (remainsize) {
140                 offset = pagenums * FW_8192C_PAGE_SIZE;
141                 page = pagenums;
142                 _rtl88e_fw_page_write(hw, page, (bufferptr + offset),
143                                       remainsize);
144         }
145 }
146
147 static int _rtl88e_fw_free_to_go(struct ieee80211_hw *hw)
148 {
149         struct rtl_priv *rtlpriv = rtl_priv(hw);
150         int err = -EIO;
151         u32 counter = 0;
152         u32 value32;
153
154         do {
155                 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
156         } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
157                  (!(value32 & FWDL_CHKSUM_RPT)));
158
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;
164         }
165
166         RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
167                  "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
168
169         value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
170         value32 |= MCUFWDL_RDY;
171         value32 &= ~WINTINI_RDY;
172         rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
173
174         rtl88e_firmware_selfreset(hw);
175         counter = 0;
176
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;
185                 }
186
187                 udelay(FW_8192C_POLLING_DELAY);
188
189         } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
190
191         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
192                  "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32);
193
194 exit:
195         return err;
196 }
197
198 int rtl88e_download_fw(struct ieee80211_hw *hw,
199                        bool buse_wake_on_wlan_fw)
200 {
201         struct rtl_priv *rtlpriv = rtl_priv(hw);
202         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
203         struct rtlwifi_firmware_header *pfwheader;
204         u8 *pfwdata;
205         u32 fwsize;
206         int err;
207         enum version_8188e version = rtlhal->version;
208
209         if (!rtlhal->pfirmware)
210                 return 1;
211
212         pfwheader = (struct rtlwifi_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);
217
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 rtlwifi_firmware_header));
223
224                 pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header);
225                 fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);
226         }
227
228         if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
229                 rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
230                 rtl88e_firmware_selfreset(hw);
231         }
232         _rtl88e_enable_fw_download(hw, true);
233         _rtl88e_write_fw(hw, version, pfwdata, fwsize);
234         _rtl88e_enable_fw_download(hw, false);
235
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");
243         }
244
245         return 0;
246 }
247
248 static bool _rtl88e_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
249 {
250         struct rtl_priv *rtlpriv = rtl_priv(hw);
251         u8 val_hmetfr;
252
253         val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
254         if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
255                 return true;
256         return false;
257 }
258
259 static void _rtl88e_fill_h2c_command(struct ieee80211_hw *hw,
260                                      u8 element_id, u32 cmd_len,
261                                      u8 *cmd_b)
262 {
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;
277
278         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
279
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);
286
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);
295
296                                 if (h2c_waitcounter > 1000)
297                                         return;
298                                 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
299                                                   flag);
300                         }
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;
306                 }
307         }
308
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;
315                 }
316
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;
339                 }
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;
348                         }
349
350                         udelay(10);
351
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);
357                 }
358
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;
364                 }
365
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);
372
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);
380
381                         for (idx = 0; idx < 4; idx++) {
382                                 rtl_write_byte(rtlpriv, box_reg + idx,
383                                                boxcontent[idx]);
384                         }
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);
395
396                         for (idx = 0; idx < 2; idx++) {
397                                 rtl_write_byte(rtlpriv, box_extreg + idx,
398                                                boxextcontent[idx]);
399                         }
400
401                         for (idx = 0; idx < 4; idx++) {
402                                 rtl_write_byte(rtlpriv, box_reg + idx,
403                                                boxcontent[idx]);
404                         }
405                         break;
406                 default:
407                         RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
408                                  "switch case not process\n");
409                         break;
410                 }
411
412                 write_sucess = true;
413
414                 rtlhal->last_hmeboxnum = boxnum + 1;
415                 if (rtlhal->last_hmeboxnum == 4)
416                         rtlhal->last_hmeboxnum = 0;
417
418                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
419                          "pHalData->last_hmeboxnum  = %d\n",
420                           rtlhal->last_hmeboxnum);
421         }
422
423         spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
424         rtlhal->h2c_setinprogress = false;
425         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
426
427         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
428 }
429
430 void rtl88e_fill_h2c_cmd(struct ieee80211_hw *hw,
431                          u8 element_id, u32 cmd_len, u8 *cmdbuffer)
432 {
433         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
434         u32 tmp_cmdbuf[2];
435
436         if (!rtlhal->fw_ready) {
437                 RT_ASSERT(false,
438                           "return H2C cmd because of Fw download fail!!!\n");
439                 return;
440         }
441
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);
445
446         return;
447 }
448
449 void rtl88e_firmware_selfreset(struct ieee80211_hw *hw)
450 {
451         u8 u1b_tmp;
452         struct rtl_priv *rtlpriv = rtl_priv(hw);
453
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");
459
460 }
461
462 void rtl88e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
463 {
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);
469
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;
482
483         SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
484
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);
490 }
491
492 void rtl88e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
493 {
494         u8 u1_joinbssrpt_parm[1] = { 0 };
495
496         SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
497
498         rtl88e_fill_h2c_cmd(hw, H2C_88E_JOINBSSRPT, 1, u1_joinbssrpt_parm);
499 }
500
501 void rtl88e_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,
502                                    u8 ap_offload_enable)
503 {
504         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
505         u8 u1_apoffload_parm[H2C_88E_AP_OFFLOAD_LENGTH] = { 0 };
506
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);
510
511         rtl88e_fill_h2c_cmd(hw, H2C_88E_AP_OFFLOAD,
512                             H2C_88E_AP_OFFLOAD_LENGTH, u1_apoffload_parm);
513
514 }
515
516 #define BEACON_PG               0 /* ->1 */
517 #define PSPOLL_PG               2
518 #define NULL_PG                 3
519 #define PROBERSP_PG             4 /* ->5 */
520
521 #define TOTAL_RESERVED_PKT_LEN  768
522
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,
541
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,
559
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,
577
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,
595
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,
613
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,
631 };
632
633 void rtl88e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
634 {
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;
646
647         /*---------------------------------------------------------
648          *                      (1) beacon
649          *---------------------------------------------------------
650          */
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);
654
655         /*-------------------------------------------------------
656          *                      (2) ps-poll
657          *--------------------------------------------------------
658          */
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);
663
664         SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
665
666         /*--------------------------------------------------------
667          *                      (3) null data
668          *---------------------------------------------------------
669          */
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);
674
675         SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
676
677         /*---------------------------------------------------------
678          *                      (4) probe response
679          *----------------------------------------------------------
680          */
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);
685
686         SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
687
688         totalpacketlen = TOTAL_RESERVED_PKT_LEN;
689
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);
696
697         skb = dev_alloc_skb(totalpacketlen);
698         memcpy(skb_put(skb, totalpacketlen),
699                &reserved_page_packet, totalpacketlen);
700
701         rtstatus = rtl_cmd_send_packet(hw, skb);
702
703         if (rtstatus)
704                 b_dlok = true;
705
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");
716 }
717
718 /*Should check FW support p2p or not.*/
719 static void rtl88e_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
720 {
721         u8 u1_ctwindow_period[1] = { ctwindow};
722
723         rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
724
725 }
726
727 void rtl88e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
728 {
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;
737
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);
750                 }
751
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;
760
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]);
766
767                         /*Get Current TSF value */
768                         tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
769
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]--;
776                                 }
777                         }
778                         rtl_write_dword(rtlpriv, 0x5E8, start_time);
779                         rtl_write_dword(rtlpriv, 0x5EC,
780                                         p2pinfo->noa_count_type[i]);
781                 }
782
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));
786
787                         p2p_ps_offload->offload_en = 1;
788
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;
794                         }
795
796                         p2p_ps_offload->discovery = 0;
797                 }
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;
810         }
811
812         rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_OFFLOAD, 1,
813                             (u8 *)p2p_ps_offload);
814
815 }