blob: a00861b26ece7ae6b2c6168ca22bdaed42c71033 [file] [log] [blame]
Larry Finger0c817332010-12-08 11:12:31 -06001/******************************************************************************
2 *
Larry Fingerfc616852012-01-07 20:46:43 -06003 * Copyright(c) 2009-2012 Realtek Corporation.
Larry Finger0c817332010-12-08 11:12:31 -06004 *
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 *
Larry Finger0c817332010-12-08 11:12:31 -060014 * 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
Larry Finger0c817332010-12-08 11:12:31 -060026#include "../wifi.h"
27#include "../pci.h"
28#include "../base.h"
Larry Finger557f9332014-09-26 16:40:27 -050029#include "../core.h"
Larry Finger1472d3a2011-02-23 10:24:58 -060030#include "../rtl8192ce/reg.h"
31#include "../rtl8192ce/def.h"
32#include "fw_common.h"
Larry Fingerd273bb22012-01-27 13:59:25 -060033#include <linux/export.h>
Larry Fingerf11bbfd2012-04-13 13:57:43 -050034#include <linux/kmemleak.h>
Larry Finger0c817332010-12-08 11:12:31 -060035
36static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable)
37{
38 struct rtl_priv *rtlpriv = rtl_priv(hw);
39 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
40
41 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU) {
42 u32 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
43 if (enable)
44 value32 |= MCUFWDL_EN;
45 else
46 value32 &= ~MCUFWDL_EN;
47 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
48 } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) {
49 u8 tmp;
50 if (enable) {
51
52 tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
53 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
54 tmp | 0x04);
55
56 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
57 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
58
59 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
60 rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
61 } else {
62
63 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
64 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
65
66 rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
67 }
68 }
69}
70
71static void _rtl92c_fw_block_write(struct ieee80211_hw *hw,
72 const u8 *buffer, u32 size)
73{
74 struct rtl_priv *rtlpriv = rtl_priv(hw);
Larry Finger9f087a92014-09-26 16:40:26 -050075 u32 blocksize = sizeof(u32);
76 u8 *bufferptr = (u8 *)buffer;
77 u32 *pu4byteptr = (u32 *)buffer;
78 u32 i, offset, blockcount, remainsize;
Larry Finger0c817332010-12-08 11:12:31 -060079
Larry Finger9f087a92014-09-26 16:40:26 -050080 blockcount = size / blocksize;
81 remainsize = size % blocksize;
Larry Finger0c817332010-12-08 11:12:31 -060082
Larry Finger9f087a92014-09-26 16:40:26 -050083 for (i = 0; i < blockcount; i++) {
84 offset = i * blocksize;
Larry Finger0c817332010-12-08 11:12:31 -060085 rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
Larry Finger9f087a92014-09-26 16:40:26 -050086 *(pu4byteptr + i));
87 }
88
89 if (remainsize) {
90 offset = blockcount * blocksize;
91 bufferptr += offset;
92 for (i = 0; i < remainsize; i++) {
93 rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS +
94 offset + i), *(bufferptr + i));
95 }
Larry Finger0c817332010-12-08 11:12:31 -060096 }
97}
98
99static void _rtl92c_fw_page_write(struct ieee80211_hw *hw,
100 u32 page, const u8 *buffer, u32 size)
101{
102 struct rtl_priv *rtlpriv = rtl_priv(hw);
103 u8 value8;
104 u8 u8page = (u8) (page & 0x07);
105
106 value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
107
108 rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
109 _rtl92c_fw_block_write(hw, buffer, size);
110}
111
112static void _rtl92c_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
113{
114 u32 fwlen = *pfwlen;
115 u8 remain = (u8) (fwlen % 4);
116
117 remain = (remain == 0) ? 0 : (4 - remain);
118
119 while (remain > 0) {
120 pfwbuf[fwlen] = 0;
121 fwlen++;
122 remain--;
123 }
124
125 *pfwlen = fwlen;
126}
127
128static void _rtl92c_write_fw(struct ieee80211_hw *hw,
129 enum version_8192c version, u8 *buffer, u32 size)
130{
131 struct rtl_priv *rtlpriv = rtl_priv(hw);
132 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
Larry Finger9f087a92014-09-26 16:40:26 -0500133 bool is_version_b;
134 u8 *bufferptr = (u8 *)buffer;
Larry Finger0c817332010-12-08 11:12:31 -0600135
Larry Finger9f087a92014-09-26 16:40:26 -0500136 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
137 is_version_b = IS_NORMAL_CHIP(version);
138 if (is_version_b) {
139 u32 pageNums, remainsize;
Larry Finger0c817332010-12-08 11:12:31 -0600140 u32 page, offset;
141
Larry Finger9f087a92014-09-26 16:40:26 -0500142 if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE)
143 _rtl92c_fill_dummy(bufferptr, &size);
Larry Finger0c817332010-12-08 11:12:31 -0600144
145 pageNums = size / FW_8192C_PAGE_SIZE;
Larry Finger9f087a92014-09-26 16:40:26 -0500146 remainsize = size % FW_8192C_PAGE_SIZE;
Larry Finger0c817332010-12-08 11:12:31 -0600147
148 if (pageNums > 4) {
149 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
Joe Perchesf30d7502012-01-04 19:40:41 -0800150 "Page numbers should not greater then 4\n");
Larry Finger0c817332010-12-08 11:12:31 -0600151 }
152
153 for (page = 0; page < pageNums; page++) {
154 offset = page * FW_8192C_PAGE_SIZE;
Larry Finger9f087a92014-09-26 16:40:26 -0500155 _rtl92c_fw_page_write(hw, page, (bufferptr + offset),
Larry Finger0c817332010-12-08 11:12:31 -0600156 FW_8192C_PAGE_SIZE);
157 }
158
Larry Finger9f087a92014-09-26 16:40:26 -0500159 if (remainsize) {
Larry Finger0c817332010-12-08 11:12:31 -0600160 offset = pageNums * FW_8192C_PAGE_SIZE;
161 page = pageNums;
Larry Finger9f087a92014-09-26 16:40:26 -0500162 _rtl92c_fw_page_write(hw, page, (bufferptr + offset),
163 remainsize);
Larry Finger0c817332010-12-08 11:12:31 -0600164 }
165 } else {
166 _rtl92c_fw_block_write(hw, buffer, size);
167 }
168}
169
170static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
171{
172 struct rtl_priv *rtlpriv = rtl_priv(hw);
Larry Finger9f087a92014-09-26 16:40:26 -0500173 int err = -EIO;
Larry Finger0c817332010-12-08 11:12:31 -0600174 u32 counter = 0;
175 u32 value32;
176
177 do {
178 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
179 } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
180 (!(value32 & FWDL_ChkSum_rpt)));
181
182 if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
183 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
Larry Finger9f087a92014-09-26 16:40:26 -0500184 "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
185 value32);
186 goto exit;
Larry Finger0c817332010-12-08 11:12:31 -0600187 }
188
189 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
Larry Finger9f087a92014-09-26 16:40:26 -0500190 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
Larry Finger0c817332010-12-08 11:12:31 -0600191
192 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
193 value32 |= MCUFWDL_RDY;
194 value32 &= ~WINTINI_RDY;
195 rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
196
197 counter = 0;
198
199 do {
200 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
201 if (value32 & WINTINI_RDY) {
202 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
Larry Finger9f087a92014-09-26 16:40:26 -0500203 "Polling FW ready success!! REG_MCUFWDL:0x%08x .\n",
204 value32);
205 err = 0;
206 goto exit;
Larry Finger0c817332010-12-08 11:12:31 -0600207 }
208
209 mdelay(FW_8192C_POLLING_DELAY);
210
211 } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
212
213 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
Larry Finger9f087a92014-09-26 16:40:26 -0500214 "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32);
215
216exit:
217 return err;
Larry Finger0c817332010-12-08 11:12:31 -0600218}
219
220int rtl92c_download_fw(struct ieee80211_hw *hw)
221{
222 struct rtl_priv *rtlpriv = rtl_priv(hw);
223 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
224 struct rtl92c_firmware_header *pfwheader;
225 u8 *pfwdata;
226 u32 fwsize;
Larry Finger9f087a92014-09-26 16:40:26 -0500227 int err;
Larry Finger0c817332010-12-08 11:12:31 -0600228 enum version_8192c version = rtlhal->version;
229
Larry Finger9f087a92014-09-26 16:40:26 -0500230 if (!rtlhal->pfirmware)
Larry Finger0c817332010-12-08 11:12:31 -0600231 return 1;
Larry Finger0c817332010-12-08 11:12:31 -0600232
233 pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
Larry Finger9f087a92014-09-26 16:40:26 -0500234 pfwdata = (u8 *)rtlhal->pfirmware;
Chaoming_Li3ac5e262011-04-25 12:53:40 -0500235 fwsize = rtlhal->fwsize;
Larry Finger0c817332010-12-08 11:12:31 -0600236
237 if (IS_FW_HEADER_EXIST(pfwheader)) {
238 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
Joe Perchesf30d7502012-01-04 19:40:41 -0800239 "Firmware Version(%d), Signature(%#x),Size(%d)\n",
Larry Finger9f087a92014-09-26 16:40:26 -0500240 pfwheader->version, pfwheader->signature,
241 (int)sizeof(struct rtl92c_firmware_header));
Larry Finger0c817332010-12-08 11:12:31 -0600242
243 pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
244 fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
245 }
246
247 _rtl92c_enable_fw_download(hw, true);
248 _rtl92c_write_fw(hw, version, pfwdata, fwsize);
249 _rtl92c_enable_fw_download(hw, false);
250
Larry Finger9f087a92014-09-26 16:40:26 -0500251 err = _rtl92c_fw_free_to_go(hw);
252 if (err) {
Larry Finger0c817332010-12-08 11:12:31 -0600253 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
Joe Perchesf30d7502012-01-04 19:40:41 -0800254 "Firmware is not ready to run!\n");
Larry Finger0c817332010-12-08 11:12:31 -0600255 } else {
256 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
Joe Perchesf30d7502012-01-04 19:40:41 -0800257 "Firmware is ready to run!\n");
Larry Finger0c817332010-12-08 11:12:31 -0600258 }
259
260 return 0;
261}
Larry Finger1472d3a2011-02-23 10:24:58 -0600262EXPORT_SYMBOL(rtl92c_download_fw);
Larry Finger0c817332010-12-08 11:12:31 -0600263
264static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
265{
266 struct rtl_priv *rtlpriv = rtl_priv(hw);
267 u8 val_hmetfr, val_mcutst_1;
268 bool result = false;
269
270 val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
271 val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
272
273 if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
274 result = true;
275 return result;
276}
277
278static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
Larry Finger9f087a92014-09-26 16:40:26 -0500279 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
Larry Finger0c817332010-12-08 11:12:31 -0600280{
281 struct rtl_priv *rtlpriv = rtl_priv(hw);
282 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
283 u8 boxnum;
Larry Finger9f219bd2011-04-13 21:00:02 -0500284 u16 box_reg = 0, box_extreg = 0;
Larry Finger0c817332010-12-08 11:12:31 -0600285 u8 u1b_tmp;
286 bool isfw_read = false;
Larry Finger9f087a92014-09-26 16:40:26 -0500287 u8 buf_index = 0;
288 bool bwrite_sucess = false;
Larry Finger0c817332010-12-08 11:12:31 -0600289 u8 wait_h2c_limmit = 100;
290 u8 wait_writeh2c_limmit = 100;
291 u8 boxcontent[4], boxextcontent[2];
292 u32 h2c_waitcounter = 0;
293 unsigned long flag;
294 u8 idx;
295
Joe Perchesf30d7502012-01-04 19:40:41 -0800296 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
Larry Finger0c817332010-12-08 11:12:31 -0600297
298 while (true) {
299 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
Larry Finger7ea47242011-02-19 16:28:57 -0600300 if (rtlhal->h2c_setinprogress) {
Larry Finger0c817332010-12-08 11:12:31 -0600301 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
Larry Finger9f087a92014-09-26 16:40:26 -0500302 "H2C set in progress! Wait to set..element_id(%d).\n",
Joe Perchesf30d7502012-01-04 19:40:41 -0800303 element_id);
Larry Finger7ea47242011-02-19 16:28:57 -0600304 while (rtlhal->h2c_setinprogress) {
Larry Finger0c817332010-12-08 11:12:31 -0600305 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
306 flag);
307 h2c_waitcounter++;
308 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
Joe Perchesf30d7502012-01-04 19:40:41 -0800309 "Wait 100 us (%d times)...\n",
Larry Finger9f087a92014-09-26 16:40:26 -0500310 h2c_waitcounter);
Larry Finger0c817332010-12-08 11:12:31 -0600311 udelay(100);
312
313 if (h2c_waitcounter > 1000)
314 return;
315 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
316 flag);
317 }
318 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
319 } else {
Larry Finger7ea47242011-02-19 16:28:57 -0600320 rtlhal->h2c_setinprogress = true;
Larry Finger0c817332010-12-08 11:12:31 -0600321 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
322 break;
323 }
324 }
325
Larry Finger9f087a92014-09-26 16:40:26 -0500326 while (!bwrite_sucess) {
Larry Finger0c817332010-12-08 11:12:31 -0600327 wait_writeh2c_limmit--;
328 if (wait_writeh2c_limmit == 0) {
329 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
Joe Perchesf30d7502012-01-04 19:40:41 -0800330 "Write H2C fail because no trigger for FW INT!\n");
Larry Finger0c817332010-12-08 11:12:31 -0600331 break;
332 }
333
334 boxnum = rtlhal->last_hmeboxnum;
335 switch (boxnum) {
336 case 0:
337 box_reg = REG_HMEBOX_0;
338 box_extreg = REG_HMEBOX_EXT_0;
339 break;
340 case 1:
341 box_reg = REG_HMEBOX_1;
342 box_extreg = REG_HMEBOX_EXT_1;
343 break;
344 case 2:
345 box_reg = REG_HMEBOX_2;
346 box_extreg = REG_HMEBOX_EXT_2;
347 break;
348 case 3:
349 box_reg = REG_HMEBOX_3;
350 box_extreg = REG_HMEBOX_EXT_3;
351 break;
352 default:
Larry Finger9f087a92014-09-26 16:40:26 -0500353 RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
354 "switch case not process\n");
Larry Finger0c817332010-12-08 11:12:31 -0600355 break;
356 }
357
358 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
359 while (!isfw_read) {
Larry Finger0c817332010-12-08 11:12:31 -0600360 wait_h2c_limmit--;
361 if (wait_h2c_limmit == 0) {
362 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
Joe Perchesf30d7502012-01-04 19:40:41 -0800363 "Waiting too long for FW read clear HMEBox(%d)!\n",
364 boxnum);
Larry Finger0c817332010-12-08 11:12:31 -0600365 break;
366 }
367
368 udelay(10);
369
370 isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
371 u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
372 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
Joe Perchesf30d7502012-01-04 19:40:41 -0800373 "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
374 boxnum, u1b_tmp);
Larry Finger0c817332010-12-08 11:12:31 -0600375 }
376
377 if (!isfw_read) {
378 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
Larry Finger9f087a92014-09-26 16:40:26 -0500379 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
Joe Perchesf30d7502012-01-04 19:40:41 -0800380 boxnum);
Larry Finger0c817332010-12-08 11:12:31 -0600381 break;
382 }
383
384 memset(boxcontent, 0, sizeof(boxcontent));
385 memset(boxextcontent, 0, sizeof(boxextcontent));
386 boxcontent[0] = element_id;
387 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
Joe Perchesf30d7502012-01-04 19:40:41 -0800388 "Write element_id box_reg(%4x) = %2x\n",
Larry Finger9f087a92014-09-26 16:40:26 -0500389 box_reg, element_id);
Larry Finger0c817332010-12-08 11:12:31 -0600390
391 switch (cmd_len) {
392 case 1:
393 boxcontent[0] &= ~(BIT(7));
Larry Finger9f087a92014-09-26 16:40:26 -0500394 memcpy((u8 *)(boxcontent) + 1,
395 cmdbuffer + buf_index, 1);
Larry Finger0c817332010-12-08 11:12:31 -0600396
397 for (idx = 0; idx < 4; idx++) {
398 rtl_write_byte(rtlpriv, box_reg + idx,
399 boxcontent[idx]);
400 }
401 break;
402 case 2:
403 boxcontent[0] &= ~(BIT(7));
Larry Finger9f087a92014-09-26 16:40:26 -0500404 memcpy((u8 *)(boxcontent) + 1,
405 cmdbuffer + buf_index, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600406
407 for (idx = 0; idx < 4; idx++) {
408 rtl_write_byte(rtlpriv, box_reg + idx,
409 boxcontent[idx]);
410 }
411 break;
412 case 3:
413 boxcontent[0] &= ~(BIT(7));
Larry Finger9f087a92014-09-26 16:40:26 -0500414 memcpy((u8 *)(boxcontent) + 1,
415 cmdbuffer + buf_index, 3);
Larry Finger0c817332010-12-08 11:12:31 -0600416
417 for (idx = 0; idx < 4; idx++) {
418 rtl_write_byte(rtlpriv, box_reg + idx,
419 boxcontent[idx]);
420 }
421 break;
422 case 4:
423 boxcontent[0] |= (BIT(7));
Larry Finger9f087a92014-09-26 16:40:26 -0500424 memcpy((u8 *)(boxextcontent),
425 cmdbuffer + buf_index, 2);
426 memcpy((u8 *)(boxcontent) + 1,
427 cmdbuffer + buf_index + 2, 2);
Larry Finger0c817332010-12-08 11:12:31 -0600428
429 for (idx = 0; idx < 2; idx++) {
430 rtl_write_byte(rtlpriv, box_extreg + idx,
431 boxextcontent[idx]);
432 }
433
434 for (idx = 0; idx < 4; idx++) {
435 rtl_write_byte(rtlpriv, box_reg + idx,
436 boxcontent[idx]);
437 }
438 break;
439 case 5:
440 boxcontent[0] |= (BIT(7));
Larry Finger9f087a92014-09-26 16:40:26 -0500441 memcpy((u8 *)(boxextcontent),
442 cmdbuffer + buf_index, 2);
443 memcpy((u8 *)(boxcontent) + 1,
444 cmdbuffer + buf_index + 2, 3);
Larry Finger0c817332010-12-08 11:12:31 -0600445
446 for (idx = 0; idx < 2; idx++) {
447 rtl_write_byte(rtlpriv, box_extreg + idx,
448 boxextcontent[idx]);
449 }
450
451 for (idx = 0; idx < 4; idx++) {
452 rtl_write_byte(rtlpriv, box_reg + idx,
453 boxcontent[idx]);
454 }
455 break;
456 default:
Larry Finger9f087a92014-09-26 16:40:26 -0500457 RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
458 "switch case not process\n");
Larry Finger0c817332010-12-08 11:12:31 -0600459 break;
460 }
461
Larry Finger9f087a92014-09-26 16:40:26 -0500462 bwrite_sucess = true;
Larry Finger0c817332010-12-08 11:12:31 -0600463
464 rtlhal->last_hmeboxnum = boxnum + 1;
465 if (rtlhal->last_hmeboxnum == 4)
466 rtlhal->last_hmeboxnum = 0;
467
468 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
Joe Perchesf30d7502012-01-04 19:40:41 -0800469 "pHalData->last_hmeboxnum = %d\n",
Larry Finger9f087a92014-09-26 16:40:26 -0500470 rtlhal->last_hmeboxnum);
Larry Finger0c817332010-12-08 11:12:31 -0600471 }
472
473 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
Larry Finger7ea47242011-02-19 16:28:57 -0600474 rtlhal->h2c_setinprogress = false;
Larry Finger0c817332010-12-08 11:12:31 -0600475 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
476
Joe Perchesf30d7502012-01-04 19:40:41 -0800477 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
Larry Finger0c817332010-12-08 11:12:31 -0600478}
479
480void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
Larry Finger9f087a92014-09-26 16:40:26 -0500481 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
Larry Finger0c817332010-12-08 11:12:31 -0600482{
Larry Finger9f087a92014-09-26 16:40:26 -0500483 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
Larry Finger0c817332010-12-08 11:12:31 -0600484 u32 tmp_cmdbuf[2];
485
Larry Finger9f087a92014-09-26 16:40:26 -0500486 if (!rtlhal->fw_ready) {
487 RT_ASSERT(false,
488 "return H2C cmd because of Fw download fail!!!\n");
489 return;
490 }
491
Larry Finger0c817332010-12-08 11:12:31 -0600492 memset(tmp_cmdbuf, 0, 8);
Larry Finger9f087a92014-09-26 16:40:26 -0500493 memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
Larry Finger0c817332010-12-08 11:12:31 -0600494 _rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
495
496 return;
497}
Larry Finger1472d3a2011-02-23 10:24:58 -0600498EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
Larry Finger0c817332010-12-08 11:12:31 -0600499
500void rtl92c_firmware_selfreset(struct ieee80211_hw *hw)
501{
502 u8 u1b_tmp;
503 u8 delay = 100;
504 struct rtl_priv *rtlpriv = rtl_priv(hw);
505
506 rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
507 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
508
509 while (u1b_tmp & BIT(2)) {
510 delay--;
511 if (delay == 0) {
Larry Finger9f087a92014-09-26 16:40:26 -0500512 RT_ASSERT(false, "8051 reset fail.\n");
Larry Finger0c817332010-12-08 11:12:31 -0600513 break;
514 }
515 udelay(50);
516 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
517 }
518}
Larry Finger1472d3a2011-02-23 10:24:58 -0600519EXPORT_SYMBOL(rtl92c_firmware_selfreset);
Larry Finger0c817332010-12-08 11:12:31 -0600520
521void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
522{
523 struct rtl_priv *rtlpriv = rtl_priv(hw);
Larry Finger9f087a92014-09-26 16:40:26 -0500524 u8 u1_h2c_set_pwrmode[3] = { 0 };
Larry Finger0c817332010-12-08 11:12:31 -0600525 struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
526
Joe Perchesf30d7502012-01-04 19:40:41 -0800527 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
Larry Finger0c817332010-12-08 11:12:31 -0600528
529 SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
Larry Finger3a16b412013-03-24 22:06:40 -0500530 SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
Larry Finger9f087a92014-09-26 16:40:26 -0500531 (rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1);
Larry Finger0c817332010-12-08 11:12:31 -0600532 SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
533 ppsc->reg_max_lps_awakeintvl);
534
535 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
Larry Finger9f087a92014-09-26 16:40:26 -0500536 "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
Larry Finger0c817332010-12-08 11:12:31 -0600537 u1_h2c_set_pwrmode, 3);
538 rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
Larry Finger0c817332010-12-08 11:12:31 -0600539}
Larry Finger1472d3a2011-02-23 10:24:58 -0600540EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
Larry Finger0c817332010-12-08 11:12:31 -0600541
Larry Finger0c817332010-12-08 11:12:31 -0600542#define BEACON_PG 0 /*->1*/
543#define PSPOLL_PG 2
544#define NULL_PG 3
545#define PROBERSP_PG 4 /*->5*/
546
547#define TOTAL_RESERVED_PKT_LEN 768
548
549static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
550 /* page 0 beacon */
551 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
552 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
553 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
554 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
555 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
556 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
557 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
558 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
559 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
560 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
561 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
562 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
563 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
564 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
565 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
566 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
567
568 /* page 1 beacon */
569 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
570 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
571 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
572 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
573 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
574 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
575 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
576 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
577 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
578 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
579 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
580 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
581 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
582 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
583 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
584 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
585
586 /* page 2 ps-poll */
587 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
588 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
589 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
590 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
591 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
592 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
593 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
594 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
595 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
596 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
597 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
599 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
600 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
601 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
602 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
603
604 /* page 3 null */
605 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
606 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
607 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
608 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
609 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
610 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
611 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
612 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
613 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
614 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
615 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
616 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
617 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
618 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
619 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
620 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
621
622 /* page 4 probe_resp */
623 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
624 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
625 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
626 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
627 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
628 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
629 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
630 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
631 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
632 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
633 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
634 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
635 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
636 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
637 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
638 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
639
640 /* page 5 probe_resp */
641 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
642 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
643 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
644 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
645 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
646 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
647 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
648 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
649 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
650 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
651 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
652 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
653 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
654 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
655 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
656 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
657};
658
Larry Finger9f087a92014-09-26 16:40:26 -0500659void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
Larry Finger0c817332010-12-08 11:12:31 -0600660{
661 struct rtl_priv *rtlpriv = rtl_priv(hw);
662 struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
663 struct sk_buff *skb = NULL;
664
665 u32 totalpacketlen;
666 bool rtstatus;
Larry Finger9f087a92014-09-26 16:40:26 -0500667 u8 u1rsvdpageloc[3] = { 0 };
668 bool b_dlok = false;
Larry Finger0c817332010-12-08 11:12:31 -0600669
670 u8 *beacon;
Larry Finger9f087a92014-09-26 16:40:26 -0500671 u8 *p_pspoll;
Larry Finger0c817332010-12-08 11:12:31 -0600672 u8 *nullfunc;
Larry Finger9f087a92014-09-26 16:40:26 -0500673 u8 *p_probersp;
Larry Finger0c817332010-12-08 11:12:31 -0600674 /*---------------------------------------------------------
675 (1) beacon
676 ---------------------------------------------------------*/
677 beacon = &reserved_page_packet[BEACON_PG * 128];
678 SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
679 SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
680
681 /*-------------------------------------------------------
682 (2) ps-poll
683 --------------------------------------------------------*/
Larry Finger9f087a92014-09-26 16:40:26 -0500684 p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
685 SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
686 SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
687 SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
Larry Finger0c817332010-12-08 11:12:31 -0600688
Larry Finger9f087a92014-09-26 16:40:26 -0500689 SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
Larry Finger0c817332010-12-08 11:12:31 -0600690
691 /*--------------------------------------------------------
692 (3) null data
693 ---------------------------------------------------------*/
694 nullfunc = &reserved_page_packet[NULL_PG * 128];
695 SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
696 SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
697 SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
698
Larry Finger9f087a92014-09-26 16:40:26 -0500699 SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
Larry Finger0c817332010-12-08 11:12:31 -0600700
701 /*---------------------------------------------------------
702 (4) probe response
703 ----------------------------------------------------------*/
Larry Finger9f087a92014-09-26 16:40:26 -0500704 p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
705 SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
706 SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
707 SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
Larry Finger0c817332010-12-08 11:12:31 -0600708
Larry Finger9f087a92014-09-26 16:40:26 -0500709 SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
Larry Finger0c817332010-12-08 11:12:31 -0600710
711 totalpacketlen = TOTAL_RESERVED_PKT_LEN;
712
713 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
Larry Finger9f087a92014-09-26 16:40:26 -0500714 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
Larry Finger0c817332010-12-08 11:12:31 -0600715 &reserved_page_packet[0], totalpacketlen);
716 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
Larry Finger9f087a92014-09-26 16:40:26 -0500717 "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
718 u1rsvdpageloc, 3);
Larry Finger0c817332010-12-08 11:12:31 -0600719
720
721 skb = dev_alloc_skb(totalpacketlen);
Larry Finger9f087a92014-09-26 16:40:26 -0500722 memcpy((u8 *)skb_put(skb, totalpacketlen),
Larry Finger0c817332010-12-08 11:12:31 -0600723 &reserved_page_packet, totalpacketlen);
724
Larry Finger557f9332014-09-26 16:40:27 -0500725 rtstatus = rtl_cmd_send_packet(hw, skb);
Larry Finger0c817332010-12-08 11:12:31 -0600726
727 if (rtstatus)
Larry Finger9f087a92014-09-26 16:40:26 -0500728 b_dlok = true;
Larry Finger0c817332010-12-08 11:12:31 -0600729
Larry Finger9f087a92014-09-26 16:40:26 -0500730 if (b_dlok) {
Larry Finger0c817332010-12-08 11:12:31 -0600731 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
Larry Finger9f087a92014-09-26 16:40:26 -0500732 "Set RSVD page location to Fw.\n");
Larry Finger0c817332010-12-08 11:12:31 -0600733 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
Larry Finger9f087a92014-09-26 16:40:26 -0500734 "H2C_RSVDPAGE:\n",
735 u1rsvdpageloc, 3);
Larry Finger0c817332010-12-08 11:12:31 -0600736 rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
Larry Finger9f087a92014-09-26 16:40:26 -0500737 sizeof(u1rsvdpageloc), u1rsvdpageloc);
Larry Finger0c817332010-12-08 11:12:31 -0600738 } else
739 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
Larry Finger9f087a92014-09-26 16:40:26 -0500740 "Set RSVD page location to Fw FAIL!!!!!!.\n");
Larry Finger0c817332010-12-08 11:12:31 -0600741}
Larry Finger1472d3a2011-02-23 10:24:58 -0600742EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
Larry Finger0c817332010-12-08 11:12:31 -0600743
744void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
745{
Larry Finger9f087a92014-09-26 16:40:26 -0500746 u8 u1_joinbssrpt_parm[1] = { 0 };
Larry Finger0c817332010-12-08 11:12:31 -0600747
748 SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
749
750 rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
751}
Larry Finger1472d3a2011-02-23 10:24:58 -0600752EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);
Larry Finger3a16b412013-03-24 22:06:40 -0500753
754static void rtl92c_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
755{
Larry Finger9f087a92014-09-26 16:40:26 -0500756 u8 u1_ctwindow_period[1] = { ctwindow};
Larry Finger3a16b412013-03-24 22:06:40 -0500757
758 rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
759}
760
Larry Finger9f087a92014-09-26 16:40:26 -0500761/* refactored routine */
762static void set_noa_data(struct rtl_priv *rtlpriv,
763 struct rtl_p2p_ps_info *p2pinfo,
764 struct p2p_ps_offload_t *p2p_ps_offload)
765{
766 int i;
767 u32 start_time, tsf_low;
768
769 /* hw only support 2 set of NoA */
770 for (i = 0 ; i < p2pinfo->noa_num ; i++) {
771 /* To control the reg setting for which NOA*/
772 rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
773 if (i == 0)
774 p2p_ps_offload->noa0_en = 1;
775 else
776 p2p_ps_offload->noa1_en = 1;
777
778 /* config P2P NoA Descriptor Register */
779 rtl_write_dword(rtlpriv, 0x5E0,
780 p2pinfo->noa_duration[i]);
781 rtl_write_dword(rtlpriv, 0x5E4,
782 p2pinfo->noa_interval[i]);
783
784 /*Get Current TSF value */
785 tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
786
787 start_time = p2pinfo->noa_start_time[i];
788 if (p2pinfo->noa_count_type[i] != 1) {
789 while (start_time <= (tsf_low+(50*1024))) {
790 start_time += p2pinfo->noa_interval[i];
791 if (p2pinfo->noa_count_type[i] != 255)
792 p2pinfo->noa_count_type[i]--;
793 }
794 }
795 rtl_write_dword(rtlpriv, 0x5E8, start_time);
796 rtl_write_dword(rtlpriv, 0x5EC,
797 p2pinfo->noa_count_type[i]);
798 }
799}
800
Larry Finger3a16b412013-03-24 22:06:40 -0500801void rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
802{
803 struct rtl_priv *rtlpriv = rtl_priv(hw);
804 struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
805 struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
806 struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
807 struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
Larry Finger3a16b412013-03-24 22:06:40 -0500808 u16 ctwindow;
Larry Finger3a16b412013-03-24 22:06:40 -0500809
810 switch (p2p_ps_state) {
811 case P2P_PS_DISABLE:
Larry Finger9f087a92014-09-26 16:40:26 -0500812 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
813 "P2P_PS_DISABLE\n");
814 memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
815 break;
Larry Finger3a16b412013-03-24 22:06:40 -0500816 case P2P_PS_ENABLE:
Larry Finger9f087a92014-09-26 16:40:26 -0500817 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
818 "P2P_PS_ENABLE\n");
819 /* update CTWindow value. */
820 if (p2pinfo->ctwindow > 0) {
821 p2p_ps_offload->ctwindow_en = 1;
822 ctwindow = p2pinfo->ctwindow;
823 rtl92c_set_p2p_ctw_period_cmd(hw, ctwindow);
824 }
825 /* call refactored routine */
826 set_noa_data(rtlpriv, p2pinfo, p2p_ps_offload);
Larry Finger3a16b412013-03-24 22:06:40 -0500827
Larry Finger9f087a92014-09-26 16:40:26 -0500828 if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
829 /* rst p2p circuit */
830 rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST,
831 BIT(4));
Larry Finger3a16b412013-03-24 22:06:40 -0500832
Larry Finger9f087a92014-09-26 16:40:26 -0500833 p2p_ps_offload->offload_en = 1;
Larry Finger3a16b412013-03-24 22:06:40 -0500834
Larry Finger9f087a92014-09-26 16:40:26 -0500835 if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
836 p2p_ps_offload->role = 1;
837 p2p_ps_offload->allstasleep = 0;
838 } else {
839 p2p_ps_offload->role = 0;
Larry Finger3a16b412013-03-24 22:06:40 -0500840 }
Larry Finger9f087a92014-09-26 16:40:26 -0500841
842 p2p_ps_offload->discovery = 0;
Larry Finger3a16b412013-03-24 22:06:40 -0500843 }
Larry Finger9f087a92014-09-26 16:40:26 -0500844 break;
Larry Finger3a16b412013-03-24 22:06:40 -0500845 case P2P_PS_SCAN:
Larry Finger9f087a92014-09-26 16:40:26 -0500846 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
847 p2p_ps_offload->discovery = 1;
848 break;
Larry Finger3a16b412013-03-24 22:06:40 -0500849 case P2P_PS_SCAN_DONE:
Larry Finger9f087a92014-09-26 16:40:26 -0500850 RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
851 "P2P_PS_SCAN_DONE\n");
852 p2p_ps_offload->discovery = 0;
853 p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
854 break;
Larry Finger3a16b412013-03-24 22:06:40 -0500855 default:
Larry Finger9f087a92014-09-26 16:40:26 -0500856 break;
Larry Finger3a16b412013-03-24 22:06:40 -0500857 }
858
859 rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
Larry Finger9f087a92014-09-26 16:40:26 -0500860
Larry Finger3a16b412013-03-24 22:06:40 -0500861}
862EXPORT_SYMBOL_GPL(rtl92c_set_p2p_ps_offload_cmd);