]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
[karo-tx-linux.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
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         b_dlok = true;
731
732         if (b_dlok) {
733                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD ,
734                          "Set RSVD page location to Fw.\n");
735                 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD ,
736                               "H2C_RSVDPAGE:\n", u1rsvdpageloc, 3);
737                 rtl92ee_fill_h2c_cmd(hw, H2C_92E_RSVDPAGE,
738                                      sizeof(u1rsvdpageloc), u1rsvdpageloc);
739         } else {
740                 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
741                          "Set RSVD page location to Fw FAIL!!!!!!.\n");
742         }
743 }
744
745 /*Shoud check FW support p2p or not.*/
746 static void rtl92ee_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
747 {
748         u8 u1_ctwindow_period[1] = {ctwindow};
749
750         rtl92ee_fill_h2c_cmd(hw, H2C_92E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
751 }
752
753 void rtl92ee_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
754 {
755         struct rtl_priv *rtlpriv = rtl_priv(hw);
756         struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
757         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
758         struct rtl_p2p_ps_info *p2pinfo = &rtlps->p2p_ps_info;
759         struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
760         u8 i;
761         u16 ctwindow;
762         u32 start_time, tsf_low;
763
764         switch (p2p_ps_state) {
765         case P2P_PS_DISABLE:
766                 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_DISABLE\n");
767                 memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
768                 break;
769         case P2P_PS_ENABLE:
770                 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_ENABLE\n");
771                 /* update CTWindow value. */
772                 if (p2pinfo->ctwindow > 0) {
773                         p2p_ps_offload->ctwindow_en = 1;
774                         ctwindow = p2pinfo->ctwindow;
775                         rtl92ee_set_p2p_ctw_period_cmd(hw, ctwindow);
776                 }
777                 /* hw only support 2 set of NoA */
778                 for (i = 0 ; i < p2pinfo->noa_num ; i++) {
779                         /* To control the register setting for which NOA*/
780                         rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
781                         if (i == 0)
782                                 p2p_ps_offload->noa0_en = 1;
783                         else
784                                 p2p_ps_offload->noa1_en = 1;
785                         /* config P2P NoA Descriptor Register */
786                         rtl_write_dword(rtlpriv, 0x5E0,
787                                         p2pinfo->noa_duration[i]);
788                         rtl_write_dword(rtlpriv, 0x5E4,
789                                         p2pinfo->noa_interval[i]);
790
791                         /*Get Current TSF value */
792                         tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
793
794                         start_time = p2pinfo->noa_start_time[i];
795                         if (p2pinfo->noa_count_type[i] != 1) {
796                                 while (start_time <= (tsf_low + (50 * 1024))) {
797                                         start_time += p2pinfo->noa_interval[i];
798                                         if (p2pinfo->noa_count_type[i] != 255)
799                                                 p2pinfo->noa_count_type[i]--;
800                                 }
801                         }
802                         rtl_write_dword(rtlpriv, 0x5E8, start_time);
803                         rtl_write_dword(rtlpriv, 0x5EC,
804                                         p2pinfo->noa_count_type[i]);
805                 }
806                 if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
807                         /* rst p2p circuit */
808                         rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
809                         p2p_ps_offload->offload_en = 1;
810
811                         if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
812                                 p2p_ps_offload->role = 1;
813                                 p2p_ps_offload->allstasleep = 0;
814                         } else {
815                                 p2p_ps_offload->role = 0;
816                         }
817                         p2p_ps_offload->discovery = 0;
818                 }
819                 break;
820         case P2P_PS_SCAN:
821                 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_SCAN\n");
822                 p2p_ps_offload->discovery = 1;
823                 break;
824         case P2P_PS_SCAN_DONE:
825                 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_SCAN_DONE\n");
826                 p2p_ps_offload->discovery = 0;
827                 p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
828                 break;
829         default:
830                 break;
831         }
832         rtl92ee_fill_h2c_cmd(hw, H2C_92E_P2P_PS_OFFLOAD, 1,
833                              (u8 *)p2p_ps_offload);
834 }
835
836 static void _rtl92ee_c2h_ra_report_handler(struct ieee80211_hw *hw,
837                                            u8 *cmd_buf, u8 cmd_len)
838 {
839         u8 rate = cmd_buf[0] & 0x3F;
840         bool collision_state = cmd_buf[3] & BIT(0);
841
842         rtl92ee_dm_dynamic_arfb_select(hw, rate, collision_state);
843 }
844
845 static void _rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id,
846                                          u8 c2h_cmd_len, u8 *tmp_buf)
847 {
848         struct rtl_priv *rtlpriv = rtl_priv(hw);
849
850         switch (c2h_cmd_id) {
851         case C2H_8192E_DBG:
852                 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
853                          "[C2H], C2H_8723BE_DBG!!\n");
854                 break;
855         case C2H_8192E_TXBF:
856                 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
857                          "[C2H], C2H_8192E_TXBF!!\n");
858                 break;
859         case C2H_8192E_TX_REPORT:
860                 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE ,
861                          "[C2H], C2H_8723BE_TX_REPORT!\n");
862                 break;
863         case C2H_8192E_BT_INFO:
864                 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
865                          "[C2H], C2H_8723BE_BT_INFO!!\n");
866                 rtlpriv->btcoexist.btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf,
867                                                               c2h_cmd_len);
868                 break;
869         case C2H_8192E_BT_MP:
870                 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
871                          "[C2H], C2H_8723BE_BT_MP!!\n");
872                 break;
873         case C2H_8192E_RA_RPT:
874                 _rtl92ee_c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len);
875                 break;
876         default:
877                 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
878                          "[C2H], Unknown packet!! CmdId(%#X)!\n", c2h_cmd_id);
879                 break;
880         }
881 }
882
883 void rtl92ee_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len)
884 {
885         struct rtl_priv *rtlpriv = rtl_priv(hw);
886         u8 c2h_cmd_id = 0, c2h_cmd_seq = 0, c2h_cmd_len = 0;
887         u8 *tmp_buf = NULL;
888
889         c2h_cmd_id = buffer[0];
890         c2h_cmd_seq = buffer[1];
891         c2h_cmd_len = len - 2;
892         tmp_buf = buffer + 2;
893
894         RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
895                  "[C2H packet], c2hCmdId=0x%x, c2hCmdSeq=0x%x, c2hCmdLen=%d\n",
896                  c2h_cmd_id, c2h_cmd_seq, c2h_cmd_len);
897
898         RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_TRACE,
899                       "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len);
900
901         _rtl92ee_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf);
902 }