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