1/******************************************************************************
2 *
3 * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
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 ******************************************************************************/
15#include <osdep_service.h>
16#include <drv_types.h>
17
18#include <hal_intf.h>
19#include <hal_com.h>
20#include <rtl8723a_hal.h>
21#include <usb_ops_linux.h>
22
23#define _HAL_INIT_C_
24
25void dump_chip_info23a(struct hal_version ChipVersion)
26{
27	int cnt = 0;
28	u8 buf[128];
29
30	cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8723A_");
31
32	cnt += sprintf((buf + cnt), "%s_", IS_NORMAL_CHIP(ChipVersion) ?
33		       "Normal_Chip" : "Test_Chip");
34	cnt += sprintf((buf + cnt), "%s_",
35		       IS_CHIP_VENDOR_TSMC(ChipVersion) ? "TSMC" : "UMC");
36	if (IS_A_CUT(ChipVersion))
37		cnt += sprintf((buf + cnt), "A_CUT_");
38	else if (IS_B_CUT(ChipVersion))
39		cnt += sprintf((buf + cnt), "B_CUT_");
40	else if (IS_C_CUT(ChipVersion))
41		cnt += sprintf((buf + cnt), "C_CUT_");
42	else if (IS_D_CUT(ChipVersion))
43		cnt += sprintf((buf + cnt), "D_CUT_");
44	else if (IS_E_CUT(ChipVersion))
45		cnt += sprintf((buf + cnt), "E_CUT_");
46	else
47		cnt += sprintf((buf + cnt), "UNKNOWN_CUT(%d)_",
48			       ChipVersion.CUTVersion);
49
50	if (IS_1T1R(ChipVersion))
51		cnt += sprintf((buf + cnt), "1T1R_");
52	else if (IS_1T2R(ChipVersion))
53		cnt += sprintf((buf + cnt), "1T2R_");
54	else if (IS_2T2R(ChipVersion))
55		cnt += sprintf((buf + cnt), "2T2R_");
56	else
57		cnt += sprintf((buf + cnt), "UNKNOWN_RFTYPE(%d)_",
58			       ChipVersion.RFType);
59
60	cnt += sprintf((buf + cnt), "RomVer(%d)\n", ChipVersion.ROMVer);
61
62	DBG_8723A("%s", buf);
63}
64
65#define	EEPROM_CHANNEL_PLAN_BY_HW_MASK	0x80
66
67/* return the final channel plan decision */
68/* hw_channel_plan:  channel plan from HW (efuse/eeprom) */
69/* sw_channel_plan:  channel plan from SW (registry/module param) */
70/* def_channel_plan: channel plan used when the former two is invalid */
71u8 hal_com_get_channel_plan23a(struct rtw_adapter *padapter, u8 hw_channel_plan,
72			    u8 sw_channel_plan, u8 def_channel_plan,
73			    bool AutoLoadFail)
74{
75	u8 swConfig;
76	u8 chnlPlan;
77
78	swConfig = true;
79	if (!AutoLoadFail) {
80		if (!rtw_is_channel_plan_valid(sw_channel_plan))
81			swConfig = false;
82		if (hw_channel_plan & EEPROM_CHANNEL_PLAN_BY_HW_MASK)
83			swConfig = false;
84	}
85
86	if (swConfig == true)
87		chnlPlan = sw_channel_plan;
88	else
89		chnlPlan = hw_channel_plan & (~EEPROM_CHANNEL_PLAN_BY_HW_MASK);
90
91	if (!rtw_is_channel_plan_valid(chnlPlan))
92		chnlPlan = def_channel_plan;
93
94	return chnlPlan;
95}
96
97u8 MRateToHwRate23a(u8 rate)
98{
99	u8 ret = DESC_RATE1M;
100
101	switch (rate) {
102		/*  CCK and OFDM non-HT rates */
103	case IEEE80211_CCK_RATE_1MB:
104		ret = DESC_RATE1M;
105		break;
106	case IEEE80211_CCK_RATE_2MB:
107		ret = DESC_RATE2M;
108		break;
109	case IEEE80211_CCK_RATE_5MB:
110		ret = DESC_RATE5_5M;
111		break;
112	case IEEE80211_CCK_RATE_11MB:
113		ret = DESC_RATE11M;
114		break;
115	case IEEE80211_OFDM_RATE_6MB:
116		ret = DESC_RATE6M;
117		break;
118	case IEEE80211_OFDM_RATE_9MB:
119		ret = DESC_RATE9M;
120		break;
121	case IEEE80211_OFDM_RATE_12MB:
122		ret = DESC_RATE12M;
123		break;
124	case IEEE80211_OFDM_RATE_18MB:
125		ret = DESC_RATE18M;
126		break;
127	case IEEE80211_OFDM_RATE_24MB:
128		ret = DESC_RATE24M;
129		break;
130	case IEEE80211_OFDM_RATE_36MB:
131		ret = DESC_RATE36M;
132		break;
133	case IEEE80211_OFDM_RATE_48MB:
134		ret = DESC_RATE48M;
135		break;
136	case IEEE80211_OFDM_RATE_54MB:
137		ret = DESC_RATE54M;
138		break;
139
140		/*  HT rates since here */
141		/* case MGN_MCS0:	ret = DESC_RATEMCS0;    break; */
142		/* case MGN_MCS1:	ret = DESC_RATEMCS1;    break; */
143		/* case MGN_MCS2:	ret = DESC_RATEMCS2;    break; */
144		/* case MGN_MCS3:	ret = DESC_RATEMCS3;    break; */
145		/* case MGN_MCS4:	ret = DESC_RATEMCS4;    break; */
146		/* case MGN_MCS5:	ret = DESC_RATEMCS5;    break; */
147		/* case MGN_MCS6:	ret = DESC_RATEMCS6;    break; */
148		/* case MGN_MCS7:	ret = DESC_RATEMCS7;    break; */
149
150	default:
151		break;
152	}
153	return ret;
154}
155
156void HalSetBrateCfg23a(struct rtw_adapter *padapter, u8 *mBratesOS)
157{
158	struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
159	u8 i, is_brate, brate;
160	u16 brate_cfg = 0;
161	u8 rate_index;
162
163	for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
164		is_brate = mBratesOS[i] & IEEE80211_BASIC_RATE_MASK;
165		brate = mBratesOS[i] & 0x7f;
166
167		if (is_brate) {
168			switch (brate) {
169			case IEEE80211_CCK_RATE_1MB:
170				brate_cfg |= RATE_1M;
171				break;
172			case IEEE80211_CCK_RATE_2MB:
173				brate_cfg |= RATE_2M;
174				break;
175			case IEEE80211_CCK_RATE_5MB:
176				brate_cfg |= RATE_5_5M;
177				break;
178			case IEEE80211_CCK_RATE_11MB:
179				brate_cfg |= RATE_11M;
180				break;
181			case IEEE80211_OFDM_RATE_6MB:
182				brate_cfg |= RATE_6M;
183				break;
184			case IEEE80211_OFDM_RATE_9MB:
185				brate_cfg |= RATE_9M;
186				break;
187			case IEEE80211_OFDM_RATE_12MB:
188				brate_cfg |= RATE_12M;
189				break;
190			case IEEE80211_OFDM_RATE_18MB:
191				brate_cfg |= RATE_18M;
192				break;
193			case IEEE80211_OFDM_RATE_24MB:
194				brate_cfg |= RATE_24M;
195				break;
196			case IEEE80211_OFDM_RATE_36MB:
197				brate_cfg |= RATE_36M;
198				break;
199			case IEEE80211_OFDM_RATE_48MB:
200				brate_cfg |= RATE_48M;
201				break;
202			case IEEE80211_OFDM_RATE_54MB:
203				brate_cfg |= RATE_54M;
204				break;
205			}
206		}
207	}
208
209	/*  2007.01.16, by Emily */
210	/*  Select RRSR (in Legacy-OFDM and CCK) */
211	/*  For 8190, we select only 24M, 12M, 6M, 11M, 5.5M, 2M,
212	    and 1M from the Basic rate. */
213	/*  We do not use other rates. */
214	/* 2011.03.30 add by Luke Lee */
215	/* CCK 2M ACK should be disabled for some BCM and Atheros AP IOT */
216	/* because CCK 2M has poor TXEVM */
217	/* CCK 5.5M & 11M ACK should be enabled for better
218	   performance */
219
220	brate_cfg = (brate_cfg | 0xd) & 0x15d;
221	pHalData->BasicRateSet = brate_cfg;
222	brate_cfg |= 0x01;	/*  default enable 1M ACK rate */
223	DBG_8723A("HW_VAR_BASIC_RATE: BrateCfg(%#x)\n", brate_cfg);
224
225	/*  Set RRSR rate table. */
226	rtl8723au_write8(padapter, REG_RRSR, brate_cfg & 0xff);
227	rtl8723au_write8(padapter, REG_RRSR + 1, (brate_cfg >> 8) & 0xff);
228	rtl8723au_write8(padapter, REG_RRSR + 2,
229			 rtl8723au_read8(padapter, REG_RRSR + 2) & 0xf0);
230
231	rate_index = 0;
232	/*  Set RTS initial rate */
233	while (brate_cfg > 0x1) {
234		brate_cfg = (brate_cfg >> 1);
235		rate_index++;
236	}
237		/*  Ziv - Check */
238	rtl8723au_write8(padapter, REG_INIRTS_RATE_SEL, rate_index);
239
240	return;
241}
242
243static void _OneOutPipeMapping(struct rtw_adapter *pAdapter)
244{
245	struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(pAdapter);
246
247	pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];	/* VO */
248	pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];	/* VI */
249	pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[0];	/* BE */
250	pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];	/* BK */
251
252	pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];	/* BCN */
253	pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];	/* MGT */
254	pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];	/* HIGH */
255	pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];	/* TXCMD */
256}
257
258static void _TwoOutPipeMapping(struct rtw_adapter *pAdapter, bool bWIFICfg)
259{
260	struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(pAdapter);
261
262	if (bWIFICfg) {		/* WMM */
263		/*    BK,   BE,   VI,   VO,   BCN,  CMD,  MGT, HIGH, HCCA */
264		/*     0,    1,    0,    1,     0,    0,    0,    0,    0 }; */
265		/* 0:H, 1:L */
266		pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[1]; /* VO */
267		pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0]; /* VI */
268		pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1]; /* BE */
269		pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0]; /* BK */
270
271		pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0]; /* BCN */
272		pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0]; /* MGT */
273		pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0]; /* HIGH */
274		pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0]; /* TXCMD*/
275	} else {		/* typical setting */
276		/*    BK,   BE,   VI,   VO,   BCN,  CMD,  MGT, HIGH, HCCA */
277		/*     1,    1,    0,    0,     0,    0,    0,    0,    0 }; */
278		/* 0:H, 1:L */
279		pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0]; /* VO */
280		pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0]; /* VI */
281		pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1]; /* BE */
282		pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1]; /* BK */
283
284		pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0]; /* BCN */
285		pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0]; /* MGT */
286		pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0]; /* HIGH */
287		pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0]; /* TXCMD*/
288	}
289}
290
291static void _ThreeOutPipeMapping(struct rtw_adapter *pAdapter, bool bWIFICfg)
292{
293	struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(pAdapter);
294
295	if (bWIFICfg) {		/* for WMM */
296		/*    BK,   BE,   VI,   VO,   BCN,  CMD,  MGT, HIGH, HCCA */
297		/*     1,    2,    1,    0,     0,    0,    0,    0,    0 }; */
298		/* 0:H, 1:N, 2:L */
299		pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0]; /* VO */
300		pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1]; /* VI */
301		pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2]; /* BE */
302		pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1]; /* BK */
303
304		pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0]; /* BCN */
305		pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0]; /* MGT */
306		pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0]; /* HIGH */
307		pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0]; /* TXCMD*/
308	} else {		/* typical setting */
309		/*    BK,   BE,   VI,   VO,   BCN,  CMD,  MGT, HIGH, HCCA */
310		/*     2,    2,    1,    0,     0,    0,    0,    0,    0 }; */
311		/* 0:H, 1:N, 2:L */
312		pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0]; /* VO */
313		pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1]; /* VI */
314		pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2]; /* BE */
315		pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[2]; /* BK */
316
317		pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0]; /* BCN */
318		pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0]; /* MGT */
319		pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0]; /* HIGH */
320		pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0]; /* TXCMD*/
321	}
322}
323
324bool Hal_MappingOutPipe23a(struct rtw_adapter *pAdapter, u8 NumOutPipe)
325{
326	struct registry_priv *pregistrypriv = &pAdapter->registrypriv;
327	bool bWIFICfg = (pregistrypriv->wifi_spec) ? true : false;
328	bool result = true;
329
330	switch (NumOutPipe) {
331	case 2:
332		_TwoOutPipeMapping(pAdapter, bWIFICfg);
333		break;
334	case 3:
335		_ThreeOutPipeMapping(pAdapter, bWIFICfg);
336		break;
337	case 1:
338		_OneOutPipeMapping(pAdapter);
339		break;
340	default:
341		result = false;
342		break;
343	}
344
345	return result;
346}
347
348/*
349* C2H event format:
350* Field	 TRIGGER		CONTENT	   CMD_SEQ	CMD_LEN		 CMD_ID
351* BITS	 [127:120]	[119:16]      [15:8]		  [7:4]		   [3:0]
352*/
353
354void c2h_evt_clear23a(struct rtw_adapter *adapter)
355{
356	rtl8723au_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE);
357}
358
359int c2h_evt_read23a(struct rtw_adapter *adapter, u8 *buf)
360{
361	int ret = _FAIL;
362	struct c2h_evt_hdr *c2h_evt;
363	int i;
364	u8 trigger;
365
366	if (buf == NULL)
367		goto exit;
368
369	trigger = rtl8723au_read8(adapter, REG_C2HEVT_CLEAR);
370
371	if (trigger == C2H_EVT_HOST_CLOSE)
372		goto exit;	/* Not ready */
373	else if (trigger != C2H_EVT_FW_CLOSE)
374		goto clear_evt;	/* Not a valid value */
375
376	c2h_evt = (struct c2h_evt_hdr *)buf;
377
378	memset(c2h_evt, 0, 16);
379
380	*buf = rtl8723au_read8(adapter, REG_C2HEVT_MSG_NORMAL);
381	*(buf + 1) = rtl8723au_read8(adapter, REG_C2HEVT_MSG_NORMAL + 1);
382
383	RT_PRINT_DATA(_module_hal_init_c_, _drv_info_, "c2h_evt_read23a(): ",
384		      &c2h_evt, sizeof(c2h_evt));
385
386	if (0) {
387		DBG_8723A("%s id:%u, len:%u, seq:%u, trigger:0x%02x\n",
388			  __func__, c2h_evt->id, c2h_evt->plen, c2h_evt->seq,
389			  trigger);
390	}
391
392	/* Read the content */
393	for (i = 0; i < c2h_evt->plen; i++)
394		c2h_evt->payload[i] = rtl8723au_read8(adapter,
395						REG_C2HEVT_MSG_NORMAL +
396						sizeof(*c2h_evt) + i);
397
398	RT_PRINT_DATA(_module_hal_init_c_, _drv_info_,
399		      "c2h_evt_read23a(): Command Content:\n", c2h_evt->payload,
400		      c2h_evt->plen);
401
402	ret = _SUCCESS;
403
404clear_evt:
405	/*
406	 * Clear event to notify FW we have read the command.
407	 * If this field isn't clear, the FW won't update the
408	 * next command message.
409	 */
410	c2h_evt_clear23a(adapter);
411exit:
412	return ret;
413}
414
415void
416rtl8723a_set_ampdu_min_space(struct rtw_adapter *padapter, u8 MinSpacingToSet)
417{
418	u8 SecMinSpace;
419
420	if (MinSpacingToSet <= 7) {
421		switch (padapter->securitypriv.dot11PrivacyAlgrthm) {
422		case 0:
423		case WLAN_CIPHER_SUITE_CCMP:
424			SecMinSpace = 0;
425			break;
426
427		case WLAN_CIPHER_SUITE_WEP40:
428		case WLAN_CIPHER_SUITE_WEP104:
429		case WLAN_CIPHER_SUITE_TKIP:
430			SecMinSpace = 6;
431			break;
432		default:
433			SecMinSpace = 7;
434			break;
435		}
436
437		if (MinSpacingToSet < SecMinSpace)
438			MinSpacingToSet = SecMinSpace;
439
440		/* RT_TRACE(COMP_MLME, DBG_LOUD,
441		   ("Set HW_VAR_AMPDU_MIN_SPACE: %#x\n",
442		   padapter->MgntInfo.MinSpaceCfg)); */
443		MinSpacingToSet |=
444			rtl8723au_read8(padapter, REG_AMPDU_MIN_SPACE) & 0xf8;
445		rtl8723au_write8(padapter, REG_AMPDU_MIN_SPACE,
446				 MinSpacingToSet);
447	}
448}
449
450void rtl8723a_set_ampdu_factor(struct rtw_adapter *padapter, u8 FactorToSet)
451{
452	u8 RegToSet_Normal[4] = { 0x41, 0xa8, 0x72, 0xb9 };
453	u8 MaxAggNum;
454	u8 *pRegToSet;
455	u8 index = 0;
456
457	pRegToSet = RegToSet_Normal;	/*  0xb972a841; */
458
459	if (rtl8723a_BT_enabled(padapter) &&
460	    rtl8723a_BT_using_antenna_1(padapter))
461		MaxAggNum = 0x8;
462	else
463		MaxAggNum = 0xF;
464
465	if (FactorToSet <= 3) {
466		FactorToSet = (1 << (FactorToSet + 2));
467		if (FactorToSet > MaxAggNum)
468			FactorToSet = MaxAggNum;
469
470		for (index = 0; index < 4; index++) {
471			if ((pRegToSet[index] & 0xf0) > (FactorToSet << 4))
472				pRegToSet[index] = (pRegToSet[index] & 0x0f) |
473					(FactorToSet << 4);
474
475			if ((pRegToSet[index] & 0x0f) > FactorToSet)
476				pRegToSet[index] = (pRegToSet[index] & 0xf0) |
477					FactorToSet;
478
479			rtl8723au_write8(padapter, REG_AGGLEN_LMT + index,
480					 pRegToSet[index]);
481		}
482
483		/* RT_TRACE(COMP_MLME, DBG_LOUD,
484		   ("Set HW_VAR_AMPDU_FACTOR: %#x\n", FactorToSet)); */
485	}
486}
487
488void rtl8723a_set_acm_ctrl(struct rtw_adapter *padapter, u8 ctrl)
489{
490	u8 hwctrl = 0;
491
492	if (ctrl != 0) {
493		hwctrl |= AcmHw_HwEn;
494
495		if (ctrl & BIT(1))	/*  BE */
496			hwctrl |= AcmHw_BeqEn;
497
498		if (ctrl & BIT(2))	/*  VI */
499			hwctrl |= AcmHw_ViqEn;
500
501		if (ctrl & BIT(3))	/*  VO */
502			hwctrl |= AcmHw_VoqEn;
503	}
504
505	DBG_8723A("[HW_VAR_ACM_CTRL] Write 0x%02X\n", hwctrl);
506	rtl8723au_write8(padapter, REG_ACMHWCTRL, hwctrl);
507}
508
509void rtl8723a_set_media_status(struct rtw_adapter *padapter, u8 status)
510{
511	u8 val8;
512
513	val8 = rtl8723au_read8(padapter, MSR) & 0x0c;
514	val8 |= status;
515	rtl8723au_write8(padapter, MSR, val8);
516}
517
518void rtl8723a_set_media_status1(struct rtw_adapter *padapter, u8 status)
519{
520	u8 val8;
521
522	val8 = rtl8723au_read8(padapter, MSR) & 0x03;
523	val8 |= status << 2;
524	rtl8723au_write8(padapter, MSR, val8);
525}
526
527void rtl8723a_set_bcn_func(struct rtw_adapter *padapter, u8 val)
528{
529	if (val)
530		SetBcnCtrlReg23a(padapter, EN_BCN_FUNCTION | EN_TXBCN_RPT, 0);
531	else
532		SetBcnCtrlReg23a(padapter, 0, EN_BCN_FUNCTION | EN_TXBCN_RPT);
533}
534
535void rtl8723a_check_bssid(struct rtw_adapter *padapter, u8 val)
536{
537	u32 val32;
538
539	val32 = rtl8723au_read32(padapter, REG_RCR);
540	if (val)
541		val32 |= RCR_CBSSID_DATA | RCR_CBSSID_BCN;
542	else
543		val32 &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN);
544	rtl8723au_write32(padapter, REG_RCR, val32);
545}
546
547void rtl8723a_mlme_sitesurvey(struct rtw_adapter *padapter, u8 flag)
548{
549	if (flag) {	/* under sitesurvey */
550		u32 v32;
551
552		/*  config RCR to receive different BSSID & not
553		    to receive data frame */
554		v32 = rtl8723au_read32(padapter, REG_RCR);
555		v32 &= ~(RCR_CBSSID_BCN);
556		rtl8723au_write32(padapter, REG_RCR, v32);
557		/*  reject all data frame */
558		rtl8723au_write16(padapter, REG_RXFLTMAP2, 0);
559
560		/*  disable update TSF */
561		SetBcnCtrlReg23a(padapter, DIS_TSF_UDT, 0);
562	} else {	/* sitesurvey done */
563
564		struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
565		struct mlme_ext_info *pmlmeinfo;
566		u32 v32;
567
568		pmlmeinfo = &pmlmeext->mlmext_info;
569
570		if ((is_client_associated_to_ap23a(padapter) == true) ||
571		    ((pmlmeinfo->state & 0x03) == MSR_ADHOC) ||
572		    ((pmlmeinfo->state & 0x03) == MSR_AP)) {
573			/*  enable to rx data frame */
574			rtl8723au_write16(padapter, REG_RXFLTMAP2, 0xFFFF);
575
576			/*  enable update TSF */
577			SetBcnCtrlReg23a(padapter, 0, DIS_TSF_UDT);
578		}
579
580		v32 = rtl8723au_read32(padapter, REG_RCR);
581		v32 |= RCR_CBSSID_BCN;
582		rtl8723au_write32(padapter, REG_RCR, v32);
583	}
584
585	rtl8723a_BT_wifiscan_notify(padapter, flag ? true : false);
586}
587
588void rtl8723a_on_rcr_am(struct rtw_adapter *padapter)
589{
590	rtl8723au_write32(padapter, REG_RCR,
591		    rtl8723au_read32(padapter, REG_RCR) | RCR_AM);
592	DBG_8723A("%s, %d, RCR = %x\n", __func__, __LINE__,
593		  rtl8723au_read32(padapter, REG_RCR));
594}
595
596void rtl8723a_off_rcr_am(struct rtw_adapter *padapter)
597{
598	rtl8723au_write32(padapter, REG_RCR,
599		    rtl8723au_read32(padapter, REG_RCR) & (~RCR_AM));
600	DBG_8723A("%s, %d, RCR = %x\n", __func__, __LINE__,
601		  rtl8723au_read32(padapter, REG_RCR));
602}
603
604void rtl8723a_set_slot_time(struct rtw_adapter *padapter, u8 slottime)
605{
606	u8 u1bAIFS, aSifsTime;
607	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
608	struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
609
610	rtl8723au_write8(padapter, REG_SLOT, slottime);
611
612	if (pmlmeinfo->WMM_enable == 0) {
613		if (pmlmeext->cur_wireless_mode == WIRELESS_11B)
614			aSifsTime = 10;
615		else
616			aSifsTime = 16;
617
618		u1bAIFS = aSifsTime + (2 * pmlmeinfo->slotTime);
619
620		/*  <Roger_EXP> Temporary removed, 2008.06.20. */
621		rtl8723au_write8(padapter, REG_EDCA_VO_PARAM, u1bAIFS);
622		rtl8723au_write8(padapter, REG_EDCA_VI_PARAM, u1bAIFS);
623		rtl8723au_write8(padapter, REG_EDCA_BE_PARAM, u1bAIFS);
624		rtl8723au_write8(padapter, REG_EDCA_BK_PARAM, u1bAIFS);
625	}
626}
627
628void rtl8723a_ack_preamble(struct rtw_adapter *padapter, u8 bShortPreamble)
629{
630	struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
631	u8 regTmp;
632
633	/*  Joseph marked out for Netgear 3500 TKIP
634	    channel 7 issue.(Temporarily) */
635	regTmp = (pHalData->nCur40MhzPrimeSC) << 5;
636	/* regTmp = 0; */
637	if (bShortPreamble)
638		regTmp |= 0x80;
639	rtl8723au_write8(padapter, REG_RRSR + 2, regTmp);
640}
641
642void rtl8723a_set_sec_cfg(struct rtw_adapter *padapter, u8 sec)
643{
644	rtl8723au_write8(padapter, REG_SECCFG, sec);
645}
646
647void rtl8723a_cam_empty_entry(struct rtw_adapter *padapter, u8 ucIndex)
648{
649	u8 i;
650	u32 ulCommand = 0;
651	u32 ulContent = 0;
652	u32 ulEncAlgo = CAM_AES;
653
654	for (i = 0; i < CAM_CONTENT_COUNT; i++) {
655		/*  filled id in CAM config 2 byte */
656		if (i == 0) {
657			ulContent |= (ucIndex & 0x03) |
658				((u16) (ulEncAlgo) << 2);
659			/* ulContent |= CAM_VALID; */
660		} else {
661			ulContent = 0;
662		}
663		/*  polling bit, and No Write enable, and address */
664		ulCommand = CAM_CONTENT_COUNT * ucIndex + i;
665		ulCommand = ulCommand | CAM_POLLINIG | CAM_WRITE;
666		/*  write content 0 is equall to mark invalid */
667		/* delay_ms(40); */
668		rtl8723au_write32(padapter, WCAMI, ulContent);
669		/* RT_TRACE(COMP_SEC, DBG_LOUD,
670		   ("rtl8723a_cam_empty_entry(): WRITE A4: %lx\n",
671		   ulContent));*/
672		/* delay_ms(40); */
673		rtl8723au_write32(padapter, REG_CAMCMD, ulCommand);
674		/* RT_TRACE(COMP_SEC, DBG_LOUD,
675		   ("rtl8723a_cam_empty_entry(): WRITE A0: %lx\n",
676		   ulCommand));*/
677	}
678}
679
680void rtl8723a_cam_invalidate_all(struct rtw_adapter *padapter)
681{
682	rtl8723au_write32(padapter, REG_CAMCMD, CAM_POLLINIG | BIT(30));
683}
684
685void rtl8723a_cam_write(struct rtw_adapter *padapter,
686			u8 entry, u16 ctrl, const u8 *mac, const u8 *key)
687{
688	u32 cmd;
689	unsigned int i, val, addr;
690	int j;
691
692	addr = entry << 3;
693
694	for (j = 5; j >= 0; j--) {
695		switch (j) {
696		case 0:
697			val = ctrl | (mac[0] << 16) | (mac[1] << 24);
698			break;
699		case 1:
700			val = mac[2] | (mac[3] << 8) |
701				(mac[4] << 16) | (mac[5] << 24);
702			break;
703		default:
704			i = (j - 2) << 2;
705			val = key[i] | (key[i+1] << 8) |
706				(key[i+2] << 16) | (key[i+3] << 24);
707			break;
708		}
709
710		rtl8723au_write32(padapter, WCAMI, val);
711		cmd = CAM_POLLINIG | CAM_WRITE | (addr + j);
712		rtl8723au_write32(padapter, REG_CAMCMD, cmd);
713
714		/* DBG_8723A("%s => cam write: %x, %x\n", __func__, cmd, val);*/
715	}
716}
717
718void rtl8723a_fifo_cleanup(struct rtw_adapter *padapter)
719{
720#define RW_RELEASE_EN		BIT(18)
721#define RXDMA_IDLE		BIT(17)
722
723	struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
724	u8 trycnt = 100;
725
726	/*  pause tx */
727	rtl8723au_write8(padapter, REG_TXPAUSE, 0xff);
728
729	/*  keep sn */
730	padapter->xmitpriv.nqos_ssn = rtl8723au_read16(padapter, REG_NQOS_SEQ);
731
732	if (pwrpriv->bkeepfwalive != true) {
733		u32 v32;
734
735		/*  RX DMA stop */
736		v32 = rtl8723au_read32(padapter, REG_RXPKT_NUM);
737		v32 |= RW_RELEASE_EN;
738		rtl8723au_write32(padapter, REG_RXPKT_NUM, v32);
739		do {
740			v32 = rtl8723au_read32(padapter,
741					       REG_RXPKT_NUM) & RXDMA_IDLE;
742			if (!v32)
743				break;
744		} while (trycnt--);
745		if (trycnt == 0)
746			DBG_8723A("Stop RX DMA failed......\n");
747
748		/*  RQPN Load 0 */
749		rtl8723au_write16(padapter, REG_RQPN_NPQ, 0);
750		rtl8723au_write32(padapter, REG_RQPN, 0x80000000);
751		mdelay(10);
752	}
753}
754
755void rtl8723a_bcn_valid(struct rtw_adapter *padapter)
756{
757	/* BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2,
758	   write 1 to clear, Clear by sw */
759	rtl8723au_write8(padapter, REG_TDECTRL + 2,
760			 rtl8723au_read8(padapter, REG_TDECTRL + 2) | BIT(0));
761}
762
763bool rtl8723a_get_bcn_valid(struct rtw_adapter *padapter)
764{
765	bool retval;
766
767	retval = (rtl8723au_read8(padapter, REG_TDECTRL + 2) & BIT(0)) ? true : false;
768
769	return retval;
770}
771
772void rtl8723a_set_beacon_interval(struct rtw_adapter *padapter, u16 interval)
773{
774	rtl8723au_write16(padapter, REG_BCN_INTERVAL, interval);
775}
776
777void rtl8723a_set_resp_sifs(struct rtw_adapter *padapter,
778			    u8 r2t1, u8 r2t2, u8 t2t1, u8 t2t2)
779{
780	/* SIFS_Timer = 0x0a0a0808; */
781	/* RESP_SIFS for CCK */
782	/*  SIFS_T2T_CCK (0x08) */
783	rtl8723au_write8(padapter, REG_R2T_SIFS, r2t1);
784	/* SIFS_R2T_CCK(0x08) */
785	rtl8723au_write8(padapter, REG_R2T_SIFS + 1, r2t2);
786	/* RESP_SIFS for OFDM */
787	/* SIFS_T2T_OFDM (0x0a) */
788	rtl8723au_write8(padapter, REG_T2T_SIFS, t2t1);
789	/* SIFS_R2T_OFDM(0x0a) */
790	rtl8723au_write8(padapter, REG_T2T_SIFS + 1, t2t2);
791}
792
793void rtl8723a_set_ac_param_vo(struct rtw_adapter *padapter, u32 vo)
794{
795	rtl8723au_write32(padapter, REG_EDCA_VO_PARAM, vo);
796}
797
798void rtl8723a_set_ac_param_vi(struct rtw_adapter *padapter, u32 vi)
799{
800	rtl8723au_write32(padapter, REG_EDCA_VI_PARAM, vi);
801}
802
803void rtl8723a_set_ac_param_be(struct rtw_adapter *padapter, u32 be)
804{
805	struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
806
807	pHalData->AcParam_BE = be;
808	rtl8723au_write32(padapter, REG_EDCA_BE_PARAM, be);
809}
810
811void rtl8723a_set_ac_param_bk(struct rtw_adapter *padapter, u32 bk)
812{
813	rtl8723au_write32(padapter, REG_EDCA_BK_PARAM, bk);
814}
815
816void rtl8723a_set_rxdma_agg_pg_th(struct rtw_adapter *padapter, u8 val)
817{
818	rtl8723au_write8(padapter, REG_RXDMA_AGG_PG_TH, val);
819}
820
821void rtl8723a_set_initial_gain(struct rtw_adapter *padapter, u32 rx_gain)
822{
823	struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
824	struct dig_t *pDigTable = &pHalData->odmpriv.DM_DigTable;
825
826	if (rx_gain == 0xff)	/* restore rx gain */
827		ODM_Write_DIG23a(&pHalData->odmpriv, pDigTable->BackupIGValue);
828	else {
829		pDigTable->BackupIGValue = pDigTable->CurIGValue;
830		ODM_Write_DIG23a(&pHalData->odmpriv, rx_gain);
831	}
832}
833
834void rtl8723a_odm_support_ability_restore(struct rtw_adapter *padapter)
835{
836	struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
837
838	pHalData->odmpriv.SupportAbility = pHalData->odmpriv.BK_SupportAbility;
839}
840
841void rtl8723a_odm_support_ability_backup(struct rtw_adapter *padapter)
842{
843	struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
844
845	pHalData->odmpriv.BK_SupportAbility = pHalData->odmpriv.SupportAbility;
846}
847
848void rtl8723a_odm_support_ability_set(struct rtw_adapter *padapter, u32 val)
849{
850	struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
851
852	if (val == DYNAMIC_ALL_FUNC_ENABLE)
853		pHalData->odmpriv.SupportAbility = pHalData->dmpriv.InitODMFlag;
854	else
855		pHalData->odmpriv.SupportAbility |= val;
856}
857
858void rtl8723a_odm_support_ability_clr(struct rtw_adapter *padapter, u32 val)
859{
860	struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
861
862	pHalData->odmpriv.SupportAbility &= val;
863}
864
865void rtl8723a_set_rpwm(struct rtw_adapter *padapter, u8 val)
866{
867	rtl8723au_write8(padapter, REG_USB_HRPWM, val);
868}
869
870u8 rtl8723a_get_rf_type(struct rtw_adapter *padapter)
871{
872	struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
873
874	return pHalData->rf_type;
875}
876
877bool rtl8723a_get_fwlps_rf_on(struct rtw_adapter *padapter)
878{
879	bool retval;
880	u32 valRCR;
881
882	/*  When we halt NIC, we should check if FW LPS is leave. */
883
884	if ((padapter->bSurpriseRemoved == true) ||
885	    (padapter->pwrctrlpriv.rf_pwrstate == rf_off)) {
886		/*  If it is in HW/SW Radio OFF or IPS state, we do
887		    not check Fw LPS Leave, because Fw is unload. */
888		retval = true;
889	} else {
890		valRCR = rtl8723au_read32(padapter, REG_RCR);
891		if (valRCR & 0x00070000)
892			retval = false;
893		else
894			retval = true;
895	}
896
897	return retval;
898}
899
900bool rtl8723a_chk_hi_queue_empty(struct rtw_adapter *padapter)
901{
902	u32 hgq;
903
904	hgq = rtl8723au_read32(padapter, REG_HGQ_INFORMATION);
905
906	return ((hgq & 0x0000ff00) == 0) ? true : false;
907}
908