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