1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2014  Realtek Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * 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 "../core.h"
30 #include "reg.h"
31 #include "def.h"
32 #include "fw.h"
33 #include "dm.h"
34 
35 static void _rtl92ee_enable_fw_download(struct ieee80211_hw *hw, bool enable)
36 {
37 	struct rtl_priv *rtlpriv = rtl_priv(hw);
38 	u8 tmp;
39 
40 	if (enable) {
41 		rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x05);
42 
43 		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
44 		rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
45 	} else {
46 		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
47 		rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
48 	}
49 }
50 
51 static void _rtl92ee_fw_block_write(struct ieee80211_hw *hw,
52 				    const u8 *buffer, u32 size)
53 {
54 	struct rtl_priv *rtlpriv = rtl_priv(hw);
55 	u32 blocksize = sizeof(u32);
56 	u8 *bufferptr = (u8 *)buffer;
57 	u32 *pu4byteptr = (u32 *)buffer;
58 	u32 i, offset, blockcount, remainsize;
59 
60 	blockcount = size / blocksize;
61 	remainsize = size % blocksize;
62 
63 	for (i = 0; i < blockcount; i++) {
64 		offset = i * blocksize;
65 		rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
66 				*(pu4byteptr + i));
67 	}
68 
69 	if (remainsize) {
70 		offset = blockcount * blocksize;
71 		bufferptr += offset;
72 		for (i = 0; i < remainsize; i++) {
73 			rtl_write_byte(rtlpriv,
74 				       (FW_8192C_START_ADDRESS + offset + i),
75 				       *(bufferptr + i));
76 		}
77 	}
78 }
79 
80 static void _rtl92ee_fw_page_write(struct ieee80211_hw *hw, u32 page,
81 				   const u8 *buffer, u32 size)
82 {
83 	struct rtl_priv *rtlpriv = rtl_priv(hw);
84 	u8 value8;
85 	u8 u8page = (u8)(page & 0x07);
86 
87 	value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
88 	rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
89 
90 	_rtl92ee_fw_block_write(hw, buffer, size);
91 }
92 
93 static void _rtl92ee_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
94 {
95 	u32 fwlen = *pfwlen;
96 	u8 remain = (u8)(fwlen % 4);
97 
98 	remain = (remain == 0) ? 0 : (4 - remain);
99 
100 	while (remain > 0) {
101 		pfwbuf[fwlen] = 0;
102 		fwlen++;
103 		remain--;
104 	}
105 
106 	*pfwlen = fwlen;
107 }
108 
109 static void _rtl92ee_write_fw(struct ieee80211_hw *hw,
110 			      enum version_8192e version,
111 			      u8 *buffer, u32 size)
112 {
113 	struct rtl_priv *rtlpriv = rtl_priv(hw);
114 	u8 *bufferptr = (u8 *)buffer;
115 	u32 pagenums, remainsize;
116 	u32 page, offset;
117 
118 	RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "FW size is %d bytes,\n", size);
119 
120 	_rtl92ee_fill_dummy(bufferptr, &size);
121 
122 	pagenums = size / FW_8192C_PAGE_SIZE;
123 	remainsize = size % FW_8192C_PAGE_SIZE;
124 
125 	if (pagenums > 8) {
126 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
127 			 "Page numbers should not greater then 8\n");
128 	}
129 
130 	for (page = 0; page < pagenums; page++) {
131 		offset = page * FW_8192C_PAGE_SIZE;
132 		_rtl92ee_fw_page_write(hw, page, (bufferptr + offset),
133 				       FW_8192C_PAGE_SIZE);
134 		udelay(2);
135 	}
136 
137 	if (remainsize) {
138 		offset = pagenums * FW_8192C_PAGE_SIZE;
139 		page = pagenums;
140 		_rtl92ee_fw_page_write(hw, page, (bufferptr + offset),
141 				       remainsize);
142 	}
143 }
144 
145 static int _rtl92ee_fw_free_to_go(struct ieee80211_hw *hw)
146 {
147 	struct rtl_priv *rtlpriv = rtl_priv(hw);
148 	int err = -EIO;
149 	u32 counter = 0;
150 	u32 value32;
151 
152 	do {
153 		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
154 	} while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
155 		 (!(value32 & FWDL_CHKSUM_RPT)));
156 
157 	if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
158 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
159 			 "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
160 			  value32);
161 		goto exit;
162 	}
163 
164 	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
165 		 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
166 
167 	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
168 	value32 |= MCUFWDL_RDY;
169 	value32 &= ~WINTINI_RDY;
170 	rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
171 
172 	rtl92ee_firmware_selfreset(hw);
173 	counter = 0;
174 
175 	do {
176 		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
177 		if (value32 & WINTINI_RDY) {
178 			RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD ,
179 				 "Polling FW ready success!! REG_MCUFWDL:0x%08x. count = %d\n",
180 				 value32, counter);
181 			err = 0;
182 			goto exit;
183 		}
184 
185 		udelay(FW_8192C_POLLING_DELAY*10);
186 
187 	} while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
188 
189 	RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
190 		 "Polling FW ready fail!! REG_MCUFWDL:0x%08x. count = %d\n",
191 		 value32, counter);
192 
193 exit:
194 	return err;
195 }
196 
197 int rtl92ee_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)
198 {
199 	struct rtl_priv *rtlpriv = rtl_priv(hw);
200 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
201 	struct rtlwifi_firmware_header *pfwheader;
202 	u8 *pfwdata;
203 	u32 fwsize;
204 	int err;
205 	enum version_8192e version = rtlhal->version;
206 
207 	if (!rtlhal->pfirmware)
208 		return 1;
209 
210 	pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware;
211 	rtlhal->fw_version = le16_to_cpu(pfwheader->version);
212 	rtlhal->fw_subversion = pfwheader->subversion;
213 	pfwdata = (u8 *)rtlhal->pfirmware;
214 	fwsize = rtlhal->fwsize;
215 	RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
216 		 "normal Firmware SIZE %d\n" , fwsize);
217 
218 	if (IS_FW_HEADER_EXIST(pfwheader)) {
219 		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
220 			 "Firmware Version(%d), Signature(%#x),Size(%d)\n",
221 			  pfwheader->version, pfwheader->signature,
222 			  (int)sizeof(struct rtlwifi_firmware_header));
223 
224 		pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header);
225 		fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);
226 	} else {
227 		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
228 			 "Firmware no Header, Signature(%#x)\n",
229 			  pfwheader->signature);
230 	}
231 
232 	if (rtlhal->mac_func_enable) {
233 		if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
234 			rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
235 			rtl92ee_firmware_selfreset(hw);
236 		}
237 	}
238 	_rtl92ee_enable_fw_download(hw, true);
239 	_rtl92ee_write_fw(hw, version, pfwdata, fwsize);
240 	_rtl92ee_enable_fw_download(hw, false);
241 
242 	err = _rtl92ee_fw_free_to_go(hw);
243 	if (err) {
244 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
245 			 "Firmware is not ready to run!\n");
246 	} else {
247 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD ,
248 			 "Firmware is ready to run!\n");
249 	}
250 
251 	return 0;
252 }
253 
254 static bool _rtl92ee_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
255 {
256 	struct rtl_priv *rtlpriv = rtl_priv(hw);
257 	u8 val_hmetfr;
258 	bool result = false;
259 
260 	val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
261 	if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
262 		result = true;
263 	return result;
264 }
265 
266 static void _rtl92ee_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id,
267 				      u32 cmd_len, u8 *cmdbuffer)
268 {
269 	struct rtl_priv *rtlpriv = rtl_priv(hw);
270 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
271 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
272 	u8 boxnum;
273 	u16 box_reg = 0, box_extreg = 0;
274 	u8 u1b_tmp;
275 	bool isfw_read = false;
276 	u8 buf_index = 0;
277 	bool bwrite_sucess = false;
278 	u8 wait_h2c_limmit = 100;
279 	u8 boxcontent[4], boxextcontent[4];
280 	u32 h2c_waitcounter = 0;
281 	unsigned long flag;
282 	u8 idx;
283 
284 	if (ppsc->dot11_psmode != EACTIVE ||
285 	    ppsc->inactive_pwrstate == ERFOFF) {
286 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
287 			 "FillH2CCommand8192E(): Return because RF is off!!!\n");
288 		return;
289 	}
290 
291 	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD , "come in\n");
292 
293 	/* 1. Prevent race condition in setting H2C cmd.
294 	 * (copy from MgntActSet_RF_State().)
295 	 */
296 	while (true) {
297 		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
298 		if (rtlhal->h2c_setinprogress) {
299 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
300 				 "H2C set in progress! Wait to set..element_id(%d).\n",
301 				  element_id);
302 
303 			while (rtlhal->h2c_setinprogress) {
304 				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
305 						       flag);
306 				h2c_waitcounter++;
307 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
308 					 "Wait 100 us (%d times)...\n",
309 					  h2c_waitcounter);
310 				udelay(100);
311 
312 				if (h2c_waitcounter > 1000)
313 					return;
314 				spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
315 						  flag);
316 			}
317 			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
318 		} else {
319 			rtlhal->h2c_setinprogress = true;
320 			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
321 			break;
322 		}
323 	}
324 
325 	while (!bwrite_sucess) {
326 		/* 2. Find the last BOX number which has been writen. */
327 		boxnum = rtlhal->last_hmeboxnum;
328 		switch (boxnum) {
329 		case 0:
330 			box_reg = REG_HMEBOX_0;
331 			box_extreg = REG_HMEBOX_EXT_0;
332 			break;
333 		case 1:
334 			box_reg = REG_HMEBOX_1;
335 			box_extreg = REG_HMEBOX_EXT_1;
336 			break;
337 		case 2:
338 			box_reg = REG_HMEBOX_2;
339 			box_extreg = REG_HMEBOX_EXT_2;
340 			break;
341 		case 3:
342 			box_reg = REG_HMEBOX_3;
343 			box_extreg = REG_HMEBOX_EXT_3;
344 			break;
345 		default:
346 			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
347 				 "switch case not process\n");
348 			break;
349 		}
350 
351 		/* 3. Check if the box content is empty. */
352 		isfw_read = false;
353 		u1b_tmp = rtl_read_byte(rtlpriv, REG_CR);
354 
355 		if (u1b_tmp != 0xea) {
356 			isfw_read = true;
357 		} else {
358 			if (rtl_read_byte(rtlpriv, REG_TXDMA_STATUS) == 0xea ||
359 			    rtl_read_byte(rtlpriv, REG_TXPKT_EMPTY) == 0xea)
360 				rtl_write_byte(rtlpriv, REG_SYS_CFG1 + 3, 0xff);
361 		}
362 
363 		if (isfw_read) {
364 			wait_h2c_limmit = 100;
365 			isfw_read = _rtl92ee_check_fw_read_last_h2c(hw, boxnum);
366 			while (!isfw_read) {
367 				wait_h2c_limmit--;
368 				if (wait_h2c_limmit == 0) {
369 					RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
370 						 "Waiting too long for FW read clear HMEBox(%d)!!!\n",
371 						 boxnum);
372 					break;
373 				}
374 				udelay(10);
375 				isfw_read =
376 				  _rtl92ee_check_fw_read_last_h2c(hw, boxnum);
377 				u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
378 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
379 					 "Waiting for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
380 					 boxnum, u1b_tmp);
381 			}
382 		}
383 
384 		/* If Fw has not read the last
385 		 * H2C cmd, break and give up this H2C.
386 		 */
387 		if (!isfw_read) {
388 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
389 				 "Write H2C reg BOX[%d] fail,Fw don't read.\n",
390 				 boxnum);
391 			break;
392 		}
393 		/* 4. Fill the H2C cmd into box */
394 		memset(boxcontent, 0, sizeof(boxcontent));
395 		memset(boxextcontent, 0, sizeof(boxextcontent));
396 		boxcontent[0] = element_id;
397 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
398 			 "Write element_id box_reg(%4x) = %2x\n",
399 			  box_reg, element_id);
400 
401 		switch (cmd_len) {
402 		case 1:
403 		case 2:
404 		case 3:
405 			/*boxcontent[0] &= ~(BIT(7));*/
406 			memcpy((u8 *)(boxcontent) + 1,
407 			       cmdbuffer + buf_index, cmd_len);
408 
409 			for (idx = 0; idx < 4; idx++) {
410 				rtl_write_byte(rtlpriv, box_reg + idx,
411 					       boxcontent[idx]);
412 			}
413 			break;
414 		case 4:
415 		case 5:
416 		case 6:
417 		case 7:
418 			/*boxcontent[0] |= (BIT(7));*/
419 			memcpy((u8 *)(boxextcontent),
420 			       cmdbuffer + buf_index+3, cmd_len-3);
421 			memcpy((u8 *)(boxcontent) + 1,
422 			       cmdbuffer + buf_index, 3);
423 
424 			for (idx = 0; idx < 4; idx++) {
425 				rtl_write_byte(rtlpriv, box_extreg + idx,
426 					       boxextcontent[idx]);
427 			}
428 
429 			for (idx = 0; idx < 4; idx++) {
430 				rtl_write_byte(rtlpriv, box_reg + idx,
431 					       boxcontent[idx]);
432 			}
433 			break;
434 		default:
435 			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
436 				 "switch case not process\n");
437 			break;
438 		}
439 
440 		bwrite_sucess = true;
441 
442 		rtlhal->last_hmeboxnum = boxnum + 1;
443 		if (rtlhal->last_hmeboxnum == 4)
444 			rtlhal->last_hmeboxnum = 0;
445 
446 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD ,
447 			 "pHalData->last_hmeboxnum  = %d\n",
448 			  rtlhal->last_hmeboxnum);
449 	}
450 
451 	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
452 	rtlhal->h2c_setinprogress = false;
453 	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
454 
455 	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD , "go out\n");
456 }
457 
458 void rtl92ee_fill_h2c_cmd(struct ieee80211_hw *hw,
459 			  u8 element_id, u32 cmd_len, u8 *cmdbuffer)
460 {
461 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
462 	u32 tmp_cmdbuf[2];
463 
464 	if (!rtlhal->fw_ready) {
465 		RT_ASSERT(false,
466 			  "return H2C cmd because of Fw download fail!!!\n");
467 		return;
468 	}
469 
470 	memset(tmp_cmdbuf, 0, 8);
471 	memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
472 	_rtl92ee_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
473 }
474 
475 void rtl92ee_firmware_selfreset(struct ieee80211_hw *hw)
476 {
477 	u8 u1b_tmp;
478 	struct rtl_priv *rtlpriv = rtl_priv(hw);
479 
480 	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
481 	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp & (~BIT(0))));
482 
483 	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
484 	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
485 
486 	udelay(50);
487 
488 	u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
489 	rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1b_tmp | BIT(0)));
490 
491 	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
492 	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp | BIT(2)));
493 
494 	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD ,
495 		 "  _8051Reset92E(): 8051 reset success .\n");
496 }
497 
498 void rtl92ee_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
499 {
500 	struct rtl_priv *rtlpriv = rtl_priv(hw);
501 	u8 u1_h2c_set_pwrmode[H2C_92E_PWEMODE_LENGTH] = { 0 };
502 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
503 	u8 rlbm , power_state = 0;
504 
505 	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD , "FW LPS mode = %d\n", mode);
506 
507 	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
508 	rlbm = 0;/*YJ,temp,120316. FW now not support RLBM=2.*/
509 	SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm);
510 	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
511 					 (rtlpriv->mac80211.p2p) ?
512 					 ppsc->smart_ps : 1);
513 	SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
514 					       ppsc->reg_max_lps_awakeintvl);
515 	SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
516 	if (mode == FW_PS_ACTIVE_MODE)
517 		power_state |= FW_PWR_STATE_ACTIVE;
518 	else
519 		power_state |= FW_PWR_STATE_RF_OFF;
520 	SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
521 
522 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
523 		      "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
524 		      u1_h2c_set_pwrmode, H2C_92E_PWEMODE_LENGTH);
525 	rtl92ee_fill_h2c_cmd(hw, H2C_92E_SETPWRMODE, H2C_92E_PWEMODE_LENGTH,
526 			     u1_h2c_set_pwrmode);
527 }
528 
529 void rtl92ee_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw, u8 mstatus)
530 {
531 	u8 parm[3] = { 0 , 0 , 0 };
532 	/* parm[0]: bit0=0-->Disconnect, bit0=1-->Connect
533 	 *          bit1=0-->update Media Status to MACID
534 	 *          bit1=1-->update Media Status from MACID to MACID_End
535 	 * parm[1]: MACID, if this is INFRA_STA, MacID = 0
536 	 * parm[2]: MACID_End
537 	 */
538 
539 	SET_H2CCMD_MSRRPT_PARM_OPMODE(parm, mstatus);
540 	SET_H2CCMD_MSRRPT_PARM_MACID_IND(parm, 0);
541 
542 	rtl92ee_fill_h2c_cmd(hw, H2C_92E_MSRRPT, 3, parm);
543 }
544 
545 #define BEACON_PG		0 /* ->1 */
546 #define PSPOLL_PG		2
547 #define NULL_PG			3
548 #define PROBERSP_PG		4 /* ->5 */
549 
550 #define TOTAL_RESERVED_PKT_LEN	768
551 
552 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
553 	/* page 0 beacon */
554 	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
555 	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
556 	0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x20, 0x00,
557 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
558 	0x64, 0x00, 0x10, 0x04, 0x00, 0x05, 0x54, 0x65,
559 	0x73, 0x74, 0x32, 0x01, 0x08, 0x82, 0x84, 0x0B,
560 	0x16, 0x24, 0x30, 0x48, 0x6C, 0x03, 0x01, 0x06,
561 	0x06, 0x02, 0x00, 0x00, 0x2A, 0x01, 0x02, 0x32,
562 	0x04, 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C,
563 	0x09, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
564 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
565 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
566 	0x00, 0x3D, 0x00, 0xDD, 0x07, 0x00, 0xE0, 0x4C,
567 	0x02, 0x02, 0x00, 0x00, 0xDD, 0x18, 0x00, 0x50,
568 	0xF2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04,
569 	0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, 0x01, 0x00,
570 
571 	/* page 1 beacon */
572 	0x00, 0x50, 0xF2, 0x02, 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 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
582 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
583 	0x10, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
584 	0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00,
585 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
586 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
587 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
588 
589 	/* page 2  ps-poll */
590 	0xA4, 0x10, 0x01, 0xC0, 0xEC, 0x1A, 0x59, 0x0B,
591 	0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
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 	0x18, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
602 	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
603 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
604 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
605 	0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
606 
607 	/* page 3  null */
608 	0x48, 0x01, 0x00, 0x00, 0xEC, 0x1A, 0x59, 0x0B,
609 	0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
610 	0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 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 	0x72, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
620 	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
621 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
622 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
623 	0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
624 
625 	/* page 4  probe_resp */
626 	0x50, 0x00, 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 	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
630 	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
631 	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
632 	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
633 	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
634 	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
635 	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
636 	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
637 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
638 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
639 	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
640 	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
641 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
642 
643 	/* page 5  probe_resp */
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 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
658 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
659 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
660 };
661 
662 void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
663 {
664 	struct rtl_priv *rtlpriv = rtl_priv(hw);
665 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
666 	struct sk_buff *skb = NULL;
667 
668 	u32 totalpacketlen;
669 	u8 u1rsvdpageloc[5] = { 0 };
670 	bool b_dlok = false;
671 
672 	u8 *beacon;
673 	u8 *p_pspoll;
674 	u8 *nullfunc;
675 	u8 *p_probersp;
676 	/*---------------------------------------------------------
677 	 *			(1) beacon
678 	 *---------------------------------------------------------
679 	 */
680 	beacon = &reserved_page_packet[BEACON_PG * 128];
681 	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
682 	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
683 
684 	/*-------------------------------------------------------
685 	 *			(2) ps-poll
686 	 *--------------------------------------------------------
687 	 */
688 	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
689 	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
690 	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
691 	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
692 
693 	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
694 
695 	/*--------------------------------------------------------
696 	 *			(3) null data
697 	 *---------------------------------------------------------
698 	 */
699 	nullfunc = &reserved_page_packet[NULL_PG * 128];
700 	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
701 	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
702 	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
703 
704 	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
705 
706 	/*---------------------------------------------------------
707 	 *			(4) probe response
708 	 *----------------------------------------------------------
709 	 */
710 	p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
711 	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
712 	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
713 	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
714 
715 	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
716 
717 	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
718 
719 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD ,
720 		      "rtl92ee_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
721 		      &reserved_page_packet[0], totalpacketlen);
722 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD ,
723 		      "rtl92ee_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
724 		      u1rsvdpageloc, 3);
725 
726 	skb = dev_alloc_skb(totalpacketlen);
727 	memcpy((u8 *)skb_put(skb, totalpacketlen),
728 	       &reserved_page_packet, totalpacketlen);
729 
730 	b_dlok = true;
731 
732 	if (b_dlok) {
733 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD ,
734 			 "Set RSVD page location to Fw.\n");
735 		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD ,
736 			      "H2C_RSVDPAGE:\n", u1rsvdpageloc, 3);
737 		rtl92ee_fill_h2c_cmd(hw, H2C_92E_RSVDPAGE,
738 				     sizeof(u1rsvdpageloc), u1rsvdpageloc);
739 	} else {
740 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
741 			 "Set RSVD page location to Fw FAIL!!!!!!.\n");
742 	}
743 }
744 
745 /*Shoud check FW support p2p or not.*/
746 static void rtl92ee_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
747 {
748 	u8 u1_ctwindow_period[1] = {ctwindow};
749 
750 	rtl92ee_fill_h2c_cmd(hw, H2C_92E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
751 }
752 
753 void rtl92ee_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
754 {
755 	struct rtl_priv *rtlpriv = rtl_priv(hw);
756 	struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
757 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
758 	struct rtl_p2p_ps_info *p2pinfo = &rtlps->p2p_ps_info;
759 	struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
760 	u8 i;
761 	u16 ctwindow;
762 	u32 start_time, tsf_low;
763 
764 	switch (p2p_ps_state) {
765 	case P2P_PS_DISABLE:
766 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_DISABLE\n");
767 		memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
768 		break;
769 	case P2P_PS_ENABLE:
770 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_ENABLE\n");
771 		/* update CTWindow value. */
772 		if (p2pinfo->ctwindow > 0) {
773 			p2p_ps_offload->ctwindow_en = 1;
774 			ctwindow = p2pinfo->ctwindow;
775 			rtl92ee_set_p2p_ctw_period_cmd(hw, ctwindow);
776 		}
777 		/* hw only support 2 set of NoA */
778 		for (i = 0 ; i < p2pinfo->noa_num ; i++) {
779 			/* To control the register setting for which NOA*/
780 			rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
781 			if (i == 0)
782 				p2p_ps_offload->noa0_en = 1;
783 			else
784 				p2p_ps_offload->noa1_en = 1;
785 			/* config P2P NoA Descriptor Register */
786 			rtl_write_dword(rtlpriv, 0x5E0,
787 					p2pinfo->noa_duration[i]);
788 			rtl_write_dword(rtlpriv, 0x5E4,
789 					p2pinfo->noa_interval[i]);
790 
791 			/*Get Current TSF value */
792 			tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
793 
794 			start_time = p2pinfo->noa_start_time[i];
795 			if (p2pinfo->noa_count_type[i] != 1) {
796 				while (start_time <= (tsf_low + (50 * 1024))) {
797 					start_time += p2pinfo->noa_interval[i];
798 					if (p2pinfo->noa_count_type[i] != 255)
799 						p2pinfo->noa_count_type[i]--;
800 				}
801 			}
802 			rtl_write_dword(rtlpriv, 0x5E8, start_time);
803 			rtl_write_dword(rtlpriv, 0x5EC,
804 					p2pinfo->noa_count_type[i]);
805 		}
806 		if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
807 			/* rst p2p circuit */
808 			rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
809 			p2p_ps_offload->offload_en = 1;
810 
811 			if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
812 				p2p_ps_offload->role = 1;
813 				p2p_ps_offload->allstasleep = 0;
814 			} else {
815 				p2p_ps_offload->role = 0;
816 			}
817 			p2p_ps_offload->discovery = 0;
818 		}
819 		break;
820 	case P2P_PS_SCAN:
821 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_SCAN\n");
822 		p2p_ps_offload->discovery = 1;
823 		break;
824 	case P2P_PS_SCAN_DONE:
825 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD , "P2P_PS_SCAN_DONE\n");
826 		p2p_ps_offload->discovery = 0;
827 		p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
828 		break;
829 	default:
830 		break;
831 	}
832 	rtl92ee_fill_h2c_cmd(hw, H2C_92E_P2P_PS_OFFLOAD, 1,
833 			     (u8 *)p2p_ps_offload);
834 }
835 
836 static void _rtl92ee_c2h_ra_report_handler(struct ieee80211_hw *hw,
837 					   u8 *cmd_buf, u8 cmd_len)
838 {
839 	u8 rate = cmd_buf[0] & 0x3F;
840 	bool collision_state = cmd_buf[3] & BIT(0);
841 
842 	rtl92ee_dm_dynamic_arfb_select(hw, rate, collision_state);
843 }
844 
845 static void _rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id,
846 					 u8 c2h_cmd_len, u8 *tmp_buf)
847 {
848 	struct rtl_priv *rtlpriv = rtl_priv(hw);
849 
850 	switch (c2h_cmd_id) {
851 	case C2H_8192E_DBG:
852 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
853 			 "[C2H], C2H_8723BE_DBG!!\n");
854 		break;
855 	case C2H_8192E_TXBF:
856 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
857 			 "[C2H], C2H_8192E_TXBF!!\n");
858 		break;
859 	case C2H_8192E_TX_REPORT:
860 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE ,
861 			 "[C2H], C2H_8723BE_TX_REPORT!\n");
862 		break;
863 	case C2H_8192E_BT_INFO:
864 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
865 			 "[C2H], C2H_8723BE_BT_INFO!!\n");
866 		rtlpriv->btcoexist.btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf,
867 							      c2h_cmd_len);
868 		break;
869 	case C2H_8192E_BT_MP:
870 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
871 			 "[C2H], C2H_8723BE_BT_MP!!\n");
872 		break;
873 	case C2H_8192E_RA_RPT:
874 		_rtl92ee_c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len);
875 		break;
876 	default:
877 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
878 			 "[C2H], Unknown packet!! CmdId(%#X)!\n", c2h_cmd_id);
879 		break;
880 	}
881 }
882 
883 void rtl92ee_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len)
884 {
885 	struct rtl_priv *rtlpriv = rtl_priv(hw);
886 	u8 c2h_cmd_id = 0, c2h_cmd_seq = 0, c2h_cmd_len = 0;
887 	u8 *tmp_buf = NULL;
888 
889 	c2h_cmd_id = buffer[0];
890 	c2h_cmd_seq = buffer[1];
891 	c2h_cmd_len = len - 2;
892 	tmp_buf = buffer + 2;
893 
894 	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
895 		 "[C2H packet], c2hCmdId=0x%x, c2hCmdSeq=0x%x, c2hCmdLen=%d\n",
896 		 c2h_cmd_id, c2h_cmd_seq, c2h_cmd_len);
897 
898 	RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_TRACE,
899 		      "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len);
900 
901 	_rtl92ee_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf);
902 }
903