]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/net/wireless/realtek/rtlwifi/rtl8192c/fw_common.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
[karo-tx-linux.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 "../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 rtlwifi_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 rtlwifi_firmware_header *)rtlhal->pfirmware;
234         pfwdata = (u8 *)rtlhal->pfirmware;
235         fwsize = rtlhal->fwsize;
236         if (IS_FW_HEADER_EXIST(pfwheader)) {
237                 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
238                          "Firmware Version(%d), Signature(%#x),Size(%d)\n",
239                           pfwheader->version, pfwheader->signature,
240                           (int)sizeof(struct rtlwifi_firmware_header));
241
242                 rtlhal->fw_version = le16_to_cpu(pfwheader->version);
243                 rtlhal->fw_subversion = pfwheader->subversion;
244                 pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header);
245                 fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);
246         }
247
248         _rtl92c_enable_fw_download(hw, true);
249         _rtl92c_write_fw(hw, version, pfwdata, fwsize);
250         _rtl92c_enable_fw_download(hw, false);
251
252         err = _rtl92c_fw_free_to_go(hw);
253         if (err) {
254                 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
255                          "Firmware is not ready to run!\n");
256         } else {
257                 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
258                          "Firmware is ready to run!\n");
259         }
260
261         return 0;
262 }
263 EXPORT_SYMBOL(rtl92c_download_fw);
264
265 static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
266 {
267         struct rtl_priv *rtlpriv = rtl_priv(hw);
268         u8 val_hmetfr, val_mcutst_1;
269         bool result = false;
270
271         val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
272         val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
273
274         if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
275                 result = true;
276         return result;
277 }
278
279 static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
280                               u8 element_id, u32 cmd_len, u8 *cmdbuffer)
281 {
282         struct rtl_priv *rtlpriv = rtl_priv(hw);
283         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
284         u8 boxnum;
285         u16 box_reg = 0, box_extreg = 0;
286         u8 u1b_tmp;
287         bool isfw_read = false;
288         u8 buf_index = 0;
289         bool bwrite_sucess = false;
290         u8 wait_h2c_limmit = 100;
291         u8 wait_writeh2c_limmit = 100;
292         u8 boxcontent[4], boxextcontent[2];
293         u32 h2c_waitcounter = 0;
294         unsigned long flag;
295         u8 idx;
296
297         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
298
299         while (true) {
300                 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
301                 if (rtlhal->h2c_setinprogress) {
302                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
303                                  "H2C set in progress! Wait to set..element_id(%d).\n",
304                                  element_id);
305                         while (rtlhal->h2c_setinprogress) {
306                                 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
307                                                        flag);
308                                 h2c_waitcounter++;
309                                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
310                                          "Wait 100 us (%d times)...\n",
311                                           h2c_waitcounter);
312                                 udelay(100);
313
314                                 if (h2c_waitcounter > 1000)
315                                         return;
316                                 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
317                                                   flag);
318                         }
319                         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
320                 } else {
321                         rtlhal->h2c_setinprogress = true;
322                         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
323                         break;
324                 }
325         }
326
327         while (!bwrite_sucess) {
328                 wait_writeh2c_limmit--;
329                 if (wait_writeh2c_limmit == 0) {
330                         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
331                                  "Write H2C fail because no trigger for FW INT!\n");
332                         break;
333                 }
334
335                 boxnum = rtlhal->last_hmeboxnum;
336                 switch (boxnum) {
337                 case 0:
338                         box_reg = REG_HMEBOX_0;
339                         box_extreg = REG_HMEBOX_EXT_0;
340                         break;
341                 case 1:
342                         box_reg = REG_HMEBOX_1;
343                         box_extreg = REG_HMEBOX_EXT_1;
344                         break;
345                 case 2:
346                         box_reg = REG_HMEBOX_2;
347                         box_extreg = REG_HMEBOX_EXT_2;
348                         break;
349                 case 3:
350                         box_reg = REG_HMEBOX_3;
351                         box_extreg = REG_HMEBOX_EXT_3;
352                         break;
353                 default:
354                         RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
355                                  "switch case not process\n");
356                         break;
357                 }
358
359                 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
360                 while (!isfw_read) {
361                         wait_h2c_limmit--;
362                         if (wait_h2c_limmit == 0) {
363                                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
364                                          "Waiting too long for FW read clear HMEBox(%d)!\n",
365                                          boxnum);
366                                 break;
367                         }
368
369                         udelay(10);
370
371                         isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
372                         u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
373                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
374                                  "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
375                                  boxnum, u1b_tmp);
376                 }
377
378                 if (!isfw_read) {
379                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
380                                  "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
381                                  boxnum);
382                         break;
383                 }
384
385                 memset(boxcontent, 0, sizeof(boxcontent));
386                 memset(boxextcontent, 0, sizeof(boxextcontent));
387                 boxcontent[0] = element_id;
388                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
389                          "Write element_id box_reg(%4x) = %2x\n",
390                           box_reg, element_id);
391
392                 switch (cmd_len) {
393                 case 1:
394                         boxcontent[0] &= ~(BIT(7));
395                         memcpy((u8 *)(boxcontent) + 1,
396                                cmdbuffer + buf_index, 1);
397
398                         for (idx = 0; idx < 4; idx++) {
399                                 rtl_write_byte(rtlpriv, box_reg + idx,
400                                                boxcontent[idx]);
401                         }
402                         break;
403                 case 2:
404                         boxcontent[0] &= ~(BIT(7));
405                         memcpy((u8 *)(boxcontent) + 1,
406                                cmdbuffer + buf_index, 2);
407
408                         for (idx = 0; idx < 4; idx++) {
409                                 rtl_write_byte(rtlpriv, box_reg + idx,
410                                                boxcontent[idx]);
411                         }
412                         break;
413                 case 3:
414                         boxcontent[0] &= ~(BIT(7));
415                         memcpy((u8 *)(boxcontent) + 1,
416                                cmdbuffer + buf_index, 3);
417
418                         for (idx = 0; idx < 4; idx++) {
419                                 rtl_write_byte(rtlpriv, box_reg + idx,
420                                                boxcontent[idx]);
421                         }
422                         break;
423                 case 4:
424                         boxcontent[0] |= (BIT(7));
425                         memcpy((u8 *)(boxextcontent),
426                                cmdbuffer + buf_index, 2);
427                         memcpy((u8 *)(boxcontent) + 1,
428                                cmdbuffer + buf_index + 2, 2);
429
430                         for (idx = 0; idx < 2; idx++) {
431                                 rtl_write_byte(rtlpriv, box_extreg + idx,
432                                                boxextcontent[idx]);
433                         }
434
435                         for (idx = 0; idx < 4; idx++) {
436                                 rtl_write_byte(rtlpriv, box_reg + idx,
437                                                boxcontent[idx]);
438                         }
439                         break;
440                 case 5:
441                         boxcontent[0] |= (BIT(7));
442                         memcpy((u8 *)(boxextcontent),
443                                cmdbuffer + buf_index, 2);
444                         memcpy((u8 *)(boxcontent) + 1,
445                                cmdbuffer + buf_index + 2, 3);
446
447                         for (idx = 0; idx < 2; idx++) {
448                                 rtl_write_byte(rtlpriv, box_extreg + idx,
449                                                boxextcontent[idx]);
450                         }
451
452                         for (idx = 0; idx < 4; idx++) {
453                                 rtl_write_byte(rtlpriv, box_reg + idx,
454                                                boxcontent[idx]);
455                         }
456                         break;
457                 default:
458                         RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
459                                  "switch case not process\n");
460                         break;
461                 }
462
463                 bwrite_sucess = true;
464
465                 rtlhal->last_hmeboxnum = boxnum + 1;
466                 if (rtlhal->last_hmeboxnum == 4)
467                         rtlhal->last_hmeboxnum = 0;
468
469                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
470                          "pHalData->last_hmeboxnum  = %d\n",
471                           rtlhal->last_hmeboxnum);
472         }
473
474         spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
475         rtlhal->h2c_setinprogress = false;
476         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
477
478         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
479 }
480
481 void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
482                          u8 element_id, u32 cmd_len, u8 *cmdbuffer)
483 {
484         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
485         u32 tmp_cmdbuf[2];
486
487         if (!rtlhal->fw_ready) {
488                 RT_ASSERT(false,
489                           "return H2C cmd because of Fw download fail!!!\n");
490                 return;
491         }
492
493         memset(tmp_cmdbuf, 0, 8);
494         memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
495         _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
496
497         return;
498 }
499 EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
500
501 void rtl92c_firmware_selfreset(struct ieee80211_hw *hw)
502 {
503         u8 u1b_tmp;
504         u8 delay = 100;
505         struct rtl_priv *rtlpriv = rtl_priv(hw);
506
507         rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
508         u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
509
510         while (u1b_tmp & BIT(2)) {
511                 delay--;
512                 if (delay == 0) {
513                         RT_ASSERT(false, "8051 reset fail.\n");
514                         break;
515                 }
516                 udelay(50);
517                 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
518         }
519 }
520 EXPORT_SYMBOL(rtl92c_firmware_selfreset);
521
522 void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
523 {
524         struct rtl_priv *rtlpriv = rtl_priv(hw);
525         u8 u1_h2c_set_pwrmode[3] = { 0 };
526         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
527
528         RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
529
530         SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
531         SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
532                 (rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1);
533         SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
534                                               ppsc->reg_max_lps_awakeintvl);
535
536         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
537                       "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
538                       u1_h2c_set_pwrmode, 3);
539         rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
540 }
541 EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
542
543 #define BEACON_PG               0 /*->1*/
544 #define PSPOLL_PG               2
545 #define NULL_PG                 3
546 #define PROBERSP_PG             4 /*->5*/
547
548 #define TOTAL_RESERVED_PKT_LEN  768
549
550 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
551         /* page 0 beacon */
552         0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
553         0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
554         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
555         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
556         0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
557         0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
558         0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
559         0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
560         0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
561         0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
562         0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
563         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
564         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
565         0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
566         0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
567         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
568
569         /* page 1 beacon */
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         0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
583         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
584         0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
585         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
586
587         /* page 2  ps-poll */
588         0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
589         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
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         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
600         0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
601         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
602         0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
603         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
604
605         /* page 3  null */
606         0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
607         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
608         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 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         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
618         0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
619         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
620         0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
621         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
622
623         /* page 4  probe_resp */
624         0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
625         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
626         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
627         0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
628         0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
629         0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
630         0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
631         0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
632         0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
633         0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
634         0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
635         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
636         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
637         0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
638         0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
639         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
640
641         /* page 5  probe_resp */
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         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
658 };
659
660 void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
661          bool (*cmd_send_packet)(struct ieee80211_hw *, struct sk_buff *))
662 {
663         struct rtl_priv *rtlpriv = rtl_priv(hw);
664         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
665         struct sk_buff *skb = NULL;
666
667         u32 totalpacketlen;
668         bool rtstatus;
669         u8 u1rsvdpageloc[3] = { 0 };
670         bool b_dlok = false;
671
672         u8 *beacon;
673         u8 *p_pspoll;
674         u8 *nullfunc;
675         u8 *p_probersp;
676         /*---------------------------------------------------------
677                                 (1) beacon
678         ---------------------------------------------------------*/
679         beacon = &reserved_page_packet[BEACON_PG * 128];
680         SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
681         SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
682
683         /*-------------------------------------------------------
684                                 (2) ps-poll
685         --------------------------------------------------------*/
686         p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
687         SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
688         SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
689         SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
690
691         SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
692
693         /*--------------------------------------------------------
694                                 (3) null data
695         ---------------------------------------------------------*/
696         nullfunc = &reserved_page_packet[NULL_PG * 128];
697         SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
698         SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
699         SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
700
701         SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
702
703         /*---------------------------------------------------------
704                                 (4) probe response
705         ----------------------------------------------------------*/
706         p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
707         SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
708         SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
709         SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
710
711         SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
712
713         totalpacketlen = TOTAL_RESERVED_PKT_LEN;
714
715         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
716                       "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
717                       &reserved_page_packet[0], totalpacketlen);
718         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
719                       "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
720                       u1rsvdpageloc, 3);
721
722
723         skb = dev_alloc_skb(totalpacketlen);
724         memcpy((u8 *)skb_put(skb, totalpacketlen),
725                &reserved_page_packet, totalpacketlen);
726
727         if (cmd_send_packet)
728                 rtstatus = cmd_send_packet(hw, skb);
729         else
730                 rtstatus = rtl_cmd_send_packet(hw, skb);
731
732         if (rtstatus)
733                 b_dlok = true;
734
735         if (b_dlok) {
736                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
737                          "Set RSVD page location to Fw.\n");
738                 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
739                                 "H2C_RSVDPAGE:\n",
740                                 u1rsvdpageloc, 3);
741                 rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
742                                     sizeof(u1rsvdpageloc), u1rsvdpageloc);
743         } else
744                 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
745                          "Set RSVD page location to Fw FAIL!!!!!!.\n");
746 }
747 EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
748
749 void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
750 {
751         u8 u1_joinbssrpt_parm[1] = { 0 };
752
753         SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
754
755         rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
756 }
757 EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);
758
759 static void rtl92c_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
760 {
761         u8 u1_ctwindow_period[1] = { ctwindow};
762
763         rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
764 }
765
766 /* refactored routine */
767 static void set_noa_data(struct rtl_priv *rtlpriv,
768                          struct rtl_p2p_ps_info *p2pinfo,
769                          struct p2p_ps_offload_t *p2p_ps_offload)
770 {
771         int i;
772         u32     start_time, tsf_low;
773
774         /* hw only support 2 set of NoA */
775         for (i = 0 ; i < p2pinfo->noa_num ; i++) {
776                 /* To control the reg setting for which NOA*/
777                 rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
778                 if (i == 0)
779                         p2p_ps_offload->noa0_en = 1;
780                 else
781                         p2p_ps_offload->noa1_en = 1;
782
783                 /* config P2P NoA Descriptor Register */
784                 rtl_write_dword(rtlpriv, 0x5E0,
785                                 p2pinfo->noa_duration[i]);
786                 rtl_write_dword(rtlpriv, 0x5E4,
787                                 p2pinfo->noa_interval[i]);
788
789                 /*Get Current TSF value */
790                 tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
791
792                 start_time = p2pinfo->noa_start_time[i];
793                 if (p2pinfo->noa_count_type[i] != 1) {
794                         while (start_time <= (tsf_low+(50*1024))) {
795                                 start_time += p2pinfo->noa_interval[i];
796                                 if (p2pinfo->noa_count_type[i] != 255)
797                                         p2pinfo->noa_count_type[i]--;
798                         }
799                 }
800                 rtl_write_dword(rtlpriv, 0x5E8, start_time);
801                 rtl_write_dword(rtlpriv, 0x5EC,
802                                 p2pinfo->noa_count_type[i]);
803         }
804 }
805
806 void rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
807 {
808         struct rtl_priv *rtlpriv = rtl_priv(hw);
809         struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
810         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
811         struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
812         struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
813         u16     ctwindow;
814
815         switch (p2p_ps_state) {
816         case P2P_PS_DISABLE:
817                         RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
818                                  "P2P_PS_DISABLE\n");
819                         memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
820                         break;
821         case P2P_PS_ENABLE:
822                         RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
823                                  "P2P_PS_ENABLE\n");
824                         /* update CTWindow value. */
825                         if (p2pinfo->ctwindow > 0) {
826                                 p2p_ps_offload->ctwindow_en = 1;
827                                 ctwindow = p2pinfo->ctwindow;
828                                 rtl92c_set_p2p_ctw_period_cmd(hw, ctwindow);
829                         }
830                         /* call refactored routine */
831                         set_noa_data(rtlpriv, p2pinfo, p2p_ps_offload);
832
833                         if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
834                                 /* rst p2p circuit */
835                                 rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST,
836                                                BIT(4));
837
838                                 p2p_ps_offload->offload_en = 1;
839
840                                 if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
841                                         p2p_ps_offload->role = 1;
842                                         p2p_ps_offload->allstasleep = 0;
843                                 } else {
844                                         p2p_ps_offload->role = 0;
845                                 }
846
847                                 p2p_ps_offload->discovery = 0;
848                         }
849                         break;
850         case P2P_PS_SCAN:
851                         RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
852                         p2p_ps_offload->discovery = 1;
853                         break;
854         case P2P_PS_SCAN_DONE:
855                         RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
856                                  "P2P_PS_SCAN_DONE\n");
857                         p2p_ps_offload->discovery = 0;
858                         p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
859                         break;
860         default:
861                         break;
862         }
863
864         rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
865
866 }
867 EXPORT_SYMBOL_GPL(rtl92c_set_p2p_ps_offload_cmd);