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