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
_rtl92c_enable_fw_download(struct ieee80211_hw * hw,bool enable)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
_rtl92c_fw_block_write(struct ieee80211_hw * hw,const u8 * buffer,u32 size)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
_rtl92c_fw_page_write(struct ieee80211_hw * hw,u32 page,const u8 * buffer,u32 size)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
_rtl92c_fill_dummy(u8 * pfwbuf,u32 * pfwlen)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
_rtl92c_write_fw(struct ieee80211_hw * hw,enum version_8192c version,u8 * buffer,u32 size)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
_rtl92c_fw_free_to_go(struct ieee80211_hw * hw)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
rtl92c_download_fw(struct ieee80211_hw * hw)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
_rtl92c_check_fw_read_last_h2c(struct ieee80211_hw * hw,u8 boxnum)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
_rtl92c_fill_h2c_command(struct ieee80211_hw * hw,u8 element_id,u32 cmd_len,u8 * cmdbuffer)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
rtl92c_fill_h2c_cmd(struct ieee80211_hw * hw,u8 element_id,u32 cmd_len,u8 * cmdbuffer)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
rtl92c_firmware_selfreset(struct ieee80211_hw * hw)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
rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw * hw,u8 mode)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
rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw * hw,bool (* cmd_send_packet)(struct ieee80211_hw *,struct sk_buff *))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
rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw * hw,u8 mstatus)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
rtl92c_set_p2p_ctw_period_cmd(struct ieee80211_hw * hw,u8 ctwindow)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 */
set_noa_data(struct rtl_priv * rtlpriv,struct rtl_p2p_ps_info * p2pinfo,struct p2p_ps_offload_t * p2p_ps_offload)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
rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw * hw,u8 p2p_ps_state)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);
867