• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2012  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 "../rtl8192ce/reg.h"
31 #include "../rtl8192ce/def.h"
32 #include "fw_common.h"
33 #include <linux/export.h>
34 #include <linux/kmemleak.h>
35 
_rtl92c_enable_fw_download(struct ieee80211_hw * hw,bool enable)36 static 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 
_rtl92c_fw_block_write(struct ieee80211_hw * hw,const u8 * buffer,u32 size)71 static void _rtl92c_fw_block_write(struct ieee80211_hw *hw,
72 				   const u8 *buffer, u32 size)
73 {
74 	struct rtl_priv *rtlpriv = rtl_priv(hw);
75 	u32 blocksize = sizeof(u32);
76 	u8 *bufferptr = (u8 *)buffer;
77 	u32 *pu4byteptr = (u32 *)buffer;
78 	u32 i, offset, blockcount, remainsize;
79 
80 	blockcount = size / blocksize;
81 	remainsize = size % blocksize;
82 
83 	for (i = 0; i < blockcount; i++) {
84 		offset = i * blocksize;
85 		rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
86 				*(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 		}
96 	}
97 }
98 
_rtl92c_fw_page_write(struct ieee80211_hw * hw,u32 page,const u8 * buffer,u32 size)99 static 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 
_rtl92c_fill_dummy(u8 * pfwbuf,u32 * pfwlen)112 static 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 
_rtl92c_write_fw(struct ieee80211_hw * hw,enum version_8192c version,u8 * buffer,u32 size)128 static 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));
133 	bool is_version_b;
134 	u8 *bufferptr = (u8 *)buffer;
135 
136 	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;
140 		u32 page, offset;
141 
142 		if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE)
143 			_rtl92c_fill_dummy(bufferptr, &size);
144 
145 		pageNums = size / FW_8192C_PAGE_SIZE;
146 		remainsize = size % FW_8192C_PAGE_SIZE;
147 
148 		if (pageNums > 4) {
149 			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
150 				 "Page numbers should not greater then 4\n");
151 		}
152 
153 		for (page = 0; page < pageNums; page++) {
154 			offset = page * FW_8192C_PAGE_SIZE;
155 			_rtl92c_fw_page_write(hw, page, (bufferptr + offset),
156 					      FW_8192C_PAGE_SIZE);
157 		}
158 
159 		if (remainsize) {
160 			offset = pageNums * FW_8192C_PAGE_SIZE;
161 			page = pageNums;
162 			_rtl92c_fw_page_write(hw, page, (bufferptr + offset),
163 					      remainsize);
164 		}
165 	} else {
166 		_rtl92c_fw_block_write(hw, buffer, size);
167 	}
168 }
169 
_rtl92c_fw_free_to_go(struct ieee80211_hw * hw)170 static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
171 {
172 	struct rtl_priv *rtlpriv = rtl_priv(hw);
173 	int err = -EIO;
174 	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,
184 			 "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
185 			  value32);
186 		goto exit;
187 	}
188 
189 	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
190 		 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
191 
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,
203 				 "Polling FW ready success!! REG_MCUFWDL:0x%08x .\n",
204 					value32);
205 			err = 0;
206 			goto exit;
207 		}
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,
214 		 "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32);
215 
216 exit:
217 	return err;
218 }
219 
rtl92c_download_fw(struct ieee80211_hw * hw)220 int 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;
227 	int err;
228 	enum version_8192c version = rtlhal->version;
229 
230 	if (!rtlhal->pfirmware)
231 		return 1;
232 
233 	pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
234 	pfwdata = (u8 *)rtlhal->pfirmware;
235 	fwsize = rtlhal->fwsize;
236 
237 	if (IS_FW_HEADER_EXIST(pfwheader)) {
238 		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
239 			 "Firmware Version(%d), Signature(%#x),Size(%d)\n",
240 			  pfwheader->version, pfwheader->signature,
241 			  (int)sizeof(struct rtl92c_firmware_header));
242 
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 
251 	err = _rtl92c_fw_free_to_go(hw);
252 	if (err) {
253 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
254 			 "Firmware is not ready to run!\n");
255 	} else {
256 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
257 			 "Firmware is ready to run!\n");
258 	}
259 
260 	return 0;
261 }
262 EXPORT_SYMBOL(rtl92c_download_fw);
263 
_rtl92c_check_fw_read_last_h2c(struct ieee80211_hw * hw,u8 boxnum)264 static 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 
_rtl92c_fill_h2c_command(struct ieee80211_hw * hw,u8 element_id,u32 cmd_len,u8 * cmdbuffer)278 static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
279 			      u8 element_id, u32 cmd_len, u8 *cmdbuffer)
280 {
281 	struct rtl_priv *rtlpriv = rtl_priv(hw);
282 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
283 	u8 boxnum;
284 	u16 box_reg = 0, box_extreg = 0;
285 	u8 u1b_tmp;
286 	bool isfw_read = false;
287 	u8 buf_index = 0;
288 	bool bwrite_sucess = false;
289 	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 
296 	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
297 
298 	while (true) {
299 		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
300 		if (rtlhal->h2c_setinprogress) {
301 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
302 				 "H2C set in progress! Wait to set..element_id(%d).\n",
303 				 element_id);
304 			while (rtlhal->h2c_setinprogress) {
305 				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
306 						       flag);
307 				h2c_waitcounter++;
308 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
309 					 "Wait 100 us (%d times)...\n",
310 					  h2c_waitcounter);
311 				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 {
320 			rtlhal->h2c_setinprogress = true;
321 			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
322 			break;
323 		}
324 	}
325 
326 	while (!bwrite_sucess) {
327 		wait_writeh2c_limmit--;
328 		if (wait_writeh2c_limmit == 0) {
329 			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
330 				 "Write H2C fail because no trigger for FW INT!\n");
331 			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:
353 			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
354 				 "switch case not process\n");
355 			break;
356 		}
357 
358 		isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
359 		while (!isfw_read) {
360 			wait_h2c_limmit--;
361 			if (wait_h2c_limmit == 0) {
362 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
363 					 "Waiting too long for FW read clear HMEBox(%d)!\n",
364 					 boxnum);
365 				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,
373 				 "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
374 				 boxnum, u1b_tmp);
375 		}
376 
377 		if (!isfw_read) {
378 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
379 				 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
380 				 boxnum);
381 			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,
388 			 "Write element_id box_reg(%4x) = %2x\n",
389 			  box_reg, element_id);
390 
391 		switch (cmd_len) {
392 		case 1:
393 			boxcontent[0] &= ~(BIT(7));
394 			memcpy((u8 *)(boxcontent) + 1,
395 			       cmdbuffer + buf_index, 1);
396 
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));
404 			memcpy((u8 *)(boxcontent) + 1,
405 			       cmdbuffer + buf_index, 2);
406 
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));
414 			memcpy((u8 *)(boxcontent) + 1,
415 			       cmdbuffer + buf_index, 3);
416 
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));
424 			memcpy((u8 *)(boxextcontent),
425 			       cmdbuffer + buf_index, 2);
426 			memcpy((u8 *)(boxcontent) + 1,
427 			       cmdbuffer + buf_index + 2, 2);
428 
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));
441 			memcpy((u8 *)(boxextcontent),
442 			       cmdbuffer + buf_index, 2);
443 			memcpy((u8 *)(boxcontent) + 1,
444 			       cmdbuffer + buf_index + 2, 3);
445 
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:
457 			RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
458 				 "switch case not process\n");
459 			break;
460 		}
461 
462 		bwrite_sucess = true;
463 
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,
469 			 "pHalData->last_hmeboxnum  = %d\n",
470 			  rtlhal->last_hmeboxnum);
471 	}
472 
473 	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
474 	rtlhal->h2c_setinprogress = false;
475 	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
476 
477 	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
478 }
479 
rtl92c_fill_h2c_cmd(struct ieee80211_hw * hw,u8 element_id,u32 cmd_len,u8 * cmdbuffer)480 void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
481 			 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
482 {
483 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
484 	u32 tmp_cmdbuf[2];
485 
486 	if (!rtlhal->fw_ready) {
487 		RT_ASSERT(false,
488 			  "return H2C cmd because of Fw download fail!!!\n");
489 		return;
490 	}
491 
492 	memset(tmp_cmdbuf, 0, 8);
493 	memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
494 	_rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
495 
496 	return;
497 }
498 EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
499 
rtl92c_firmware_selfreset(struct ieee80211_hw * hw)500 void 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) {
512 			RT_ASSERT(false, "8051 reset fail.\n");
513 			break;
514 		}
515 		udelay(50);
516 		u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
517 	}
518 }
519 EXPORT_SYMBOL(rtl92c_firmware_selfreset);
520 
rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw * hw,u8 mode)521 void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
522 {
523 	struct rtl_priv *rtlpriv = rtl_priv(hw);
524 	u8 u1_h2c_set_pwrmode[3] = { 0 };
525 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
526 
527 	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
528 
529 	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
530 	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
531 		(rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1);
532 	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,
536 		      "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
537 		      u1_h2c_set_pwrmode, 3);
538 	rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
539 }
540 EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
541 
542 #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 
549 static 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 
rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw * hw,bool (* cmd_send_packet)(struct ieee80211_hw *,struct sk_buff *))659 void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
660 	 bool (*cmd_send_packet)(struct ieee80211_hw *, struct sk_buff *))
661 {
662 	struct rtl_priv *rtlpriv = rtl_priv(hw);
663 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
664 	struct sk_buff *skb = NULL;
665 
666 	u32 totalpacketlen;
667 	bool rtstatus;
668 	u8 u1rsvdpageloc[3] = { 0 };
669 	bool b_dlok = false;
670 
671 	u8 *beacon;
672 	u8 *p_pspoll;
673 	u8 *nullfunc;
674 	u8 *p_probersp;
675 	/*---------------------------------------------------------
676 				(1) beacon
677 	---------------------------------------------------------*/
678 	beacon = &reserved_page_packet[BEACON_PG * 128];
679 	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
680 	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
681 
682 	/*-------------------------------------------------------
683 				(2) ps-poll
684 	--------------------------------------------------------*/
685 	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
686 	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
687 	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
688 	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
689 
690 	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
691 
692 	/*--------------------------------------------------------
693 				(3) null data
694 	---------------------------------------------------------*/
695 	nullfunc = &reserved_page_packet[NULL_PG * 128];
696 	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
697 	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
698 	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
699 
700 	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
701 
702 	/*---------------------------------------------------------
703 				(4) probe response
704 	----------------------------------------------------------*/
705 	p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
706 	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
707 	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
708 	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
709 
710 	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
711 
712 	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
713 
714 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
715 		      "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
716 		      &reserved_page_packet[0], totalpacketlen);
717 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
718 		      "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
719 		      u1rsvdpageloc, 3);
720 
721 
722 	skb = dev_alloc_skb(totalpacketlen);
723 	memcpy((u8 *)skb_put(skb, totalpacketlen),
724 	       &reserved_page_packet, totalpacketlen);
725 
726 	if (cmd_send_packet)
727 		rtstatus = cmd_send_packet(hw, skb);
728 	else
729 		rtstatus = rtl_cmd_send_packet(hw, skb);
730 
731 	if (rtstatus)
732 		b_dlok = true;
733 
734 	if (b_dlok) {
735 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
736 			 "Set RSVD page location to Fw.\n");
737 		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
738 				"H2C_RSVDPAGE:\n",
739 				u1rsvdpageloc, 3);
740 		rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
741 				    sizeof(u1rsvdpageloc), u1rsvdpageloc);
742 	} else
743 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
744 			 "Set RSVD page location to Fw FAIL!!!!!!.\n");
745 }
746 EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
747 
rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw * hw,u8 mstatus)748 void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
749 {
750 	u8 u1_joinbssrpt_parm[1] = { 0 };
751 
752 	SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
753 
754 	rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
755 }
756 EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);
757 
rtl92c_set_p2p_ctw_period_cmd(struct ieee80211_hw * hw,u8 ctwindow)758 static void rtl92c_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
759 {
760 	u8 u1_ctwindow_period[1] = { ctwindow};
761 
762 	rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
763 }
764 
765 /* refactored routine */
set_noa_data(struct rtl_priv * rtlpriv,struct rtl_p2p_ps_info * p2pinfo,struct p2p_ps_offload_t * p2p_ps_offload)766 static void set_noa_data(struct rtl_priv *rtlpriv,
767 			 struct rtl_p2p_ps_info *p2pinfo,
768 			 struct p2p_ps_offload_t *p2p_ps_offload)
769 {
770 	int i;
771 	u32	start_time, tsf_low;
772 
773 	/* hw only support 2 set of NoA */
774 	for (i = 0 ; i < p2pinfo->noa_num ; i++) {
775 		/* To control the reg setting for which NOA*/
776 		rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
777 		if (i == 0)
778 			p2p_ps_offload->noa0_en = 1;
779 		else
780 			p2p_ps_offload->noa1_en = 1;
781 
782 		/* config P2P NoA Descriptor Register */
783 		rtl_write_dword(rtlpriv, 0x5E0,
784 				p2pinfo->noa_duration[i]);
785 		rtl_write_dword(rtlpriv, 0x5E4,
786 				p2pinfo->noa_interval[i]);
787 
788 		/*Get Current TSF value */
789 		tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
790 
791 		start_time = p2pinfo->noa_start_time[i];
792 		if (p2pinfo->noa_count_type[i] != 1) {
793 			while (start_time <= (tsf_low+(50*1024))) {
794 				start_time += p2pinfo->noa_interval[i];
795 				if (p2pinfo->noa_count_type[i] != 255)
796 					p2pinfo->noa_count_type[i]--;
797 			}
798 		}
799 		rtl_write_dword(rtlpriv, 0x5E8, start_time);
800 		rtl_write_dword(rtlpriv, 0x5EC,
801 				p2pinfo->noa_count_type[i]);
802 	}
803 }
804 
rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw * hw,u8 p2p_ps_state)805 void rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
806 {
807 	struct rtl_priv *rtlpriv = rtl_priv(hw);
808 	struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
809 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
810 	struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
811 	struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
812 	u16	ctwindow;
813 
814 	switch (p2p_ps_state) {
815 	case P2P_PS_DISABLE:
816 			RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
817 				 "P2P_PS_DISABLE\n");
818 			memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
819 			break;
820 	case P2P_PS_ENABLE:
821 			RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
822 				 "P2P_PS_ENABLE\n");
823 			/* update CTWindow value. */
824 			if (p2pinfo->ctwindow > 0) {
825 				p2p_ps_offload->ctwindow_en = 1;
826 				ctwindow = p2pinfo->ctwindow;
827 				rtl92c_set_p2p_ctw_period_cmd(hw, ctwindow);
828 			}
829 			/* call refactored routine */
830 			set_noa_data(rtlpriv, p2pinfo, p2p_ps_offload);
831 
832 			if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
833 				/* rst p2p circuit */
834 				rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST,
835 					       BIT(4));
836 
837 				p2p_ps_offload->offload_en = 1;
838 
839 				if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
840 					p2p_ps_offload->role = 1;
841 					p2p_ps_offload->allstasleep = 0;
842 				} else {
843 					p2p_ps_offload->role = 0;
844 				}
845 
846 				p2p_ps_offload->discovery = 0;
847 			}
848 			break;
849 	case P2P_PS_SCAN:
850 			RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
851 			p2p_ps_offload->discovery = 1;
852 			break;
853 	case P2P_PS_SCAN_DONE:
854 			RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
855 				 "P2P_PS_SCAN_DONE\n");
856 			p2p_ps_offload->discovery = 0;
857 			p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
858 			break;
859 	default:
860 			break;
861 	}
862 
863 	rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
864 
865 }
866 EXPORT_SYMBOL_GPL(rtl92c_set_p2p_ps_offload_cmd);
867