GNU Linux-libre 4.14.251-gnu1
[releases.git] / drivers / net / wireless / realtek / 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 "../efuse.h"
31 #include "reg.h"
32 #include "def.h"
33 #include "fw.h"
34
35 static void _rtl88e_enable_fw_download(struct ieee80211_hw *hw, bool enable)
36 {
37         struct rtl_priv *rtlpriv = rtl_priv(hw);
38         u8 tmp;
39
40         if (enable) {
41                 tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
42                 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
43
44                 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
45                 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
46
47                 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
48                 rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
49         } else {
50                 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
51                 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
52
53                 rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
54         }
55 }
56
57 static void _rtl88e_write_fw(struct ieee80211_hw *hw,
58                              enum version_8188e version, u8 *buffer, u32 size)
59 {
60         struct rtl_priv *rtlpriv = rtl_priv(hw);
61         u8 *bufferptr = (u8 *)buffer;
62         u32 pagenums, remainsize;
63         u32 page, offset;
64
65         RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "FW size is %d bytes,\n", size);
66
67         rtl_fill_dummy(bufferptr, &size);
68
69         pagenums = size / FW_8192C_PAGE_SIZE;
70         remainsize = size % FW_8192C_PAGE_SIZE;
71
72         if (pagenums > 8)
73                 pr_err("Page numbers should not greater then 8\n");
74
75         for (page = 0; page < pagenums; page++) {
76                 offset = page * FW_8192C_PAGE_SIZE;
77                 rtl_fw_page_write(hw, page, (bufferptr + offset),
78                                   FW_8192C_PAGE_SIZE);
79         }
80
81         if (remainsize) {
82                 offset = pagenums * FW_8192C_PAGE_SIZE;
83                 page = pagenums;
84                 rtl_fw_page_write(hw, page, (bufferptr + offset), remainsize);
85         }
86 }
87
88 static int _rtl88e_fw_free_to_go(struct ieee80211_hw *hw)
89 {
90         struct rtl_priv *rtlpriv = rtl_priv(hw);
91         int err = -EIO;
92         u32 counter = 0;
93         u32 value32;
94
95         do {
96                 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
97         } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
98                  (!(value32 & FWDL_CHKSUM_RPT)));
99
100         if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
101                 pr_err("chksum report fail! REG_MCUFWDL:0x%08x .\n",
102                        value32);
103                 goto exit;
104         }
105         value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
106         value32 |= MCUFWDL_RDY;
107         value32 &= ~WINTINI_RDY;
108         rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
109
110         rtl88e_firmware_selfreset(hw);
111         counter = 0;
112
113         do {
114                 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
115                 if (value32 & WINTINI_RDY)
116                         return 0;
117
118                 udelay(FW_8192C_POLLING_DELAY);
119
120         } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
121
122         pr_err("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n",
123                value32);
124
125 exit:
126         return err;
127 }
128
129 int rtl88e_download_fw(struct ieee80211_hw *hw,
130                        bool buse_wake_on_wlan_fw)
131 {
132         struct rtl_priv *rtlpriv = rtl_priv(hw);
133         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
134         struct rtlwifi_firmware_header *pfwheader;
135         u8 *pfwdata;
136         u32 fwsize;
137         int err;
138         enum version_8188e version = rtlhal->version;
139
140         if (!rtlhal->pfirmware)
141                 return 1;
142
143         pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware;
144         pfwdata = rtlhal->pfirmware;
145         fwsize = rtlhal->fwsize;
146         RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
147                  "normal Firmware SIZE %d\n", fwsize);
148
149         if (IS_FW_HEADER_EXIST(pfwheader)) {
150                 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
151                          "Firmware Version(%d), Signature(%#x), Size(%d)\n",
152                           pfwheader->version, pfwheader->signature,
153                           (int)sizeof(struct rtlwifi_firmware_header));
154
155                 pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header);
156                 fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);
157         }
158
159         if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
160                 rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
161                 rtl88e_firmware_selfreset(hw);
162         }
163         _rtl88e_enable_fw_download(hw, true);
164         _rtl88e_write_fw(hw, version, pfwdata, fwsize);
165         _rtl88e_enable_fw_download(hw, false);
166
167         err = _rtl88e_fw_free_to_go(hw);
168         if (err)
169                 pr_err("Firmware is not ready to run!\n");
170
171         return 0;
172 }
173
174 static bool _rtl88e_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
175 {
176         struct rtl_priv *rtlpriv = rtl_priv(hw);
177         u8 val_hmetfr;
178
179         val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
180         if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
181                 return true;
182         return false;
183 }
184
185 static void _rtl88e_fill_h2c_command(struct ieee80211_hw *hw,
186                                      u8 element_id, u32 cmd_len,
187                                      u8 *cmd_b)
188 {
189         struct rtl_priv *rtlpriv = rtl_priv(hw);
190         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
191         u8 boxnum;
192         u16 box_reg = 0, box_extreg = 0;
193         u8 u1b_tmp;
194         bool isfw_read = false;
195         u8 buf_index = 0;
196         bool write_sucess = false;
197         u8 wait_h2c_limmit = 100;
198         u8 wait_writeh2c_limit = 100;
199         u8 boxcontent[4], boxextcontent[4];
200         u32 h2c_waitcounter = 0;
201         unsigned long flag;
202         u8 idx;
203
204         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
205
206         while (true) {
207                 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
208                 if (rtlhal->h2c_setinprogress) {
209                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
210                                  "H2C set in progress! Wait to set..element_id(%d).\n",
211                                  element_id);
212
213                         while (rtlhal->h2c_setinprogress) {
214                                 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
215                                                        flag);
216                                 h2c_waitcounter++;
217                                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
218                                          "Wait 100 us (%d times)...\n",
219                                          h2c_waitcounter);
220                                 udelay(100);
221
222                                 if (h2c_waitcounter > 1000)
223                                         return;
224                                 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
225                                                   flag);
226                         }
227                         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
228                 } else {
229                         rtlhal->h2c_setinprogress = true;
230                         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
231                         break;
232                 }
233         }
234
235         while (!write_sucess) {
236                 wait_writeh2c_limit--;
237                 if (wait_writeh2c_limit == 0) {
238                         pr_err("Write H2C fail because no trigger for FW INT!\n");
239                         break;
240                 }
241
242                 boxnum = rtlhal->last_hmeboxnum;
243                 switch (boxnum) {
244                 case 0:
245                         box_reg = REG_HMEBOX_0;
246                         box_extreg = REG_HMEBOX_EXT_0;
247                         break;
248                 case 1:
249                         box_reg = REG_HMEBOX_1;
250                         box_extreg = REG_HMEBOX_EXT_1;
251                         break;
252                 case 2:
253                         box_reg = REG_HMEBOX_2;
254                         box_extreg = REG_HMEBOX_EXT_2;
255                         break;
256                 case 3:
257                         box_reg = REG_HMEBOX_3;
258                         box_extreg = REG_HMEBOX_EXT_3;
259                         break;
260                 default:
261                         RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
262                                  "switch case %#x not processed\n", boxnum);
263                         break;
264                 }
265                 isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
266                 while (!isfw_read) {
267                         wait_h2c_limmit--;
268                         if (wait_h2c_limmit == 0) {
269                                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
270                                          "Waiting too long for FW read clear HMEBox(%d)!\n",
271                                          boxnum);
272                                 break;
273                         }
274
275                         udelay(10);
276
277                         isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
278                         u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
279                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
280                                  "Waiting for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
281                                  boxnum, u1b_tmp);
282                 }
283
284                 if (!isfw_read) {
285                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
286                                  "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
287                                  boxnum);
288                         break;
289                 }
290
291                 memset(boxcontent, 0, sizeof(boxcontent));
292                 memset(boxextcontent, 0, sizeof(boxextcontent));
293                 boxcontent[0] = element_id;
294                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
295                          "Write element_id box_reg(%4x) = %2x\n",
296                          box_reg, element_id);
297
298                 switch (cmd_len) {
299                 case 1:
300                 case 2:
301                 case 3:
302                         /*boxcontent[0] &= ~(BIT(7));*/
303                         memcpy((u8 *)(boxcontent) + 1,
304                                cmd_b + buf_index, cmd_len);
305
306                         for (idx = 0; idx < 4; idx++) {
307                                 rtl_write_byte(rtlpriv, box_reg + idx,
308                                                boxcontent[idx]);
309                         }
310                         break;
311                 case 4:
312                 case 5:
313                 case 6:
314                 case 7:
315                         /*boxcontent[0] |= (BIT(7));*/
316                         memcpy((u8 *)(boxextcontent),
317                                cmd_b + buf_index+3, cmd_len-3);
318                         memcpy((u8 *)(boxcontent) + 1,
319                                cmd_b + buf_index, 3);
320
321                         for (idx = 0; idx < 2; idx++) {
322                                 rtl_write_byte(rtlpriv, box_extreg + idx,
323                                                boxextcontent[idx]);
324                         }
325
326                         for (idx = 0; idx < 4; idx++) {
327                                 rtl_write_byte(rtlpriv, box_reg + idx,
328                                                boxcontent[idx]);
329                         }
330                         break;
331                 default:
332                         RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
333                                  "switch case %#x not processed\n", cmd_len);
334                         break;
335                 }
336
337                 write_sucess = true;
338
339                 rtlhal->last_hmeboxnum = boxnum + 1;
340                 if (rtlhal->last_hmeboxnum == 4)
341                         rtlhal->last_hmeboxnum = 0;
342
343                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
344                          "pHalData->last_hmeboxnum  = %d\n",
345                           rtlhal->last_hmeboxnum);
346         }
347
348         spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
349         rtlhal->h2c_setinprogress = false;
350         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
351
352         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
353 }
354
355 void rtl88e_fill_h2c_cmd(struct ieee80211_hw *hw,
356                          u8 element_id, u32 cmd_len, u8 *cmdbuffer)
357 {
358         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
359         u32 tmp_cmdbuf[2];
360
361         if (!rtlhal->fw_ready) {
362                 WARN_ONCE(true,
363                           "rtl8188ee: error H2C cmd because of Fw download fail!!!\n");
364                 return;
365         }
366
367         memset(tmp_cmdbuf, 0, 8);
368         memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
369         _rtl88e_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
370
371         return;
372 }
373
374 void rtl88e_firmware_selfreset(struct ieee80211_hw *hw)
375 {
376         u8 u1b_tmp;
377         struct rtl_priv *rtlpriv = rtl_priv(hw);
378
379         u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1);
380         rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2))));
381         rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp | BIT(2)));
382         RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
383                  "8051Reset88E(): 8051 reset success\n");
384
385 }
386
387 void rtl88e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
388 {
389         struct rtl_priv *rtlpriv = rtl_priv(hw);
390         u8 u1_h2c_set_pwrmode[H2C_88E_PWEMODE_LENGTH] = { 0 };
391         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
392         u8 rlbm, power_state = 0;
393         RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
394
395         SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
396         rlbm = 0;/*YJ, temp, 120316. FW now not support RLBM=2.*/
397         SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm);
398         SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
399                 (rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1);
400         SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
401                 ppsc->reg_max_lps_awakeintvl);
402         SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
403         if (mode == FW_PS_ACTIVE_MODE)
404                 power_state |= FW_PWR_STATE_ACTIVE;
405         else
406                 power_state |= FW_PWR_STATE_RF_OFF;
407
408         SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
409
410         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
411                       "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
412                       u1_h2c_set_pwrmode, H2C_88E_PWEMODE_LENGTH);
413         rtl88e_fill_h2c_cmd(hw, H2C_88E_SETPWRMODE,
414                             H2C_88E_PWEMODE_LENGTH, u1_h2c_set_pwrmode);
415 }
416
417 void rtl88e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
418 {
419         u8 u1_joinbssrpt_parm[1] = { 0 };
420
421         SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
422
423         rtl88e_fill_h2c_cmd(hw, H2C_88E_JOINBSSRPT, 1, u1_joinbssrpt_parm);
424 }
425
426 void rtl88e_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,
427                                    u8 ap_offload_enable)
428 {
429         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
430         u8 u1_apoffload_parm[H2C_88E_AP_OFFLOAD_LENGTH] = { 0 };
431
432         SET_H2CCMD_AP_OFFLOAD_ON(u1_apoffload_parm, ap_offload_enable);
433         SET_H2CCMD_AP_OFFLOAD_HIDDEN(u1_apoffload_parm, mac->hiddenssid);
434         SET_H2CCMD_AP_OFFLOAD_DENYANY(u1_apoffload_parm, 0);
435
436         rtl88e_fill_h2c_cmd(hw, H2C_88E_AP_OFFLOAD,
437                             H2C_88E_AP_OFFLOAD_LENGTH, u1_apoffload_parm);
438
439 }
440
441 #define BEACON_PG               0 /* ->1 */
442 #define PSPOLL_PG               2
443 #define NULL_PG                 3
444 #define PROBERSP_PG             4 /* ->5 */
445
446 #define TOTAL_RESERVED_PKT_LEN  768
447
448 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
449         /* page 0 beacon */
450         0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
451         0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
452         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
453         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
454         0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
455         0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
456         0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
457         0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
458         0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
459         0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
460         0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
461         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
462         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
463         0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
464         0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
465         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
466
467         /* page 1 beacon */
468         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
469         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
470         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
471         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
472         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
473         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
474         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
475         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
476         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
477         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
478         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
479         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
480         0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
481         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
482         0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
483         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
484
485         /* page 2  ps-poll */
486         0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
487         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
488         0x00, 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         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
492         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
493         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
494         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         0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
499         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
500         0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
501         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
502
503         /* page 3  null */
504         0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
505         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
506         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
507         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
508         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
509         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
510         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
511         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
512         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
513         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
514         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
515         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
516         0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
517         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
518         0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
519         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
520
521         /* page 4  probe_resp */
522         0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
523         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
524         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
525         0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
526         0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
527         0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
528         0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
529         0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
530         0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
531         0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
532         0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
533         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
534         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
535         0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
536         0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
537         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
538
539         /* page 5  probe_resp */
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         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         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
556 };
557
558 void rtl88e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
559 {
560         struct rtl_priv *rtlpriv = rtl_priv(hw);
561         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
562         struct sk_buff *skb = NULL;
563         u32 totalpacketlen;
564         bool rtstatus;
565         u8 u1rsvdpageloc[5] = { 0 };
566         bool b_dlok = false;
567         u8 *beacon;
568         u8 *p_pspoll;
569         u8 *nullfunc;
570         u8 *p_probersp;
571
572         /*---------------------------------------------------------
573          *                      (1) beacon
574          *---------------------------------------------------------
575          */
576         beacon = &reserved_page_packet[BEACON_PG * 128];
577         SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
578         SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
579
580         /*-------------------------------------------------------
581          *                      (2) ps-poll
582          *--------------------------------------------------------
583          */
584         p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
585         SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
586         SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
587         SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
588
589         SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
590
591         /*--------------------------------------------------------
592          *                      (3) null data
593          *---------------------------------------------------------
594          */
595         nullfunc = &reserved_page_packet[NULL_PG * 128];
596         SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
597         SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
598         SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
599
600         SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
601
602         /*---------------------------------------------------------
603          *                      (4) probe response
604          *----------------------------------------------------------
605          */
606         p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
607         SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
608         SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
609         SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
610
611         SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
612
613         totalpacketlen = TOTAL_RESERVED_PKT_LEN;
614
615         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
616                       "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
617                       &reserved_page_packet[0], totalpacketlen);
618         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
619                       "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
620                       u1rsvdpageloc, 3);
621
622         skb = dev_alloc_skb(totalpacketlen);
623         if (!skb)
624                 return;
625         skb_put_data(skb, &reserved_page_packet, totalpacketlen);
626
627         rtstatus = rtl_cmd_send_packet(hw, skb);
628
629         if (rtstatus)
630                 b_dlok = true;
631
632         if (b_dlok) {
633                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
634                          "Set RSVD page location to Fw.\n");
635                 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
636                               "H2C_RSVDPAGE:\n", u1rsvdpageloc, 3);
637                 rtl88e_fill_h2c_cmd(hw, H2C_88E_RSVDPAGE,
638                                     sizeof(u1rsvdpageloc), u1rsvdpageloc);
639         } else
640                 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
641                          "Set RSVD page location to Fw FAIL!!!!!!.\n");
642 }
643
644 /*Should check FW support p2p or not.*/
645 static void rtl88e_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
646 {
647         u8 u1_ctwindow_period[1] = { ctwindow};
648
649         rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
650
651 }
652
653 void rtl88e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
654 {
655         struct rtl_priv *rtlpriv = rtl_priv(hw);
656         struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
657         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
658         struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
659         struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
660         u8      i;
661         u16     ctwindow;
662         u32     start_time, tsf_low;
663
664         switch (p2p_ps_state) {
665         case P2P_PS_DISABLE:
666                 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
667                 memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
668                 break;
669         case P2P_PS_ENABLE:
670                 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
671                 /* update CTWindow value. */
672                 if (p2pinfo->ctwindow > 0) {
673                         p2p_ps_offload->ctwindow_en = 1;
674                         ctwindow = p2pinfo->ctwindow;
675                         rtl88e_set_p2p_ctw_period_cmd(hw, ctwindow);
676                 }
677
678                 /* hw only support 2 set of NoA */
679                 for (i = 0 ; i < p2pinfo->noa_num; i++) {
680                         /* To control the register setting for which NOA*/
681                         rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
682                         if (i == 0)
683                                 p2p_ps_offload->noa0_en = 1;
684                         else
685                                 p2p_ps_offload->noa1_en = 1;
686
687                         /* config P2P NoA Descriptor Register */
688                         rtl_write_dword(rtlpriv, 0x5E0,
689                                         p2pinfo->noa_duration[i]);
690                         rtl_write_dword(rtlpriv, 0x5E4,
691                                         p2pinfo->noa_interval[i]);
692
693                         /*Get Current TSF value */
694                         tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
695
696                         start_time = p2pinfo->noa_start_time[i];
697                         if (p2pinfo->noa_count_type[i] != 1) {
698                                 while (start_time <= (tsf_low+(50*1024))) {
699                                         start_time += p2pinfo->noa_interval[i];
700                                         if (p2pinfo->noa_count_type[i] != 255)
701                                                 p2pinfo->noa_count_type[i]--;
702                                 }
703                         }
704                         rtl_write_dword(rtlpriv, 0x5E8, start_time);
705                         rtl_write_dword(rtlpriv, 0x5EC,
706                                         p2pinfo->noa_count_type[i]);
707                 }
708
709                 if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
710                         /* rst p2p circuit */
711                         rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
712
713                         p2p_ps_offload->offload_en = 1;
714
715                         if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
716                                 p2p_ps_offload->role = 1;
717                                 p2p_ps_offload->allstasleep = -1;
718                         } else {
719                                 p2p_ps_offload->role = 0;
720                         }
721
722                         p2p_ps_offload->discovery = 0;
723                 }
724                 break;
725         case P2P_PS_SCAN:
726                 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
727                 p2p_ps_offload->discovery = 1;
728                 break;
729         case P2P_PS_SCAN_DONE:
730                 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
731                 p2p_ps_offload->discovery = 0;
732                 p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
733                 break;
734         default:
735                 break;
736         }
737
738         rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_OFFLOAD, 1,
739                             (u8 *)p2p_ps_offload);
740
741 }