blob: 17f6903c14bbe6f33067b83529a6f124a0b0270d [file] [log] [blame]
Chaoming Li985d4d32011-06-10 15:09:40 -05001/******************************************************************************
2 *
Larry Finger6a57b082012-01-07 20:46:46 -06003 * Copyright(c) 2009-2012 Realtek Corporation.
Chaoming Li985d4d32011-06-10 15:09:40 -05004 *
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 *
Chaoming Li985d4d32011-06-10 15:09:40 -050014 * 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 "reg.h"
30#include "def.h"
31#include "fw.h"
32#include "sw.h"
33
34static bool _rtl92d_is_fw_downloaded(struct rtl_priv *rtlpriv)
35{
36 return (rtl_read_dword(rtlpriv, REG_MCUFWDL) & MCUFWDL_RDY) ?
37 true : false;
38}
39
40static void _rtl92d_enable_fw_download(struct ieee80211_hw *hw, bool enable)
41{
42 struct rtl_priv *rtlpriv = rtl_priv(hw);
43 u8 tmp;
44
45 if (enable) {
46 tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
47 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
48 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
49 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
50 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
51 rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
52 } else {
53 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
54 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
55 /* Reserved for fw extension.
56 * 0x81[7] is used for mac0 status ,
57 * so don't write this reg here
58 * rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);*/
59 }
60}
61
62static void _rtl92d_fw_block_write(struct ieee80211_hw *hw,
63 const u8 *buffer, u32 size)
64{
65 struct rtl_priv *rtlpriv = rtl_priv(hw);
66 u32 blocksize = sizeof(u32);
67 u8 *bufferptr = (u8 *) buffer;
68 u32 *pu4BytePtr = (u32 *) buffer;
69 u32 i, offset, blockCount, remainSize;
70
71 blockCount = size / blocksize;
72 remainSize = size % blocksize;
73 for (i = 0; i < blockCount; i++) {
74 offset = i * blocksize;
75 rtl_write_dword(rtlpriv, (FW_8192D_START_ADDRESS + offset),
76 *(pu4BytePtr + i));
77 }
78 if (remainSize) {
79 offset = blockCount * blocksize;
80 bufferptr += offset;
81 for (i = 0; i < remainSize; i++) {
82 rtl_write_byte(rtlpriv, (FW_8192D_START_ADDRESS +
83 offset + i), *(bufferptr + i));
84 }
85 }
86}
87
88static void _rtl92d_fw_page_write(struct ieee80211_hw *hw,
89 u32 page, const u8 *buffer, u32 size)
90{
91 struct rtl_priv *rtlpriv = rtl_priv(hw);
92 u8 value8;
93 u8 u8page = (u8) (page & 0x07);
94
95 value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
96 rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
97 _rtl92d_fw_block_write(hw, buffer, size);
98}
99
100static void _rtl92d_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
101{
102 u32 fwlen = *pfwlen;
103 u8 remain = (u8) (fwlen % 4);
104
105 remain = (remain == 0) ? 0 : (4 - remain);
106 while (remain > 0) {
107 pfwbuf[fwlen] = 0;
108 fwlen++;
109 remain--;
110 }
111 *pfwlen = fwlen;
112}
113
114static void _rtl92d_write_fw(struct ieee80211_hw *hw,
115 enum version_8192d version, u8 *buffer, u32 size)
116{
117 struct rtl_priv *rtlpriv = rtl_priv(hw);
118 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
Joe Perches2c208892012-06-04 12:44:17 +0000119 u8 *bufferPtr = buffer;
Chaoming Li985d4d32011-06-10 15:09:40 -0500120 u32 pagenums, remainSize;
121 u32 page, offset;
122
Joe Perchesf30d7502012-01-04 19:40:41 -0800123 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
Chaoming Li985d4d32011-06-10 15:09:40 -0500124 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE)
125 _rtl92d_fill_dummy(bufferPtr, &size);
126 pagenums = size / FW_8192D_PAGE_SIZE;
127 remainSize = size % FW_8192D_PAGE_SIZE;
128 if (pagenums > 8) {
129 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
Joe Perchesf30d7502012-01-04 19:40:41 -0800130 "Page numbers should not greater then 8\n");
Chaoming Li985d4d32011-06-10 15:09:40 -0500131 }
132 for (page = 0; page < pagenums; page++) {
133 offset = page * FW_8192D_PAGE_SIZE;
134 _rtl92d_fw_page_write(hw, page, (bufferPtr + offset),
135 FW_8192D_PAGE_SIZE);
136 }
137 if (remainSize) {
138 offset = pagenums * FW_8192D_PAGE_SIZE;
139 page = pagenums;
140 _rtl92d_fw_page_write(hw, page, (bufferPtr + offset),
141 remainSize);
142 }
143}
144
145static int _rtl92d_fw_free_to_go(struct ieee80211_hw *hw)
146{
147 struct rtl_priv *rtlpriv = rtl_priv(hw);
148 u32 counter = 0;
149 u32 value32;
150
151 do {
152 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
153 } while ((counter++ < FW_8192D_POLLING_TIMEOUT_COUNT) &&
154 (!(value32 & FWDL_ChkSum_rpt)));
155 if (counter >= FW_8192D_POLLING_TIMEOUT_COUNT) {
156 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
Joe Perchesf30d7502012-01-04 19:40:41 -0800157 "chksum report faill ! REG_MCUFWDL:0x%08x\n",
158 value32);
Chaoming Li985d4d32011-06-10 15:09:40 -0500159 return -EIO;
160 }
161 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
Joe Perchesf30d7502012-01-04 19:40:41 -0800162 "Checksum report OK ! REG_MCUFWDL:0x%08x\n", value32);
Chaoming Li985d4d32011-06-10 15:09:40 -0500163 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
164 value32 |= MCUFWDL_RDY;
165 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
166 return 0;
167}
168
169void rtl92d_firmware_selfreset(struct ieee80211_hw *hw)
170{
171 struct rtl_priv *rtlpriv = rtl_priv(hw);
172 u8 u1b_tmp;
173 u8 delay = 100;
174
175 /* Set (REG_HMETFR + 3) to 0x20 is reset 8051 */
176 rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
177 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
178 while (u1b_tmp & BIT(2)) {
179 delay--;
180 if (delay == 0)
181 break;
182 udelay(50);
183 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
184 }
Joe Perches9d833ed2012-01-04 19:40:43 -0800185 RT_ASSERT((delay > 0), "8051 reset failed!\n");
Chaoming Li985d4d32011-06-10 15:09:40 -0500186 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
Joe Perchesf30d7502012-01-04 19:40:41 -0800187 "=====> 8051 reset success (%d)\n", delay);
Chaoming Li985d4d32011-06-10 15:09:40 -0500188}
189
190static int _rtl92d_fw_init(struct ieee80211_hw *hw)
191{
192 struct rtl_priv *rtlpriv = rtl_priv(hw);
193 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
194 u32 counter;
195
Joe Perchesf30d7502012-01-04 19:40:41 -0800196 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, "FW already have download\n");
Chaoming Li985d4d32011-06-10 15:09:40 -0500197 /* polling for FW ready */
198 counter = 0;
199 do {
200 if (rtlhal->interfaceindex == 0) {
201 if (rtl_read_byte(rtlpriv, FW_MAC0_READY) &
202 MAC0_READY) {
203 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
Joe Perchesf30d7502012-01-04 19:40:41 -0800204 "Polling FW ready success!! REG_MCUFWDL: 0x%x\n",
Chaoming Li985d4d32011-06-10 15:09:40 -0500205 rtl_read_byte(rtlpriv,
Joe Perchesf30d7502012-01-04 19:40:41 -0800206 FW_MAC0_READY));
Chaoming Li985d4d32011-06-10 15:09:40 -0500207 return 0;
208 }
209 udelay(5);
210 } else {
211 if (rtl_read_byte(rtlpriv, FW_MAC1_READY) &
212 MAC1_READY) {
213 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
Joe Perchesf30d7502012-01-04 19:40:41 -0800214 "Polling FW ready success!! REG_MCUFWDL: 0x%x\n",
Chaoming Li985d4d32011-06-10 15:09:40 -0500215 rtl_read_byte(rtlpriv,
Joe Perchesf30d7502012-01-04 19:40:41 -0800216 FW_MAC1_READY));
Chaoming Li985d4d32011-06-10 15:09:40 -0500217 return 0;
218 }
219 udelay(5);
220 }
221 } while (counter++ < POLLING_READY_TIMEOUT_COUNT);
222
223 if (rtlhal->interfaceindex == 0) {
224 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
Joe Perchesf30d7502012-01-04 19:40:41 -0800225 "Polling FW ready fail!! MAC0 FW init not ready: 0x%x\n",
226 rtl_read_byte(rtlpriv, FW_MAC0_READY));
Chaoming Li985d4d32011-06-10 15:09:40 -0500227 } else {
228 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
Joe Perchesf30d7502012-01-04 19:40:41 -0800229 "Polling FW ready fail!! MAC1 FW init not ready: 0x%x\n",
230 rtl_read_byte(rtlpriv, FW_MAC1_READY));
Chaoming Li985d4d32011-06-10 15:09:40 -0500231 }
232 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
Joe Perchesf30d7502012-01-04 19:40:41 -0800233 "Polling FW ready fail!! REG_MCUFWDL:0x%08ul\n",
234 rtl_read_dword(rtlpriv, REG_MCUFWDL));
Chaoming Li985d4d32011-06-10 15:09:40 -0500235 return -1;
236}
237
238int rtl92d_download_fw(struct ieee80211_hw *hw)
239{
240 struct rtl_priv *rtlpriv = rtl_priv(hw);
241 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
242 u8 *pfwheader;
243 u8 *pfwdata;
244 u32 fwsize;
245 int err;
246 enum version_8192d version = rtlhal->version;
247 u8 value;
248 u32 count;
249 bool fw_downloaded = false, fwdl_in_process = false;
250 unsigned long flags;
251
Larry Fingerb0302ab2012-01-30 09:54:49 -0600252 if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
Chaoming Li985d4d32011-06-10 15:09:40 -0500253 return 1;
254 fwsize = rtlhal->fwsize;
Joe Perches2c208892012-06-04 12:44:17 +0000255 pfwheader = rtlhal->pfirmware;
256 pfwdata = rtlhal->pfirmware;
Chaoming Li985d4d32011-06-10 15:09:40 -0500257 rtlhal->fw_version = (u16) GET_FIRMWARE_HDR_VERSION(pfwheader);
258 rtlhal->fw_subversion = (u16) GET_FIRMWARE_HDR_SUB_VER(pfwheader);
Joe Perchesf30d7502012-01-04 19:40:41 -0800259 RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
260 "FirmwareVersion(%d), FirmwareSubVersion(%d), Signature(%#x)\n",
261 rtlhal->fw_version, rtlhal->fw_subversion,
262 GET_FIRMWARE_HDR_SIGNATURE(pfwheader));
Chaoming Li985d4d32011-06-10 15:09:40 -0500263 if (IS_FW_HEADER_EXIST(pfwheader)) {
264 RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
Joe Perchesf30d7502012-01-04 19:40:41 -0800265 "Shift 32 bytes for FW header!!\n");
Chaoming Li985d4d32011-06-10 15:09:40 -0500266 pfwdata = pfwdata + 32;
267 fwsize = fwsize - 32;
268 }
269
270 spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
271 fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv);
272 if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5))
273 fwdl_in_process = true;
274 else
275 fwdl_in_process = false;
276 if (fw_downloaded) {
277 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
278 goto exit;
279 } else if (fwdl_in_process) {
280 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
281 for (count = 0; count < 5000; count++) {
282 udelay(500);
283 spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
284 fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv);
285 if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5))
286 fwdl_in_process = true;
287 else
288 fwdl_in_process = false;
289 spin_unlock_irqrestore(&globalmutex_for_fwdownload,
290 flags);
291 if (fw_downloaded)
292 goto exit;
293 else if (!fwdl_in_process)
294 break;
295 else
296 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
Joe Perchesf30d7502012-01-04 19:40:41 -0800297 "Wait for another mac download fw\n");
Chaoming Li985d4d32011-06-10 15:09:40 -0500298 }
299 spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
300 value = rtl_read_byte(rtlpriv, 0x1f);
301 value |= BIT(5);
302 rtl_write_byte(rtlpriv, 0x1f, value);
303 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
304 } else {
305 value = rtl_read_byte(rtlpriv, 0x1f);
306 value |= BIT(5);
307 rtl_write_byte(rtlpriv, 0x1f, value);
308 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
309 }
310
311 /* If 8051 is running in RAM code, driver should
312 * inform Fw to reset by itself, or it will cause
313 * download Fw fail.*/
314 /* 8051 RAM code */
315 if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
316 rtl92d_firmware_selfreset(hw);
317 rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
318 }
319 _rtl92d_enable_fw_download(hw, true);
320 _rtl92d_write_fw(hw, version, pfwdata, fwsize);
321 _rtl92d_enable_fw_download(hw, false);
322 spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
323 err = _rtl92d_fw_free_to_go(hw);
324 /* download fw over,clear 0x1f[5] */
325 value = rtl_read_byte(rtlpriv, 0x1f);
326 value &= (~BIT(5));
327 rtl_write_byte(rtlpriv, 0x1f, value);
328 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
329 if (err) {
330 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
Joe Perchesf30d7502012-01-04 19:40:41 -0800331 "fw is not ready to run!\n");
Chaoming Li985d4d32011-06-10 15:09:40 -0500332 goto exit;
333 } else {
Joe Perchesf30d7502012-01-04 19:40:41 -0800334 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "fw is ready to run!\n");
Chaoming Li985d4d32011-06-10 15:09:40 -0500335 }
336exit:
337 err = _rtl92d_fw_init(hw);
338 return err;
339}
340
341static bool _rtl92d_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
342{
343 struct rtl_priv *rtlpriv = rtl_priv(hw);
344 u8 val_hmetfr;
345 bool result = false;
346
347 val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
348 if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
349 result = true;
350 return result;
351}
352
353static void _rtl92d_fill_h2c_command(struct ieee80211_hw *hw,
354 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
355{
356 struct rtl_priv *rtlpriv = rtl_priv(hw);
357 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
358 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
359 u8 boxnum;
360 u16 box_reg = 0, box_extreg = 0;
361 u8 u1b_tmp;
362 bool isfw_read = false;
363 u8 buf_index = 0;
Anatol Pomozov4907cb72012-09-01 10:31:09 -0700364 bool bwrite_success = false;
Chaoming Li985d4d32011-06-10 15:09:40 -0500365 u8 wait_h2c_limmit = 100;
366 u8 wait_writeh2c_limmit = 100;
367 u8 boxcontent[4], boxextcontent[2];
368 u32 h2c_waitcounter = 0;
369 unsigned long flag;
370 u8 idx;
371
372 if (ppsc->rfpwr_state == ERFOFF || ppsc->inactive_pwrstate == ERFOFF) {
373 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
Joe Perchesf30d7502012-01-04 19:40:41 -0800374 "Return as RF is off!!!\n");
Chaoming Li985d4d32011-06-10 15:09:40 -0500375 return;
376 }
Joe Perchesf30d7502012-01-04 19:40:41 -0800377 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
Chaoming Li985d4d32011-06-10 15:09:40 -0500378 while (true) {
379 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
380 if (rtlhal->h2c_setinprogress) {
381 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
Joe Perchesf30d7502012-01-04 19:40:41 -0800382 "H2C set in progress! Wait to set..element_id(%d)\n",
383 element_id);
Chaoming Li985d4d32011-06-10 15:09:40 -0500384
385 while (rtlhal->h2c_setinprogress) {
386 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
387 flag);
388 h2c_waitcounter++;
389 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
Joe Perchesf30d7502012-01-04 19:40:41 -0800390 "Wait 100 us (%d times)...\n",
391 h2c_waitcounter);
Chaoming Li985d4d32011-06-10 15:09:40 -0500392 udelay(100);
393
394 if (h2c_waitcounter > 1000)
395 return;
396
397 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
398 flag);
399 }
400 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
401 } else {
402 rtlhal->h2c_setinprogress = true;
403 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
404 break;
405 }
406 }
Anatol Pomozov4907cb72012-09-01 10:31:09 -0700407 while (!bwrite_success) {
Chaoming Li985d4d32011-06-10 15:09:40 -0500408 wait_writeh2c_limmit--;
409 if (wait_writeh2c_limmit == 0) {
410 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
Joe Perchesf30d7502012-01-04 19:40:41 -0800411 "Write H2C fail because no trigger for FW INT!\n");
Chaoming Li985d4d32011-06-10 15:09:40 -0500412 break;
413 }
414 boxnum = rtlhal->last_hmeboxnum;
415 switch (boxnum) {
416 case 0:
417 box_reg = REG_HMEBOX_0;
418 box_extreg = REG_HMEBOX_EXT_0;
419 break;
420 case 1:
421 box_reg = REG_HMEBOX_1;
422 box_extreg = REG_HMEBOX_EXT_1;
423 break;
424 case 2:
425 box_reg = REG_HMEBOX_2;
426 box_extreg = REG_HMEBOX_EXT_2;
427 break;
428 case 3:
429 box_reg = REG_HMEBOX_3;
430 box_extreg = REG_HMEBOX_EXT_3;
431 break;
432 default:
433 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
Joe Perchesad574882016-09-23 11:27:19 -0700434 "switch case %#x not processed\n", boxnum);
Chaoming Li985d4d32011-06-10 15:09:40 -0500435 break;
436 }
437 isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);
438 while (!isfw_read) {
439 wait_h2c_limmit--;
440 if (wait_h2c_limmit == 0) {
441 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
Joe Perchesf30d7502012-01-04 19:40:41 -0800442 "Waiting too long for FW read clear HMEBox(%d)!\n",
443 boxnum);
Chaoming Li985d4d32011-06-10 15:09:40 -0500444 break;
445 }
446 udelay(10);
447 isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);
448 u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
449 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
Joe Perchesf30d7502012-01-04 19:40:41 -0800450 "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
451 boxnum, u1b_tmp);
Chaoming Li985d4d32011-06-10 15:09:40 -0500452 }
453 if (!isfw_read) {
454 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
Joe Perchesf30d7502012-01-04 19:40:41 -0800455 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
456 boxnum);
Chaoming Li985d4d32011-06-10 15:09:40 -0500457 break;
458 }
459 memset(boxcontent, 0, sizeof(boxcontent));
460 memset(boxextcontent, 0, sizeof(boxextcontent));
461 boxcontent[0] = element_id;
462 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
Joe Perchesf30d7502012-01-04 19:40:41 -0800463 "Write element_id box_reg(%4x) = %2x\n",
464 box_reg, element_id);
Chaoming Li985d4d32011-06-10 15:09:40 -0500465 switch (cmd_len) {
466 case 1:
467 boxcontent[0] &= ~(BIT(7));
468 memcpy(boxcontent + 1, cmdbuffer + buf_index, 1);
469 for (idx = 0; idx < 4; idx++)
470 rtl_write_byte(rtlpriv, box_reg + idx,
471 boxcontent[idx]);
472 break;
473 case 2:
474 boxcontent[0] &= ~(BIT(7));
475 memcpy(boxcontent + 1, cmdbuffer + buf_index, 2);
476 for (idx = 0; idx < 4; idx++)
477 rtl_write_byte(rtlpriv, box_reg + idx,
478 boxcontent[idx]);
479 break;
480 case 3:
481 boxcontent[0] &= ~(BIT(7));
482 memcpy(boxcontent + 1, cmdbuffer + buf_index, 3);
483 for (idx = 0; idx < 4; idx++)
484 rtl_write_byte(rtlpriv, box_reg + idx,
485 boxcontent[idx]);
486 break;
487 case 4:
488 boxcontent[0] |= (BIT(7));
489 memcpy(boxextcontent, cmdbuffer + buf_index, 2);
490 memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 2);
491 for (idx = 0; idx < 2; idx++)
492 rtl_write_byte(rtlpriv, box_extreg + idx,
493 boxextcontent[idx]);
494 for (idx = 0; idx < 4; idx++)
495 rtl_write_byte(rtlpriv, box_reg + idx,
496 boxcontent[idx]);
497 break;
498 case 5:
499 boxcontent[0] |= (BIT(7));
500 memcpy(boxextcontent, cmdbuffer + buf_index, 2);
501 memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 3);
502 for (idx = 0; idx < 2; idx++)
503 rtl_write_byte(rtlpriv, box_extreg + idx,
504 boxextcontent[idx]);
505 for (idx = 0; idx < 4; idx++)
506 rtl_write_byte(rtlpriv, box_reg + idx,
507 boxcontent[idx]);
508 break;
509 default:
510 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
Joe Perchesad574882016-09-23 11:27:19 -0700511 "switch case %#x not processed\n", cmd_len);
Chaoming Li985d4d32011-06-10 15:09:40 -0500512 break;
513 }
Anatol Pomozov4907cb72012-09-01 10:31:09 -0700514 bwrite_success = true;
Chaoming Li985d4d32011-06-10 15:09:40 -0500515 rtlhal->last_hmeboxnum = boxnum + 1;
516 if (rtlhal->last_hmeboxnum == 4)
517 rtlhal->last_hmeboxnum = 0;
518 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
Joe Perchesf30d7502012-01-04 19:40:41 -0800519 "pHalData->last_hmeboxnum = %d\n",
520 rtlhal->last_hmeboxnum);
Chaoming Li985d4d32011-06-10 15:09:40 -0500521 }
522 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
523 rtlhal->h2c_setinprogress = false;
524 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
Joe Perchesf30d7502012-01-04 19:40:41 -0800525 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
Chaoming Li985d4d32011-06-10 15:09:40 -0500526}
527
528void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw,
529 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
530{
Chaoming Li985d4d32011-06-10 15:09:40 -0500531 u32 tmp_cmdbuf[2];
532
Chaoming Li985d4d32011-06-10 15:09:40 -0500533 memset(tmp_cmdbuf, 0, 8);
534 memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
535 _rtl92d_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
536 return;
537}
538
Chaoming Li985d4d32011-06-10 15:09:40 -0500539static bool _rtl92d_cmd_send_packet(struct ieee80211_hw *hw,
540 struct sk_buff *skb)
541{
542 struct rtl_priv *rtlpriv = rtl_priv(hw);
543 struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
544 struct rtl8192_tx_ring *ring;
545 struct rtl_tx_desc *pdesc;
546 u8 idx = 0;
547 unsigned long flags;
548 struct sk_buff *pskb;
549
550 ring = &rtlpci->tx_ring[BEACON_QUEUE];
551 pskb = __skb_dequeue(&ring->queue);
Wei Yongjund6b389e2012-08-28 21:11:34 +0800552 kfree_skb(pskb);
Chaoming Li985d4d32011-06-10 15:09:40 -0500553 spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
554 pdesc = &ring->desc[idx];
555 /* discard output from call below */
556 rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
557 rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
558 __skb_queue_tail(&ring->queue, skb);
559 spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
560 rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
561 return true;
562}
563
564#define BEACON_PG 0 /*->1 */
565#define PSPOLL_PG 2
566#define NULL_PG 3
567#define PROBERSP_PG 4 /*->5 */
568#define TOTAL_RESERVED_PKT_LEN 768
569
570static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
571 /* page 0 beacon */
572 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
573 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
574 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
575 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
576 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
577 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
578 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
579 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
580 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
581 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
582 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
583 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
584 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
585 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
586 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
587 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
588
589 /* page 1 beacon */
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
600 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
601 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
602 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
603 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
604 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
605 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
606
607 /* page 2 ps-poll */
608 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
609 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
618 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
619 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
620 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
621 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
622 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
623 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
624
625 /* page 3 null */
626 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
627 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
628 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
629 0x00, 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
639 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
640 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
641 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
642
643 /* page 4 probe_resp */
644 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
645 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
646 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
647 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
648 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
649 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
650 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
651 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
652 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
653 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
654 0x03, 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 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
658 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
659 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
660
661 /* page 5 probe_resp */
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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
668 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
669 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
671 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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};
679
680void rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
681{
682 struct rtl_priv *rtlpriv = rtl_priv(hw);
683 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
684 struct sk_buff *skb = NULL;
685 u32 totalpacketlen;
686 bool rtstatus;
687 u8 u1RsvdPageLoc[3] = { 0 };
688 bool dlok = false;
689 u8 *beacon;
690 u8 *p_pspoll;
691 u8 *nullfunc;
692 u8 *p_probersp;
693 /*---------------------------------------------------------
694 (1) beacon
695 ---------------------------------------------------------*/
696 beacon = &reserved_page_packet[BEACON_PG * 128];
697 SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
698 SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
699 /*-------------------------------------------------------
700 (2) ps-poll
701 --------------------------------------------------------*/
702 p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
703 SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
704 SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
705 SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
706 SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
707 /*--------------------------------------------------------
708 (3) null data
709 ---------------------------------------------------------*/
710 nullfunc = &reserved_page_packet[NULL_PG * 128];
711 SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
712 SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
713 SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
714 SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
715 /*---------------------------------------------------------
716 (4) probe response
717 ----------------------------------------------------------*/
718 p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
719 SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
720 SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
721 SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
722 SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
723 totalpacketlen = TOTAL_RESERVED_PKT_LEN;
724 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
Joe Perchesaf086872012-01-04 19:40:40 -0800725 "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
Chaoming Li985d4d32011-06-10 15:09:40 -0500726 &reserved_page_packet[0], totalpacketlen);
727 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
Joe Perchesaf086872012-01-04 19:40:40 -0800728 "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
Chaoming Li985d4d32011-06-10 15:09:40 -0500729 u1RsvdPageLoc, 3);
730 skb = dev_alloc_skb(totalpacketlen);
Larry Finger76a92be2012-01-07 20:46:40 -0600731 if (!skb) {
732 dlok = false;
733 } else {
734 memcpy((u8 *) skb_put(skb, totalpacketlen),
735 &reserved_page_packet, totalpacketlen);
736 rtstatus = _rtl92d_cmd_send_packet(hw, skb);
Chaoming Li985d4d32011-06-10 15:09:40 -0500737
Larry Finger76a92be2012-01-07 20:46:40 -0600738 if (rtstatus)
739 dlok = true;
740 }
Chaoming Li985d4d32011-06-10 15:09:40 -0500741 if (dlok) {
742 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
Joe Perchesf30d7502012-01-04 19:40:41 -0800743 "Set RSVD page location to Fw\n");
Chaoming Li985d4d32011-06-10 15:09:40 -0500744 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
Joe Perchesaf086872012-01-04 19:40:40 -0800745 "H2C_RSVDPAGE", u1RsvdPageLoc, 3);
Chaoming Li985d4d32011-06-10 15:09:40 -0500746 rtl92d_fill_h2c_cmd(hw, H2C_RSVDPAGE,
747 sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
748 } else
749 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
Joe Perchesf30d7502012-01-04 19:40:41 -0800750 "Set RSVD page location to Fw FAIL!!!!!!\n");
Chaoming Li985d4d32011-06-10 15:09:40 -0500751}
752
753void rtl92d_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
754{
755 u8 u1_joinbssrpt_parm[1] = {0};
756
757 SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
758 rtl92d_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
759}