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