Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  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 "../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!! "
209					 "REG_MCUFWDL: 0x%x .\n",
210					 rtl_read_byte(rtlpriv,
211					 FW_MAC0_READY)));
212				return 0;
213			}
214			udelay(5);
215		} else {
216			if (rtl_read_byte(rtlpriv, FW_MAC1_READY) &
217			    MAC1_READY) {
218				RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
219					 ("Polling FW ready success!! "
220					 "REG_MCUFWDL: 0x%x .\n",
221					 rtl_read_byte(rtlpriv,
222						       FW_MAC1_READY)));
223				return 0;
224			}
225			udelay(5);
226		}
227	} while (counter++ < POLLING_READY_TIMEOUT_COUNT);
228
229	if (rtlhal->interfaceindex == 0) {
230		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
231			 ("Polling FW ready fail!! MAC0 FW init not ready: "
232			 "0x%x .\n",
233			 rtl_read_byte(rtlpriv, FW_MAC0_READY)));
234	} else {
235		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
236			 ("Polling FW ready fail!! MAC1 FW init not ready: "
237			 "0x%x .\n",
238			 rtl_read_byte(rtlpriv, FW_MAC1_READY)));
239	}
240	RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
241		 ("Polling FW ready fail!! REG_MCUFWDL:0x%08ul .\n",
242		 rtl_read_dword(rtlpriv, REG_MCUFWDL)));
243	return -1;
244}
245
246int rtl92d_download_fw(struct ieee80211_hw *hw)
247{
248	struct rtl_priv *rtlpriv = rtl_priv(hw);
249	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
250	u8 *pfwheader;
251	u8 *pfwdata;
252	u32 fwsize;
253	int err;
254	enum version_8192d version = rtlhal->version;
255	u8 value;
256	u32 count;
257	bool fw_downloaded = false, fwdl_in_process = false;
258	unsigned long flags;
259
260	if (!rtlhal->pfirmware)
261		return 1;
262	fwsize = rtlhal->fwsize;
263	pfwheader = (u8 *) rtlhal->pfirmware;
264	pfwdata = (u8 *) rtlhal->pfirmware;
265	rtlhal->fw_version = (u16) GET_FIRMWARE_HDR_VERSION(pfwheader);
266	rtlhal->fw_subversion = (u16) GET_FIRMWARE_HDR_SUB_VER(pfwheader);
267	RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, (" FirmwareVersion(%d),"
268		 "FirmwareSubVersion(%d), Signature(%#x)\n",
269		 rtlhal->fw_version,	rtlhal->fw_subversion,
270		 GET_FIRMWARE_HDR_SIGNATURE(pfwheader)));
271	if (IS_FW_HEADER_EXIST(pfwheader)) {
272		RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
273			 ("Shift 32 bytes for FW header!!\n"));
274		pfwdata = pfwdata + 32;
275		fwsize = fwsize - 32;
276	}
277
278	spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
279	fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv);
280	if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5))
281		fwdl_in_process = true;
282	else
283		fwdl_in_process = false;
284	if (fw_downloaded) {
285		spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
286		goto exit;
287	} else if (fwdl_in_process) {
288		spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
289		for (count = 0; count < 5000; count++) {
290			udelay(500);
291			spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
292			fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv);
293			if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5))
294				fwdl_in_process = true;
295			else
296				fwdl_in_process = false;
297			spin_unlock_irqrestore(&globalmutex_for_fwdownload,
298					       flags);
299			if (fw_downloaded)
300				goto exit;
301			else if (!fwdl_in_process)
302				break;
303			else
304				RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
305					 ("Wait for another mac "
306					 "download fw\n"));
307		}
308		spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
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	} else {
314		value = rtl_read_byte(rtlpriv, 0x1f);
315		value |= BIT(5);
316		rtl_write_byte(rtlpriv, 0x1f, value);
317		spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
318	}
319
320	/* If 8051 is running in RAM code, driver should
321	 * inform Fw to reset by itself, or it will cause
322	 * download Fw fail.*/
323	/* 8051 RAM code */
324	if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
325		rtl92d_firmware_selfreset(hw);
326		rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
327	}
328	_rtl92d_enable_fw_download(hw, true);
329	_rtl92d_write_fw(hw, version, pfwdata, fwsize);
330	_rtl92d_enable_fw_download(hw, false);
331	spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
332	err = _rtl92d_fw_free_to_go(hw);
333	/* download fw over,clear 0x1f[5] */
334	value = rtl_read_byte(rtlpriv, 0x1f);
335	value &= (~BIT(5));
336	rtl_write_byte(rtlpriv, 0x1f, value);
337	spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
338	if (err) {
339		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
340			 ("fw is not ready to run!\n"));
341		goto exit;
342	} else {
343		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
344			 ("fw is ready to run!\n"));
345	}
346exit:
347	err = _rtl92d_fw_init(hw);
348	return err;
349}
350
351static bool _rtl92d_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
352{
353	struct rtl_priv *rtlpriv = rtl_priv(hw);
354	u8 val_hmetfr;
355	bool result = false;
356
357	val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
358	if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
359		result = true;
360	return result;
361}
362
363static void _rtl92d_fill_h2c_command(struct ieee80211_hw *hw,
364			      u8 element_id, u32 cmd_len, u8 *cmdbuffer)
365{
366	struct rtl_priv *rtlpriv = rtl_priv(hw);
367	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
368	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
369	u8 boxnum;
370	u16 box_reg = 0, box_extreg = 0;
371	u8 u1b_tmp;
372	bool isfw_read = false;
373	u8 buf_index = 0;
374	bool bwrite_sucess = false;
375	u8 wait_h2c_limmit = 100;
376	u8 wait_writeh2c_limmit = 100;
377	u8 boxcontent[4], boxextcontent[2];
378	u32 h2c_waitcounter = 0;
379	unsigned long flag;
380	u8 idx;
381
382	if (ppsc->rfpwr_state == ERFOFF || ppsc->inactive_pwrstate == ERFOFF) {
383		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
384			 ("Return as RF is off!!!\n"));
385		return;
386	}
387	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("come in\n"));
388	while (true) {
389		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
390		if (rtlhal->h2c_setinprogress) {
391			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
392				 ("H2C set in progress! Wait to set.."
393				 "element_id(%d).\n", element_id));
394
395			while (rtlhal->h2c_setinprogress) {
396				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
397						       flag);
398				h2c_waitcounter++;
399				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
400					 ("Wait 100 us (%d times)...\n",
401					 h2c_waitcounter));
402				udelay(100);
403
404				if (h2c_waitcounter > 1000)
405					return;
406
407				spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
408						  flag);
409			}
410			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
411		} else {
412			rtlhal->h2c_setinprogress = true;
413			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
414			break;
415		}
416	}
417	while (!bwrite_sucess) {
418		wait_writeh2c_limmit--;
419		if (wait_writeh2c_limmit == 0) {
420			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
421				 ("Write H2C fail because no trigger "
422				 "for FW INT!\n"));
423			break;
424		}
425		boxnum = rtlhal->last_hmeboxnum;
426		switch (boxnum) {
427		case 0:
428			box_reg = REG_HMEBOX_0;
429			box_extreg = REG_HMEBOX_EXT_0;
430			break;
431		case 1:
432			box_reg = REG_HMEBOX_1;
433			box_extreg = REG_HMEBOX_EXT_1;
434			break;
435		case 2:
436			box_reg = REG_HMEBOX_2;
437			box_extreg = REG_HMEBOX_EXT_2;
438			break;
439		case 3:
440			box_reg = REG_HMEBOX_3;
441			box_extreg = REG_HMEBOX_EXT_3;
442			break;
443		default:
444			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
445				 ("switch case not process\n"));
446			break;
447		}
448		isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);
449		while (!isfw_read) {
450			wait_h2c_limmit--;
451			if (wait_h2c_limmit == 0) {
452				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
453					 ("Wating too long for FW read "
454					 "clear HMEBox(%d)!\n", boxnum));
455				break;
456			}
457			udelay(10);
458			isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);
459			u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
460			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
461				 ("Wating for FW read clear HMEBox(%d)!!! "
462				 "0x1BF = %2x\n", boxnum, u1b_tmp));
463		}
464		if (!isfw_read) {
465			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
466				 ("Write H2C register BOX[%d] fail!!!!! "
467				 "Fw do not read.\n", boxnum));
468			break;
469		}
470		memset(boxcontent, 0, sizeof(boxcontent));
471		memset(boxextcontent, 0, sizeof(boxextcontent));
472		boxcontent[0] = element_id;
473		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
474			 ("Write element_id box_reg(%4x) = %2x\n",
475			 box_reg, element_id));
476		switch (cmd_len) {
477		case 1:
478			boxcontent[0] &= ~(BIT(7));
479			memcpy(boxcontent + 1, cmdbuffer + buf_index, 1);
480			for (idx = 0; idx < 4; idx++)
481				rtl_write_byte(rtlpriv, box_reg + idx,
482					       boxcontent[idx]);
483			break;
484		case 2:
485			boxcontent[0] &= ~(BIT(7));
486			memcpy(boxcontent + 1, cmdbuffer + buf_index, 2);
487			for (idx = 0; idx < 4; idx++)
488				rtl_write_byte(rtlpriv, box_reg + idx,
489					       boxcontent[idx]);
490			break;
491		case 3:
492			boxcontent[0] &= ~(BIT(7));
493			memcpy(boxcontent + 1, cmdbuffer + buf_index, 3);
494			for (idx = 0; idx < 4; idx++)
495				rtl_write_byte(rtlpriv, box_reg + idx,
496					       boxcontent[idx]);
497			break;
498		case 4:
499			boxcontent[0] |= (BIT(7));
500			memcpy(boxextcontent, cmdbuffer + buf_index, 2);
501			memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 2);
502			for (idx = 0; idx < 2; idx++)
503				rtl_write_byte(rtlpriv, box_extreg + idx,
504					       boxextcontent[idx]);
505			for (idx = 0; idx < 4; idx++)
506				rtl_write_byte(rtlpriv, box_reg + idx,
507					       boxcontent[idx]);
508			break;
509		case 5:
510			boxcontent[0] |= (BIT(7));
511			memcpy(boxextcontent, cmdbuffer + buf_index, 2);
512			memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 3);
513			for (idx = 0; idx < 2; idx++)
514				rtl_write_byte(rtlpriv, box_extreg + idx,
515					       boxextcontent[idx]);
516			for (idx = 0; idx < 4; idx++)
517				rtl_write_byte(rtlpriv, box_reg + idx,
518					       boxcontent[idx]);
519			break;
520		default:
521			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
522				("switch case not process\n"));
523			break;
524		}
525		bwrite_sucess = true;
526		rtlhal->last_hmeboxnum = boxnum + 1;
527		if (rtlhal->last_hmeboxnum == 4)
528			rtlhal->last_hmeboxnum = 0;
529		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
530			 ("pHalData->last_hmeboxnum  = %d\n",
531			  rtlhal->last_hmeboxnum));
532	}
533	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
534	rtlhal->h2c_setinprogress = false;
535	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
536	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("go out\n"));
537}
538
539void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw,
540			 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
541{
542	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
543	u32 tmp_cmdbuf[2];
544
545	if (rtlhal->fw_ready == false) {
546		RT_ASSERT(false, ("return H2C cmd because of Fw "
547				  "download fail!!!\n"));
548		return;
549	}
550	memset(tmp_cmdbuf, 0, 8);
551	memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
552	_rtl92d_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
553	return;
554}
555
556void rtl92d_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
557{
558	struct rtl_priv *rtlpriv = rtl_priv(hw);
559	u8 u1_h2c_set_pwrmode[3] = { 0 };
560	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
561
562	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("FW LPS mode = %d\n", mode));
563	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
564	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
565	SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
566					      ppsc->reg_max_lps_awakeintvl);
567	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
568		      "rtl92d_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
569		      u1_h2c_set_pwrmode, 3);
570	rtl92d_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
571}
572
573static bool _rtl92d_cmd_send_packet(struct ieee80211_hw *hw,
574				    struct sk_buff *skb)
575{
576	struct rtl_priv *rtlpriv = rtl_priv(hw);
577	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
578	struct rtl8192_tx_ring *ring;
579	struct rtl_tx_desc *pdesc;
580	u8 idx = 0;
581	unsigned long flags;
582	struct sk_buff *pskb;
583
584	ring = &rtlpci->tx_ring[BEACON_QUEUE];
585	pskb = __skb_dequeue(&ring->queue);
586	if (pskb)
587		kfree_skb(pskb);
588	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
589	pdesc = &ring->desc[idx];
590	/* discard output from call below */
591	rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
592	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
593	__skb_queue_tail(&ring->queue, skb);
594	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
595	rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
596	return true;
597}
598
599#define BEACON_PG		0	/*->1 */
600#define PSPOLL_PG		2
601#define NULL_PG			3
602#define PROBERSP_PG		4	/*->5 */
603#define TOTAL_RESERVED_PKT_LEN	768
604
605static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
606	/* page 0 beacon */
607	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
608	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
609	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
610	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
611	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
612	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
613	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
614	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
615	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
616	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
617	0x03, 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	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
621	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
622	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
623
624	/* page 1 beacon */
625	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
626	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
627	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
628	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
629	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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	0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
638	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
639	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
640	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
641
642	/* page 2  ps-poll */
643	0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
644	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
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	0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
656	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
657	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
658	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
659
660	/* page 3  null */
661	0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
662	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
663	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 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	0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
674	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
675	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
676	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
677
678	/* page 4  probe_resp */
679	0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
680	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
681	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
682	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
683	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
684	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
685	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
686	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
687	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
688	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
689	0x03, 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	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
693	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
694	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
695
696	/* page 5  probe_resp */
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	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
701	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
702	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
703	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
704	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
705	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
706	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
707	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
708	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
709	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
710	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
711	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
712	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
713};
714
715void rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
716{
717	struct rtl_priv *rtlpriv = rtl_priv(hw);
718	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
719	struct sk_buff *skb = NULL;
720	u32 totalpacketlen;
721	bool rtstatus;
722	u8 u1RsvdPageLoc[3] = { 0 };
723	bool dlok = false;
724	u8 *beacon;
725	u8 *p_pspoll;
726	u8 *nullfunc;
727	u8 *p_probersp;
728	/*---------------------------------------------------------
729						(1) beacon
730	---------------------------------------------------------*/
731	beacon = &reserved_page_packet[BEACON_PG * 128];
732	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
733	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
734	/*-------------------------------------------------------
735						(2) ps-poll
736	--------------------------------------------------------*/
737	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
738	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
739	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
740	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
741	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
742	/*--------------------------------------------------------
743						(3) null data
744	---------------------------------------------------------*/
745	nullfunc = &reserved_page_packet[NULL_PG * 128];
746	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
747	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
748	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
749	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
750	/*---------------------------------------------------------
751						(4) probe response
752	----------------------------------------------------------*/
753	p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
754	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
755	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
756	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
757	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
758	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
759	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
760		      "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
761		      &reserved_page_packet[0], totalpacketlen);
762	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
763		      "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
764		      u1RsvdPageLoc, 3);
765	skb = dev_alloc_skb(totalpacketlen);
766	memcpy((u8 *) skb_put(skb, totalpacketlen), &reserved_page_packet,
767		totalpacketlen);
768	rtstatus = _rtl92d_cmd_send_packet(hw, skb);
769
770	if (rtstatus)
771		dlok = true;
772	if (dlok) {
773		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
774			("Set RSVD page location to Fw.\n"));
775		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
776			      "H2C_RSVDPAGE:\n", u1RsvdPageLoc, 3);
777		rtl92d_fill_h2c_cmd(hw, H2C_RSVDPAGE,
778			sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
779	} else
780		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
781			("Set RSVD page location to Fw FAIL!!!!!!.\n"));
782}
783
784void rtl92d_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
785{
786	u8 u1_joinbssrpt_parm[1] = {0};
787
788	SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
789	rtl92d_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
790}