blob: 1234e3b32fbfe276aa7821017688f7dbcedc7fa7 [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;
Larry Fingerabfabc92011-11-17 12:14:44 -0600111 u32 data;
Larry Finger0c817332010-12-08 11:12:31 -0600112
Larry Fingerff6ff962011-11-17 12:14:43 -0600113 if (rtlpriv->io.writeN_sync) {
114 rtl_block_fw_writeN(hw, buffer, size);
115 return;
116 }
Larry Finger0c817332010-12-08 11:12:31 -0600117 blockCount = size / blockSize;
118 remainSize = size % blockSize;
Larry Fingerabfabc92011-11-17 12:14:44 -0600119 if (remainSize) {
120 /* the last word is < 4 bytes - pad it with zeros */
121 for (i = 0; i < 4 - remainSize; i++)
122 *(bufferPtr + size + i) = 0;
123 blockCount++;
124 }
Larry Finger0c817332010-12-08 11:12:31 -0600125
126 for (i = 0; i < blockCount; i++) {
127 offset = i * blockSize;
Larry Fingerabfabc92011-11-17 12:14:44 -0600128 /* for big-endian platforms, the firmware data need to be byte
129 * swapped as it was read as a byte string and will be written
130 * as 32-bit dwords and byte swapped when written
131 */
132 data = le32_to_cpu(*(__le32 *)(pu4BytePtr + i));
Larry Finger0c817332010-12-08 11:12:31 -0600133 rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
Larry Fingerabfabc92011-11-17 12:14:44 -0600134 data);
Larry Finger0c817332010-12-08 11:12:31 -0600135 }
136}
137
138static void _rtl92c_fw_page_write(struct ieee80211_hw *hw,
139 u32 page, const u8 *buffer, u32 size)
140{
141 struct rtl_priv *rtlpriv = rtl_priv(hw);
142 u8 value8;
143 u8 u8page = (u8) (page & 0x07);
144
145 value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
146
147 rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
148 _rtl92c_fw_block_write(hw, buffer, size);
149}
150
151static void _rtl92c_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
152{
153 u32 fwlen = *pfwlen;
154 u8 remain = (u8) (fwlen % 4);
155
156 remain = (remain == 0) ? 0 : (4 - remain);
157
158 while (remain > 0) {
159 pfwbuf[fwlen] = 0;
160 fwlen++;
161 remain--;
162 }
163
164 *pfwlen = fwlen;
165}
166
167static void _rtl92c_write_fw(struct ieee80211_hw *hw,
168 enum version_8192c version, u8 *buffer, u32 size)
169{
170 struct rtl_priv *rtlpriv = rtl_priv(hw);
171 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
Larry Finger0c817332010-12-08 11:12:31 -0600172 u8 *bufferPtr = (u8 *) buffer;
173
174 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, ("FW size is %d bytes,\n", size));
175
Larry Finger25b2bc32011-02-11 14:34:03 -0600176 if (IS_CHIP_VER_B(version)) {
Larry Finger0c817332010-12-08 11:12:31 -0600177 u32 pageNums, remainSize;
178 u32 page, offset;
179
Larry Finger25b2bc32011-02-11 14:34:03 -0600180 if (IS_HARDWARE_TYPE_8192CE(rtlhal))
Larry Finger0c817332010-12-08 11:12:31 -0600181 _rtl92c_fill_dummy(bufferPtr, &size);
182
183 pageNums = size / FW_8192C_PAGE_SIZE;
184 remainSize = size % FW_8192C_PAGE_SIZE;
185
186 if (pageNums > 4) {
187 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
188 ("Page numbers should not greater then 4\n"));
189 }
190
191 for (page = 0; page < pageNums; page++) {
192 offset = page * FW_8192C_PAGE_SIZE;
193 _rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
194 FW_8192C_PAGE_SIZE);
195 }
196
197 if (remainSize) {
198 offset = pageNums * FW_8192C_PAGE_SIZE;
199 page = pageNums;
200 _rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
201 remainSize);
202 }
203 } else {
204 _rtl92c_fw_block_write(hw, buffer, size);
205 }
206}
207
208static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
209{
210 struct rtl_priv *rtlpriv = rtl_priv(hw);
Larry Finger0c817332010-12-08 11:12:31 -0600211 u32 counter = 0;
212 u32 value32;
213
214 do {
215 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
216 } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
217 (!(value32 & FWDL_ChkSum_rpt)));
218
219 if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
220 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
221 ("chksum report faill ! REG_MCUFWDL:0x%08x .\n",
222 value32));
Larry Finger32473282011-03-27 16:19:57 -0500223 return -EIO;
Larry Finger0c817332010-12-08 11:12:31 -0600224 }
225
226 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
227 ("Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32));
228
229 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
230 value32 |= MCUFWDL_RDY;
231 value32 &= ~WINTINI_RDY;
232 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
233
234 counter = 0;
235
236 do {
237 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
238 if (value32 & WINTINI_RDY) {
239 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
240 ("Polling FW ready success!!"
241 " REG_MCUFWDL:0x%08x .\n",
242 value32));
Larry Finger32473282011-03-27 16:19:57 -0500243 return 0;
Larry Finger0c817332010-12-08 11:12:31 -0600244 }
245
246 mdelay(FW_8192C_POLLING_DELAY);
247
248 } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
249
250 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
251 ("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32));
Larry Finger32473282011-03-27 16:19:57 -0500252 return -EIO;
Larry Finger0c817332010-12-08 11:12:31 -0600253}
254
255int rtl92c_download_fw(struct ieee80211_hw *hw)
256{
257 struct rtl_priv *rtlpriv = rtl_priv(hw);
258 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
259 struct rtl92c_firmware_header *pfwheader;
260 u8 *pfwdata;
261 u32 fwsize;
Larry Finger0c817332010-12-08 11:12:31 -0600262 enum version_8192c version = rtlhal->version;
263
Joe Perches292b1192011-07-20 08:51:35 -0700264 pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name);
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500265 if (!rtlhal->pfirmware)
Larry Finger0c817332010-12-08 11:12:31 -0600266 return 1;
Larry Finger0c817332010-12-08 11:12:31 -0600267
268 pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
269 pfwdata = (u8 *) rtlhal->pfirmware;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500270 fwsize = rtlhal->fwsize;
Larry Finger0c817332010-12-08 11:12:31 -0600271
272 if (IS_FW_HEADER_EXIST(pfwheader)) {
273 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
274 ("Firmware Version(%d), Signature(%#x),Size(%d)\n",
Larry Fingerabfabc92011-11-17 12:14:44 -0600275 le16_to_cpu(pfwheader->version),
276 le16_to_cpu(pfwheader->signature),
277 (uint)sizeof(struct rtl92c_firmware_header)));
Larry Finger0c817332010-12-08 11:12:31 -0600278
279 pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
280 fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
281 }
282
283 _rtl92c_enable_fw_download(hw, true);
284 _rtl92c_write_fw(hw, version, pfwdata, fwsize);
285 _rtl92c_enable_fw_download(hw, false);
286
Larry Finger32473282011-03-27 16:19:57 -0500287 if (_rtl92c_fw_free_to_go(hw)) {
Larry Finger0c817332010-12-08 11:12:31 -0600288 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
289 ("Firmware is not ready to run!\n"));
290 } else {
291 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
292 ("Firmware is ready to run!\n"));
293 }
294
295 return 0;
296}
Larry Finger1472d3a2011-02-23 10:24:58 -0600297EXPORT_SYMBOL(rtl92c_download_fw);
Larry Finger0c817332010-12-08 11:12:31 -0600298
299static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
300{
301 struct rtl_priv *rtlpriv = rtl_priv(hw);
302 u8 val_hmetfr, val_mcutst_1;
303 bool result = false;
304
305 val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
306 val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
307
308 if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
309 result = true;
310 return result;
311}
312
313static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
314 u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
315{
316 struct rtl_priv *rtlpriv = rtl_priv(hw);
317 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
318 u8 boxnum;
Larry Finger9f219bd2011-04-13 21:00:02 -0500319 u16 box_reg = 0, box_extreg = 0;
Larry Finger0c817332010-12-08 11:12:31 -0600320 u8 u1b_tmp;
321 bool isfw_read = false;
Larry Finger0c817332010-12-08 11:12:31 -0600322 bool bwrite_sucess = false;
323 u8 wait_h2c_limmit = 100;
324 u8 wait_writeh2c_limmit = 100;
325 u8 boxcontent[4], boxextcontent[2];
326 u32 h2c_waitcounter = 0;
327 unsigned long flag;
328 u8 idx;
329
330 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("come in\n"));
331
332 while (true) {
333 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
Larry Finger7ea47242011-02-19 16:28:57 -0600334 if (rtlhal->h2c_setinprogress) {
Larry Finger0c817332010-12-08 11:12:31 -0600335 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
336 ("H2C set in progress! Wait to set.."
337 "element_id(%d).\n", element_id));
338
Larry Finger7ea47242011-02-19 16:28:57 -0600339 while (rtlhal->h2c_setinprogress) {
Larry Finger0c817332010-12-08 11:12:31 -0600340 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
341 flag);
342 h2c_waitcounter++;
343 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
344 ("Wait 100 us (%d times)...\n",
345 h2c_waitcounter));
346 udelay(100);
347
348 if (h2c_waitcounter > 1000)
349 return;
350 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
351 flag);
352 }
353 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
354 } else {
Larry Finger7ea47242011-02-19 16:28:57 -0600355 rtlhal->h2c_setinprogress = true;
Larry Finger0c817332010-12-08 11:12:31 -0600356 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
357 break;
358 }
359 }
360
361 while (!bwrite_sucess) {
362 wait_writeh2c_limmit--;
363 if (wait_writeh2c_limmit == 0) {
364 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
365 ("Write H2C fail because no trigger "
366 "for FW INT!\n"));
367 break;
368 }
369
370 boxnum = rtlhal->last_hmeboxnum;
371 switch (boxnum) {
372 case 0:
373 box_reg = REG_HMEBOX_0;
374 box_extreg = REG_HMEBOX_EXT_0;
375 break;
376 case 1:
377 box_reg = REG_HMEBOX_1;
378 box_extreg = REG_HMEBOX_EXT_1;
379 break;
380 case 2:
381 box_reg = REG_HMEBOX_2;
382 box_extreg = REG_HMEBOX_EXT_2;
383 break;
384 case 3:
385 box_reg = REG_HMEBOX_3;
386 box_extreg = REG_HMEBOX_EXT_3;
387 break;
388 default:
389 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
390 ("switch case not process\n"));
391 break;
392 }
393
394 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
395 while (!isfw_read) {
396
397 wait_h2c_limmit--;
398 if (wait_h2c_limmit == 0) {
399 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
400 ("Wating too long for FW read "
401 "clear HMEBox(%d)!\n", boxnum));
402 break;
403 }
404
405 udelay(10);
406
407 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
408 u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
409 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
410 ("Wating for FW read clear HMEBox(%d)!!! "
411 "0x1BF = %2x\n", boxnum, u1b_tmp));
412 }
413
414 if (!isfw_read) {
415 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
416 ("Write H2C register BOX[%d] fail!!!!! "
417 "Fw do not read.\n", boxnum));
418 break;
419 }
420
421 memset(boxcontent, 0, sizeof(boxcontent));
422 memset(boxextcontent, 0, sizeof(boxextcontent));
423 boxcontent[0] = element_id;
424 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
425 ("Write element_id box_reg(%4x) = %2x\n",
426 box_reg, element_id));
427
428 switch (cmd_len) {
429 case 1:
430 boxcontent[0] &= ~(BIT(7));
431 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500432 p_cmdbuffer, 1);
Larry Finger0c817332010-12-08 11:12:31 -0600433
434 for (idx = 0; idx < 4; idx++) {
435 rtl_write_byte(rtlpriv, box_reg + idx,
436 boxcontent[idx]);
437 }
438 break;
439 case 2:
440 boxcontent[0] &= ~(BIT(7));
441 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500442 p_cmdbuffer, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600443
444 for (idx = 0; idx < 4; idx++) {
445 rtl_write_byte(rtlpriv, box_reg + idx,
446 boxcontent[idx]);
447 }
448 break;
449 case 3:
450 boxcontent[0] &= ~(BIT(7));
451 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500452 p_cmdbuffer, 3);
Larry Finger0c817332010-12-08 11:12:31 -0600453
454 for (idx = 0; idx < 4; idx++) {
455 rtl_write_byte(rtlpriv, box_reg + idx,
456 boxcontent[idx]);
457 }
458 break;
459 case 4:
460 boxcontent[0] |= (BIT(7));
461 memcpy((u8 *) (boxextcontent),
Larry Finger32473282011-03-27 16:19:57 -0500462 p_cmdbuffer, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600463 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500464 p_cmdbuffer + 2, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600465
466 for (idx = 0; idx < 2; idx++) {
467 rtl_write_byte(rtlpriv, box_extreg + idx,
468 boxextcontent[idx]);
469 }
470
471 for (idx = 0; idx < 4; idx++) {
472 rtl_write_byte(rtlpriv, box_reg + idx,
473 boxcontent[idx]);
474 }
475 break;
476 case 5:
477 boxcontent[0] |= (BIT(7));
478 memcpy((u8 *) (boxextcontent),
Larry Finger32473282011-03-27 16:19:57 -0500479 p_cmdbuffer, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600480 memcpy((u8 *) (boxcontent) + 1,
Larry Finger32473282011-03-27 16:19:57 -0500481 p_cmdbuffer + 2, 3);
Larry Finger0c817332010-12-08 11:12:31 -0600482
483 for (idx = 0; idx < 2; idx++) {
484 rtl_write_byte(rtlpriv, box_extreg + idx,
485 boxextcontent[idx]);
486 }
487
488 for (idx = 0; idx < 4; idx++) {
489 rtl_write_byte(rtlpriv, box_reg + idx,
490 boxcontent[idx]);
491 }
492 break;
493 default:
494 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
495 ("switch case not process\n"));
496 break;
497 }
498
499 bwrite_sucess = true;
500
501 rtlhal->last_hmeboxnum = boxnum + 1;
502 if (rtlhal->last_hmeboxnum == 4)
503 rtlhal->last_hmeboxnum = 0;
504
505 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
506 ("pHalData->last_hmeboxnum = %d\n",
507 rtlhal->last_hmeboxnum));
508 }
509
510 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
Larry Finger7ea47242011-02-19 16:28:57 -0600511 rtlhal->h2c_setinprogress = false;
Larry Finger0c817332010-12-08 11:12:31 -0600512 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
513
514 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("go out\n"));
515}
516
517void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
518 u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
519{
520 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
521 u32 tmp_cmdbuf[2];
522
Larry Finger7ea47242011-02-19 16:28:57 -0600523 if (rtlhal->fw_ready == false) {
Larry Finger0c817332010-12-08 11:12:31 -0600524 RT_ASSERT(false, ("return H2C cmd because of Fw "
525 "download fail!!!\n"));
526 return;
527 }
528
529 memset(tmp_cmdbuf, 0, 8);
530 memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
531 _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
532
533 return;
534}
Larry Finger1472d3a2011-02-23 10:24:58 -0600535EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
Larry Finger0c817332010-12-08 11:12:31 -0600536
537void rtl92c_firmware_selfreset(struct ieee80211_hw *hw)
538{
539 u8 u1b_tmp;
540 u8 delay = 100;
541 struct rtl_priv *rtlpriv = rtl_priv(hw);
542
543 rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
544 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
545
546 while (u1b_tmp & BIT(2)) {
547 delay--;
548 if (delay == 0) {
549 RT_ASSERT(false, ("8051 reset fail.\n"));
550 break;
551 }
552 udelay(50);
553 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
554 }
555}
Larry Finger1472d3a2011-02-23 10:24:58 -0600556EXPORT_SYMBOL(rtl92c_firmware_selfreset);
Larry Finger0c817332010-12-08 11:12:31 -0600557
558void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
559{
560 struct rtl_priv *rtlpriv = rtl_priv(hw);
561 u8 u1_h2c_set_pwrmode[3] = {0};
562 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
563
564 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("FW LPS mode = %d\n", mode));
565
566 SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
567 SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
568 SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
569 ppsc->reg_max_lps_awakeintvl);
570
571 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
572 "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
573 u1_h2c_set_pwrmode, 3);
574 rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
575
576}
Larry Finger1472d3a2011-02-23 10:24:58 -0600577EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
Larry Finger0c817332010-12-08 11:12:31 -0600578
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500579static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
580 struct sk_buff *skb)
581{
582 struct rtl_priv *rtlpriv = rtl_priv(hw);
583 struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
584 struct rtl8192_tx_ring *ring;
585 struct rtl_tx_desc *pdesc;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500586 unsigned long flags;
587 struct sk_buff *pskb = NULL;
588
589 ring = &rtlpci->tx_ring[BEACON_QUEUE];
590
591 pskb = __skb_dequeue(&ring->queue);
592 if (pskb)
593 kfree_skb(pskb);
594
595 spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
596
597 pdesc = &ring->desc[0];
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500598
599 rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
600
601 __skb_queue_tail(&ring->queue, skb);
602
603 spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
604
605 rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
606
607 return true;
608}
609
Larry Finger0c817332010-12-08 11:12:31 -0600610#define BEACON_PG 0 /*->1*/
611#define PSPOLL_PG 2
612#define NULL_PG 3
613#define PROBERSP_PG 4 /*->5*/
614
615#define TOTAL_RESERVED_PKT_LEN 768
616
617static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
618 /* page 0 beacon */
619 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
620 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
621 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
622 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
623 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
624 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
625 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
626 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
627 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
628 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
629 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
630 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
631 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
632 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
633 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
634 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
635
636 /* page 1 beacon */
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 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 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
650 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
651 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
652 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
653
654 /* page 2 ps-poll */
655 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
656 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
664 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
665 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
666 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
667 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
668 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
669 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
671
672 /* page 3 null */
673 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
674 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
675 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 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 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
686 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
687 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
688 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
689
690 /* page 4 probe_resp */
691 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
692 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
693 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
694 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
695 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
696 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
697 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
698 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
699 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
700 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
701 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
702 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
703 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
704 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
705 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
706 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
707
708 /* page 5 probe_resp */
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
722 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
723 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
724 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
725};
726
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500727void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
Larry Finger0c817332010-12-08 11:12:31 -0600728{
729 struct rtl_priv *rtlpriv = rtl_priv(hw);
730 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
731 struct sk_buff *skb = NULL;
732
733 u32 totalpacketlen;
734 bool rtstatus;
735 u8 u1RsvdPageLoc[3] = {0};
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500736 bool dlok = false;
Larry Finger0c817332010-12-08 11:12:31 -0600737
738 u8 *beacon;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500739 u8 *pspoll;
Larry Finger0c817332010-12-08 11:12:31 -0600740 u8 *nullfunc;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500741 u8 *probersp;
Larry Finger0c817332010-12-08 11:12:31 -0600742 /*---------------------------------------------------------
743 (1) beacon
744 ---------------------------------------------------------*/
745 beacon = &reserved_page_packet[BEACON_PG * 128];
746 SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
747 SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
748
749 /*-------------------------------------------------------
750 (2) ps-poll
751 --------------------------------------------------------*/
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500752 pspoll = &reserved_page_packet[PSPOLL_PG * 128];
753 SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000));
754 SET_80211_PS_POLL_BSSID(pspoll, mac->bssid);
755 SET_80211_PS_POLL_TA(pspoll, mac->mac_addr);
Larry Finger0c817332010-12-08 11:12:31 -0600756
757 SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
758
759 /*--------------------------------------------------------
760 (3) null data
761 ---------------------------------------------------------*/
762 nullfunc = &reserved_page_packet[NULL_PG * 128];
763 SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
764 SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
765 SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
766
767 SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
768
769 /*---------------------------------------------------------
770 (4) probe response
771 ----------------------------------------------------------*/
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500772 probersp = &reserved_page_packet[PROBERSP_PG * 128];
773 SET_80211_HDR_ADDRESS1(probersp, mac->bssid);
774 SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr);
775 SET_80211_HDR_ADDRESS3(probersp, mac->bssid);
Larry Finger0c817332010-12-08 11:12:31 -0600776
777 SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
778
779 totalpacketlen = TOTAL_RESERVED_PKT_LEN;
780
781 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
782 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
783 &reserved_page_packet[0], totalpacketlen);
784 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
785 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
786 u1RsvdPageLoc, 3);
787
788
789 skb = dev_alloc_skb(totalpacketlen);
790 memcpy((u8 *) skb_put(skb, totalpacketlen),
791 &reserved_page_packet, totalpacketlen);
792
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500793 rtstatus = _rtl92c_cmd_send_packet(hw, skb);
Larry Finger0c817332010-12-08 11:12:31 -0600794
795 if (rtstatus)
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500796 dlok = true;
Larry Finger0c817332010-12-08 11:12:31 -0600797
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500798 if (dlok) {
Larry Finger0c817332010-12-08 11:12:31 -0600799 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
800 ("Set RSVD page location to Fw.\n"));
801 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
802 "H2C_RSVDPAGE:\n",
803 u1RsvdPageLoc, 3);
804 rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
805 sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
806 } else
807 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
808 ("Set RSVD page location to Fw FAIL!!!!!!.\n"));
809}
Larry Finger1472d3a2011-02-23 10:24:58 -0600810EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
Larry Finger0c817332010-12-08 11:12:31 -0600811
812void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
813{
814 u8 u1_joinbssrpt_parm[1] = {0};
815
816 SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
817
818 rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
819}
Larry Finger1472d3a2011-02-23 10:24:58 -0600820EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);