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