Linux Audio

Check our new training course

Loading...
  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 * 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 "../wifi.h"
 31#include "../pci.h"
 32#include "../base.h"
 33#include "reg.h"
 34#include "def.h"
 35#include "fw.h"
 36#include "sw.h"
 37
 38static bool _rtl92d_is_fw_downloaded(struct rtl_priv *rtlpriv)
 39{
 40	return (rtl_read_dword(rtlpriv, REG_MCUFWDL) & MCUFWDL_RDY) ?
 41		true : false;
 42}
 43
 44static void _rtl92d_enable_fw_download(struct ieee80211_hw *hw, bool enable)
 45{
 46	struct rtl_priv *rtlpriv = rtl_priv(hw);
 47	u8 tmp;
 48
 49	if (enable) {
 50		tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
 51		rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
 52		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
 53		rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
 54		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
 55		rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
 56	} else {
 57		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
 58		rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
 59		/* Reserved for fw extension.
 60		 * 0x81[7] is used for mac0 status ,
 61		 * so don't write this reg here
 62		 * rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);*/
 63	}
 64}
 65
 66static void _rtl92d_fw_block_write(struct ieee80211_hw *hw,
 67				   const u8 *buffer, u32 size)
 68{
 69	struct rtl_priv *rtlpriv = rtl_priv(hw);
 70	u32 blocksize = sizeof(u32);
 71	u8 *bufferptr = (u8 *) buffer;
 72	u32 *pu4BytePtr = (u32 *) buffer;
 73	u32 i, offset, blockCount, remainSize;
 74
 75	blockCount = size / blocksize;
 76	remainSize = size % blocksize;
 77	for (i = 0; i < blockCount; i++) {
 78		offset = i * blocksize;
 79		rtl_write_dword(rtlpriv, (FW_8192D_START_ADDRESS + offset),
 80				*(pu4BytePtr + i));
 81	}
 82	if (remainSize) {
 83		offset = blockCount * blocksize;
 84		bufferptr += offset;
 85		for (i = 0; i < remainSize; i++) {
 86			rtl_write_byte(rtlpriv, (FW_8192D_START_ADDRESS +
 87						 offset + i), *(bufferptr + i));
 88		}
 89	}
 90}
 91
 92static void _rtl92d_fw_page_write(struct ieee80211_hw *hw,
 93				  u32 page, const u8 *buffer, u32 size)
 94{
 95	struct rtl_priv *rtlpriv = rtl_priv(hw);
 96	u8 value8;
 97	u8 u8page = (u8) (page & 0x07);
 98
 99	value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
100	rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
101	_rtl92d_fw_block_write(hw, buffer, size);
102}
103
104static void _rtl92d_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
105{
106	u32 fwlen = *pfwlen;
107	u8 remain = (u8) (fwlen % 4);
108
109	remain = (remain == 0) ? 0 : (4 - remain);
110	while (remain > 0) {
111		pfwbuf[fwlen] = 0;
112		fwlen++;
113		remain--;
114	}
115	*pfwlen = fwlen;
116}
117
118static void _rtl92d_write_fw(struct ieee80211_hw *hw,
119			     enum version_8192d version, u8 *buffer, u32 size)
120{
121	struct rtl_priv *rtlpriv = rtl_priv(hw);
122	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
123	u8 *bufferPtr = (u8 *) buffer;
124	u32 pagenums, remainSize;
125	u32 page, offset;
126
127	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
128	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE)
129		_rtl92d_fill_dummy(bufferPtr, &size);
130	pagenums = size / FW_8192D_PAGE_SIZE;
131	remainSize = size % FW_8192D_PAGE_SIZE;
132	if (pagenums > 8) {
133		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
134			 "Page numbers should not greater then 8\n");
135	}
136	for (page = 0; page < pagenums; page++) {
137		offset = page * FW_8192D_PAGE_SIZE;
138		_rtl92d_fw_page_write(hw, page, (bufferPtr + offset),
139				      FW_8192D_PAGE_SIZE);
140	}
141	if (remainSize) {
142		offset = pagenums * FW_8192D_PAGE_SIZE;
143		page = pagenums;
144		_rtl92d_fw_page_write(hw, page, (bufferPtr + offset),
145				      remainSize);
146	}
147}
148
149static int _rtl92d_fw_free_to_go(struct ieee80211_hw *hw)
150{
151	struct rtl_priv *rtlpriv = rtl_priv(hw);
152	u32 counter = 0;
153	u32 value32;
154
155	do {
156		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
157	} while ((counter++ < FW_8192D_POLLING_TIMEOUT_COUNT) &&
158		 (!(value32 & FWDL_ChkSum_rpt)));
159	if (counter >= FW_8192D_POLLING_TIMEOUT_COUNT) {
160		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
161			 "chksum report faill ! REG_MCUFWDL:0x%08x\n",
162			 value32);
163		return -EIO;
164	}
165	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
166		 "Checksum report OK ! REG_MCUFWDL:0x%08x\n", value32);
167	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
168	value32 |= MCUFWDL_RDY;
169	rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
170	return 0;
171}
172
173void rtl92d_firmware_selfreset(struct ieee80211_hw *hw)
174{
175	struct rtl_priv *rtlpriv = rtl_priv(hw);
176	u8 u1b_tmp;
177	u8 delay = 100;
178
179	/* Set (REG_HMETFR + 3) to  0x20 is reset 8051 */
180	rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
181	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
182	while (u1b_tmp & BIT(2)) {
183		delay--;
184		if (delay == 0)
185			break;
186		udelay(50);
187		u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
188	}
189	RT_ASSERT((delay > 0), "8051 reset failed!\n");
190	RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
191		 "=====> 8051 reset success (%d)\n", delay);
192}
193
194static int _rtl92d_fw_init(struct ieee80211_hw *hw)
195{
196	struct rtl_priv *rtlpriv = rtl_priv(hw);
197	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
198	u32 counter;
199
200	RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, "FW already have download\n");
201	/* polling for FW ready */
202	counter = 0;
203	do {
204		if (rtlhal->interfaceindex == 0) {
205			if (rtl_read_byte(rtlpriv, FW_MAC0_READY) &
206			    MAC0_READY) {
207				RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
208					 "Polling FW ready success!! REG_MCUFWDL: 0x%x\n",
209					 rtl_read_byte(rtlpriv,
210						       FW_MAC0_READY));
211				return 0;
212			}
213			udelay(5);
214		} else {
215			if (rtl_read_byte(rtlpriv, FW_MAC1_READY) &
216			    MAC1_READY) {
217				RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
218					 "Polling FW ready success!! REG_MCUFWDL: 0x%x\n",
219					 rtl_read_byte(rtlpriv,
220						       FW_MAC1_READY));
221				return 0;
222			}
223			udelay(5);
224		}
225	} while (counter++ < POLLING_READY_TIMEOUT_COUNT);
226
227	if (rtlhal->interfaceindex == 0) {
228		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
229			 "Polling FW ready fail!! MAC0 FW init not ready: 0x%x\n",
230			 rtl_read_byte(rtlpriv, FW_MAC0_READY));
231	} else {
232		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
233			 "Polling FW ready fail!! MAC1 FW init not ready: 0x%x\n",
234			 rtl_read_byte(rtlpriv, FW_MAC1_READY));
235	}
236	RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
237		 "Polling FW ready fail!! REG_MCUFWDL:0x%08ul\n",
238		 rtl_read_dword(rtlpriv, REG_MCUFWDL));
239	return -1;
240}
241
242int rtl92d_download_fw(struct ieee80211_hw *hw)
243{
244	struct rtl_priv *rtlpriv = rtl_priv(hw);
245	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
246	u8 *pfwheader;
247	u8 *pfwdata;
248	u32 fwsize;
249	int err;
250	enum version_8192d version = rtlhal->version;
251	u8 value;
252	u32 count;
253	bool fw_downloaded = false, fwdl_in_process = false;
254	unsigned long flags;
255
256	if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
257		return 1;
258	fwsize = rtlhal->fwsize;
259	pfwheader = (u8 *) rtlhal->pfirmware;
260	pfwdata = (u8 *) rtlhal->pfirmware;
261	rtlhal->fw_version = (u16) GET_FIRMWARE_HDR_VERSION(pfwheader);
262	rtlhal->fw_subversion = (u16) GET_FIRMWARE_HDR_SUB_VER(pfwheader);
263	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
264		 "FirmwareVersion(%d), FirmwareSubVersion(%d), Signature(%#x)\n",
265		 rtlhal->fw_version, rtlhal->fw_subversion,
266		 GET_FIRMWARE_HDR_SIGNATURE(pfwheader));
267	if (IS_FW_HEADER_EXIST(pfwheader)) {
268		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
269			 "Shift 32 bytes for FW header!!\n");
270		pfwdata = pfwdata + 32;
271		fwsize = fwsize - 32;
272	}
273
274	spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
275	fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv);
276	if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5))
277		fwdl_in_process = true;
278	else
279		fwdl_in_process = false;
280	if (fw_downloaded) {
281		spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
282		goto exit;
283	} else if (fwdl_in_process) {
284		spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
285		for (count = 0; count < 5000; count++) {
286			udelay(500);
287			spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
288			fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv);
289			if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5))
290				fwdl_in_process = true;
291			else
292				fwdl_in_process = false;
293			spin_unlock_irqrestore(&globalmutex_for_fwdownload,
294					       flags);
295			if (fw_downloaded)
296				goto exit;
297			else if (!fwdl_in_process)
298				break;
299			else
300				RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
301					 "Wait for another mac download fw\n");
302		}
303		spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
304		value = rtl_read_byte(rtlpriv, 0x1f);
305		value |= BIT(5);
306		rtl_write_byte(rtlpriv, 0x1f, value);
307		spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
308	} else {
309		value = rtl_read_byte(rtlpriv, 0x1f);
310		value |= BIT(5);
311		rtl_write_byte(rtlpriv, 0x1f, value);
312		spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
313	}
314
315	/* If 8051 is running in RAM code, driver should
316	 * inform Fw to reset by itself, or it will cause
317	 * download Fw fail.*/
318	/* 8051 RAM code */
319	if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
320		rtl92d_firmware_selfreset(hw);
321		rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
322	}
323	_rtl92d_enable_fw_download(hw, true);
324	_rtl92d_write_fw(hw, version, pfwdata, fwsize);
325	_rtl92d_enable_fw_download(hw, false);
326	spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
327	err = _rtl92d_fw_free_to_go(hw);
328	/* download fw over,clear 0x1f[5] */
329	value = rtl_read_byte(rtlpriv, 0x1f);
330	value &= (~BIT(5));
331	rtl_write_byte(rtlpriv, 0x1f, value);
332	spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
333	if (err) {
334		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
335			 "fw is not ready to run!\n");
336		goto exit;
337	} else {
338		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "fw is ready to run!\n");
339	}
340exit:
341	err = _rtl92d_fw_init(hw);
342	return err;
343}
344
345static bool _rtl92d_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
346{
347	struct rtl_priv *rtlpriv = rtl_priv(hw);
348	u8 val_hmetfr;
349	bool result = false;
350
351	val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
352	if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
353		result = true;
354	return result;
355}
356
357static void _rtl92d_fill_h2c_command(struct ieee80211_hw *hw,
358			      u8 element_id, u32 cmd_len, u8 *cmdbuffer)
359{
360	struct rtl_priv *rtlpriv = rtl_priv(hw);
361	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
362	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
363	u8 boxnum;
364	u16 box_reg = 0, box_extreg = 0;
365	u8 u1b_tmp;
366	bool isfw_read = false;
367	u8 buf_index = 0;
368	bool bwrite_sucess = false;
369	u8 wait_h2c_limmit = 100;
370	u8 wait_writeh2c_limmit = 100;
371	u8 boxcontent[4], boxextcontent[2];
372	u32 h2c_waitcounter = 0;
373	unsigned long flag;
374	u8 idx;
375
376	if (ppsc->rfpwr_state == ERFOFF || ppsc->inactive_pwrstate == ERFOFF) {
377		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
378			 "Return as RF is off!!!\n");
379		return;
380	}
381	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
382	while (true) {
383		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
384		if (rtlhal->h2c_setinprogress) {
385			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
386				 "H2C set in progress! Wait to set..element_id(%d)\n",
387				 element_id);
388
389			while (rtlhal->h2c_setinprogress) {
390				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
391						       flag);
392				h2c_waitcounter++;
393				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
394					 "Wait 100 us (%d times)...\n",
395					 h2c_waitcounter);
396				udelay(100);
397
398				if (h2c_waitcounter > 1000)
399					return;
400
401				spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
402						  flag);
403			}
404			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
405		} else {
406			rtlhal->h2c_setinprogress = true;
407			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
408			break;
409		}
410	}
411	while (!bwrite_sucess) {
412		wait_writeh2c_limmit--;
413		if (wait_writeh2c_limmit == 0) {
414			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
415				 "Write H2C fail because no trigger for FW INT!\n");
416			break;
417		}
418		boxnum = rtlhal->last_hmeboxnum;
419		switch (boxnum) {
420		case 0:
421			box_reg = REG_HMEBOX_0;
422			box_extreg = REG_HMEBOX_EXT_0;
423			break;
424		case 1:
425			box_reg = REG_HMEBOX_1;
426			box_extreg = REG_HMEBOX_EXT_1;
427			break;
428		case 2:
429			box_reg = REG_HMEBOX_2;
430			box_extreg = REG_HMEBOX_EXT_2;
431			break;
432		case 3:
433			box_reg = REG_HMEBOX_3;
434			box_extreg = REG_HMEBOX_EXT_3;
435			break;
436		default:
437			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
438				 "switch case not processed\n");
439			break;
440		}
441		isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);
442		while (!isfw_read) {
443			wait_h2c_limmit--;
444			if (wait_h2c_limmit == 0) {
445				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
446					 "Waiting too long for FW read clear HMEBox(%d)!\n",
447					 boxnum);
448				break;
449			}
450			udelay(10);
451			isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);
452			u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
453			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
454				 "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
455				 boxnum, u1b_tmp);
456		}
457		if (!isfw_read) {
458			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
459				 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
460				 boxnum);
461			break;
462		}
463		memset(boxcontent, 0, sizeof(boxcontent));
464		memset(boxextcontent, 0, sizeof(boxextcontent));
465		boxcontent[0] = element_id;
466		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
467			 "Write element_id box_reg(%4x) = %2x\n",
468			 box_reg, element_id);
469		switch (cmd_len) {
470		case 1:
471			boxcontent[0] &= ~(BIT(7));
472			memcpy(boxcontent + 1, cmdbuffer + buf_index, 1);
473			for (idx = 0; idx < 4; idx++)
474				rtl_write_byte(rtlpriv, box_reg + idx,
475					       boxcontent[idx]);
476			break;
477		case 2:
478			boxcontent[0] &= ~(BIT(7));
479			memcpy(boxcontent + 1, cmdbuffer + buf_index, 2);
480			for (idx = 0; idx < 4; idx++)
481				rtl_write_byte(rtlpriv, box_reg + idx,
482					       boxcontent[idx]);
483			break;
484		case 3:
485			boxcontent[0] &= ~(BIT(7));
486			memcpy(boxcontent + 1, cmdbuffer + buf_index, 3);
487			for (idx = 0; idx < 4; idx++)
488				rtl_write_byte(rtlpriv, box_reg + idx,
489					       boxcontent[idx]);
490			break;
491		case 4:
492			boxcontent[0] |= (BIT(7));
493			memcpy(boxextcontent, cmdbuffer + buf_index, 2);
494			memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 2);
495			for (idx = 0; idx < 2; idx++)
496				rtl_write_byte(rtlpriv, box_extreg + idx,
497					       boxextcontent[idx]);
498			for (idx = 0; idx < 4; idx++)
499				rtl_write_byte(rtlpriv, box_reg + idx,
500					       boxcontent[idx]);
501			break;
502		case 5:
503			boxcontent[0] |= (BIT(7));
504			memcpy(boxextcontent, cmdbuffer + buf_index, 2);
505			memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 3);
506			for (idx = 0; idx < 2; idx++)
507				rtl_write_byte(rtlpriv, box_extreg + idx,
508					       boxextcontent[idx]);
509			for (idx = 0; idx < 4; idx++)
510				rtl_write_byte(rtlpriv, box_reg + idx,
511					       boxcontent[idx]);
512			break;
513		default:
514			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
515				 "switch case not processed\n");
516			break;
517		}
518		bwrite_sucess = true;
519		rtlhal->last_hmeboxnum = boxnum + 1;
520		if (rtlhal->last_hmeboxnum == 4)
521			rtlhal->last_hmeboxnum = 0;
522		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
523			 "pHalData->last_hmeboxnum  = %d\n",
524			 rtlhal->last_hmeboxnum);
525	}
526	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
527	rtlhal->h2c_setinprogress = false;
528	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
529	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
530}
531
532void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw,
533			 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
534{
535	u32 tmp_cmdbuf[2];
536
537	memset(tmp_cmdbuf, 0, 8);
538	memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
539	_rtl92d_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
540	return;
541}
542
543void rtl92d_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	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
551	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
552	SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
553					      ppsc->reg_max_lps_awakeintvl);
554	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
555		      "rtl92d_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode",
556		      u1_h2c_set_pwrmode, 3);
557	rtl92d_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
558}
559
560static bool _rtl92d_cmd_send_packet(struct ieee80211_hw *hw,
561				    struct sk_buff *skb)
562{
563	struct rtl_priv *rtlpriv = rtl_priv(hw);
564	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
565	struct rtl8192_tx_ring *ring;
566	struct rtl_tx_desc *pdesc;
567	u8 idx = 0;
568	unsigned long flags;
569	struct sk_buff *pskb;
570
571	ring = &rtlpci->tx_ring[BEACON_QUEUE];
572	pskb = __skb_dequeue(&ring->queue);
573	if (pskb)
574		kfree_skb(pskb);
575	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
576	pdesc = &ring->desc[idx];
577	/* discard output from call below */
578	rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
579	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
580	__skb_queue_tail(&ring->queue, skb);
581	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
582	rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
583	return true;
584}
585
586#define BEACON_PG		0	/*->1 */
587#define PSPOLL_PG		2
588#define NULL_PG			3
589#define PROBERSP_PG		4	/*->5 */
590#define TOTAL_RESERVED_PKT_LEN	768
591
592static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
593	/* page 0 beacon */
594	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
595	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
596	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
597	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
599	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
600	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
601	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
602	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
603	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
604	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
605	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
606	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
607	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
608	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
609	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
610
611	/* page 1 beacon */
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	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
622	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
623	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
624	0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
625	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
626	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
627	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
628
629	/* page 2  ps-poll */
630	0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
631	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
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	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
640	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
641	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
642	0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
643	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
644	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
645	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
646
647	/* page 3  null */
648	0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
649	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
650	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 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	0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
661	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
662	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
663	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
664
665	/* page 4  probe_resp */
666	0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
667	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
668	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
669	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
670	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
671	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
672	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
673	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
674	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
675	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
676	0x03, 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	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
680	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
681	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
682
683	/* page 5  probe_resp */
684	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
685	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
686	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
687	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
688	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
689	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
690	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
691	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
692	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
693	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
694	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
695	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
696	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
697	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
698	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
699	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
700};
701
702void rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
703{
704	struct rtl_priv *rtlpriv = rtl_priv(hw);
705	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
706	struct sk_buff *skb = NULL;
707	u32 totalpacketlen;
708	bool rtstatus;
709	u8 u1RsvdPageLoc[3] = { 0 };
710	bool dlok = false;
711	u8 *beacon;
712	u8 *p_pspoll;
713	u8 *nullfunc;
714	u8 *p_probersp;
715	/*---------------------------------------------------------
716						(1) beacon
717	---------------------------------------------------------*/
718	beacon = &reserved_page_packet[BEACON_PG * 128];
719	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
720	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
721	/*-------------------------------------------------------
722						(2) ps-poll
723	--------------------------------------------------------*/
724	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
725	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
726	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
727	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
728	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
729	/*--------------------------------------------------------
730						(3) null data
731	---------------------------------------------------------*/
732	nullfunc = &reserved_page_packet[NULL_PG * 128];
733	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
734	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
735	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
736	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
737	/*---------------------------------------------------------
738						(4) probe response
739	----------------------------------------------------------*/
740	p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
741	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
742	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
743	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
744	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
745	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
746	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
747		      "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
748		      &reserved_page_packet[0], totalpacketlen);
749	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
750		      "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
751		      u1RsvdPageLoc, 3);
752	skb = dev_alloc_skb(totalpacketlen);
753	if (!skb) {
754		dlok = false;
755	} else {
756		memcpy((u8 *) skb_put(skb, totalpacketlen),
757			&reserved_page_packet, totalpacketlen);
758		rtstatus = _rtl92d_cmd_send_packet(hw, skb);
759
760		if (rtstatus)
761			dlok = true;
762	}
763	if (dlok) {
764		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
765			 "Set RSVD page location to Fw\n");
766		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
767			      "H2C_RSVDPAGE", u1RsvdPageLoc, 3);
768		rtl92d_fill_h2c_cmd(hw, H2C_RSVDPAGE,
769			sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
770	} else
771		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
772			 "Set RSVD page location to Fw FAIL!!!!!!\n");
773}
774
775void rtl92d_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
776{
777	u8 u1_joinbssrpt_parm[1] = {0};
778
779	SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
780	rtl92d_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
781}