GNU Linux-libre 4.4.288-gnu1
[releases.git] / drivers / net / wireless / realtek / rtlwifi / rtl8192ee / fw.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2014  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 #include "dm.h"
34
35 static void _rtl92ee_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                 rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x05);
42
43                 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
44                 rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
45         } else {
46                 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
47                 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
48         }
49 }
50
51 static void _rtl92ee_fw_block_write(struct ieee80211_hw *hw,
52                                     const u8 *buffer, u32 size)
53 {
54         struct rtl_priv *rtlpriv = rtl_priv(hw);
55         u32 blocksize = sizeof(u32);
56         u8 *bufferptr = (u8 *)buffer;
57         u32 *pu4byteptr = (u32 *)buffer;
58         u32 i, offset, blockcount, remainsize;
59
60         blockcount = size / blocksize;
61         remainsize = size % blocksize;
62
63         for (i = 0; i < blockcount; i++) {
64                 offset = i * blocksize;
65                 rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
66                                 *(pu4byteptr + i));
67         }
68
69         if (remainsize) {
70                 offset = blockcount * blocksize;
71                 bufferptr += offset;
72                 for (i = 0; i < remainsize; i++) {
73                         rtl_write_byte(rtlpriv,
74                                        (FW_8192C_START_ADDRESS + offset + i),
75                                        *(bufferptr + i));
76                 }
77         }
78 }
79
80 static void _rtl92ee_fw_page_write(struct ieee80211_hw *hw, u32 page,
81                                    const u8 *buffer, u32 size)
82 {
83         struct rtl_priv *rtlpriv = rtl_priv(hw);
84         u8 value8;
85         u8 u8page = (u8)(page & 0x07);
86
87         value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
88         rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
89
90         _rtl92ee_fw_block_write(hw, buffer, size);
91 }
92
93 static void _rtl92ee_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
94 {
95         u32 fwlen = *pfwlen;
96         u8 remain = (u8)(fwlen % 4);
97
98         remain = (remain == 0) ? 0 : (4 - remain);
99
100         while (remain > 0) {
101                 pfwbuf[fwlen] = 0;
102                 fwlen++;
103                 remain--;
104         }
105
106         *pfwlen = fwlen;
107 }
108
109 static void _rtl92ee_write_fw(struct ieee80211_hw *hw,
110                               enum version_8192e version,
111                               u8 *buffer, u32 size)
112 {
113         struct rtl_priv *rtlpriv = rtl_priv(hw);
114         u8 *bufferptr = (u8 *)buffer;
115         u32 pagenums, remainsize;
116         u32 page, offset;
117
118         RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "FW size is %d bytes,\n", size);
119
120         _rtl92ee_fill_dummy(bufferptr, &size);
121
122         pagenums = size / FW_8192C_PAGE_SIZE;
123         remainsize = size % FW_8192C_PAGE_SIZE;
124
125         if (pagenums > 8) {
126                 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
127                          "Page numbers should not greater then 8\n");
128         }
129
130         for (page = 0; page < pagenums; page++) {
131                 offset = page * FW_8192C_PAGE_SIZE;
132                 _rtl92ee_fw_page_write(hw, page, (bufferptr + offset),
133                                        FW_8192C_PAGE_SIZE);
134                 udelay(2);
135         }
136
137         if (remainsize) {
138                 offset = pagenums * FW_8192C_PAGE_SIZE;
139                 page = pagenums;
140                 _rtl92ee_fw_page_write(hw, page, (bufferptr + offset),
141                                        remainsize);
142         }
143 }
144
145 static int _rtl92ee_fw_free_to_go(struct ieee80211_hw *hw)
146 {
147         struct rtl_priv *rtlpriv = rtl_priv(hw);
148         int err = -EIO;
149         u32 counter = 0;
150         u32 value32;
151
152         do {
153                 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
154         } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
155                  (!(value32 & FWDL_CHKSUM_RPT)));
156
157         if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
158                 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
159                          "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
160                           value32);
161                 goto exit;
162         }
163
164         RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
165                  "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
166
167         value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
168         value32 |= MCUFWDL_RDY;
169         value32 &= ~WINTINI_RDY;
170         rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
171
172         rtl92ee_firmware_selfreset(hw);
173         counter = 0;
174
175         do {
176                 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
177                 if (value32 & WINTINI_RDY) {
178                         RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD ,
179                                  "Polling FW ready success!! REG_MCUFWDL:0x%08x. count = %d\n",
180                                  value32, counter);
181                         err = 0;
182                         goto exit;
183                 }
184
185                 udelay(FW_8192C_POLLING_DELAY*10);
186
187         } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
188
189         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
190                  "Polling FW ready fail!! REG_MCUFWDL:0x%08x. count = %d\n",
191                  value32, counter);
192
193 exit:
194         return err;
195 }
196
197 int rtl92ee_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)
198 {
199         struct rtl_priv *rtlpriv = rtl_priv(hw);
200         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
201         struct rtlwifi_firmware_header *pfwheader;
202         u8 *pfwdata;
203         u32 fwsize;
204         int err;
205         enum version_8192e version = rtlhal->version;
206
207         if (!rtlhal->pfirmware)
208                 return 1;
209
210         pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware;
211         rtlhal->fw_version = le16_to_cpu(pfwheader->version);
212         rtlhal->fw_subversion = pfwheader->subversion;
213         pfwdata = (u8 *)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         } else {
227                 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
228                          "Firmware no Header, Signature(%#x)\n",
229                           pfwheader->signature);
230         }
231
232         if (rtlhal->mac_func_enable) {
233                 if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
234                         rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
235                         rtl92ee_firmware_selfreset(hw);
236                 }
237         }
238         _rtl92ee_enable_fw_download(hw, true);
239         _rtl92ee_write_fw(hw, version, pfwdata, fwsize);
240         _rtl92ee_enable_fw_download(hw, false);
241
242         err = _rtl92ee_fw_free_to_go(hw);
243         if (err) {
244                 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
245                          "Firmware is not ready to run!\n");
246         } else {
247                 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD ,
248                          "Firmware is ready to run!\n");
249         }
250
251         return 0;
252 }
253
254 static bool _rtl92ee_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
255 {
256         struct rtl_priv *rtlpriv = rtl_priv(hw);
257         u8 val_hmetfr;
258         bool result = false;
259
260         val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
261         if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
262                 result = true;
263         return result;
264 }
265
266 static void _rtl92ee_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id,
267                                       u32 cmd_len, u8 *cmdbuffer)
268 {
269         struct rtl_priv *rtlpriv = rtl_priv(hw);
270         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
271         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
272         u8 boxnum;
273         u16 box_reg = 0, box_extreg = 0;
274         u8 u1b_tmp;
275         bool isfw_read = false;
276         u8 buf_index = 0;
277         bool bwrite_sucess = false;
278         u8 wait_h2c_limmit = 100;
279         u8 boxcontent[4], boxextcontent[4];
280         u32 h2c_waitcounter = 0;
281         unsigned long flag;
282         u8 idx;
283
284         if (ppsc->dot11_psmode != EACTIVE ||
285             ppsc->inactive_pwrstate == ERFOFF) {
286                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
287                          "FillH2CCommand8192E(): Return because RF is off!!!\n");
288                 return;
289         }
290
291         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD , "come in\n");
292
293         /* 1. Prevent race condition in setting H2C cmd.
294          * (copy from MgntActSet_RF_State().)
295          */
296         while (true) {
297                 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
298                 if (rtlhal->h2c_setinprogress) {
299                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
300                                  "H2C set in progress! Wait to set..element_id(%d).\n",
301                                   element_id);
302
303                         while (rtlhal->h2c_setinprogress) {
304                                 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
305                                                        flag);
306                                 h2c_waitcounter++;
307                                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
308                                          "Wait 100 us (%d times)...\n",
309                                           h2c_waitcounter);
310                                 udelay(100);
311
312                                 if (h2c_waitcounter > 1000)
313                                         return;
314                                 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
315                                                   flag);
316                         }
317                         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
318                 } else {
319                         rtlhal->h2c_setinprogress = true;
320                         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
321                         break;
322                 }
323         }
324
325         while (!bwrite_sucess) {
326                 /* 2. Find the last BOX number which has been writen. */
327                 boxnum = rtlhal->last_hmeboxnum;
328                 switch (boxnum) {
329                 case 0:
330                         box_reg = REG_HMEBOX_0;
331                         box_extreg = REG_HMEBOX_EXT_0;
332                         break;
333                 case 1:
334                         box_reg = REG_HMEBOX_1;
335                         box_extreg = REG_HMEBOX_EXT_1;
336                         break;
337                 case 2:
338                         box_reg = REG_HMEBOX_2;
339                         box_extreg = REG_HMEBOX_EXT_2;
340                         break;
341                 case 3:
342                         box_reg = REG_HMEBOX_3;
343                         box_extreg = REG_HMEBOX_EXT_3;
344                         break;
345                 default:
346                         RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
347                                  "switch case not process\n");
348                         break;
349                 }
350
351                 /* 3. Check if the box content is empty. */
352                 isfw_read = false;
353                 u1b_tmp = rtl_read_byte(rtlpriv, REG_CR);
354
355                 if (u1b_tmp != 0xea) {
356                         isfw_read = true;
357                 } else {
358                         if (rtl_read_byte(rtlpriv, REG_TXDMA_STATUS) == 0xea ||
359                             rtl_read_byte(rtlpriv, REG_TXPKT_EMPTY) == 0xea)
360                                 rtl_write_byte(rtlpriv, REG_SYS_CFG1 + 3, 0xff);
361                 }
362
363                 if (isfw_read) {
364                         wait_h2c_limmit = 100;
365                         isfw_read = _rtl92ee_check_fw_read_last_h2c(hw, boxnum);
366                         while (!isfw_read) {
367                                 wait_h2c_limmit--;
368                                 if (wait_h2c_limmit == 0) {
369                                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
370                                                  "Waiting too long for FW read clear HMEBox(%d)!!!\n",
371                                                  boxnum);
372                                         break;
373                                 }
374                                 udelay(10);
375                                 isfw_read =
376                                   _rtl92ee_check_fw_read_last_h2c(hw, boxnum);
377                                 u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
378                                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
379                                          "Waiting for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
380                                          boxnum, u1b_tmp);
381                         }
382                 }
383
384                 /* If Fw has not read the last
385                  * H2C cmd, break and give up this H2C.
386                  */
387                 if (!isfw_read) {
388                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
389                                  "Write H2C reg BOX[%d] fail,Fw don't read.\n",
390                                  boxnum);
391                         break;
392                 }
393                 /* 4. Fill the H2C cmd into box */
394                 memset(boxcontent, 0, sizeof(boxcontent));
395                 memset(boxextcontent, 0, sizeof(boxextcontent));
396                 boxcontent[0] = element_id;
397                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
398                          "Write element_id box_reg(%4x) = %2x\n",
399                           box_reg, element_id);
400
401                 switch (cmd_len) {
402                 case 1:
403                 case 2:
404                 case 3:
405                         /*boxcontent[0] &= ~(BIT(7));*/
406                         memcpy((u8 *)(boxcontent) + 1,
407                                cmdbuffer + buf_index, cmd_len);
408
409                         for (idx = 0; idx < 4; idx++) {
410                                 rtl_write_byte(rtlpriv, box_reg + idx,
411                                                boxcontent[idx]);
412                         }
413                         break;
414                 case 4:
415                 case 5:
416                 case 6:
417                 case 7:
418                         /*boxcontent[0] |= (BIT(7));*/
419                         memcpy((u8 *)(boxextcontent),
420                                cmdbuffer + buf_index+3, cmd_len-3);
421                         memcpy((u8 *)(boxcontent) + 1,
422                                cmdbuffer + buf_index, 3);
423
424                         for (idx = 0; idx < 4; idx++) {
425                                 rtl_write_byte(rtlpriv, box_extreg + idx,
426                                                boxextcontent[idx]);
427                         }
428
429                         for (idx = 0; idx < 4; idx++) {
430                                 rtl_write_byte(rtlpriv, box_reg + idx,
431                                                boxcontent[idx]);
432                         }
433                         break;
434                 default:
435                         RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
436                                  "switch case not process\n");
437                         break;
438                 }
439
440                 bwrite_sucess = true;
441
442                 rtlhal->last_hmeboxnum = boxnum + 1;
443                 if (rtlhal->last_hmeboxnum == 4)
444                         rtlhal->last_hmeboxnum = 0;
445
446                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
447                          "pHalData->last_hmeboxnum  = %d\n",
448                           rtlhal->last_hmeboxnum);
449         }
450
451         spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
452         rtlhal->h2c_setinprogress = false;
453         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
454
455         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD , "go out\n");
456 }
457
458 void rtl92ee_fill_h2c_cmd(struct ieee80211_hw *hw,
459                           u8 element_id, u32 cmd_len, u8 *cmdbuffer)
460 {
461         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
462         u32 tmp_cmdbuf[2];
463
464         if (!rtlhal->fw_ready) {
465                 RT_ASSERT(false,
466                           "return H2C cmd because of Fw download fail!!!\n");
467                 return;
468         }
469
470         memset(tmp_cmdbuf, 0, 8);
471         memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
472         _rtl92ee_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
473 }
474
475 void rtl92ee_firmware_selfreset(struct ieee80211_hw *hw)
476 {
477         u8 u1b_tmp;
478         struct rtl_priv *rtlpriv = rtl_priv(hw);
479
480         u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
481         rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0))));
482
483         u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
484         rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
485
486         udelay(50);
487
488         u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
489         rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp | BIT(0)));
490
491         u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
492         rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp | BIT(2)));
493
494         RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD ,
495                  "  _8051Reset92E(): 8051 reset success .\n");
496 }
497
498 void rtl92ee_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
499 {
500         struct rtl_priv *rtlpriv = rtl_priv(hw);
501         u8 u1_h2c_set_pwrmode[H2C_92E_PWEMODE_LENGTH] = { 0 };
502         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
503         u8 rlbm , power_state = 0;
504
505         RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD , "FW LPS mode = %d\n", mode);
506
507         SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
508         rlbm = 0;/*YJ,temp,120316. FW now not support RLBM=2.*/
509         SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm);
510         SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
511                                          (rtlpriv->mac80211.p2p) ?
512                                          ppsc->smart_ps : 1);
513         SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
514                                                ppsc->reg_max_lps_awakeintvl);
515         SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
516         if (mode == FW_PS_ACTIVE_MODE)
517                 power_state |= FW_PWR_STATE_ACTIVE;
518         else
519                 power_state |= FW_PWR_STATE_RF_OFF;
520         SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
521
522         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
523                       "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
524                       u1_h2c_set_pwrmode, H2C_92E_PWEMODE_LENGTH);
525         rtl92ee_fill_h2c_cmd(hw, H2C_92E_SETPWRMODE, H2C_92E_PWEMODE_LENGTH,
526                              u1_h2c_set_pwrmode);
527 }
528
529 void rtl92ee_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw, u8 mstatus)
530 {
531         u8 parm[3] = { 0 , 0 , 0 };
532         /* parm[0]: bit0=0-->Disconnect, bit0=1-->Connect
533          *          bit1=0-->update Media Status to MACID
534          *          bit1=1-->update Media Status from MACID to MACID_End
535          * parm[1]: MACID, if this is INFRA_STA, MacID = 0
536          * parm[2]: MACID_End
537          */
538
539         SET_H2CCMD_MSRRPT_PARM_OPMODE(parm, mstatus);
540         SET_H2CCMD_MSRRPT_PARM_MACID_IND(parm, 0);
541
542         rtl92ee_fill_h2c_cmd(hw, H2C_92E_MSRRPT, 3, parm);
543 }
544
545 #define BEACON_PG               0 /* ->1 */
546 #define PSPOLL_PG               2
547 #define NULL_PG                 3
548 #define PROBERSP_PG             4 /* ->5 */
549
550 #define TOTAL_RESERVED_PKT_LEN  768
551
552 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
553         /* page 0 beacon */
554         0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
555         0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
556         0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x20, 0x00,
557         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
558         0x64, 0x00, 0x10, 0x04, 0x00, 0x05, 0x54, 0x65,
559         0x73, 0x74, 0x32, 0x01, 0x08, 0x82, 0x84, 0x0B,
560         0x16, 0x24, 0x30, 0x48, 0x6C, 0x03, 0x01, 0x06,
561         0x06, 0x02, 0x00, 0x00, 0x2A, 0x01, 0x02, 0x32,
562         0x04, 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C,
563         0x09, 0x03, 0xFF, 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, 0x3D, 0x00, 0xDD, 0x07, 0x00, 0xE0, 0x4C,
567         0x02, 0x02, 0x00, 0x00, 0xDD, 0x18, 0x00, 0x50,
568         0xF2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04,
569         0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, 0x01, 0x00,
570
571         /* page 1 beacon */
572         0x00, 0x50, 0xF2, 0x02, 0x00, 0x00, 0x00, 0x00,
573         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
574         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
575         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
576         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
577         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
578         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
579         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
580         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
581         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
582         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
583         0x10, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
584         0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 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
589         /* page 2  ps-poll */
590         0xA4, 0x10, 0x01, 0xC0, 0xEC, 0x1A, 0x59, 0x0B,
591         0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
592         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
593         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
594         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
595         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
596         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
597         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
599         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
600         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
601         0x18, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
602         0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
603         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
604         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
605         0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
606
607         /* page 3  null */
608         0x48, 0x01, 0x00, 0x00, 0xEC, 0x1A, 0x59, 0x0B,
609         0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
610         0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x00, 0x00,
611         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
612         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
613         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
614         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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         0x72, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
620         0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
621         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
622         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
623         0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
624
625         /* page 4  probe_resp */
626         0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
627         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
628         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
629         0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
630         0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
631         0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
632         0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
633         0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
634         0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
635         0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
636         0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
637         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
638         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
639         0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
640         0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
641         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
642
643         /* page 5  probe_resp */
644         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
645         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
646         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
647         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
648         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
649         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
650         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
651         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
652         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
653         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
654         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
655         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
656         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
657         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
658         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
659         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
660 };
661
662 void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
663 {
664         struct rtl_priv *rtlpriv = rtl_priv(hw);
665         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
666         struct sk_buff *skb = NULL;
667         bool rtstatus;
668         u32 totalpacketlen;
669         u8 u1rsvdpageloc[5] = { 0 };
670         bool b_dlok = false;
671
672         u8 *beacon;
673         u8 *p_pspoll;
674         u8 *nullfunc;
675         u8 *p_probersp;
676         /*---------------------------------------------------------
677          *                      (1) beacon
678          *---------------------------------------------------------
679          */
680         beacon = &reserved_page_packet[BEACON_PG * 128];
681         SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
682         SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
683
684         /*-------------------------------------------------------
685          *                      (2) ps-poll
686          *--------------------------------------------------------
687          */
688         p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
689         SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
690         SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
691         SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
692
693         SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
694
695         /*--------------------------------------------------------
696          *                      (3) null data
697          *---------------------------------------------------------
698          */
699         nullfunc = &reserved_page_packet[NULL_PG * 128];
700         SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
701         SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
702         SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
703
704         SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
705
706         /*---------------------------------------------------------
707          *                      (4) probe response
708          *----------------------------------------------------------
709          */
710         p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
711         SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
712         SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
713         SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
714
715         SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
716
717         totalpacketlen = TOTAL_RESERVED_PKT_LEN;
718
719         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD ,
720                       "rtl92ee_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
721                       &reserved_page_packet[0], totalpacketlen);
722         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD ,
723                       "rtl92ee_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
724                       u1rsvdpageloc, 3);
725
726         skb = dev_alloc_skb(totalpacketlen);
727         memcpy((u8 *)skb_put(skb, totalpacketlen),
728                &reserved_page_packet, totalpacketlen);
729
730         rtstatus = rtl_cmd_send_packet(hw, skb);
731         if (rtstatus)
732                 b_dlok = true;
733
734         if (b_dlok) {
735                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD ,
736                          "Set RSVD page location to Fw.\n");
737                 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD ,
738                               "H2C_RSVDPAGE:\n", u1rsvdpageloc, 3);
739                 rtl92ee_fill_h2c_cmd(hw, H2C_92E_RSVDPAGE,
740                                      sizeof(u1rsvdpageloc), u1rsvdpageloc);
741         } else {
742                 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
743                          "Set RSVD page location to Fw FAIL!!!!!!.\n");
744         }
745 }
746
747 /*Shoud check FW support p2p or not.*/
748 static void rtl92ee_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
749 {
750         u8 u1_ctwindow_period[1] = {ctwindow};
751
752         rtl92ee_fill_h2c_cmd(hw, H2C_92E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
753 }
754
755 void rtl92ee_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
756 {
757         struct rtl_priv *rtlpriv = rtl_priv(hw);
758         struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
759         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
760         struct rtl_p2p_ps_info *p2pinfo = &rtlps->p2p_ps_info;
761         struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
762         u8 i;
763         u16 ctwindow;
764         u32 start_time, tsf_low;
765
766         switch (p2p_ps_state) {
767         case P2P_PS_DISABLE:
768                 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_DISABLE\n");
769                 memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
770                 break;
771         case P2P_PS_ENABLE:
772                 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_ENABLE\n");
773                 /* update CTWindow value. */
774                 if (p2pinfo->ctwindow > 0) {
775                         p2p_ps_offload->ctwindow_en = 1;
776                         ctwindow = p2pinfo->ctwindow;
777                         rtl92ee_set_p2p_ctw_period_cmd(hw, ctwindow);
778                 }
779                 /* hw only support 2 set of NoA */
780                 for (i = 0 ; i < p2pinfo->noa_num ; i++) {
781                         /* To control the register setting for which NOA*/
782                         rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
783                         if (i == 0)
784                                 p2p_ps_offload->noa0_en = 1;
785                         else
786                                 p2p_ps_offload->noa1_en = 1;
787                         /* config P2P NoA Descriptor Register */
788                         rtl_write_dword(rtlpriv, 0x5E0,
789                                         p2pinfo->noa_duration[i]);
790                         rtl_write_dword(rtlpriv, 0x5E4,
791                                         p2pinfo->noa_interval[i]);
792
793                         /*Get Current TSF value */
794                         tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
795
796                         start_time = p2pinfo->noa_start_time[i];
797                         if (p2pinfo->noa_count_type[i] != 1) {
798                                 while (start_time <= (tsf_low + (50 * 1024))) {
799                                         start_time += p2pinfo->noa_interval[i];
800                                         if (p2pinfo->noa_count_type[i] != 255)
801                                                 p2pinfo->noa_count_type[i]--;
802                                 }
803                         }
804                         rtl_write_dword(rtlpriv, 0x5E8, start_time);
805                         rtl_write_dword(rtlpriv, 0x5EC,
806                                         p2pinfo->noa_count_type[i]);
807                 }
808                 if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
809                         /* rst p2p circuit */
810                         rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
811                         p2p_ps_offload->offload_en = 1;
812
813                         if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
814                                 p2p_ps_offload->role = 1;
815                                 p2p_ps_offload->allstasleep = 0;
816                         } else {
817                                 p2p_ps_offload->role = 0;
818                         }
819                         p2p_ps_offload->discovery = 0;
820                 }
821                 break;
822         case P2P_PS_SCAN:
823                 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_SCAN\n");
824                 p2p_ps_offload->discovery = 1;
825                 break;
826         case P2P_PS_SCAN_DONE:
827                 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_SCAN_DONE\n");
828                 p2p_ps_offload->discovery = 0;
829                 p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
830                 break;
831         default:
832                 break;
833         }
834         rtl92ee_fill_h2c_cmd(hw, H2C_92E_P2P_PS_OFFLOAD, 1,
835                              (u8 *)p2p_ps_offload);
836 }
837
838 static void _rtl92ee_c2h_ra_report_handler(struct ieee80211_hw *hw,
839                                            u8 *cmd_buf, u8 cmd_len)
840 {
841         u8 rate = cmd_buf[0] & 0x3F;
842         bool collision_state = cmd_buf[3] & BIT(0);
843
844         rtl92ee_dm_dynamic_arfb_select(hw, rate, collision_state);
845 }
846
847 static void _rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id,
848                                          u8 c2h_cmd_len, u8 *tmp_buf)
849 {
850         struct rtl_priv *rtlpriv = rtl_priv(hw);
851
852         switch (c2h_cmd_id) {
853         case C2H_8192E_DBG:
854                 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
855                          "[C2H], C2H_8723BE_DBG!!\n");
856                 break;
857         case C2H_8192E_TXBF:
858                 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
859                          "[C2H], C2H_8192E_TXBF!!\n");
860                 break;
861         case C2H_8192E_TX_REPORT:
862                 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE ,
863                          "[C2H], C2H_8723BE_TX_REPORT!\n");
864                 break;
865         case C2H_8192E_BT_INFO:
866                 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
867                          "[C2H], C2H_8723BE_BT_INFO!!\n");
868                 rtlpriv->btcoexist.btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf,
869                                                               c2h_cmd_len);
870                 break;
871         case C2H_8192E_BT_MP:
872                 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
873                          "[C2H], C2H_8723BE_BT_MP!!\n");
874                 break;
875         case C2H_8192E_RA_RPT:
876                 _rtl92ee_c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len);
877                 break;
878         default:
879                 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
880                          "[C2H], Unknown packet!! CmdId(%#X)!\n", c2h_cmd_id);
881                 break;
882         }
883 }
884
885 void rtl92ee_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len)
886 {
887         struct rtl_priv *rtlpriv = rtl_priv(hw);
888         u8 c2h_cmd_id = 0, c2h_cmd_seq = 0, c2h_cmd_len = 0;
889         u8 *tmp_buf = NULL;
890
891         c2h_cmd_id = buffer[0];
892         c2h_cmd_seq = buffer[1];
893         c2h_cmd_len = len - 2;
894         tmp_buf = buffer + 2;
895
896         RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
897                  "[C2H packet], c2hCmdId=0x%x, c2hCmdSeq=0x%x, c2hCmdLen=%d\n",
898                  c2h_cmd_id, c2h_cmd_seq, c2h_cmd_len);
899
900         RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_TRACE,
901                       "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len);
902
903         _rtl92ee_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf);
904 }