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