blob: ebb73a2fae915d20462e8b62d695bbc9d8ce6570 [file] [log] [blame]
Larry Finger0c817332010-12-08 11:12:31 -06001/******************************************************************************
2 *
3 * Copyright(c) 2009-2010 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 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17 *
18 * The full GNU General Public License is included in this distribution in the
19 * file called LICENSE.
20 *
21 * Contact Information:
22 * wlanfae <wlanfae@realtek.com>
23 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
24 * Hsinchu 300, Taiwan.
25 *
26 * Larry Finger <Larry.Finger@lwfinger.net>
27 *
28 *****************************************************************************/
29
Joe Perches292b1192011-07-20 08:51:35 -070030#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
31
Larry Finger0c817332010-12-08 11:12:31 -060032#include <linux/firmware.h>
33#include "../wifi.h"
34#include "../pci.h"
35#include "../base.h"
Larry Finger1472d3a2011-02-23 10:24:58 -060036#include "../rtl8192ce/reg.h"
37#include "../rtl8192ce/def.h"
38#include "fw_common.h"
Larry Finger0c817332010-12-08 11:12:31 -060039
40static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable)
41{
42 struct rtl_priv *rtlpriv = rtl_priv(hw);
43 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
44
45 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU) {
46 u32 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
47 if (enable)
48 value32 |= MCUFWDL_EN;
49 else
50 value32 &= ~MCUFWDL_EN;
51 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
52 } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) {
53 u8 tmp;
54 if (enable) {
55
56 tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
57 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
58 tmp | 0x04);
59
60 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
61 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
62
63 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
64 rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
65 } else {
66
67 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
68 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
69
70 rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
71 }
72 }
73}
74
Larry Fingerff6ff962011-11-17 12:14:43 -060075static void rtl_block_fw_writeN(struct ieee80211_hw *hw, const u8 *buffer,
76 u32 size)
77{
78 struct rtl_priv *rtlpriv = rtl_priv(hw);
79 u32 blockSize = REALTEK_USB_VENQT_MAX_BUF_SIZE - 20;
80 u8 *bufferPtr = (u8 *) buffer;
81 u32 i, offset, blockCount, remainSize;
82
83 blockCount = size / blockSize;
84 remainSize = size % blockSize;
85
86 for (i = 0; i < blockCount; i++) {
87 offset = i * blockSize;
88 rtlpriv->io.writeN_sync(rtlpriv,
89 (FW_8192C_START_ADDRESS + offset),
90 (void *)(bufferPtr + offset),
91 blockSize);
92 }
93
94 if (remainSize) {
95 offset = blockCount * blockSize;
96 rtlpriv->io.writeN_sync(rtlpriv,
97 (FW_8192C_START_ADDRESS + offset),
98 (void *)(bufferPtr + offset),
99 remainSize);
100 }
101}
102
Larry Finger0c817332010-12-08 11:12:31 -0600103static void _rtl92c_fw_block_write(struct ieee80211_hw *hw,
104 const u8 *buffer, u32 size)
105{
106 struct rtl_priv *rtlpriv = rtl_priv(hw);
107 u32 blockSize = sizeof(u32);
108 u8 *bufferPtr = (u8 *) buffer;
109 u32 *pu4BytePtr = (u32 *) buffer;
110 u32 i, offset, blockCount, remainSize;
111
Larry Fingerff6ff962011-11-17 12:14:43 -0600112 if (rtlpriv->io.writeN_sync) {
113 rtl_block_fw_writeN(hw, buffer, size);
114 return;
115 }
Larry Finger0c817332010-12-08 11:12:31 -0600116 blockCount = size / blockSize;
117 remainSize = size % blockSize;
118
119 for (i = 0; i < blockCount; i++) {
120 offset = i * blockSize;
121 rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
122 *(pu4BytePtr + i));
123 }
124
125 if (remainSize) {
126 offset = blockCount * blockSize;
127 bufferPtr += offset;
128 for (i = 0; i < remainSize; i++) {
129 rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS +
130 offset + i), *(bufferPtr + i));
131 }
132 }
133}
134
135static void _rtl92c_fw_page_write(struct ieee80211_hw *hw,
136 u32 page, const u8 *buffer, u32 size)
137{
138 struct rtl_priv *rtlpriv = rtl_priv(hw);
139 u8 value8;
140 u8 u8page = (u8) (page & 0x07);
141
142 value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
143
144 rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
145 _rtl92c_fw_block_write(hw, buffer, size);
146}
147
148static void _rtl92c_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
149{
150 u32 fwlen = *pfwlen;
151 u8 remain = (u8) (fwlen % 4);
152
153 remain = (remain == 0) ? 0 : (4 - remain);
154
155 while (remain > 0) {
156 pfwbuf[fwlen] = 0;
157 fwlen++;
158 remain--;
159 }
160
161 *pfwlen = fwlen;
162}
163
164static void _rtl92c_write_fw(struct ieee80211_hw *hw,
165 enum version_8192c version, u8 *buffer, u32 size)
166{
167 struct rtl_priv *rtlpriv = rtl_priv(hw);
168 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
Larry Finger0c817332010-12-08 11:12:31 -0600169 u8 *bufferPtr = (u8 *) buffer;
170
171 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, ("FW size is %d bytes,\n", size));
172
Larry Finger25b2bc32011-02-11 14:34:03 -0600173 if (IS_CHIP_VER_B(version)) {
Larry Finger0c817332010-12-08 11:12:31 -0600174 u32 pageNums, remainSize;
175 u32 page, offset;
176
Larry Finger25b2bc32011-02-11 14:34:03 -0600177 if (IS_HARDWARE_TYPE_8192CE(rtlhal))
Larry Finger0c817332010-12-08 11:12:31 -0600178 _rtl92c_fill_dummy(bufferPtr, &size);
179
180 pageNums = size / FW_8192C_PAGE_SIZE;
181 remainSize = size % FW_8192C_PAGE_SIZE;
182
183 if (pageNums > 4) {
184 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
185 ("Page numbers should not greater then 4\n"));
186 }
187
188 for (page = 0; page < pageNums; page++) {
189 offset = page * FW_8192C_PAGE_SIZE;
190 _rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
191 FW_8192C_PAGE_SIZE);
192 }
193
194 if (remainSize) {
195 offset = pageNums * FW_8192C_PAGE_SIZE;
196 page = pageNums;
197 _rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
198 remainSize);
199 }
200 } else {
201 _rtl92c_fw_block_write(hw, buffer, size);
202 }
203}
204
205static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
206{
207 struct rtl_priv *rtlpriv = rtl_priv(hw);
Larry Finger0c817332010-12-08 11:12:31 -0600208 u32 counter = 0;
209 u32 value32;
210
211 do {
212 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
213 } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
214 (!(value32 & FWDL_ChkSum_rpt)));
215
216 if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
217 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
218 ("chksum report faill ! REG_MCUFWDL:0x%08x .\n",
219 value32));
Larry Finger32473282011-03-27 16:19:57 -0500220 return -EIO;
Larry Finger0c817332010-12-08 11:12:31 -0600221 }
222
223 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
224 ("Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32));
225
226 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
227 value32 |= MCUFWDL_RDY;
228 value32 &= ~WINTINI_RDY;
229 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
230
231 counter = 0;
232
233 do {
234 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
235 if (value32 & WINTINI_RDY) {
236 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
237 ("Polling FW ready success!!"
238 " REG_MCUFWDL:0x%08x .\n",
239 value32));
Larry Finger32473282011-03-27 16:19:57 -0500240 return 0;
Larry Finger0c817332010-12-08 11:12:31 -0600241 }
242
243 mdelay(FW_8192C_POLLING_DELAY);
244
245 } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
246
247 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
248 ("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32));
Larry Finger32473282011-03-27 16:19:57 -0500249 return -EIO;
Larry Finger0c817332010-12-08 11:12:31 -0600250}
251
252int rtl92c_download_fw(struct ieee80211_hw *hw)
253{
254 struct rtl_priv *rtlpriv = rtl_priv(hw);
255 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
256 struct rtl92c_firmware_header *pfwheader;
257 u8 *pfwdata;
258 u32 fwsize;
Larry Finger0c817332010-12-08 11:12:31 -0600259 enum version_8192c version = rtlhal->version;
260
Joe Perches292b1192011-07-20 08:51:35 -0700261 pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name);
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500262 if (!rtlhal->pfirmware)
Larry Finger0c817332010-12-08 11:12:31 -0600263 return 1;
Larry Finger0c817332010-12-08 11:12:31 -0600264
265 pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
266 pfwdata = (u8 *) rtlhal->pfirmware;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500267 fwsize = rtlhal->fwsize;
Larry Finger0c817332010-12-08 11:12:31 -0600268
269 if (IS_FW_HEADER_EXIST(pfwheader)) {
270 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
271 ("Firmware Version(%d), Signature(%#x),Size(%d)\n",
272 pfwheader->version, pfwheader->signature,
273 (uint)sizeof(struct rtl92c_firmware_header)));
274
275 pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
276 fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
277 }
278
279 _rtl92c_enable_fw_download(hw, true);
280 _rtl92c_write_fw(hw, version, pfwdata, fwsize);
281 _rtl92c_enable_fw_download(hw, false);
282
Larry Finger32473282011-03-27 16:19:57 -0500283 if (_rtl92c_fw_free_to_go(hw)) {
Larry Finger0c817332010-12-08 11:12:31 -0600284 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
285 ("Firmware is not ready to run!\n"));
286 } else {
287 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
288 ("Firmware is ready to run!\n"));
289 }
290
291 return 0;
292}
Larry Finger1472d3a2011-02-23 10:24:58 -0600293EXPORT_SYMBOL(rtl92c_download_fw);
Larry Finger0c817332010-12-08 11:12:31 -0600294
295static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
296{
297 struct rtl_priv *rtlpriv = rtl_priv(hw);
298 u8 val_hmetfr, val_mcutst_1;
299 bool result = false;
300
301 val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
302 val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
303
304 if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
305 result = true;
306 return result;
307}
308
309static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
310 u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
311{
312 struct rtl_priv *rtlpriv = rtl_priv(hw);
313 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
314 u8 boxnum;
Larry Finger9f219bd2011-04-13 21:00:02 -0500315 u16 box_reg = 0, box_extreg = 0;
Larry Finger0c817332010-12-08 11:12:31 -0600316 u8 u1b_tmp;
317 bool isfw_read = false;
Larry Finger0c817332010-12-08 11:12:31 -0600318 bool bwrite_sucess = false;
319 u8 wait_h2c_limmit = 100;
320 u8 wait_writeh2c_limmit = 100;
321 u8 boxcontent[4], boxextcontent[2];
322 u32 h2c_waitcounter = 0;
323 unsigned long flag;
324 u8 idx;
325
326 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("come in\n"));
327
328 while (true) {
329 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
Larry Finger7ea47242011-02-19 16:28:57 -0600330 if (rtlhal->h2c_setinprogress) {
Larry Finger0c817332010-12-08 11:12:31 -0600331 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
332 ("H2C set in progress! Wait to set.."
333 "element_id(%d).\n", element_id));
334
Larry Finger7ea47242011-02-19 16:28:57 -0600335 while (rtlhal->h2c_setinprogress) {
Larry Finger0c817332010-12-08 11:12:31 -0600336 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
337 flag);
338 h2c_waitcounter++;
339 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
340 ("Wait 100 us (%d times)...\n",
341 h2c_waitcounter));
342 udelay(100);
343
344 if (h2c_waitcounter > 1000)
345 return;
346 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
347 flag);
348 }
349 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
350 } else {
Larry Finger7ea47242011-02-19 16:28:57 -0600351 rtlhal->h2c_setinprogress = true;
Larry Finger0c817332010-12-08 11:12:31 -0600352 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
353 break;
354 }
355 }
356
357 while (!bwrite_sucess) {
358 wait_writeh2c_limmit--;
359 if (wait_writeh2c_limmit == 0) {
360 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
361 ("Write H2C fail because no trigger "
362 "for FW INT!\n"));
363 break;
364 }
365
366 boxnum = rtlhal->last_hmeboxnum;
367 switch (boxnum) {
368 case 0:
369 box_reg = REG_HMEBOX_0;
370 box_extreg = REG_HMEBOX_EXT_0;
371 break;
372 case 1:
373 box_reg = REG_HMEBOX_1;
374 box_extreg = REG_HMEBOX_EXT_1;
375 break;
376 case 2:
377 box_reg = REG_HMEBOX_2;
378 box_extreg = REG_HMEBOX_EXT_2;
379 break;
380 case 3:
381 box_reg = REG_HMEBOX_3;
382 box_extreg = REG_HMEBOX_EXT_3;
383 break;
384 default:
385 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
386 ("switch case not process\n"));
387 break;
388 }
389
390 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
391 while (!isfw_read) {
392
393 wait_h2c_limmit--;
394 if (wait_h2c_limmit == 0) {
395 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
396 ("Wating too long for FW read "
397 "clear HMEBox(%d)!\n", boxnum));
398 break;
399 }
400
401 udelay(10);
402
403 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
404 u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
405 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
406 ("Wating for FW read clear HMEBox(%d)!!! "
407 "0x1BF = %2x\n", boxnum, u1b_tmp));
408 }
409
410 if (!isfw_read) {
411 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
412 ("Write H2C register BOX[%d] fail!!!!! "
413 "Fw do not read.\n", boxnum));
414 break;
415 }
416
417 memset(boxcontent, 0, sizeof(boxcontent));
418 memset(boxextcontent, 0, sizeof(boxextcontent));
419 boxcontent[0] = element_id;
420 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
421 ("Write element_id box_reg(%4x) = %2x\n",
422 box_reg, element_id));
423
424 switch (cmd_len) {
425 case 1:
426 boxcontent[0] &= ~(BIT(7));
427 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500428 p_cmdbuffer, 1);
Larry Finger0c817332010-12-08 11:12:31 -0600429
430 for (idx = 0; idx < 4; idx++) {
431 rtl_write_byte(rtlpriv, box_reg + idx,
432 boxcontent[idx]);
433 }
434 break;
435 case 2:
436 boxcontent[0] &= ~(BIT(7));
437 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500438 p_cmdbuffer, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600439
440 for (idx = 0; idx < 4; idx++) {
441 rtl_write_byte(rtlpriv, box_reg + idx,
442 boxcontent[idx]);
443 }
444 break;
445 case 3:
446 boxcontent[0] &= ~(BIT(7));
447 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500448 p_cmdbuffer, 3);
Larry Finger0c817332010-12-08 11:12:31 -0600449
450 for (idx = 0; idx < 4; idx++) {
451 rtl_write_byte(rtlpriv, box_reg + idx,
452 boxcontent[idx]);
453 }
454 break;
455 case 4:
456 boxcontent[0] |= (BIT(7));
457 memcpy((u8 *) (boxextcontent),
Larry Finger32473282011-03-27 16:19:57 -0500458 p_cmdbuffer, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600459 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500460 p_cmdbuffer + 2, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600461
462 for (idx = 0; idx < 2; idx++) {
463 rtl_write_byte(rtlpriv, box_extreg + idx,
464 boxextcontent[idx]);
465 }
466
467 for (idx = 0; idx < 4; idx++) {
468 rtl_write_byte(rtlpriv, box_reg + idx,
469 boxcontent[idx]);
470 }
471 break;
472 case 5:
473 boxcontent[0] |= (BIT(7));
474 memcpy((u8 *) (boxextcontent),
Larry Finger32473282011-03-27 16:19:57 -0500475 p_cmdbuffer, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600476 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500477 p_cmdbuffer + 2, 3);
Larry Finger0c817332010-12-08 11:12:31 -0600478
479 for (idx = 0; idx < 2; idx++) {
480 rtl_write_byte(rtlpriv, box_extreg + idx,
481 boxextcontent[idx]);
482 }
483
484 for (idx = 0; idx < 4; idx++) {
485 rtl_write_byte(rtlpriv, box_reg + idx,
486 boxcontent[idx]);
487 }
488 break;
489 default:
490 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
491 ("switch case not process\n"));
492 break;
493 }
494
495 bwrite_sucess = true;
496
497 rtlhal->last_hmeboxnum = boxnum + 1;
498 if (rtlhal->last_hmeboxnum == 4)
499 rtlhal->last_hmeboxnum = 0;
500
501 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
502 ("pHalData->last_hmeboxnum = %d\n",
503 rtlhal->last_hmeboxnum));
504 }
505
506 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
Larry Finger7ea47242011-02-19 16:28:57 -0600507 rtlhal->h2c_setinprogress = false;
Larry Finger0c817332010-12-08 11:12:31 -0600508 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
509
510 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("go out\n"));
511}
512
513void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
514 u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
515{
516 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
517 u32 tmp_cmdbuf[2];
518
Larry Finger7ea47242011-02-19 16:28:57 -0600519 if (rtlhal->fw_ready == false) {
Larry Finger0c817332010-12-08 11:12:31 -0600520 RT_ASSERT(false, ("return H2C cmd because of Fw "
521 "download fail!!!\n"));
522 return;
523 }
524
525 memset(tmp_cmdbuf, 0, 8);
526 memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
527 _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
528
529 return;
530}
Larry Finger1472d3a2011-02-23 10:24:58 -0600531EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
Larry Finger0c817332010-12-08 11:12:31 -0600532
533void rtl92c_firmware_selfreset(struct ieee80211_hw *hw)
534{
535 u8 u1b_tmp;
536 u8 delay = 100;
537 struct rtl_priv *rtlpriv = rtl_priv(hw);
538
539 rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
540 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
541
542 while (u1b_tmp & BIT(2)) {
543 delay--;
544 if (delay == 0) {
545 RT_ASSERT(false, ("8051 reset fail.\n"));
546 break;
547 }
548 udelay(50);
549 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
550 }
551}
Larry Finger1472d3a2011-02-23 10:24:58 -0600552EXPORT_SYMBOL(rtl92c_firmware_selfreset);
Larry Finger0c817332010-12-08 11:12:31 -0600553
554void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
555{
556 struct rtl_priv *rtlpriv = rtl_priv(hw);
557 u8 u1_h2c_set_pwrmode[3] = {0};
558 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
559
560 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("FW LPS mode = %d\n", mode));
561
562 SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
563 SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
564 SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
565 ppsc->reg_max_lps_awakeintvl);
566
567 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
568 "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
569 u1_h2c_set_pwrmode, 3);
570 rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
571
572}
Larry Finger1472d3a2011-02-23 10:24:58 -0600573EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
Larry Finger0c817332010-12-08 11:12:31 -0600574
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500575static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
576 struct sk_buff *skb)
577{
578 struct rtl_priv *rtlpriv = rtl_priv(hw);
579 struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
580 struct rtl8192_tx_ring *ring;
581 struct rtl_tx_desc *pdesc;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500582 unsigned long flags;
583 struct sk_buff *pskb = NULL;
584
585 ring = &rtlpci->tx_ring[BEACON_QUEUE];
586
587 pskb = __skb_dequeue(&ring->queue);
588 if (pskb)
589 kfree_skb(pskb);
590
591 spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
592
593 pdesc = &ring->desc[0];
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500594
595 rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
596
597 __skb_queue_tail(&ring->queue, skb);
598
599 spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
600
601 rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
602
603 return true;
604}
605
Larry Finger0c817332010-12-08 11:12:31 -0600606#define BEACON_PG 0 /*->1*/
607#define PSPOLL_PG 2
608#define NULL_PG 3
609#define PROBERSP_PG 4 /*->5*/
610
611#define TOTAL_RESERVED_PKT_LEN 768
612
613static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
614 /* page 0 beacon */
615 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
616 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
617 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
618 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
619 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
620 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
621 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
622 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
623 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
624 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
625 0x03, 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 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
629 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
630 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
631
632 /* page 1 beacon */
633 0x00, 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
637 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
638 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
639 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
646 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
647 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
648 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
649
650 /* page 2 ps-poll */
651 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
652 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
653 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
654 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
655 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
656 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
657 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
658 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
659 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
660 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
661 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
662 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
663 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
664 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
665 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
666 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
667
668 /* page 3 null */
669 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
670 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
671 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
672 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
682 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
683 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
684 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
685
686 /* page 4 probe_resp */
687 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
688 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
689 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
690 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
691 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
692 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
693 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
694 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
695 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
696 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
697 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
698 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
699 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
700 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
701 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
702 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
703
704 /* page 5 probe_resp */
705 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
706 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
707 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
708 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
709 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
710 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
711 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
712 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
713 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
714 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
715 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
716 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
717 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
718 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
719 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
720 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
721};
722
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500723void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
Larry Finger0c817332010-12-08 11:12:31 -0600724{
725 struct rtl_priv *rtlpriv = rtl_priv(hw);
726 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
727 struct sk_buff *skb = NULL;
728
729 u32 totalpacketlen;
730 bool rtstatus;
731 u8 u1RsvdPageLoc[3] = {0};
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500732 bool dlok = false;
Larry Finger0c817332010-12-08 11:12:31 -0600733
734 u8 *beacon;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500735 u8 *pspoll;
Larry Finger0c817332010-12-08 11:12:31 -0600736 u8 *nullfunc;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500737 u8 *probersp;
Larry Finger0c817332010-12-08 11:12:31 -0600738 /*---------------------------------------------------------
739 (1) beacon
740 ---------------------------------------------------------*/
741 beacon = &reserved_page_packet[BEACON_PG * 128];
742 SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
743 SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
744
745 /*-------------------------------------------------------
746 (2) ps-poll
747 --------------------------------------------------------*/
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500748 pspoll = &reserved_page_packet[PSPOLL_PG * 128];
749 SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000));
750 SET_80211_PS_POLL_BSSID(pspoll, mac->bssid);
751 SET_80211_PS_POLL_TA(pspoll, mac->mac_addr);
Larry Finger0c817332010-12-08 11:12:31 -0600752
753 SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
754
755 /*--------------------------------------------------------
756 (3) null data
757 ---------------------------------------------------------*/
758 nullfunc = &reserved_page_packet[NULL_PG * 128];
759 SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
760 SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
761 SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
762
763 SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
764
765 /*---------------------------------------------------------
766 (4) probe response
767 ----------------------------------------------------------*/
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500768 probersp = &reserved_page_packet[PROBERSP_PG * 128];
769 SET_80211_HDR_ADDRESS1(probersp, mac->bssid);
770 SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr);
771 SET_80211_HDR_ADDRESS3(probersp, mac->bssid);
Larry Finger0c817332010-12-08 11:12:31 -0600772
773 SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
774
775 totalpacketlen = TOTAL_RESERVED_PKT_LEN;
776
777 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
778 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
779 &reserved_page_packet[0], totalpacketlen);
780 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
781 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
782 u1RsvdPageLoc, 3);
783
784
785 skb = dev_alloc_skb(totalpacketlen);
786 memcpy((u8 *) skb_put(skb, totalpacketlen),
787 &reserved_page_packet, totalpacketlen);
788
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500789 rtstatus = _rtl92c_cmd_send_packet(hw, skb);
Larry Finger0c817332010-12-08 11:12:31 -0600790
791 if (rtstatus)
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500792 dlok = true;
Larry Finger0c817332010-12-08 11:12:31 -0600793
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500794 if (dlok) {
Larry Finger0c817332010-12-08 11:12:31 -0600795 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
796 ("Set RSVD page location to Fw.\n"));
797 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
798 "H2C_RSVDPAGE:\n",
799 u1RsvdPageLoc, 3);
800 rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
801 sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
802 } else
803 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
804 ("Set RSVD page location to Fw FAIL!!!!!!.\n"));
805}
Larry Finger1472d3a2011-02-23 10:24:58 -0600806EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
Larry Finger0c817332010-12-08 11:12:31 -0600807
808void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
809{
810 u8 u1_joinbssrpt_parm[1] = {0};
811
812 SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
813
814 rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
815}
Larry Finger1472d3a2011-02-23 10:24:58 -0600816EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);