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