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